Publish SDK packages #141
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish SDK packages | |
| env: | |
| HUSKY: 0 | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| dist-tag: | |
| description: "Tag to publish under" | |
| type: choice | |
| required: true | |
| default: "prerelease" | |
| options: | |
| - latest | |
| - prerelease | |
| - unstable | |
| - canary | |
| version: | |
| description: "Version override (optional, e.g., 1.0.0). If empty, auto-increments. Unstable overrides must use <core>-unstable." | |
| type: string | |
| required: false | |
| mode: | |
| description: "Publish or validate without registry and release mutations" | |
| type: choice | |
| required: true | |
| default: publish | |
| options: | |
| - publish | |
| - dry-run | |
| runtime: | |
| description: "Runtime metadata (automation only)" | |
| type: string | |
| required: false | |
| test-policy: | |
| description: "Runtime E2E test policy" | |
| type: choice | |
| required: true | |
| default: required | |
| options: | |
| - required | |
| - advisory | |
| - skipped | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ inputs.mode == 'dry-run' && format('publish-dry-run-{0}', github.run_id) || inputs.runtime != '' && format('publish-runtime-{0}', github.run_id) || inputs.dist-tag == 'unstable' && 'sdk-runtime-public-unstable' || 'publish' }} | |
| cancel-in-progress: false | |
| jobs: | |
| validate-dispatch: | |
| name: Validate dispatch | |
| runs-on: ubuntu-latest | |
| outputs: | |
| kind: ${{ steps.validate.outputs.kind }} | |
| runtime_run_id: ${{ steps.validate.outputs.runtime_run_id }} | |
| runtime_sha: ${{ steps.validate.outputs.runtime_sha }} | |
| runtime_version: ${{ steps.validate.outputs.runtime_version }} | |
| test_policy: ${{ steps.validate.outputs.test_policy }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "22.x" | |
| - run: npm ci --ignore-scripts | |
| working-directory: ./nodejs | |
| - name: Validate release dispatch | |
| id: validate | |
| working-directory: ./nodejs | |
| env: | |
| DIST_TAG: ${{ inputs.dist-tag }} | |
| MODE: ${{ inputs.mode }} | |
| RUNTIME_JSON: ${{ inputs.runtime }} | |
| TEST_POLICY: ${{ inputs.test-policy }} | |
| VERSION_OVERRIDE: ${{ inputs.version }} | |
| run: npx tsx scripts/runtime-release-identity.ts | |
| # Shared job to calculate version once for all publish jobs | |
| version: | |
| name: Calculate Version | |
| needs: validate-dispatch | |
| if: needs.validate-dispatch.outputs.kind == 'direct' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: read | |
| outputs: | |
| version: ${{ steps.unstable_version.outputs.VERSION || steps.version.outputs.VERSION }} | |
| current: ${{ steps.version.outputs.CURRENT }} | |
| current-prerelease: ${{ steps.version.outputs.CURRENT_PRERELEASE }} | |
| defaults: | |
| run: | |
| working-directory: ./nodejs | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: ${{ inputs.dist-tag == 'unstable' && '0' || '1' }} | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "22.x" | |
| - run: npm ci --ignore-scripts | |
| - name: Plan unstable version | |
| if: inputs.dist-tag == 'unstable' | |
| id: unstable_version | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| SDK_CHANNEL: unstable | |
| SDK_SHA: ${{ github.sha }} | |
| SDK_VERSION_OVERRIDE: ${{ inputs.version }} | |
| WORKFLOW_RUN_ID: ${{ github.run_id }} | |
| run: | | |
| set -euo pipefail | |
| WORKFLOW_CREATED_AT="$(gh api "/repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" --jq .created_at)" | |
| gh api --paginate "/repos/$GITHUB_REPOSITORY/releases?per_page=100" | | |
| jq -s 'add' > "$RUNNER_TEMP/sdk-releases.json" | |
| export SDK_RELEASES_FILE="$RUNNER_TEMP/sdk-releases.json" | |
| export WORKFLOW_CREATED_AT | |
| VERSION="$(npx tsx scripts/unstable-version.ts)" | |
| npm exec -- semver "$VERSION" >/dev/null | |
| echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "Planned unstable version: $VERSION" >> "$GITHUB_STEP_SUMMARY" | |
| - name: Get version | |
| if: inputs.dist-tag != 'unstable' | |
| id: version | |
| run: | | |
| CURRENT="$(node scripts/get-version.js current)" | |
| echo "CURRENT=$CURRENT" >> $GITHUB_OUTPUT | |
| echo "Current latest version: $CURRENT" >> $GITHUB_STEP_SUMMARY | |
| CURRENT_PRERELEASE="$(node scripts/get-version.js current-prerelease)" | |
| echo "CURRENT_PRERELEASE=$CURRENT_PRERELEASE" >> $GITHUB_OUTPUT | |
| echo "Current prerelease version: $CURRENT_PRERELEASE" >> $GITHUB_STEP_SUMMARY | |
| if [ -n "${{ github.event.inputs.version }}" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| # Validate version format matches dist-tag | |
| if [ "${{ github.event.inputs.dist-tag }}" = "latest" ]; then | |
| if [[ "$VERSION" == *-* ]]; then | |
| echo "❌ Error: Version '$VERSION' has a prerelease suffix but dist-tag is 'latest'" >> $GITHUB_STEP_SUMMARY | |
| echo "Use a version without suffix (e.g., '1.0.0') for latest releases" | |
| exit 1 | |
| fi | |
| else | |
| if [[ "$VERSION" != *-* ]]; then | |
| echo "❌ Error: Version '$VERSION' has no prerelease suffix but dist-tag is '${{ github.event.inputs.dist-tag }}'" >> $GITHUB_STEP_SUMMARY | |
| echo "Use a version with suffix (e.g., '1.0.0-preview.0') for prerelease" | |
| exit 1 | |
| fi | |
| fi | |
| echo "Using manual version override: $VERSION" >> $GITHUB_STEP_SUMMARY | |
| else | |
| VERSION="$(node scripts/get-version.js ${{ github.event.inputs.dist-tag }})" | |
| echo "Auto-incremented version: $VERSION" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Verify version is available on public npm | |
| if: inputs.dist-tag != 'unstable' | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| run: | | |
| node scripts/npm-release.js preflight \ | |
| @github/copilot-sdk \ | |
| "$VERSION" \ | |
| https://registry.npmjs.org | |
| package-nodejs: | |
| name: Package Node.js SDK | |
| needs: version | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| working-directory: ./nodejs | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "22.x" | |
| - run: npm ci --ignore-scripts | |
| - name: Set version | |
| run: node scripts/set-version.js | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| - name: Build | |
| run: npm run build | |
| - name: Pack | |
| run: | | |
| npm run pack:release | |
| TARBALL_COUNT="$(find . -maxdepth 1 -name 'github-copilot-sdk-*.tgz' | wc -l | tr -d ' ')" | |
| if [ "$TARBALL_COUNT" -ne 9 ]; then | |
| echo "::error::Expected nine Node.js package tarballs, found $TARBALL_COUNT." | |
| exit 1 | |
| fi | |
| npm run verify:release-packages | |
| - name: Create unstable package manifest | |
| if: inputs.dist-tag == 'unstable' | |
| env: | |
| SDK_VERSION: ${{ needs.version.outputs.version }} | |
| run: npm run release:manifest -- create-package-set package-set-manifest.json . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: nodejs-package | |
| path: | | |
| nodejs/github-copilot-sdk-*.tgz | |
| nodejs/package-set-manifest.json | |
| if-no-files-found: error | |
| publish-nodejs: | |
| name: Publish Node.js SDK | |
| needs: package-nodejs | |
| if: inputs.mode == 'publish' && (github.ref == 'refs/heads/main' || inputs.dist-tag == 'unstable') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "22.x" | |
| - name: Install release dependencies | |
| if: inputs.dist-tag == 'unstable' | |
| working-directory: ./nodejs | |
| run: npm ci --ignore-scripts | |
| - name: Update npm for OIDC support | |
| run: npm i -g "npm@11.6.3" | |
| - name: Download Node.js package | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: nodejs-package | |
| path: ./dist | |
| - name: Publish tarball to public npm | |
| env: | |
| DIST_TAG: ${{ github.event.inputs.dist-tag }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$DIST_TAG" = "unstable" ]; then | |
| node nodejs/scripts/npm-release.js publish-manifest \ | |
| dist/package-set-manifest.json dist unstable https://registry.npmjs.org public | |
| exit 0 | |
| fi | |
| shopt -s nullglob | |
| TARBALLS=(./dist/*.tgz) | |
| if [ "${#TARBALLS[@]}" -ne 9 ]; then | |
| echo "::error::Expected nine Node.js package tarballs, found ${#TARBALLS[@]}." | |
| exit 1 | |
| fi | |
| MAIN_TARBALL="" | |
| for TARBALL in "${TARBALLS[@]}"; do | |
| PACKAGE_NAME="$(tar -xOf "$TARBALL" package/package.json | jq -r .name)" | |
| if [ "$PACKAGE_NAME" = "@github/copilot-sdk" ]; then | |
| MAIN_TARBALL="$TARBALL" | |
| continue | |
| fi | |
| node nodejs/scripts/npm-release.js publish \ | |
| "$TARBALL" \ | |
| "$DIST_TAG" \ | |
| https://registry.npmjs.org \ | |
| public | |
| done | |
| if [ -z "$MAIN_TARBALL" ]; then | |
| echo "::error::Main @github/copilot-sdk tarball not found." | |
| exit 1 | |
| fi | |
| node nodejs/scripts/npm-release.js publish \ | |
| "$MAIN_TARBALL" \ | |
| "$DIST_TAG" \ | |
| https://registry.npmjs.org \ | |
| public | |
| publish-nodejs-internal: | |
| name: Publish Node.js SDK to internal feed | |
| needs: publish-nodejs | |
| environment: cicd | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: sdk-runtime-internal-${{ inputs.dist-tag }} | |
| cancel-in-progress: false | |
| queue: max | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| env: | |
| ADO_RESOURCE: 499b84ac-1321-427f-aa17-267ca6975798 | |
| FEED_URL: https://pkgs.dev.azure.com/devdiv/_packaging/copilot-canary/npm/registry/ | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "22.x" | |
| - name: Install release dependencies | |
| if: inputs.dist-tag == 'unstable' | |
| working-directory: ./nodejs | |
| run: npm ci --ignore-scripts | |
| - name: Download Node.js package | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: nodejs-package | |
| path: ./dist | |
| - name: Azure Login (OIDC -> id-cpd-ci) | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: "${{ vars.CPD_ID_CLIENT_ID }}" # id-cpd-ci | |
| tenant-id: "${{ vars.CPD_ID_TENANT_ID }}" | |
| allow-no-subscriptions: true | |
| - name: Configure feed auth | |
| run: | | |
| set -euo pipefail | |
| TOKEN="$(az account get-access-token --resource "$ADO_RESOURCE" --query accessToken -o tsv)" | |
| echo "::add-mask::$TOKEN" | |
| FEED_AUTH_REGISTRY="${FEED_URL#https:}" | |
| FEED_AUTH_BASE="${FEED_AUTH_REGISTRY%registry/}" | |
| printf '%s\n' \ | |
| "${FEED_AUTH_REGISTRY}:_authToken=${TOKEN}" \ | |
| "${FEED_AUTH_BASE}:_authToken=${TOKEN}" > "$HOME/.npmrc" | |
| - name: Publish tarball to internal feed | |
| env: | |
| DIST_TAG: ${{ github.event.inputs.dist-tag }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$FEED_URL" != "https://pkgs.dev.azure.com/devdiv/_packaging/copilot-canary/npm/registry/" ]; then | |
| echo "::error::FEED_URL ('$FEED_URL') is not the expected internal feed. Refusing to publish." | |
| exit 1 | |
| fi | |
| if [ "$DIST_TAG" = "unstable" ]; then | |
| node nodejs/scripts/npm-release.js publish-manifest \ | |
| dist/package-set-manifest.json dist unstable "$FEED_URL" azure | |
| exit 0 | |
| fi | |
| shopt -s nullglob | |
| TARBALLS=(./dist/*.tgz) | |
| if [ "${#TARBALLS[@]}" -ne 9 ]; then | |
| echo "::error::Expected nine Node.js package tarballs, found ${#TARBALLS[@]}." | |
| exit 1 | |
| fi | |
| MAIN_TARBALL="" | |
| for TARBALL in "${TARBALLS[@]}"; do | |
| PACKAGE_NAME="$(tar -xOf "$TARBALL" package/package.json | jq -r .name)" | |
| if [ "$PACKAGE_NAME" = "@github/copilot-sdk" ]; then | |
| MAIN_TARBALL="$TARBALL" | |
| continue | |
| fi | |
| node nodejs/scripts/npm-release.js publish \ | |
| "$TARBALL" \ | |
| "$DIST_TAG" \ | |
| "$FEED_URL" \ | |
| azure | |
| done | |
| if [ -z "$MAIN_TARBALL" ]; then | |
| echo "::error::Main @github/copilot-sdk tarball not found." | |
| exit 1 | |
| fi | |
| node nodejs/scripts/npm-release.js publish \ | |
| "$MAIN_TARBALL" \ | |
| "$DIST_TAG" \ | |
| "$FEED_URL" \ | |
| azure | |
| publish-dotnet: | |
| name: Publish .NET SDK | |
| if: inputs.dist-tag != 'unstable' | |
| needs: version | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| defaults: | |
| run: | |
| working-directory: ./dotnet | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Restore dependencies | |
| run: dotnet restore | |
| - name: Build and pack | |
| run: dotnet pack src/GitHub.Copilot.SDK.csproj -c Release -p:Version=${{ needs.version.outputs.version }} -o ./artifacts | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: dotnet-package | |
| path: | | |
| dotnet/artifacts/*.nupkg | |
| dotnet/artifacts/*.snupkg | |
| - name: NuGet login (OIDC) | |
| if: github.ref == 'refs/heads/main' | |
| uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0 | |
| id: nuget-login | |
| with: | |
| # The following must be a username, not an organization name, and that user must have configured Trusted Publishing | |
| # for this owner/repo/workflow combination in their NuGet.org account settings. We could set up a dedicated user for | |
| # this purpose if needed, but then we'd have to manage that account separately. Other GitHub-owned packages on NuGet | |
| # are associated with individual maintainers' accounts too. | |
| user: stevesanderson | |
| - name: Publish to NuGet | |
| if: github.ref == 'refs/heads/main' | |
| run: | | |
| dotnet nuget push ./artifacts/*.nupkg --api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate --no-symbols | |
| dotnet nuget push ./artifacts/*.snupkg --api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate | |
| publish-dotnet-internal: | |
| name: Publish .NET SDK to internal feed | |
| needs: publish-dotnet | |
| if: github.ref == 'refs/heads/main' | |
| environment: cicd | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| env: | |
| ADO_RESOURCE: 499b84ac-1321-427f-aa17-267ca6975798 | |
| FEED_URL: https://pkgs.dev.azure.com/devdiv/_packaging/copilot-canary/nuget/v3/index.json | |
| steps: | |
| - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Download .NET package | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: dotnet-package | |
| path: ./dist | |
| - name: Azure Login (OIDC -> id-cpd-ci) | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| client-id: "${{ vars.CPD_ID_CLIENT_ID }}" # id-cpd-ci | |
| tenant-id: "${{ vars.CPD_ID_TENANT_ID }}" | |
| allow-no-subscriptions: true | |
| - name: Publish package to internal feed | |
| run: | | |
| set -euo pipefail | |
| if [ "$FEED_URL" != "https://pkgs.dev.azure.com/devdiv/_packaging/copilot-canary/nuget/v3/index.json" ]; then | |
| echo "::error::FEED_URL ('$FEED_URL') is not the expected internal feed. Refusing to publish." | |
| exit 1 | |
| fi | |
| shopt -s nullglob | |
| PACKAGES=(./dist/*.nupkg) | |
| if [ "${#PACKAGES[@]}" -ne 1 ]; then | |
| echo "::error::Expected one .NET package, found ${#PACKAGES[@]}." | |
| exit 1 | |
| fi | |
| TOKEN="$(az account get-access-token --resource "$ADO_RESOURCE" --query accessToken -o tsv)" | |
| echo "::add-mask::$TOKEN" | |
| dotnet nuget add source "$FEED_URL" --name CopilotInternal | |
| # Keep the short-lived token out of NuGet.Config and command-line arguments. | |
| export NuGetPackageSourceCredentials_CopilotInternal="Username=azure;Password=$TOKEN;ValidAuthenticationTypes=Basic" | |
| # Azure Artifacts does not support .snupkg symbol packages. | |
| dotnet nuget push "${PACKAGES[0]}" \ | |
| --api-key AzureArtifacts \ | |
| --source CopilotInternal \ | |
| --skip-duplicate \ | |
| --no-symbols | |
| publish-rust: | |
| name: Publish Rust SDK | |
| if: inputs.dist-tag != 'unstable' | |
| needs: version | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: ./rust | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable | |
| with: | |
| toolchain: "1.94.0" | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| workspaces: "rust" | |
| - name: Set version | |
| run: sed -i -E 's/^version = ".*"$/version = "${{ needs.version.outputs.version }}"/' Cargo.toml | |
| - name: Snapshot CLI version + hashes for build.rs | |
| run: | | |
| bash scripts/snapshot-bundled-cli-version.sh | |
| bash scripts/snapshot-bundled-in-process-version.sh | |
| - name: Verify CLI version snapshots exist | |
| run: | | |
| for snapshot in cli-version.txt cli-version-in-process.txt; do | |
| if [[ ! -f "${snapshot}" ]]; then | |
| echo "::error::${snapshot} was not generated. The Snapshot step must run before packaging." | |
| exit 1 | |
| fi | |
| done | |
| - name: Package (dry run) | |
| run: cargo publish --dry-run --allow-dirty | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: rust-package | |
| path: rust/target/package/*.crate | |
| - name: Publish to crates.io | |
| if: github.ref == 'refs/heads/main' | |
| run: cargo publish --allow-dirty | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| publish-python: | |
| name: Publish Python SDK | |
| if: inputs.dist-tag != 'unstable' | |
| needs: version | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| defaults: | |
| run: | |
| working-directory: ./python | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 | |
| with: | |
| python-version: "3.12" | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "22.x" | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 | |
| - name: Set version | |
| run: sed -i "s/^version = .*/version = \"${{ needs.version.outputs.version }}\"/" pyproject.toml | |
| - name: Inject CLI version | |
| run: node scripts/inject-cli-version.mjs | |
| - name: Build wheel | |
| run: uv build --wheel --out-dir dist | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: python-package | |
| path: python/dist/* | |
| - name: Publish to PyPI | |
| if: github.ref == 'refs/heads/main' | |
| uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 | |
| with: | |
| packages-dir: python/dist/ | |
| publish-java: | |
| name: Publish Java SDK | |
| if: inputs.dist-tag != 'unstable' && github.ref == 'refs/heads/main' | |
| needs: version | |
| permissions: | |
| contents: read | |
| uses: ./.github/workflows/java-publish-maven.yml | |
| with: | |
| releaseVersion: ${{ needs.version.outputs.version }} | |
| sourceSha: ${{ github.sha }} | |
| prerelease: ${{ github.event.inputs.dist-tag == 'prerelease' }} | |
| secrets: inherit | |
| github-release: | |
| name: Create GitHub Release | |
| needs: | |
| [ | |
| version, | |
| publish-nodejs, | |
| publish-dotnet, | |
| publish-python, | |
| publish-rust, | |
| publish-java, | |
| ] | |
| if: | | |
| always() && | |
| github.ref == 'refs/heads/main' && | |
| inputs.dist-tag != 'unstable' && | |
| needs.version.result == 'success' && | |
| needs.publish-nodejs.result == 'success' && | |
| needs.publish-dotnet.result == 'success' && | |
| needs.publish-python.result == 'success' && | |
| needs.publish-rust.result == 'success' && | |
| needs.publish-java.outputs.mavenPublished == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: write | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Create GitHub Release | |
| if: github.event.inputs.dist-tag == 'latest' | |
| run: | | |
| NOTES_FLAG="" | |
| if git rev-parse "v${{ needs.version.outputs.current }}" >/dev/null 2>&1; then | |
| NOTES_FLAG="--notes-start-tag v${{ needs.version.outputs.current }}" | |
| fi | |
| gh release create "v${{ needs.version.outputs.version }}" \ | |
| --title "v${{ needs.version.outputs.version }}" \ | |
| --generate-notes $NOTES_FLAG \ | |
| --target ${{ github.sha }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create GitHub Pre-Release | |
| if: github.event.inputs.dist-tag == 'prerelease' | |
| run: | | |
| NOTES_FLAG="" | |
| if git rev-parse "v${{ needs.version.outputs.current-prerelease }}" >/dev/null 2>&1; then | |
| NOTES_FLAG="--notes-start-tag v${{ needs.version.outputs.current-prerelease }}" | |
| fi | |
| gh release create "v${{ needs.version.outputs.version }}" \ | |
| --prerelease \ | |
| --title "v${{ needs.version.outputs.version }}" \ | |
| --generate-notes $NOTES_FLAG \ | |
| --target ${{ github.sha }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Trigger changelog generation | |
| run: gh workflow run release-changelog.lock.yml -f tag="v${{ needs.version.outputs.version }}" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Tag Go SDK submodule | |
| if: github.event.inputs.dist-tag == 'latest' || github.event.inputs.dist-tag == 'prerelease' | |
| run: | | |
| set -e | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git fetch --tags | |
| TAG_NAME="go/v${{ needs.version.outputs.version }}" | |
| # Try to create the tag - will fail if it already exists | |
| if git tag "$TAG_NAME" ${{ github.sha }} 2>/dev/null; then | |
| git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git "$TAG_NAME" | |
| echo "Created and pushed tag $TAG_NAME" | |
| else | |
| echo "Tag $TAG_NAME already exists, skipping" | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Tag Rust SDK | |
| # Keep a language-scoped source tag for traceability. Rust is | |
| # included in the cross-language `vX.Y.Z` GitHub Release. | |
| if: github.event.inputs.dist-tag == 'latest' || github.event.inputs.dist-tag == 'prerelease' | |
| run: | | |
| set -e | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git fetch --tags | |
| VERSION="${{ needs.version.outputs.version }}" | |
| TAG_NAME="rust/v${VERSION}" | |
| if git tag "$TAG_NAME" ${{ github.sha }} 2>/dev/null; then | |
| git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git "$TAG_NAME" | |
| echo "Created and pushed tag $TAG_NAME" | |
| else | |
| echo "Tag $TAG_NAME already exists, skipping tag push" | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| tag-java: | |
| name: Tag Java SDK | |
| needs: [version, publish-java, github-release] | |
| if: | | |
| success() && | |
| (github.event.inputs.dist-tag == 'latest' || | |
| github.event.inputs.dist-tag == 'prerelease') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: ${{ needs.publish-java.outputs.sourceSha }} | |
| fetch-depth: 0 | |
| - name: Tag Java SDK | |
| # Reuse a tag only when it identifies the source that was published. | |
| run: | | |
| set -euo pipefail | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git fetch --tags origin | |
| TAG_NAME="java/v${VERSION}" | |
| if git show-ref --verify --quiet "refs/tags/$TAG_NAME"; then | |
| TAG_COMMIT=$(git rev-parse --verify "refs/tags/${TAG_NAME}^{commit}") | |
| if [ "$TAG_COMMIT" != "$SOURCE_SHA" ]; then | |
| echo "::error::Tag $TAG_NAME points to $TAG_COMMIT, expected $SOURCE_SHA. Refusing to overwrite it." | |
| exit 1 | |
| fi | |
| echo "Tag $TAG_NAME already points to the release source, skipping tag push" | |
| else | |
| STATUS=$? | |
| if [ "$STATUS" -ne 1 ]; then | |
| echo "::error::Could not inspect tag $TAG_NAME." | |
| exit "$STATUS" | |
| fi | |
| git tag "$TAG_NAME" "$SOURCE_SHA" | |
| git push origin "refs/tags/$TAG_NAME" | |
| echo "Created and pushed tag $TAG_NAME" | |
| fi | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| SOURCE_SHA: ${{ needs.publish-java.outputs.sourceSha }} | |
| deploy-java-site: | |
| name: Deploy Java documentation site | |
| needs: [version, tag-java] | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Trigger Java documentation site deploy | |
| # A failed dispatch can be retried without recreating the GitHub release. | |
| run: | | |
| set -euo pipefail | |
| TAG="java/v${VERSION}" | |
| PUBLISH_AS_LATEST=true | |
| if [ "$DIST_TAG" = "prerelease" ]; then | |
| PUBLISH_AS_LATEST=false | |
| fi | |
| echo "Triggering site deployment for version ${VERSION} (tag: ${TAG})" | |
| gh workflow run deploy-site.yml \ | |
| --repo github/copilot-sdk-java \ | |
| -f version="${VERSION}" \ | |
| -f publish_as_latest="${PUBLISH_AS_LATEST}" \ | |
| -f monorepo_tag="${TAG}" | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| DIST_TAG: ${{ github.event.inputs.dist-tag }} | |
| GITHUB_TOKEN: ${{ secrets.JAVA_RELEASE_GITHUB_TOKEN }} | |
| runtime-plan: | |
| name: Plan runtime release | |
| needs: validate-dispatch | |
| if: needs.validate-dispatch.outputs.kind == 'runtime' | |
| runs-on: ubuntu-latest | |
| environment: cicd | |
| permissions: | |
| actions: read | |
| contents: read | |
| outputs: | |
| artifact_name: ${{ steps.plan.outputs.artifact_name }} | |
| sdk_version: ${{ steps.plan.outputs.sdk_version }} | |
| workflow_created_at: ${{ steps.plan.outputs.workflow_created_at }} | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| cache: npm | |
| cache-dependency-path: ./nodejs/package-lock.json | |
| node-version: 22 | |
| - run: npm ci --ignore-scripts | |
| working-directory: ./nodejs | |
| - name: Calculate the release identity | |
| id: plan | |
| working-directory: ./nodejs | |
| env: | |
| CHANNEL: ${{ inputs.dist-tag }} | |
| GH_TOKEN: ${{ github.token }} | |
| SDK_CHANNEL: ${{ inputs.dist-tag }} | |
| SDK_SHA: ${{ github.sha }} | |
| WORKFLOW_RUN_ID: ${{ github.run_id }} | |
| WORKFLOW_RUN_NUMBER: ${{ github.run_number }} | |
| run: | | |
| set -euo pipefail | |
| WORKFLOW_CREATED_AT="$(gh api "/repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" --jq .created_at)" | |
| gh api --paginate "/repos/$GITHUB_REPOSITORY/releases?per_page=100" | | |
| jq -s 'add' > "$RUNNER_TEMP/sdk-releases.json" | |
| export SDK_RELEASES_FILE="$RUNNER_TEMP/sdk-releases.json" | |
| export WORKFLOW_CREATED_AT | |
| SDK_VERSION="$(npx tsx scripts/unstable-version.ts)" | |
| npm exec -- semver "$SDK_VERSION" >/dev/null | |
| ARTIFACT_NAME="nodejs-${CHANNEL}-${SDK_VERSION}" | |
| echo "Runtime E2E test policy: ${{ needs.validate-dispatch.outputs.test_policy }}" >> "$GITHUB_STEP_SUMMARY" | |
| { | |
| echo "artifact_name=$ARTIFACT_NAME" | |
| echo "sdk_version=$SDK_VERSION" | |
| echo "workflow_created_at=$WORKFLOW_CREATED_AT" | |
| } >> "$GITHUB_OUTPUT" | |
| runtime-acquire: | |
| name: Acquire runtime | |
| needs: [validate-dispatch, runtime-plan] | |
| runs-on: ubuntu-latest | |
| environment: cicd | |
| permissions: | |
| contents: read | |
| packages: read | |
| defaults: | |
| run: | |
| shell: bash | |
| working-directory: ./nodejs | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| cache: npm | |
| cache-dependency-path: ./nodejs/package-lock.json | |
| node-version: 22 | |
| - run: npm ci --ignore-scripts | |
| - name: Configure authentication-only GitHub Packages access | |
| env: | |
| NODE_AUTH_TOKEN: ${{ github.token }} | |
| run: echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" > "$HOME/.npmrc" | |
| - name: Download and validate all runtime platforms | |
| env: | |
| NODE_AUTH_TOKEN: ${{ github.token }} | |
| RUNTIME_SHA: ${{ needs.validate-dispatch.outputs.runtime_sha }} | |
| RUNTIME_VERSION: ${{ needs.validate-dispatch.outputs.runtime_version }} | |
| run: | | |
| npm run acquire:runtime-packages -- \ | |
| --version "$RUNTIME_VERSION" \ | |
| --sha "$RUNTIME_SHA" \ | |
| --output "$RUNNER_TEMP/runtime-packages" | |
| - name: Archive validated runtime packages | |
| run: tar -czf "$RUNNER_TEMP/runtime-packages.tar.gz" --exclude "runtime-packages/tarballs" -C "$RUNNER_TEMP" runtime-packages | |
| - name: Upload validated runtime packages | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: runtime-${{ inputs.dist-tag }}-${{ needs.validate-dispatch.outputs.runtime_version }}-${{ needs.validate-dispatch.outputs.runtime_sha }} | |
| path: ${{ runner.temp }}/runtime-packages.tar.gz | |
| if-no-files-found: error | |
| retention-days: 7 | |
| runtime-test: | |
| name: Test runtime (${{ matrix.os }}, ${{ matrix.transport }}) | |
| needs: [validate-dispatch, runtime-plan, runtime-acquire] | |
| if: needs.validate-dispatch.outputs.test_policy != 'skipped' | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| transport: ["default", "inprocess"] | |
| runs-on: ${{ matrix.os }} | |
| environment: cicd | |
| defaults: | |
| run: | |
| shell: bash | |
| working-directory: ./nodejs | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| cache: npm | |
| cache-dependency-path: ./nodejs/package-lock.json | |
| node-version: 22 | |
| - run: npm ci --ignore-scripts | |
| - name: Install test harness dependencies | |
| working-directory: ./test/harness | |
| run: npm ci --ignore-scripts | |
| - name: Download validated runtime packages | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: runtime-${{ inputs.dist-tag }}-${{ needs.validate-dispatch.outputs.runtime_version }}-${{ needs.validate-dispatch.outputs.runtime_sha }} | |
| path: ${{ runner.temp }}/runtime-package-artifact | |
| - name: Extract validated runtime packages | |
| run: | | |
| runner_temp="$RUNNER_TEMP" | |
| if command -v cygpath >/dev/null 2>&1; then | |
| runner_temp="$(cygpath -u "$runner_temp")" | |
| fi | |
| rm -rf "$runner_temp/runtime-packages" | |
| tar -xzf "$runner_temp/runtime-package-artifact/runtime-packages.tar.gz" -C "$runner_temp" | |
| - name: Select the acquired runtime | |
| env: | |
| COPILOT_SDK_RUNTIME_PACKAGE_DIR: ${{ runner.temp }}/runtime-packages | |
| RUNTIME_VERSION: ${{ needs.validate-dispatch.outputs.runtime_version }} | |
| run: | | |
| node scripts/set-cli-version.js "$RUNTIME_VERSION" --local-package | |
| runtime_path="$(npm run --silent prepare:runtime -- --print-path)" | |
| echo "COPILOT_SDK_RUNTIME_PACKAGE_DIR=$COPILOT_SDK_RUNTIME_PACKAGE_DIR" >> "$GITHUB_ENV" | |
| echo "COPILOT_CLI_PATH=$runtime_path" >> "$GITHUB_ENV" | |
| - run: npm run build | |
| - name: Warm up PowerShell | |
| if: runner.os == 'Windows' | |
| run: pwsh.exe -Command "Write-Host 'PowerShell ready'" | |
| - name: Select inprocess transport | |
| if: matrix.transport == 'inprocess' | |
| run: echo "COPILOT_SDK_DEFAULT_CONNECTION=inprocess" >> "$GITHUB_ENV" | |
| - name: Run Node SDK tests | |
| id: e2e | |
| continue-on-error: ${{ needs.validate-dispatch.outputs.test_policy == 'advisory' }} | |
| env: | |
| COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} | |
| run: npm test | |
| - name: Report advisory E2E failure | |
| if: needs.validate-dispatch.outputs.test_policy == 'advisory' && steps.e2e.outcome == 'failure' | |
| env: | |
| RUNNER_OS: ${{ runner.os }} | |
| run: | | |
| echo "::warning::Runtime-backed Node SDK E2E tests failed on ${RUNNER_OS}; continuing because test-policy is advisory." | |
| { | |
| echo "### Advisory runtime E2E failure" | |
| echo | |
| echo "Runtime-backed Node SDK E2E tests failed on **${RUNNER_OS}**. Publication remains eligible because \`test-policy\` is \`advisory\`." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| runtime-package: | |
| name: Build SDK packages | |
| needs: [validate-dispatch, runtime-plan, runtime-acquire, runtime-test] | |
| if: | | |
| always() && | |
| !cancelled() && | |
| needs.validate-dispatch.result == 'success' && | |
| needs.runtime-plan.result == 'success' && | |
| needs.runtime-acquire.result == 'success' && | |
| ( | |
| needs.runtime-test.result == 'success' || | |
| (needs.validate-dispatch.outputs.test_policy == 'skipped' && needs.runtime-test.result == 'skipped') | |
| ) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| shell: bash | |
| working-directory: ./nodejs | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| cache: npm | |
| cache-dependency-path: ./nodejs/package-lock.json | |
| node-version: 22 | |
| - run: npm ci --ignore-scripts | |
| - name: Download validated runtime packages | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: runtime-${{ inputs.dist-tag }}-${{ needs.validate-dispatch.outputs.runtime_version }}-${{ needs.validate-dispatch.outputs.runtime_sha }} | |
| path: ${{ runner.temp }}/runtime-package-artifact | |
| - name: Extract validated runtime packages | |
| run: | | |
| runner_temp="$RUNNER_TEMP" | |
| if command -v cygpath >/dev/null 2>&1; then | |
| runner_temp="$(cygpath -u "$runner_temp")" | |
| fi | |
| rm -rf "$runner_temp/runtime-packages" | |
| tar -xzf "$runner_temp/runtime-package-artifact/runtime-packages.tar.gz" -C "$runner_temp" | |
| - name: Build and verify exact package set | |
| env: | |
| COPILOT_SDK_RUNTIME_PACKAGE_DIR: ${{ runner.temp }}/runtime-packages | |
| RUNTIME_VERSION: ${{ needs.validate-dispatch.outputs.runtime_version }} | |
| SDK_VERSION: ${{ needs.runtime-plan.outputs.sdk_version }} | |
| run: | | |
| VERSION="$SDK_VERSION" node scripts/set-version.js | |
| node scripts/set-cli-version.js "$RUNTIME_VERSION" --local-package | |
| grep -F "COPILOT_CLI_USE_NPM_PACKAGE = false" src/cliVersion.ts | |
| npm run build | |
| npm run pack:release | |
| npm run verify:release-packages | |
| - name: Create immutable release manifest | |
| env: | |
| RELEASE_CHANNEL: ${{ inputs.dist-tag }} | |
| RUNTIME_RUN_ID: ${{ needs.validate-dispatch.outputs.runtime_run_id }} | |
| RUNTIME_SHA: ${{ needs.validate-dispatch.outputs.runtime_sha }} | |
| RUNTIME_VERSION: ${{ needs.validate-dispatch.outputs.runtime_version }} | |
| SDK_REF: ${{ github.ref }} | |
| SDK_SHA: ${{ github.sha }} | |
| SDK_VERSION: ${{ needs.runtime-plan.outputs.sdk_version }} | |
| TEST_POLICY: ${{ needs.validate-dispatch.outputs.test_policy }} | |
| WORKFLOW_CREATED_AT: ${{ needs.runtime-plan.outputs.workflow_created_at }} | |
| WORKFLOW_RUN_ID: ${{ github.run_id }} | |
| WORKFLOW_RUN_NUMBER: ${{ github.run_number }} | |
| run: | | |
| npm run release:manifest -- create release-manifest.json . | |
| - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: ${{ needs.runtime-plan.outputs.artifact_name }} | |
| path: | | |
| nodejs/release-manifest.json | |
| nodejs/github-copilot-sdk-*.tgz | |
| if-no-files-found: error | |
| retention-days: 30 | |
| runtime-publish-internal: | |
| name: Publish SDK internally | |
| if: | | |
| always() && | |
| !cancelled() && | |
| inputs.mode == 'publish' && | |
| needs.runtime-plan.result == 'success' && | |
| needs.runtime-package.result == 'success' | |
| needs: [validate-dispatch, runtime-plan, runtime-package] | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: sdk-runtime-internal-${{ inputs.dist-tag }} | |
| cancel-in-progress: false | |
| queue: max | |
| environment: cicd | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| env: | |
| ADO_RESOURCE: 499b84ac-1321-427f-aa17-267ca6975798 | |
| FEED_URL: https://pkgs.dev.azure.com/devdiv/_packaging/copilot-canary/npm/registry/ | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: 22 | |
| - run: npm ci --ignore-scripts | |
| working-directory: ./nodejs | |
| - name: Download retained release | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: ${{ needs.runtime-plan.outputs.artifact_name }} | |
| path: ./dist | |
| - name: Validate retained release | |
| run: | | |
| node nodejs/node_modules/.bin/tsx nodejs/scripts/release-manifest.ts verify dist/release-manifest.json dist | |
| [ "$(jq -r .workflow.runId dist/release-manifest.json)" = "${{ github.run_id }}" ] || | |
| { echo "::error::Retained release belongs to a different workflow run."; exit 1; } | |
| [ "$(jq -r .channel dist/release-manifest.json)" = "${{ inputs.dist-tag }}" ] || | |
| { echo "::error::Retained release channel does not match the requested channel."; exit 1; } | |
| - name: Azure login | |
| uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 | |
| with: | |
| allow-no-subscriptions: true | |
| client-id: ${{ vars.CPD_ID_CLIENT_ID }} | |
| tenant-id: ${{ vars.CPD_ID_TENANT_ID }} | |
| - name: Configure authentication-only Azure npm access | |
| run: | | |
| TOKEN="$(az account get-access-token --resource "$ADO_RESOURCE" --query accessToken -o tsv)" | |
| echo "::add-mask::$TOKEN" | |
| FEED_AUTH_REGISTRY="${FEED_URL#https:}" | |
| FEED_AUTH_BASE="${FEED_AUTH_REGISTRY%registry/}" | |
| printf '%s\n' \ | |
| "${FEED_AUTH_REGISTRY}:_authToken=${TOKEN}" \ | |
| "${FEED_AUTH_BASE}:_authToken=${TOKEN}" > "$HOME/.npmrc" | |
| - name: Publish exact tarballs internally | |
| run: | | |
| node nodejs/scripts/npm-release.js publish-manifest \ | |
| dist/release-manifest.json dist "${{ inputs.dist-tag }}" "$FEED_URL" azure | |
| runtime-publish-public: | |
| name: Publish SDK publicly | |
| if: | | |
| always() && | |
| !cancelled() && | |
| inputs.dist-tag == 'unstable' && | |
| inputs.mode == 'publish' && | |
| needs.runtime-plan.result == 'success' && | |
| needs.runtime-publish-internal.result == 'success' | |
| needs: [runtime-plan, runtime-publish-internal] | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: sdk-runtime-public-unstable | |
| cancel-in-progress: false | |
| queue: max | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: 22 | |
| - run: npm ci --ignore-scripts | |
| working-directory: ./nodejs | |
| - name: Update npm for trusted publishing | |
| run: npm install -g npm@11.6.3 | |
| - name: Download retained release | |
| uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 | |
| with: | |
| name: ${{ needs.runtime-plan.outputs.artifact_name }} | |
| path: ./dist | |
| - name: Validate retained release | |
| run: | | |
| node nodejs/node_modules/.bin/tsx nodejs/scripts/release-manifest.ts verify \ | |
| dist/release-manifest.json dist | |
| - name: Publish the same tarballs to public npm | |
| run: | | |
| node nodejs/scripts/npm-release.js publish-manifest \ | |
| dist/release-manifest.json dist unstable https://registry.npmjs.org public |