From c95e4f6d8662bb70851dc6acdc66f5eab594ac80 Mon Sep 17 00:00:00 2001 From: mcollinscodat Date: Tue, 4 Aug 2026 10:56:52 +0100 Subject: [PATCH 01/12] feat/CONN-1273-release-stubs: Replace Speakeasy generate/release workflows with thin stubs pointing at the central pipeline - bank_feeds_generate.yaml - generation moved to Codat SDK Codegen; stub warns and exits 0 - bank_feeds_release.yaml - queues the central Azure DevOps npm publish pipeline - lending_generate.yaml - generation moved to Codat SDK Codegen; stub warns and exits 0 - lending_release.yaml - queues the central Azure DevOps npm publish pipeline - platform_generate.yaml - generation moved to Codat SDK Codegen; stub warns and exits 0 - platform_release.yaml - queues the central Azure DevOps npm publish pipeline - sync_for_expenses_generate.yaml - generation moved to Codat SDK Codegen; stub warns and exits 0 - sync_for_expenses_release.yaml - queues the central Azure DevOps npm publish pipeline - sync_for_payables_generate.yaml - generation moved to Codat SDK Codegen; stub warns and exits 0 - sync_for_payables_release.yaml - queues the central Azure DevOps npm publish pipeline --- .github/workflows/bank_feeds_generate.yaml | 25 ++++++++------- .github/workflows/bank_feeds_release.yaml | 31 +++++++++++++++---- .github/workflows/lending_generate.yaml | 25 ++++++++------- .github/workflows/lending_release.yaml | 31 +++++++++++++++---- .github/workflows/platform_generate.yaml | 25 ++++++++------- .github/workflows/platform_release.yaml | 31 +++++++++++++++---- .../workflows/sync_for_expenses_generate.yaml | 25 ++++++++------- .../workflows/sync_for_expenses_release.yaml | 31 +++++++++++++++---- .../workflows/sync_for_payables_generate.yaml | 25 ++++++++------- .../workflows/sync_for_payables_release.yaml | 31 +++++++++++++++---- 10 files changed, 190 insertions(+), 90 deletions(-) diff --git a/.github/workflows/bank_feeds_generate.yaml b/.github/workflows/bank_feeds_generate.yaml index 3fd2640e8..642f7ac2f 100644 --- a/.github/workflows/bank_feeds_generate.yaml +++ b/.github/workflows/bank_feeds_generate.yaml @@ -1,3 +1,7 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK +# Codegen generates this SDK and opens a versioned PR here, dispatched by the +# oas pipeline. This stub only says so. name: Generate Bank Feeds library 'on': workflow_dispatch: @@ -11,15 +15,12 @@ name: Generate Bank Feeds library type: string jobs: generate: - uses: speakeasy-api/sdk-generation-action/.github/workflows/workflow-executor.yaml@v15 - with: - mode: pr - speakeasy_version: latest - force: ${{ github.event.inputs.force }} - set_version: ${{ github.event.inputs.set_version }} - target: bank-feeds-library - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Generation moved to Codat SDK Codegen + run: | + echo "::warning::This workflow no longer generates anything. bank-feeds is generated by generate-and-pr.yml in Codat SDK Codegen, dispatched by the oas pipeline, which opens a versioned PR on this repo." + # Exits 0 because the oas pipeline still runs this workflow on every OAS + # merge; flip to exit 1 in the same change that switches the oas trigger + # to the repository dispatch, so stray runs become loud. + exit 0 diff --git a/.github/workflows/bank_feeds_release.yaml b/.github/workflows/bank_feeds_release.yaml index b7f18fd18..6070dc67b 100644 --- a/.github/workflows/bank_feeds_release.yaml +++ b/.github/workflows/bank_feeds_release.yaml @@ -1,3 +1,8 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Publishing no longer runs in this repo. The packaging checks, the npm publish +# and the tag all run centrally in the Azure DevOps npm publish pipeline - no +# check has been dropped, they just moved. This stub only queues that pipeline, +# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. name: Release Bank Feeds library 'on': push: @@ -5,11 +10,25 @@ name: Release Bank Feeds library - bank-feeds/RELEASES.md branches: - main + workflow_dispatch: {} +concurrency: publish-bank-feeds-typescript jobs: publish: - uses: speakeasy-api/sdk-generation-action/.github/workflows/sdk-publish.yaml@v15 - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Queue the central npm publish pipeline + run: | + if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then + echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" + exit 1 + fi + if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then + echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" + exit 1 + fi + curl --fail-with-body --silent --show-error -X POST \ + -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ + -d '{"templateParameters": {"product": "bank-feeds", "sha": "${{ github.sha }}"}}' + echo "npm publish pipeline queued for bank-feeds @ ${{ github.sha }}" diff --git a/.github/workflows/lending_generate.yaml b/.github/workflows/lending_generate.yaml index 9b471fd32..370a0b71b 100644 --- a/.github/workflows/lending_generate.yaml +++ b/.github/workflows/lending_generate.yaml @@ -1,3 +1,7 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK +# Codegen generates this SDK and opens a versioned PR here, dispatched by the +# oas pipeline. This stub only says so. name: Generate Lending library 'on': workflow_dispatch: @@ -11,15 +15,12 @@ name: Generate Lending library type: string jobs: generate: - uses: speakeasy-api/sdk-generation-action/.github/workflows/workflow-executor.yaml@v15 - with: - mode: pr - speakeasy_version: latest - force: ${{ github.event.inputs.force }} - set_version: ${{ github.event.inputs.set_version }} - target: lending-library - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Generation moved to Codat SDK Codegen + run: | + echo "::warning::This workflow no longer generates anything. lending is generated by generate-and-pr.yml in Codat SDK Codegen, dispatched by the oas pipeline, which opens a versioned PR on this repo." + # Exits 0 because the oas pipeline still runs this workflow on every OAS + # merge; flip to exit 1 in the same change that switches the oas trigger + # to the repository dispatch, so stray runs become loud. + exit 0 diff --git a/.github/workflows/lending_release.yaml b/.github/workflows/lending_release.yaml index 6b655201a..d863b0d51 100644 --- a/.github/workflows/lending_release.yaml +++ b/.github/workflows/lending_release.yaml @@ -1,3 +1,8 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Publishing no longer runs in this repo. The packaging checks, the npm publish +# and the tag all run centrally in the Azure DevOps npm publish pipeline - no +# check has been dropped, they just moved. This stub only queues that pipeline, +# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. name: Release Lending library 'on': push: @@ -5,11 +10,25 @@ name: Release Lending library - lending/RELEASES.md branches: - main + workflow_dispatch: {} +concurrency: publish-lending-typescript jobs: publish: - uses: speakeasy-api/sdk-generation-action/.github/workflows/sdk-publish.yaml@v15 - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Queue the central npm publish pipeline + run: | + if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then + echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" + exit 1 + fi + if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then + echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" + exit 1 + fi + curl --fail-with-body --silent --show-error -X POST \ + -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ + -d '{"templateParameters": {"product": "lending", "sha": "${{ github.sha }}"}}' + echo "npm publish pipeline queued for lending @ ${{ github.sha }}" diff --git a/.github/workflows/platform_generate.yaml b/.github/workflows/platform_generate.yaml index 430b55a9a..8b8936e35 100644 --- a/.github/workflows/platform_generate.yaml +++ b/.github/workflows/platform_generate.yaml @@ -1,3 +1,7 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK +# Codegen generates this SDK and opens a versioned PR here, dispatched by the +# oas pipeline. This stub only says so. name: Generate Platform library 'on': workflow_dispatch: @@ -11,15 +15,12 @@ name: Generate Platform library type: string jobs: generate: - uses: speakeasy-api/sdk-generation-action/.github/workflows/workflow-executor.yaml@v15 - with: - mode: pr - speakeasy_version: latest - force: ${{ github.event.inputs.force }} - set_version: ${{ github.event.inputs.set_version }} - target: platform-library - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Generation moved to Codat SDK Codegen + run: | + echo "::warning::This workflow no longer generates anything. platform is generated by generate-and-pr.yml in Codat SDK Codegen, dispatched by the oas pipeline, which opens a versioned PR on this repo." + # Exits 0 because the oas pipeline still runs this workflow on every OAS + # merge; flip to exit 1 in the same change that switches the oas trigger + # to the repository dispatch, so stray runs become loud. + exit 0 diff --git a/.github/workflows/platform_release.yaml b/.github/workflows/platform_release.yaml index 3f29ca9b8..9f5e29161 100644 --- a/.github/workflows/platform_release.yaml +++ b/.github/workflows/platform_release.yaml @@ -1,3 +1,8 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Publishing no longer runs in this repo. The packaging checks, the npm publish +# and the tag all run centrally in the Azure DevOps npm publish pipeline - no +# check has been dropped, they just moved. This stub only queues that pipeline, +# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. name: Release Platform library 'on': push: @@ -5,11 +10,25 @@ name: Release Platform library - platform/RELEASES.md branches: - main + workflow_dispatch: {} +concurrency: publish-platform-typescript jobs: publish: - uses: speakeasy-api/sdk-generation-action/.github/workflows/sdk-publish.yaml@v15 - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Queue the central npm publish pipeline + run: | + if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then + echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" + exit 1 + fi + if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then + echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" + exit 1 + fi + curl --fail-with-body --silent --show-error -X POST \ + -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ + -d '{"templateParameters": {"product": "platform", "sha": "${{ github.sha }}"}}' + echo "npm publish pipeline queued for platform @ ${{ github.sha }}" diff --git a/.github/workflows/sync_for_expenses_generate.yaml b/.github/workflows/sync_for_expenses_generate.yaml index c3c913524..cc7e6a8af 100644 --- a/.github/workflows/sync_for_expenses_generate.yaml +++ b/.github/workflows/sync_for_expenses_generate.yaml @@ -1,3 +1,7 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK +# Codegen generates this SDK and opens a versioned PR here, dispatched by the +# oas pipeline. This stub only says so. name: Generate Sync for Expenses library 'on': workflow_dispatch: @@ -11,15 +15,12 @@ name: Generate Sync for Expenses library type: string jobs: generate: - uses: speakeasy-api/sdk-generation-action/.github/workflows/workflow-executor.yaml@v15 - with: - mode: pr - speakeasy_version: latest - force: ${{ github.event.inputs.force }} - set_version: ${{ github.event.inputs.set_version }} - target: sync-for-expenses-library - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Generation moved to Codat SDK Codegen + run: | + echo "::warning::This workflow no longer generates anything. sync-for-expenses is generated by generate-and-pr.yml in Codat SDK Codegen, dispatched by the oas pipeline, which opens a versioned PR on this repo." + # Exits 0 because the oas pipeline still runs this workflow on every OAS + # merge; flip to exit 1 in the same change that switches the oas trigger + # to the repository dispatch, so stray runs become loud. + exit 0 diff --git a/.github/workflows/sync_for_expenses_release.yaml b/.github/workflows/sync_for_expenses_release.yaml index 6256868f3..95ebfcc5f 100644 --- a/.github/workflows/sync_for_expenses_release.yaml +++ b/.github/workflows/sync_for_expenses_release.yaml @@ -1,3 +1,8 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Publishing no longer runs in this repo. The packaging checks, the npm publish +# and the tag all run centrally in the Azure DevOps npm publish pipeline - no +# check has been dropped, they just moved. This stub only queues that pipeline, +# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. name: Release Sync for Expenses library 'on': push: @@ -5,11 +10,25 @@ name: Release Sync for Expenses library - sync-for-expenses/RELEASES.md branches: - main + workflow_dispatch: {} +concurrency: publish-sync-for-expenses-typescript jobs: publish: - uses: speakeasy-api/sdk-generation-action/.github/workflows/sdk-publish.yaml@v15 - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Queue the central npm publish pipeline + run: | + if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then + echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" + exit 1 + fi + if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then + echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" + exit 1 + fi + curl --fail-with-body --silent --show-error -X POST \ + -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ + -d '{"templateParameters": {"product": "sync-for-expenses", "sha": "${{ github.sha }}"}}' + echo "npm publish pipeline queued for sync-for-expenses @ ${{ github.sha }}" diff --git a/.github/workflows/sync_for_payables_generate.yaml b/.github/workflows/sync_for_payables_generate.yaml index 06552ce6f..114079a5e 100644 --- a/.github/workflows/sync_for_payables_generate.yaml +++ b/.github/workflows/sync_for_payables_generate.yaml @@ -1,3 +1,7 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK +# Codegen generates this SDK and opens a versioned PR here, dispatched by the +# oas pipeline. This stub only says so. name: Generate Sync for Payables library 'on': workflow_dispatch: @@ -11,15 +15,12 @@ name: Generate Sync for Payables library type: string jobs: generate: - uses: speakeasy-api/sdk-generation-action/.github/workflows/workflow-executor.yaml@v15 - with: - mode: pr - speakeasy_version: latest - force: ${{ github.event.inputs.force }} - set_version: ${{ github.event.inputs.set_version }} - target: sync-for-payables-library - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Generation moved to Codat SDK Codegen + run: | + echo "::warning::This workflow no longer generates anything. sync-for-payables is generated by generate-and-pr.yml in Codat SDK Codegen, dispatched by the oas pipeline, which opens a versioned PR on this repo." + # Exits 0 because the oas pipeline still runs this workflow on every OAS + # merge; flip to exit 1 in the same change that switches the oas trigger + # to the repository dispatch, so stray runs become loud. + exit 0 diff --git a/.github/workflows/sync_for_payables_release.yaml b/.github/workflows/sync_for_payables_release.yaml index b855fa109..6edd09cd6 100644 --- a/.github/workflows/sync_for_payables_release.yaml +++ b/.github/workflows/sync_for_payables_release.yaml @@ -1,3 +1,8 @@ +# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Publishing no longer runs in this repo. The packaging checks, the npm publish +# and the tag all run centrally in the Azure DevOps npm publish pipeline - no +# check has been dropped, they just moved. This stub only queues that pipeline, +# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. name: Release Sync for Payables library 'on': push: @@ -5,11 +10,25 @@ name: Release Sync for Payables library - sync-for-payables/RELEASES.md branches: - main + workflow_dispatch: {} +concurrency: publish-sync-for-payables-typescript jobs: publish: - uses: speakeasy-api/sdk-generation-action/.github/workflows/sdk-publish.yaml@v15 - secrets: - github_access_token: ${{ secrets.GITHUB_TOKEN }} - speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }} - slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} - npm_token: ${{ secrets.NPM_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Queue the central npm publish pipeline + run: | + if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then + echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" + exit 1 + fi + if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then + echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" + exit 1 + fi + curl --fail-with-body --silent --show-error -X POST \ + -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ + -d '{"templateParameters": {"product": "sync-for-payables", "sha": "${{ github.sha }}"}}' + echo "npm publish pipeline queued for sync-for-payables @ ${{ github.sha }}" From e2d61b585ac3930f6861758cb368e291b2647953 Mon Sep 17 00:00:00 2001 From: mcollinscodat Date: Tue, 4 Aug 2026 14:29:01 +0100 Subject: [PATCH 02/12] feat/CONN-1273-release-stubs: the release stubs stop queuing the publish pipeline, and the pipeline itself lands in this repo .azuredevops/npm-publish.yml - new: builds, checks and publishes the released package to npm, triggered by the push to /RELEASES.md; written by sdk-codegen (cutover/npm_publish_pipeline.yml), do not edit by hand .github/workflows/bank_feeds_release.yaml - stub no longer queues Azure DevOps over REST, it just records where publishing went; no token, no pipeline url, no concurrency group .github/workflows/lending_release.yaml - same .github/workflows/platform_release.yaml - same .github/workflows/sync_for_expenses_release.yaml - same .github/workflows/sync_for_payables_release.yaml - same --- .azuredevops/npm-publish.yml | 324 ++++++++++++++++++ .github/workflows/bank_feeds_release.yaml | 28 +- .github/workflows/lending_release.yaml | 28 +- .github/workflows/platform_release.yaml | 28 +- .../workflows/sync_for_expenses_release.yaml | 28 +- .../workflows/sync_for_payables_release.yaml | 28 +- 6 files changed, 364 insertions(+), 100 deletions(-) create mode 100644 .azuredevops/npm-publish.yml diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml new file mode 100644 index 000000000..47b3c1fb4 --- /dev/null +++ b/.azuredevops/npm-publish.yml @@ -0,0 +1,324 @@ +# Publishes one @codat/* TypeScript SDK package to public npm. +# +# This file lives in the SDK repo (codatio/client-sdk-typescript) at +# .azuredevops/npm-publish.yml, not in this repo: Azure Pipelines CI triggers +# only fire for the repository the YAML is committed to. The copy here is the +# source of truth that gets delivered into the SDK repo. +# +# It fires when a versioned release PR merges to main, which it recognises by a +# change to /RELEASES.md. The detect step works out which product that +# was; a versioned PR only ever touches one, so two at once is an error rather +# than a guess. A manual run can override the product for testing. +# +# Build stage: builds and packs the package at the merged commit and runs the +# packaging checks that used to run in the GitHub Actions release rehearsal +# (mirror_release_workflows.py). Publish stage: publishes the tarball under the +# "next" dist-tag; if the version is already on npm it skips and stays green, so +# a re-run is harmless. The npm credential lives in the +# codat-npm-publish-packages service connection and never leaves Azure. + +trigger: + branches: + include: [main] + paths: + include: + - bank-feeds/RELEASES.md + - lending/RELEASES.md + - platform/RELEASES.md + - sync-for-expenses/RELEASES.md + - sync-for-payables/RELEASES.md + +pr: none + +parameters: + - name: product + displayName: Product to publish ("auto" reads it from the merged commit) + type: string + default: auto + values: + - auto + - bank-feeds + - lending + - platform + - sync-for-expenses + - sync-for-payables + +resources: + repositories: + # Checkout-only: the check scripts (exports_smoke.mjs), products.json and + # the feed .npmrc live in the codegen repo. No trigger comes from here. + - repository: codegen + type: github + name: codat-internal/sdk-codegen + ref: refs/heads/main + endpoint: codat-tech + +variables: + nodeVersion: "20.x" + # Two repos are checked out, so each checkout step pins its own folder + # rather than relying on the default multi-repo layout. + sdkDir: $(Agent.BuildDirectory)/s/sdk + codegenDir: $(Agent.BuildDirectory)/s/codegen + publicNpmRegistry: "https://registry.npmjs.org/" + npmServiceConnection: "codat-npm-publish-packages" + packageArtifact: "npm-package" + distTag: "next" + +stages: + - stage: BuildValidate + displayName: "Build & validate" + jobs: + - job: BuildValidate + displayName: "Build, pack and check the package" + pool: codat-intg-managed-devops-pool-linux + variables: + NPM_CONFIG_USERCONFIG: $(Agent.TempDirectory)/.npmrc + steps: + # Two commits so the detect step can diff the merge against its parent. + - checkout: self + fetchDepth: 2 + path: s/sdk + - checkout: codegen + fetchDepth: 1 + path: s/codegen + + - task: Bash@3 + displayName: "Work out which product this release is for" + inputs: + targetType: inline + workingDirectory: $(sdkDir) + script: | + set -euo pipefail + override="${{ parameters.product }}" + if [ "$override" != "auto" ]; then + echo "Manual override: publishing $override" + echo "##vso[task.setvariable variable=product]$override" + exit 0 + fi + if ! git rev-parse --verify --quiet HEAD^ >/dev/null; then + echo "##[error]No parent commit to diff against — re-run with the product parameter set" + exit 1 + fi + # No match is a normal outcome here, not a script failure, so + # the guidance below gets a chance to print. + changed=$(git diff --name-only HEAD^ HEAD \ + | grep -E '^(bank-feeds|lending|platform|sync-for-expenses|sync-for-payables)/RELEASES\.md$' \ + | cut -d/ -f1 | sort -u || true) + count=$(echo "$changed" | grep -c . || true) + if [ "$count" -eq 0 ]; then + echo "##[error]No /RELEASES.md changed in $(git rev-parse --short HEAD) — nothing to publish. Re-run with the product parameter if this was intentional." + exit 1 + fi + if [ "$count" -gt 1 ]; then + echo "##[error]More than one product released in one commit: $(echo $changed). Release PRs are one product each — re-run per product with the product parameter." + exit 1 + fi + echo "Releasing $changed" + echo "##vso[task.setvariable variable=product]$changed" + + - task: UseNode@1 + displayName: "Install Node.js" + inputs: + version: $(nodeVersion) + + # Installs go through Codat's verified feed, not public npm — the feed + # mirrors npmjs and everything on it has been through safe-package-feeder. + # First run needs the feed owner to approve this pipeline's access. + - task: Bash@3 + displayName: "Point npm at Codat's verified feed" + inputs: + targetType: inline + script: cp "$(codegenDir)/parity/typescript/.npmrc.example" "$(Agent.TempDirectory)/.npmrc" + + - task: npmAuthenticate@0 + displayName: "Authenticate to the feed" + inputs: + workingFile: $(Agent.TempDirectory)/.npmrc + + - task: Bash@3 + displayName: "Check the product folder is there" + inputs: + targetType: inline + workingDirectory: $(sdkDir) + script: | + set -euo pipefail + if [ ! -f "$(product)/package.json" ]; then + echo "##[error]No $(product)/package.json at this commit — is the product folder name right?" + exit 1 + fi + + - task: Bash@3 + displayName: "Build and pack" + inputs: + targetType: inline + workingDirectory: $(sdkDir) + script: | + set -euo pipefail + cd "$(product)" + if [ -f package-lock.json ]; then npm ci; else npm install; fi + npm run build + cd .. + mkdir -p "$(Build.ArtifactStagingDirectory)/pack-out" + npm pack "./$(product)" --pack-destination "$(Build.ArtifactStagingDirectory)/pack-out" + + - task: Bash@3 + displayName: "Check the tarball carries the stamped version" + inputs: + targetType: inline + workingDirectory: $(Build.ArtifactStagingDirectory)/pack-out + script: | + set -euo pipefail + stamped=$(node -p "require('$(sdkDir)/$(product)/package.json').version") + echo "stamped version: $stamped" + ls | grep -F -- "-$stamped.tgz" >/dev/null || { + echo "##[error]Tarball does not carry version $stamped"; ls; exit 1; } + + - task: Bash@3 + displayName: "Tarball tripwire (dist populated, no .npmrc)" + inputs: + targetType: inline + workingDirectory: $(Build.ArtifactStagingDirectory)/pack-out + script: | + set -euo pipefail + tgz=$(ls *.tgz) + dist_js=$(tar -tzf "$tgz" | grep -c '^package/dist/.*\.js$' || true) + echo "built dist/*.js files in tarball: $dist_js" + if [ "$dist_js" -eq 0 ]; then + echo "##[error]Tarball has no built dist/*.js — the package would install empty" + tar -tzf "$tgz" | head -40; exit 1 + fi + if tar -tzf "$tgz" | grep -q '^package/\.npmrc$'; then + echo "##[error]Tarball contains .npmrc — private-feed credentials must never be published"; exit 1 + fi + + - task: Bash@3 + displayName: "npm publish dry run" + inputs: + targetType: inline + workingDirectory: $(Build.ArtifactStagingDirectory)/pack-out + script: npm publish ./*.tgz --dry-run --registry=$(publicNpmRegistry) + + - task: Bash@3 + displayName: "Install into a scratch consumer, compile and load" + inputs: + targetType: inline + script: | + set -euo pipefail + client=$(node -p " + const p = require('$(codegenDir)/products.json').products; + p['$(product)'].typescript.client_class_name") + mkdir "$(Agent.TempDirectory)/consumer" && cd "$(Agent.TempDirectory)/consumer" + npm init -y >/dev/null + npm install "$(Build.ArtifactStagingDirectory)"/pack-out/*.tgz typescript @types/node >/dev/null + cat > smoke.ts <&1) + status=$? + set -e + if [ $status -eq 0 ] && [ "$output" = "$version" ]; then + echo "##vso[task.setvariable variable=alreadyPublished]true" + echo "$name@$version is already on npm — nothing to publish." + elif { [ $status -eq 0 ] && [ -z "$output" ]; } || echo "$output" | grep -q "E404\|No match found for version"; then + echo "##vso[task.setvariable variable=alreadyPublished]false" + echo "$name@$version is not on npm yet — publishing under --tag $(distTag)." + else + echo "$output" + echo "##[error]Could not determine whether $name@$version is already on npm" + exit 1 + fi + + - task: Bash@3 + displayName: "Prepare public npm .npmrc" + inputs: + targetType: inline + workingDirectory: $(Pipeline.Workspace)/pack-out + script: | + { + echo "registry=$(publicNpmRegistry)" + echo "always-auth=true" + } > .npmrc + + - task: npmAuthenticate@0 + displayName: "Authenticate to public npm" + inputs: + workingFile: $(Pipeline.Workspace)/pack-out/.npmrc + customEndpoint: $(npmServiceConnection) + + - task: Bash@3 + displayName: "Publish" + inputs: + targetType: inline + workingDirectory: $(Pipeline.Workspace)/pack-out + script: | + set -euo pipefail + if [ "$(alreadyPublished)" = "true" ]; then + echo "Version already on npm — skipping publish." + exit 0 + fi + npm publish ./*.tgz --access public --tag $(distTag) diff --git a/.github/workflows/bank_feeds_release.yaml b/.github/workflows/bank_feeds_release.yaml index 6070dc67b..722033b28 100644 --- a/.github/workflows/bank_feeds_release.yaml +++ b/.github/workflows/bank_feeds_release.yaml @@ -1,8 +1,9 @@ # Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. -# Publishing no longer runs in this repo. The packaging checks, the npm publish -# and the tag all run centrally in the Azure DevOps npm publish pipeline - no -# check has been dropped, they just moved. This stub only queues that pipeline, -# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. +# Publishing no longer runs in this repo. The packaging checks, the upload to +# npm and the tag all run centrally in the Azure DevOps pipeline at +# .azuredevops/npm-publish.yml - no check has been dropped, they just moved. +# That pipeline watches this same RELEASES.md push itself, so this stub has +# nothing to hand on and only says where publishing went. name: Release Bank Feeds library 'on': push: @@ -11,24 +12,11 @@ name: Release Bank Feeds library branches: - main workflow_dispatch: {} -concurrency: publish-bank-feeds-typescript jobs: publish: runs-on: ubuntu-latest steps: - - name: Queue the central npm publish pipeline + - name: Publishing moved to the Azure DevOps pipeline run: | - if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then - echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" - exit 1 - fi - if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then - echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" - exit 1 - fi - curl --fail-with-body --silent --show-error -X POST \ - -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ - -H "Content-Type: application/json" \ - "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ - -d '{"templateParameters": {"product": "bank-feeds", "sha": "${{ github.sha }}"}}' - echo "npm publish pipeline queued for bank-feeds @ ${{ github.sha }}" + echo "::warning::This workflow no longer publishes anything. bank-feeds is built, checked and published to npm by .azuredevops/npm-publish.yml, which triggers on this same push to bank-feeds/RELEASES.md." + exit 0 diff --git a/.github/workflows/lending_release.yaml b/.github/workflows/lending_release.yaml index d863b0d51..c78aa9f08 100644 --- a/.github/workflows/lending_release.yaml +++ b/.github/workflows/lending_release.yaml @@ -1,8 +1,9 @@ # Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. -# Publishing no longer runs in this repo. The packaging checks, the npm publish -# and the tag all run centrally in the Azure DevOps npm publish pipeline - no -# check has been dropped, they just moved. This stub only queues that pipeline, -# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. +# Publishing no longer runs in this repo. The packaging checks, the upload to +# npm and the tag all run centrally in the Azure DevOps pipeline at +# .azuredevops/npm-publish.yml - no check has been dropped, they just moved. +# That pipeline watches this same RELEASES.md push itself, so this stub has +# nothing to hand on and only says where publishing went. name: Release Lending library 'on': push: @@ -11,24 +12,11 @@ name: Release Lending library branches: - main workflow_dispatch: {} -concurrency: publish-lending-typescript jobs: publish: runs-on: ubuntu-latest steps: - - name: Queue the central npm publish pipeline + - name: Publishing moved to the Azure DevOps pipeline run: | - if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then - echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" - exit 1 - fi - if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then - echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" - exit 1 - fi - curl --fail-with-body --silent --show-error -X POST \ - -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ - -H "Content-Type: application/json" \ - "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ - -d '{"templateParameters": {"product": "lending", "sha": "${{ github.sha }}"}}' - echo "npm publish pipeline queued for lending @ ${{ github.sha }}" + echo "::warning::This workflow no longer publishes anything. lending is built, checked and published to npm by .azuredevops/npm-publish.yml, which triggers on this same push to lending/RELEASES.md." + exit 0 diff --git a/.github/workflows/platform_release.yaml b/.github/workflows/platform_release.yaml index 9f5e29161..b06111665 100644 --- a/.github/workflows/platform_release.yaml +++ b/.github/workflows/platform_release.yaml @@ -1,8 +1,9 @@ # Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. -# Publishing no longer runs in this repo. The packaging checks, the npm publish -# and the tag all run centrally in the Azure DevOps npm publish pipeline - no -# check has been dropped, they just moved. This stub only queues that pipeline, -# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. +# Publishing no longer runs in this repo. The packaging checks, the upload to +# npm and the tag all run centrally in the Azure DevOps pipeline at +# .azuredevops/npm-publish.yml - no check has been dropped, they just moved. +# That pipeline watches this same RELEASES.md push itself, so this stub has +# nothing to hand on and only says where publishing went. name: Release Platform library 'on': push: @@ -11,24 +12,11 @@ name: Release Platform library branches: - main workflow_dispatch: {} -concurrency: publish-platform-typescript jobs: publish: runs-on: ubuntu-latest steps: - - name: Queue the central npm publish pipeline + - name: Publishing moved to the Azure DevOps pipeline run: | - if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then - echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" - exit 1 - fi - if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then - echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" - exit 1 - fi - curl --fail-with-body --silent --show-error -X POST \ - -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ - -H "Content-Type: application/json" \ - "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ - -d '{"templateParameters": {"product": "platform", "sha": "${{ github.sha }}"}}' - echo "npm publish pipeline queued for platform @ ${{ github.sha }}" + echo "::warning::This workflow no longer publishes anything. platform is built, checked and published to npm by .azuredevops/npm-publish.yml, which triggers on this same push to platform/RELEASES.md." + exit 0 diff --git a/.github/workflows/sync_for_expenses_release.yaml b/.github/workflows/sync_for_expenses_release.yaml index 95ebfcc5f..d47c6e38a 100644 --- a/.github/workflows/sync_for_expenses_release.yaml +++ b/.github/workflows/sync_for_expenses_release.yaml @@ -1,8 +1,9 @@ # Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. -# Publishing no longer runs in this repo. The packaging checks, the npm publish -# and the tag all run centrally in the Azure DevOps npm publish pipeline - no -# check has been dropped, they just moved. This stub only queues that pipeline, -# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. +# Publishing no longer runs in this repo. The packaging checks, the upload to +# npm and the tag all run centrally in the Azure DevOps pipeline at +# .azuredevops/npm-publish.yml - no check has been dropped, they just moved. +# That pipeline watches this same RELEASES.md push itself, so this stub has +# nothing to hand on and only says where publishing went. name: Release Sync for Expenses library 'on': push: @@ -11,24 +12,11 @@ name: Release Sync for Expenses library branches: - main workflow_dispatch: {} -concurrency: publish-sync-for-expenses-typescript jobs: publish: runs-on: ubuntu-latest steps: - - name: Queue the central npm publish pipeline + - name: Publishing moved to the Azure DevOps pipeline run: | - if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then - echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" - exit 1 - fi - if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then - echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" - exit 1 - fi - curl --fail-with-body --silent --show-error -X POST \ - -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ - -H "Content-Type: application/json" \ - "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ - -d '{"templateParameters": {"product": "sync-for-expenses", "sha": "${{ github.sha }}"}}' - echo "npm publish pipeline queued for sync-for-expenses @ ${{ github.sha }}" + echo "::warning::This workflow no longer publishes anything. sync-for-expenses is built, checked and published to npm by .azuredevops/npm-publish.yml, which triggers on this same push to sync-for-expenses/RELEASES.md." + exit 0 diff --git a/.github/workflows/sync_for_payables_release.yaml b/.github/workflows/sync_for_payables_release.yaml index 6edd09cd6..d59a0d1b4 100644 --- a/.github/workflows/sync_for_payables_release.yaml +++ b/.github/workflows/sync_for_payables_release.yaml @@ -1,8 +1,9 @@ # Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. -# Publishing no longer runs in this repo. The packaging checks, the npm publish -# and the tag all run centrally in the Azure DevOps npm publish pipeline - no -# check has been dropped, they just moved. This stub only queues that pipeline, -# at the url in the ADO_PUBLISH_PIPELINE_URL repo variable. +# Publishing no longer runs in this repo. The packaging checks, the upload to +# npm and the tag all run centrally in the Azure DevOps pipeline at +# .azuredevops/npm-publish.yml - no check has been dropped, they just moved. +# That pipeline watches this same RELEASES.md push itself, so this stub has +# nothing to hand on and only says where publishing went. name: Release Sync for Payables library 'on': push: @@ -11,24 +12,11 @@ name: Release Sync for Payables library branches: - main workflow_dispatch: {} -concurrency: publish-sync-for-payables-typescript jobs: publish: runs-on: ubuntu-latest steps: - - name: Queue the central npm publish pipeline + - name: Publishing moved to the Azure DevOps pipeline run: | - if [ -z "${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" ]; then - echo "::error::ADO_PUBLISH_TRIGGER_TOKEN secret is not set - needed to queue the Azure DevOps npm publish pipeline" - exit 1 - fi - if [ -z "${{ vars.ADO_PUBLISH_PIPELINE_URL }}" ]; then - echo "::error::ADO_PUBLISH_PIPELINE_URL repo variable is not set - expected https://dev.azure.com///_apis/pipelines/" - exit 1 - fi - curl --fail-with-body --silent --show-error -X POST \ - -u ":${{ secrets.ADO_PUBLISH_TRIGGER_TOKEN }}" \ - -H "Content-Type: application/json" \ - "${{ vars.ADO_PUBLISH_PIPELINE_URL }}/runs?api-version=7.1" \ - -d '{"templateParameters": {"product": "sync-for-payables", "sha": "${{ github.sha }}"}}' - echo "npm publish pipeline queued for sync-for-payables @ ${{ github.sha }}" + echo "::warning::This workflow no longer publishes anything. sync-for-payables is built, checked and published to npm by .azuredevops/npm-publish.yml, which triggers on this same push to sync-for-payables/RELEASES.md." + exit 0 From 146cfa82a9218c37da4c2cf1f7e3e55fff57a485 Mon Sep 17 00:00:00 2001 From: mcollinscodat Date: Tue, 4 Aug 2026 15:13:08 +0100 Subject: [PATCH 03/12] feat/CONN-1273-release-stubs: re-deliver the publish pipeline after its comments were reworded .azuredevops/npm-publish.yml - re-emitted from cutover/npm_publish_pipeline.yml in sdk-codegen: clearer header comments and the two source paths now read from $(Build.SourcesDirectory); no change to what the pipeline does --- .azuredevops/npm-publish.yml | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index 47b3c1fb4..b7cd679ab 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -1,18 +1,17 @@ # Publishes one @codat/* TypeScript SDK package to public npm. # -# This file lives in the SDK repo (codatio/client-sdk-typescript) at -# .azuredevops/npm-publish.yml, not in this repo: Azure Pipelines CI triggers -# only fire for the repository the YAML is committed to. The copy here is the -# source of truth that gets delivered into the SDK repo. +# This file actually lives in the SDK repo (codatio/client-sdk-typescript) at +# .azuredevops/npm-publish.yml, not in this repo because Azure Pipelines CI +# triggers only fire for the repository the YAML is committed to. The copy here +# is the source of truth that gets delivered into the SDK repo. # # It fires when a versioned release PR merges to main, which it recognises by a # change to /RELEASES.md. The detect step works out which product that -# was; a versioned PR only ever touches one, so two at once is an error rather -# than a guess. A manual run can override the product for testing. +# was; a versioned PR only ever touches one product at a time, so two at once +# will error. A manual run can override the product for testing. # -# Build stage: builds and packs the package at the merged commit and runs the -# packaging checks that used to run in the GitHub Actions release rehearsal -# (mirror_release_workflows.py). Publish stage: publishes the tarball under the +# Build stage: builds and packs the package at the merged commit and runs +# packaging checks. Publish stage: publishes the tarball under the # "next" dist-tag; if the version is already on npm it skips and stays green, so # a re-run is harmless. The npm credential lives in the # codat-npm-publish-packages service connection and never leaves Azure. @@ -45,8 +44,6 @@ parameters: resources: repositories: - # Checkout-only: the check scripts (exports_smoke.mjs), products.json and - # the feed .npmrc live in the codegen repo. No trigger comes from here. - repository: codegen type: github name: codat-internal/sdk-codegen @@ -55,10 +52,9 @@ resources: variables: nodeVersion: "20.x" - # Two repos are checked out, so each checkout step pins its own folder - # rather than relying on the default multi-repo layout. - sdkDir: $(Agent.BuildDirectory)/s/sdk - codegenDir: $(Agent.BuildDirectory)/s/codegen + # Both checkouts pin their folder, so these paths don't depend on ADO's default naming + sdkDir: $(Build.SourcesDirectory)/sdk + codegenDir: $(Build.SourcesDirectory)/codegen publicNpmRegistry: "https://registry.npmjs.org/" npmServiceConnection: "codat-npm-publish-packages" packageArtifact: "npm-package" From dd18d0aff3de41c0d815bec2d84a3f1d101f9aa3 Mon Sep 17 00:00:00 2001 From: mcollinscodat Date: Tue, 4 Aug 2026 15:33:18 +0100 Subject: [PATCH 04/12] feat/CONN-1273-release-stubs: re-deliver after the header wording was tidied .azuredevops/npm-publish.yml - the header no longer says "this repo", which flipped meaning depending on which copy you read; it names both repos and carries the written-by line the stubs have .github/workflows - all ten stubs: the written-by line names just the emitter file, not its path --- .azuredevops/npm-publish.yml | 9 +++++---- .github/workflows/bank_feeds_generate.yaml | 2 +- .github/workflows/bank_feeds_release.yaml | 2 +- .github/workflows/lending_generate.yaml | 2 +- .github/workflows/lending_release.yaml | 2 +- .github/workflows/platform_generate.yaml | 2 +- .github/workflows/platform_release.yaml | 2 +- .github/workflows/sync_for_expenses_generate.yaml | 2 +- .github/workflows/sync_for_expenses_release.yaml | 2 +- .github/workflows/sync_for_payables_generate.yaml | 2 +- .github/workflows/sync_for_payables_release.yaml | 2 +- 11 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index b7cd679ab..e1a1f48fc 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -1,9 +1,10 @@ # Publishes one @codat/* TypeScript SDK package to public npm. # -# This file actually lives in the SDK repo (codatio/client-sdk-typescript) at -# .azuredevops/npm-publish.yml, not in this repo because Azure Pipelines CI -# triggers only fire for the repository the YAML is committed to. The copy here -# is the source of truth that gets delivered into the SDK repo. +# Written by sdk-codegen (npm_publish_pipeline.yml); do not edit by hand. +# It runs from codatio/client-sdk-typescript at .azuredevops/npm-publish.yml, +# because an Azure Pipelines CI trigger only fires for the repository the YAML +# is committed to. codat-internal/sdk-codegen holds the source of truth and +# delivers a copy into the SDK repo. # # It fires when a versioned release PR merges to main, which it recognises by a # change to /RELEASES.md. The detect step works out which product that diff --git a/.github/workflows/bank_feeds_generate.yaml b/.github/workflows/bank_feeds_generate.yaml index 642f7ac2f..2fd103af1 100644 --- a/.github/workflows/bank_feeds_generate.yaml +++ b/.github/workflows/bank_feeds_generate.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK # Codegen generates this SDK and opens a versioned PR here, dispatched by the # oas pipeline. This stub only says so. diff --git a/.github/workflows/bank_feeds_release.yaml b/.github/workflows/bank_feeds_release.yaml index 722033b28..84949dc01 100644 --- a/.github/workflows/bank_feeds_release.yaml +++ b/.github/workflows/bank_feeds_release.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Publishing no longer runs in this repo. The packaging checks, the upload to # npm and the tag all run centrally in the Azure DevOps pipeline at # .azuredevops/npm-publish.yml - no check has been dropped, they just moved. diff --git a/.github/workflows/lending_generate.yaml b/.github/workflows/lending_generate.yaml index 370a0b71b..93bcaab3b 100644 --- a/.github/workflows/lending_generate.yaml +++ b/.github/workflows/lending_generate.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK # Codegen generates this SDK and opens a versioned PR here, dispatched by the # oas pipeline. This stub only says so. diff --git a/.github/workflows/lending_release.yaml b/.github/workflows/lending_release.yaml index c78aa9f08..7836d26fa 100644 --- a/.github/workflows/lending_release.yaml +++ b/.github/workflows/lending_release.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Publishing no longer runs in this repo. The packaging checks, the upload to # npm and the tag all run centrally in the Azure DevOps pipeline at # .azuredevops/npm-publish.yml - no check has been dropped, they just moved. diff --git a/.github/workflows/platform_generate.yaml b/.github/workflows/platform_generate.yaml index 8b8936e35..a0dc2273e 100644 --- a/.github/workflows/platform_generate.yaml +++ b/.github/workflows/platform_generate.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK # Codegen generates this SDK and opens a versioned PR here, dispatched by the # oas pipeline. This stub only says so. diff --git a/.github/workflows/platform_release.yaml b/.github/workflows/platform_release.yaml index b06111665..1e86161e9 100644 --- a/.github/workflows/platform_release.yaml +++ b/.github/workflows/platform_release.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Publishing no longer runs in this repo. The packaging checks, the upload to # npm and the tag all run centrally in the Azure DevOps pipeline at # .azuredevops/npm-publish.yml - no check has been dropped, they just moved. diff --git a/.github/workflows/sync_for_expenses_generate.yaml b/.github/workflows/sync_for_expenses_generate.yaml index cc7e6a8af..fafe61375 100644 --- a/.github/workflows/sync_for_expenses_generate.yaml +++ b/.github/workflows/sync_for_expenses_generate.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK # Codegen generates this SDK and opens a versioned PR here, dispatched by the # oas pipeline. This stub only says so. diff --git a/.github/workflows/sync_for_expenses_release.yaml b/.github/workflows/sync_for_expenses_release.yaml index d47c6e38a..3fde6470d 100644 --- a/.github/workflows/sync_for_expenses_release.yaml +++ b/.github/workflows/sync_for_expenses_release.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Publishing no longer runs in this repo. The packaging checks, the upload to # npm and the tag all run centrally in the Azure DevOps pipeline at # .azuredevops/npm-publish.yml - no check has been dropped, they just moved. diff --git a/.github/workflows/sync_for_payables_generate.yaml b/.github/workflows/sync_for_payables_generate.yaml index 114079a5e..fb56617ce 100644 --- a/.github/workflows/sync_for_payables_generate.yaml +++ b/.github/workflows/sync_for_payables_generate.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Generation no longer runs in this repo: generate-and-pr.yml in Codat SDK # Codegen generates this SDK and opens a versioned PR here, dispatched by the # oas pipeline. This stub only says so. diff --git a/.github/workflows/sync_for_payables_release.yaml b/.github/workflows/sync_for_payables_release.yaml index d59a0d1b4..33c6b8a9d 100644 --- a/.github/workflows/sync_for_payables_release.yaml +++ b/.github/workflows/sync_for_payables_release.yaml @@ -1,4 +1,4 @@ -# Written by sdk-codegen (cutover/emit_workflow_stubs.py); do not edit by hand. +# Written by sdk-codegen (emit_workflow_stubs.py); do not edit by hand. # Publishing no longer runs in this repo. The packaging checks, the upload to # npm and the tag all run centrally in the Azure DevOps pipeline at # .azuredevops/npm-publish.yml - no check has been dropped, they just moved. From 449ed4415358373f6fa84f585a4bbeebd3b967b9 Mon Sep 17 00:00:00 2001 From: mcollinscodat Date: Tue, 11 Aug 2026 12:15:37 +0100 Subject: [PATCH 05/12] feat/CONN-1273-release-stubs: re-deliver the npm publish pipeline so a release gets tagged again - .azuredevops/npm-publish.yml - re-emitted from sdk-codegen main: brings back the release-facts step, the OAS variable group, the GitHub App token mint, and the tag and GitHub release steps that were added to the pipeline centrally after this branch was last delivered --- .azuredevops/npm-publish.yml | 133 ++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index e1a1f48fc..22abd42d5 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -12,10 +12,20 @@ # will error. A manual run can override the product for testing. # # Build stage: builds and packs the package at the merged commit and runs -# packaging checks. Publish stage: publishes the tarball under the -# "next" dist-tag; if the version is already on npm it skips and stays green, so -# a re-run is harmless. The npm credential lives in the +# packaging checks. Publish stage: publishes the tarball under the "next" +# dist-tag, then creates the tag and the GitHub release on the SDK repo; if the +# version is already on npm it skips both and stays green, so a re-run is +# harmless. Tagging comes last, so a failed publish leaves no tag +# (docs/RELEASE-PATH.md). The npm credential lives in the # codat-npm-publish-packages service connection and never leaves Azure. +# +# The tag needs contents:write on the SDK repo. The publish stage mints a +# short-lived (~1h) GitHub App installation token from codat-oas-publisher's +# codatio installation, the same way the oas pipeline does, so no long-lived +# GitHub credential is stored anywhere. The App credentials come from the +# OAS variable group the oas pipeline already reads (oas_app_id, +# oas_app_installation_id, oas_app_private_key — the private key may be stored +# base64-encoded), so there is one copy of the key to rotate, not two. trigger: branches: @@ -59,6 +69,8 @@ variables: publicNpmRegistry: "https://registry.npmjs.org/" npmServiceConnection: "codat-npm-publish-packages" packageArtifact: "npm-package" + releaseFactsArtifact: "release-facts" + sdkRepoSlug: "codatio/client-sdk-typescript" distTag: "next" stages: @@ -228,6 +240,34 @@ stages: cp "$(codegenDir)/cutover/exports_smoke.mjs" . node exports_smoke.mjs "@codat/$(product)" + # Read the tag, title and release body out of the merged commit here, while + # both checkouts are on disk, and hand them to the publish stage as an + # artifact. A commit whose package.json and RELEASES.md disagree on the + # version fails the run before anything is published. + - task: UsePythonVersion@0 + displayName: "Install Python" + inputs: + versionSpec: "3.12" + + - task: Bash@3 + displayName: "Read the release facts from the merged commit" + inputs: + targetType: inline + workingDirectory: $(codegenDir) + script: | + set -euo pipefail + facts_dir="$(Build.ArtifactStagingDirectory)/release-facts" + mkdir -p "$facts_dir" + python cutover/release_metadata.py --clone "$(sdkDir)" \ + --product "$(product)" --lang ts \ + --body-file "$facts_dir/body.md" | tee "$facts_dir/facts.env" + + - task: PublishPipelineArtifact@1 + displayName: "Publish the release facts" + inputs: + targetPath: $(Build.ArtifactStagingDirectory)/release-facts + artifact: $(releaseFactsArtifact) + - task: PublishPipelineArtifact@1 displayName: "Publish the packed tarball" inputs: @@ -243,6 +283,8 @@ stages: - job: Publish displayName: "npm publish under the pre-release tag" pool: codat-intg-managed-devops-pool-linux + variables: + - group: OAS steps: - checkout: none @@ -257,6 +299,53 @@ stages: artifact: $(packageArtifact) path: $(Pipeline.Workspace)/pack-out + - task: DownloadPipelineArtifact@2 + displayName: "Download the release facts" + inputs: + artifact: $(releaseFactsArtifact) + path: $(Pipeline.Workspace)/release-facts + + # Mints the short-lived token the tag and release steps use, the same + # way the oas pipeline does (tools/mint-github-app-token.sh there). + # Running it before the publish means missing App credentials can + # never leave a published-but-untagged release behind. + - task: Bash@3 + displayName: "Mint the SDK repo token from the GitHub App" + inputs: + targetType: inline + script: | + set -euo pipefail + if [ -z "${GITHUB_APP_ID:-}" ] || [ -z "${GITHUB_APP_INSTALLATION_ID:-}" ] || [ -z "${GITHUB_APP_PRIVATE_KEY:-}" ]; then + echo "##[error]GitHub App credentials are not set — authorise the OAS variable group (oas_app_id, oas_app_installation_id, oas_app_private_key)" + exit 1 + fi + b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; } + # The key may be stored base64-encoded; multi-line secrets are + # awkward in Azure DevOps variable groups. + if [[ "$GITHUB_APP_PRIVATE_KEY" != *"BEGIN"* ]]; then + GITHUB_APP_PRIVATE_KEY=$(printf '%s' "$GITHUB_APP_PRIVATE_KEY" | openssl base64 -d -A) + fi + now=$(date +%s) + header=$(printf '{"alg":"RS256","typ":"JWT"}' | b64url) + # iat 60s in the past for clock drift; exp must be <= 10 minutes. + payload=$(printf '{"iat":%d,"exp":%d,"iss":"%s"}' "$((now - 60))" "$((now + 540))" "$GITHUB_APP_ID" | b64url) + signature=$(printf '%s.%s' "$header" "$payload" | openssl dgst -sha256 -sign <(printf '%s' "$GITHUB_APP_PRIVATE_KEY") | b64url) + response=$(curl --silent --fail-with-body --show-error -X POST \ + -H "Authorization: Bearer $header.$payload.$signature" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/app/installations/$GITHUB_APP_INSTALLATION_ID/access_tokens") + token=$(printf '%s' "$response" | node -p "JSON.parse(require('fs').readFileSync(0)).token") + if [ -z "$token" ] || [ "$token" = "null" ] || [ "$token" = "undefined" ]; then + echo "##[error]Installation token response did not contain a token" + exit 1 + fi + echo "##vso[task.setvariable variable=github_token;issecret=true]$token" + echo "Minted a GitHub App installation token (expires in ~1 hour)." + env: + GITHUB_APP_ID: $(oas_app_id) + GITHUB_APP_INSTALLATION_ID: $(oas_app_installation_id) + GITHUB_APP_PRIVATE_KEY: $(oas_app_private_key) + - task: Bash@3 displayName: "Skip if this version is already on npm" inputs: @@ -319,3 +408,41 @@ stages: exit 0 fi npm publish ./*.tgz --access public --tag $(distTag) + + # Last, so a tag only ever exists for a version that really published. + # Matches Speakeasy's tag and title shape so changelogs keep working. + - task: Bash@3 + displayName: "Tag the release on the SDK repo" + inputs: + targetType: inline + workingDirectory: $(Pipeline.Workspace)/release-facts + script: | + set -euo pipefail + if [ "$(alreadyPublished)" = "true" ]; then + echo "Version already on npm — leaving the existing tag alone." + exit 0 + fi + tag=$(sed -n 's/^tag=//p' facts.env) + title=$(sed -n 's/^title=//p' facts.env) + api="https://api.github.com/repos/$(sdkRepoSlug)" + if curl --silent --fail -H "Authorization: Bearer $GITHUB_TOKEN" \ + "$api/git/ref/tags/$tag" >/dev/null 2>&1; then + echo "$tag already exists on $(sdkRepoSlug) — leaving it alone." + exit 0 + fi + # Node rather than python: this job installs Node and checks nothing out. + TAG="$tag" TITLE="$title" node -e ' + const fs = require("fs"); + fs.writeFileSync("payload.json", JSON.stringify({ + tag_name: process.env.TAG, + target_commitish: "$(Build.SourceVersion)", + name: process.env.TITLE, + body: fs.readFileSync("body.md", "utf8"), + }));' + curl --fail-with-body --silent --show-error -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + "$api/releases" --data @payload.json > /dev/null + echo "created $tag and its release on $(sdkRepoSlug)" + env: + GITHUB_TOKEN: $(github_token) From e45d06314c08c9a1363d25e8ff43e7f6e4847b3c Mon Sep 17 00:00:00 2001 From: Codat Pipeline Bot Date: Thu, 13 Aug 2026 11:34:03 +0100 Subject: [PATCH 06/12] feat/CONN-1273-release-stubs: refresh the delivered npm publish pipeline so the build skips lint tooling the feed lacks - .azuredevops/npm-publish.yml - build step installs prod deps + the pinned TypeScript compiler and skips the eslint/typescript-eslint toolchain (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index 22abd42d5..c5644e8f8 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -164,7 +164,19 @@ stages: script: | set -euo pipefail cd "$(product)" - if [ -f package-lock.json ]; then npm ci; else npm install; fi + # The publish build only compiles and packs, so install the + # production dependencies plus the TypeScript compiler and skip + # the lint toolchain (eslint, typescript-eslint). Those are + # dev-only, and their pinned versions aren't always on the + # verified feed, which fails the install for no benefit. + if [ -f package-lock.json ]; then + npm ci --omit=dev + tsc_version=$(node -p "require('./package-lock.json').packages['node_modules/typescript'].version") + else + npm install --omit=dev + tsc_version=$(node -p "require('./package.json').devDependencies.typescript") + fi + npm install --no-save --no-package-lock "typescript@$tsc_version" npm run build cd .. mkdir -p "$(Build.ArtifactStagingDirectory)/pack-out" From 9863c0a5c96d29d32b31493cca00bf92d3fa552e Mon Sep 17 00:00:00 2001 From: Codat Pipeline Bot Date: Thu, 13 Aug 2026 11:45:31 +0100 Subject: [PATCH 07/12] feat/CONN-1273-release-stubs: refresh the delivered npm publish pipeline so the compiler install omits dev deps - .azuredevops/npm-publish.yml - the typescript install now passes --omit=dev so it no longer pulls the eslint/typescript-eslint tree (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index c5644e8f8..3f9a3384d 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -176,7 +176,8 @@ stages: npm install --omit=dev tsc_version=$(node -p "require('./package.json').devDependencies.typescript") fi - npm install --no-save --no-package-lock "typescript@$tsc_version" + # --omit=dev so adding the compiler does not drag in the dev tree + npm install --no-save --no-package-lock --omit=dev "typescript@$tsc_version" npm run build cd .. mkdir -p "$(Build.ArtifactStagingDirectory)/pack-out" From 737c8e45033f40f43ef198adce412f04f65162d4 Mon Sep 17 00:00:00 2001 From: Codat Pipeline Bot Date: Thu, 13 Aug 2026 11:54:24 +0100 Subject: [PATCH 08/12] feat/CONN-1273-release-stubs: refresh the delivered npm publish pipeline to install the compiler in isolation - .azuredevops/npm-publish.yml - install TypeScript in a directory with no package.json and build with it on PATH, so npm never resolves the eslint/typescript-eslint dev tree (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index 3f9a3384d..75add4d11 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -163,12 +163,16 @@ stages: workingDirectory: $(sdkDir) script: | set -euo pipefail + # The publish build only compiles and packs, so it needs the + # production dependencies plus the TypeScript compiler, not the + # SDK's lint toolchain (eslint, typescript-eslint). That toolchain + # is dev-only and its pinned versions aren't all on the verified + # feed. `npm install` inside this package resolves the dev tree + # from package.json even with --omit=dev, so install the compiler + # in a separate directory that has no package.json, then build + # with it on PATH. `npm ci --omit=dev` for the prod deps is fine: + # it installs from the lockfile and never touches the dev tree. cd "$(product)" - # The publish build only compiles and packs, so install the - # production dependencies plus the TypeScript compiler and skip - # the lint toolchain (eslint, typescript-eslint). Those are - # dev-only, and their pinned versions aren't always on the - # verified feed, which fails the install for no benefit. if [ -f package-lock.json ]; then npm ci --omit=dev tsc_version=$(node -p "require('./package-lock.json').packages['node_modules/typescript'].version") @@ -176,10 +180,12 @@ stages: npm install --omit=dev tsc_version=$(node -p "require('./package.json').devDependencies.typescript") fi - # --omit=dev so adding the compiler does not drag in the dev tree - npm install --no-save --no-package-lock --omit=dev "typescript@$tsc_version" - npm run build cd .. + compiler_home="$(Agent.TempDirectory)/tsc" + mkdir -p "$compiler_home" + ( cd "$compiler_home" && npm install --no-save "typescript@$tsc_version" ) + export PATH="$compiler_home/node_modules/.bin:$PATH" + ( cd "$(product)" && npm run build ) mkdir -p "$(Build.ArtifactStagingDirectory)/pack-out" npm pack "./$(product)" --pack-destination "$(Build.ArtifactStagingDirectory)/pack-out" From 8f22c9c514161d04d8a6428d5a988b38ceea709d Mon Sep 17 00:00:00 2001 From: Codat Pipeline Bot Date: Thu, 13 Aug 2026 12:02:22 +0100 Subject: [PATCH 09/12] feat/CONN-1273-release-stubs: refresh the delivered npm publish pipeline so the tarball tripwire matches the SDK layout - .azuredevops/npm-publish.yml - tripwire checks built .js at the package root and the declared entry point, not a dist/ dir these SDKs never produce (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index 75add4d11..c2d4c8f19 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -202,17 +202,27 @@ stages: echo "##[error]Tarball does not carry version $stamped"; ls; exit 1; } - task: Bash@3 - displayName: "Tarball tripwire (dist populated, no .npmrc)" + displayName: "Tarball tripwire (built JS present, no .npmrc)" inputs: targetType: inline workingDirectory: $(Build.ArtifactStagingDirectory)/pack-out script: | set -euo pipefail tgz=$(ls *.tgz) - dist_js=$(tar -tzf "$tgz" | grep -c '^package/dist/.*\.js$' || true) - echo "built dist/*.js files in tarball: $dist_js" - if [ "$dist_js" -eq 0 ]; then - echo "##[error]Tarball has no built dist/*.js — the package would install empty" + # The SDK compiles in place (tsconfig outDir "."), so the built JS + # mirrors src at the package root (sdk/, funcs/, ...), not under + # dist/. Confirm the package's declared entry point is present and + # the package carries built .js, or it would install empty. + entry=$(tar -xzOf "$tgz" package/package.json \ + | node -p "(JSON.parse(require('fs').readFileSync(0)).main || 'index.js').replace(/^\.\//, '')") + built_js=$(tar -tzf "$tgz" | grep -Ec '^package/.+\.js$' || true) + echo "built .js files in tarball: $built_js (entry: $entry)" + if ! tar -tzf "$tgz" | grep -qx "package/$entry"; then + echo "##[error]Tarball is missing its entry point package/$entry — did the build run?" + tar -tzf "$tgz" | head -40; exit 1 + fi + if [ "$built_js" -eq 0 ]; then + echo "##[error]Tarball has no built .js — the package would install empty" tar -tzf "$tgz" | head -40; exit 1 fi if tar -tzf "$tgz" | grep -q '^package/\.npmrc$'; then From 78f7f8d80e1674720e3ec2c4c132a21d75e19973 Mon Sep 17 00:00:00 2001 From: Codat Pipeline Bot Date: Thu, 13 Aug 2026 12:08:17 +0100 Subject: [PATCH 10/12] feat/CONN-1273-release-stubs: refresh the delivered npm publish pipeline with the SIGPIPE-safe tarball tripwire - .azuredevops/npm-publish.yml - tripwire lists the tarball once and matches with here-strings so grep/head no longer SIGPIPEs tar under pipefail (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index c2d4c8f19..4a14d2669 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -212,20 +212,23 @@ stages: # The SDK compiles in place (tsconfig outDir "."), so the built JS # mirrors src at the package root (sdk/, funcs/, ...), not under # dist/. Confirm the package's declared entry point is present and - # the package carries built .js, or it would install empty. + # the package carries built .js, or it would install empty. List + # the tarball once and match with here-strings, so an early-exiting + # grep or head never SIGPIPEs tar under pipefail. + listing=$(tar -tzf "$tgz") entry=$(tar -xzOf "$tgz" package/package.json \ | node -p "(JSON.parse(require('fs').readFileSync(0)).main || 'index.js').replace(/^\.\//, '')") - built_js=$(tar -tzf "$tgz" | grep -Ec '^package/.+\.js$' || true) + built_js=$(grep -Ec '^package/.+\.js$' <<<"$listing" || true) echo "built .js files in tarball: $built_js (entry: $entry)" - if ! tar -tzf "$tgz" | grep -qx "package/$entry"; then + if ! grep -qx "package/$entry" <<<"$listing"; then echo "##[error]Tarball is missing its entry point package/$entry — did the build run?" - tar -tzf "$tgz" | head -40; exit 1 + head -40 <<<"$listing"; exit 1 fi if [ "$built_js" -eq 0 ]; then echo "##[error]Tarball has no built .js — the package would install empty" - tar -tzf "$tgz" | head -40; exit 1 + head -40 <<<"$listing"; exit 1 fi - if tar -tzf "$tgz" | grep -q '^package/\.npmrc$'; then + if grep -q '^package/\.npmrc$' <<<"$listing"; then echo "##[error]Tarball contains .npmrc — private-feed credentials must never be published"; exit 1 fi From a97577e1102a633bd8453824f29dc9d43bdc04f2 Mon Sep 17 00:00:00 2001 From: Codat Pipeline Bot Date: Thu, 13 Aug 2026 12:12:43 +0100 Subject: [PATCH 11/12] feat/CONN-1273-release-stubs: refresh the delivered npm publish pipeline to pin the consumer's TypeScript - .azuredevops/npm-publish.yml - scratch consumer pins typescript at the SDK's version so it doesn't pull native TS 7 (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index 4a14d2669..73f6015fa 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -250,7 +250,11 @@ stages: p['$(product)'].typescript.client_class_name") mkdir "$(Agent.TempDirectory)/consumer" && cd "$(Agent.TempDirectory)/consumer" npm init -y >/dev/null - npm install "$(Build.ArtifactStagingDirectory)"/pack-out/*.tgz typescript @types/node >/dev/null + # Pin the compiler to the SDK's version. An unpinned typescript + # pulls the feed's latest, which is the native TypeScript 7 whose + # tsc loads a platform binary package the feed does not carry. + tsc_version=$(node -p "require('$(sdkDir)/$(product)/package.json').devDependencies.typescript") + npm install "$(Build.ArtifactStagingDirectory)"/pack-out/*.tgz "typescript@$tsc_version" @types/node >/dev/null cat > smoke.ts < Date: Mon, 17 Aug 2026 11:18:51 +0100 Subject: [PATCH 12/12] feat/CONN-1273-release-stubs: build and publish on Node 24 instead of the end-of-life Node 20 - .azuredevops/npm-publish.yml - moves the pipeline's Node version from 20.x to 24.x (delivered verbatim from sdk-codegen npm_publish_pipeline.yml) --- .azuredevops/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azuredevops/npm-publish.yml b/.azuredevops/npm-publish.yml index 73f6015fa..258ca840d 100644 --- a/.azuredevops/npm-publish.yml +++ b/.azuredevops/npm-publish.yml @@ -62,7 +62,7 @@ resources: endpoint: codat-tech variables: - nodeVersion: "20.x" + nodeVersion: "24.x" # Both checkouts pin their folder, so these paths don't depend on ADO's default naming sdkDir: $(Build.SourcesDirectory)/sdk codegenDir: $(Build.SourcesDirectory)/codegen