feat(release): add Alibaba Cloud OSS distribution (#166)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
name: Test Alibaba Cloud OSS publishing
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
staging:
|
||||
name: Verify GitHub OIDC staging access
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
environment:
|
||||
name: oss-staging
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Validate OSS environment configuration
|
||||
env:
|
||||
ALIYUN_OIDC_PROVIDER_ARN: ${{ vars.ALIYUN_OIDC_PROVIDER_ARN }}
|
||||
ALIYUN_ROLE_ARN: ${{ vars.ALIYUN_ROLE_ARN }}
|
||||
OSS_BUCKET: ${{ vars.OSS_BUCKET }}
|
||||
OSS_REGION: ${{ vars.OSS_REGION }}
|
||||
OSS_ENDPOINT: ${{ vars.OSS_ENDPOINT }}
|
||||
OSS_PUBLIC_BASE_URL: ${{ vars.OSS_PUBLIC_BASE_URL }}
|
||||
run: |
|
||||
set -eu
|
||||
for name in ALIYUN_OIDC_PROVIDER_ARN ALIYUN_ROLE_ARN OSS_BUCKET OSS_REGION OSS_ENDPOINT OSS_PUBLIC_BASE_URL; do
|
||||
eval "value=\${$name:-}"
|
||||
if [ -z "$value" ]; then
|
||||
echo "error: $name is not configured in the oss-staging environment" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Download and verify ossutil
|
||||
run: |
|
||||
sh scripts/install-ossutil.sh "$RUNNER_TEMP/ossutil-bin"
|
||||
echo "$RUNNER_TEMP/ossutil-bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Exchange GitHub OIDC token for Alibaba Cloud credentials
|
||||
id: aliyun
|
||||
uses: aliyun/configure-aliyun-credentials-action@1e5248c8d5d93a8781ac344a68e19a43341e79e6
|
||||
with:
|
||||
oidc-provider-arn: ${{ vars.ALIYUN_OIDC_PROVIDER_ARN }}
|
||||
role-to-assume: ${{ vars.ALIYUN_ROLE_ARN }}
|
||||
role-session-name: penguin-oss-staging-${{ github.run_id }}
|
||||
role-session-expiration: 1800
|
||||
audience: github-actions
|
||||
|
||||
- name: Verify staging access boundaries
|
||||
env:
|
||||
OSS_ACCESS_KEY_ID: ${{ steps.aliyun.outputs['aliyun-access-key-id'] }}
|
||||
OSS_ACCESS_KEY_SECRET: ${{ steps.aliyun.outputs['aliyun-access-key-secret'] }}
|
||||
OSS_SESSION_TOKEN: ${{ steps.aliyun.outputs['aliyun-security-token'] }}
|
||||
OSS_BUCKET: ${{ vars.OSS_BUCKET }}
|
||||
OSS_REGION: ${{ vars.OSS_REGION }}
|
||||
OSS_ENDPOINT: ${{ vars.OSS_ENDPOINT }}
|
||||
OSS_PUBLIC_BASE_URL: ${{ vars.OSS_PUBLIC_BASE_URL }}
|
||||
run: sh scripts/test-oss-staging.sh
|
||||
@@ -1,8 +1,8 @@
|
||||
# Release: tag v* -> build the one-line install artifacts and publish a GitHub Release.
|
||||
# Releases are immutable: once published, assets can never be replaced. A tiny check-release
|
||||
# job therefore gates the release job on the tag's Release not existing yet — dispatching an
|
||||
# already-released tag skips the build/upload entirely and only re-runs npm publishing.
|
||||
# Two parallel jobs (the release job is gated on the existence check):
|
||||
# already-released tag skips the GitHub build/upload while still retrying the OSS mirror and npm publishing.
|
||||
# Release jobs (the release job is gated on the existence check):
|
||||
# - release: build the monorepo -> pnpm deploy a production CLI dir -> assemble penguin/ (bin + lib + web)
|
||||
# -> one program payload per target (four platform payloads bundling the official Node runtime,
|
||||
# a win-x64 payload with runtime + MinGit, and a runtime-less universal payload) -> wrap each
|
||||
@@ -31,6 +31,10 @@
|
||||
# that failed mid-chain can be re-run as-is after fixing the config.
|
||||
# npm publishing lives here rather than a separate `on: release: published` workflow: the Release is created
|
||||
# by this workflow's GITHUB_TOKEN, and GitHub won't trigger other workflows' release events from that.
|
||||
# - mirror-oss: download the exact GitHub Release assets, verify their checksums, then mirror the same bytes
|
||||
# to immutable releases/<tag>/ keys in Alibaba Cloud OSS through GitHub OIDC. The GitHub Environment
|
||||
# `oss-production` supplies the provider/role ARNs and OSS settings. latest.json is uploaded last and only
|
||||
# when the tag is still GitHub's current latest Release. Manual retries also work after a Release exists.
|
||||
name: Release
|
||||
|
||||
on:
|
||||
@@ -54,7 +58,7 @@ env:
|
||||
|
||||
jobs:
|
||||
# Skip the build/upload when the tag's Release already exists (immutable releases forbid
|
||||
# replacing assets, so re-uploading can only fail; npm publishing is idempotent on its own).
|
||||
# replacing assets, so re-uploading can only fail; OSS mirroring and npm publishing are idempotent).
|
||||
check-release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -278,7 +282,7 @@ jobs:
|
||||
- name: Generate SHA256SUMS
|
||||
run: |
|
||||
cd dist-artifacts
|
||||
sha256sum *.tar.gz *.zip > SHA256SUMS
|
||||
sha256sum -- *.tar.gz *.zip > SHA256SUMS
|
||||
|
||||
# Release notes come from changelog/<version>/RELEASE.md, written during release preparation and
|
||||
# committed BEFORE the tag (the release job runs on the tag's checkout, so a file added afterwards
|
||||
@@ -319,6 +323,98 @@ jobs:
|
||||
install.sh
|
||||
install.ps1
|
||||
|
||||
mirror-oss:
|
||||
name: Mirror GitHub Release to Alibaba Cloud OSS
|
||||
needs: [check-release, release]
|
||||
if: >-
|
||||
${{ always() && needs.check-release.result == 'success' &&
|
||||
(needs.release.result == 'success' || needs.release.result == 'skipped') }}
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: penguin-oss-production
|
||||
cancel-in-progress: false
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
environment:
|
||||
name: oss-production
|
||||
url: ${{ vars.OSS_PUBLIC_BASE_URL }}
|
||||
steps:
|
||||
# On workflow_dispatch, use the selected branch's current mirror scripts while downloading
|
||||
# the requested tag's immutable Release assets. A tag push naturally checks out that tag.
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Validate OSS environment configuration
|
||||
env:
|
||||
ALIYUN_OIDC_PROVIDER_ARN: ${{ vars.ALIYUN_OIDC_PROVIDER_ARN }}
|
||||
ALIYUN_ROLE_ARN: ${{ vars.ALIYUN_ROLE_ARN }}
|
||||
OSS_BUCKET: ${{ vars.OSS_BUCKET }}
|
||||
OSS_REGION: ${{ vars.OSS_REGION }}
|
||||
OSS_ENDPOINT: ${{ vars.OSS_ENDPOINT }}
|
||||
OSS_PUBLIC_BASE_URL: ${{ vars.OSS_PUBLIC_BASE_URL }}
|
||||
run: |
|
||||
set -eu
|
||||
for name in ALIYUN_OIDC_PROVIDER_ARN ALIYUN_ROLE_ARN OSS_BUCKET OSS_REGION OSS_ENDPOINT OSS_PUBLIC_BASE_URL; do
|
||||
eval "value=\${$name:-}"
|
||||
if [ -z "$value" ]; then
|
||||
echo "error: $name is not configured in the oss-production environment" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Download and verify ossutil
|
||||
run: |
|
||||
sh scripts/install-ossutil.sh "$RUNNER_TEMP/ossutil-bin"
|
||||
echo "$RUNNER_TEMP/ossutil-bin" >> "$GITHUB_PATH"
|
||||
|
||||
# Pinned v1 commit. audience must match the client ID configured on the Alibaba Cloud
|
||||
# OIDC provider; this project deliberately uses `github-actions`.
|
||||
- name: Exchange GitHub OIDC token for Alibaba Cloud credentials
|
||||
id: aliyun
|
||||
uses: aliyun/configure-aliyun-credentials-action@1e5248c8d5d93a8781ac344a68e19a43341e79e6
|
||||
with:
|
||||
oidc-provider-arn: ${{ vars.ALIYUN_OIDC_PROVIDER_ARN }}
|
||||
role-to-assume: ${{ vars.ALIYUN_ROLE_ARN }}
|
||||
role-session-name: penguin-oss-${{ github.run_id }}
|
||||
role-session-expiration: 1800
|
||||
audience: github-actions
|
||||
|
||||
- name: Download exact GitHub Release assets
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
|
||||
run: |
|
||||
mkdir -p release-assets
|
||||
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null
|
||||
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir release-assets
|
||||
|
||||
- name: Determine whether the tag is the latest Release
|
||||
id: latest
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
|
||||
run: |
|
||||
LATEST_TAG="$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName --jq .tagName)"
|
||||
if [ "$TAG" = "$LATEST_TAG" ]; then
|
||||
echo "update=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "update=false" >> "$GITHUB_OUTPUT"
|
||||
echo "$TAG will be mirrored without replacing latest.json (current latest: $LATEST_TAG)."
|
||||
fi
|
||||
|
||||
- name: Mirror and verify OSS objects
|
||||
env:
|
||||
TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
OSS_ACCESS_KEY_ID: ${{ steps.aliyun.outputs['aliyun-access-key-id'] }}
|
||||
OSS_ACCESS_KEY_SECRET: ${{ steps.aliyun.outputs['aliyun-access-key-secret'] }}
|
||||
OSS_SESSION_TOKEN: ${{ steps.aliyun.outputs['aliyun-security-token'] }}
|
||||
OSS_BUCKET: ${{ vars.OSS_BUCKET }}
|
||||
OSS_REGION: ${{ vars.OSS_REGION }}
|
||||
OSS_ENDPOINT: ${{ vars.OSS_ENDPOINT }}
|
||||
OSS_PUBLIC_BASE_URL: ${{ vars.OSS_PUBLIC_BASE_URL }}
|
||||
run: sh scripts/publish-release-to-oss.sh release-assets "$TAG" "${{ steps.latest.outputs.update }}"
|
||||
|
||||
publish-npm:
|
||||
name: Publish npm packages
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
Reference in New Issue
Block a user