From d073e943586276dbe8b9dc3c96b53c0acc5a6f4e Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 14:43:22 -0800 Subject: [PATCH 01/30] Add AzDO pipeline to bump decoupled local dependencies after publish --- .../azure-pipelines/bump-decoupled-deps.yaml | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 common/config/azure-pipelines/bump-decoupled-deps.yaml diff --git a/common/config/azure-pipelines/bump-decoupled-deps.yaml b/common/config/azure-pipelines/bump-decoupled-deps.yaml new file mode 100644 index 0000000000..3aa3f815b4 --- /dev/null +++ b/common/config/azure-pipelines/bump-decoupled-deps.yaml @@ -0,0 +1,150 @@ +parameters: + - name: delayMinutes + displayName: 'Minutes to wait for packages to propagate before running' + type: number + default: 5 + +variables: + - name: FORCE_COLOR + value: 1 + - name: BranchName + value: 'automated/bump-decoupled-deps' + - name: CommitMessage + value: 'chore: bump decoupled local dependencies' + +resources: + pipelines: + - pipeline: npmPublish + source: 'rushstack NPM Publish' + trigger: + branches: + include: + - main + - pipeline: npmPublishRush + source: 'rushstack NPM Publish (rush)' + trigger: + branches: + include: + - main + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + os: windows + stages: + - stage: + jobs: + - job: + pool: + name: publish-rushstack + os: linux + steps: + - checkout: self + persistCredentials: true + + - bash: | + echo "Waiting ${{ parameters.delayMinutes }} minute(s) for packages to propagate to npm..." + sleep $(( ${{ parameters.delayMinutes }} * 60 )) + displayName: 'Wait for packages to propagate' + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + - script: 'git config --local user.email rushbot@users.noreply.github.com' + displayName: 'git config email' + + - script: 'git config --local user.name Rushbot' + displayName: 'git config name' + + - script: 'node common/scripts/install-run-rush.js install' + displayName: 'Rush Install' + + - script: 'node common/scripts/install-run-rush.js build --to repo-toolbox --verbose' + displayName: 'Rush Build (repo-toolbox)' + + - script: 'node repo-scripts/repo-toolbox/lib-commonjs/start.js bump-decoupled-local-dependencies' + displayName: 'Bump decoupled local dependencies' + + - script: 'node common/scripts/install-run-rush.js update' + displayName: 'Rush Update' + + - bash: | + set -e + + if git diff --quiet; then + echo "No changes detected. Skipping commit and PR." + echo "##vso[task.setvariable variable=HasChanges]false" + exit 0 + fi + + echo "##vso[task.setvariable variable=HasChanges]true" + + git checkout -B $(BranchName) + git add --all + git commit -m "$(CommitMessage)" + displayName: 'Commit dependency changes' + + - bash: | + set -e + + node common/scripts/install-run-rush.js change \ + --bulk \ + --bump-type none \ + --commit-message "chore: generate change files for decoupled dependency bump" + displayName: 'Generate change files' + condition: and(succeeded(), eq(variables.HasChanges, 'true')) + + - bash: | + set -e + git push origin $(BranchName) --force + displayName: 'Push branch' + condition: and(succeeded(), eq(variables.HasChanges, 'true')) + + - bash: | + set -e + + # Derive owner/repo from the git remote + REPO_SLUG=$(git remote get-url origin | sed -E 's#.*github\.com[:/](.+/[^.]+)(\.git)?$#\1#') + echo "Repository: ${REPO_SLUG}" + + PR_TITLE="$(CommitMessage)" + PR_BODY="Automated PR to bump decoupled local dependencies to the latest published versions." + API_BASE="https://api.github.com/repos/${REPO_SLUG}" + + # Check if a PR already exists for this branch + EXISTING_PR=$(curl -sf \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "${API_BASE}/pulls?head=$(echo "${REPO_SLUG}" | cut -d/ -f1):$(BranchName)&state=open" \ + | jq '.[0].number // empty') + + if [ -n "$EXISTING_PR" ]; then + echo "Updating existing PR #${EXISTING_PR}" + curl -sf -X PATCH \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "${API_BASE}/pulls/${EXISTING_PR}" \ + -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" + else + echo "Creating new PR" + curl -sf -X POST \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "${API_BASE}/pulls" \ + -d "$(jq -n \ + --arg title "$PR_TITLE" \ + --arg body "$PR_BODY" \ + --arg head "$(BranchName)" \ + --arg base "main" \ + '{title: $title, body: $body, head: $head, base: $base}')" + fi + displayName: 'Create or update GitHub PR' + condition: and(succeeded(), eq(variables.HasChanges, 'true')) + env: + GITHUB_TOKEN: $(GitHubToken) From f934b71776a86864c9844c5bdc014076cde92336 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 14:59:13 -0800 Subject: [PATCH 02/30] Fix GitHub PR step to show API error responses on failure --- .../azure-pipelines/bump-decoupled-deps.yaml | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/common/config/azure-pipelines/bump-decoupled-deps.yaml b/common/config/azure-pipelines/bump-decoupled-deps.yaml index 3aa3f815b4..ac5d432256 100644 --- a/common/config/azure-pipelines/bump-decoupled-deps.yaml +++ b/common/config/azure-pipelines/bump-decoupled-deps.yaml @@ -117,23 +117,40 @@ extends: PR_BODY="Automated PR to bump decoupled local dependencies to the latest published versions." API_BASE="https://api.github.com/repos/${REPO_SLUG}" + # Helper to call the GitHub API and fail with a visible error + github_api() { + local RESPONSE HTTP_CODE + RESPONSE=$(curl -s -w "\n%{http_code}" "$@") + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | sed '$d') + + if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then + echo "$BODY" + else + echo "::error::GitHub API returned HTTP ${HTTP_CODE}:" >&2 + echo "$BODY" >&2 + return 1 + fi + } + # Check if a PR already exists for this branch - EXISTING_PR=$(curl -sf \ + OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) + EXISTING_PR=$(github_api \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Accept: application/vnd.github+json" \ - "${API_BASE}/pulls?head=$(echo "${REPO_SLUG}" | cut -d/ -f1):$(BranchName)&state=open" \ + "${API_BASE}/pulls?head=${OWNER}:$(BranchName)&state=open" \ | jq '.[0].number // empty') if [ -n "$EXISTING_PR" ]; then echo "Updating existing PR #${EXISTING_PR}" - curl -sf -X PATCH \ + github_api -X PATCH \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls/${EXISTING_PR}" \ -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" else echo "Creating new PR" - curl -sf -X POST \ + github_api -X POST \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls" \ From e9dabf81206a2bd26aa28a5a1c26659a49b6d12b Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 15:15:15 -0800 Subject: [PATCH 03/30] Use service connection credentials from git config for GitHub API calls --- .../azure-pipelines/bump-decoupled-deps.yaml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/common/config/azure-pipelines/bump-decoupled-deps.yaml b/common/config/azure-pipelines/bump-decoupled-deps.yaml index ac5d432256..629cb6108a 100644 --- a/common/config/azure-pipelines/bump-decoupled-deps.yaml +++ b/common/config/azure-pipelines/bump-decoupled-deps.yaml @@ -113,6 +113,13 @@ extends: REPO_SLUG=$(git remote get-url origin | sed -E 's#.*github\.com[:/](.+/[^.]+)(\.git)?$#\1#') echo "Repository: ${REPO_SLUG}" + # Extract the authorization header that AzDO configured via persistCredentials + AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') + if [ -z "$AUTH_HEADER" ]; then + echo "##[error]Could not extract authorization header from git config" + exit 1 + fi + PR_TITLE="$(CommitMessage)" PR_BODY="Automated PR to bump decoupled local dependencies to the latest published versions." API_BASE="https://api.github.com/repos/${REPO_SLUG}" @@ -136,7 +143,7 @@ extends: # Check if a PR already exists for this branch OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) EXISTING_PR=$(github_api \ - -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "$AUTH_HEADER" \ -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls?head=${OWNER}:$(BranchName)&state=open" \ | jq '.[0].number // empty') @@ -144,14 +151,14 @@ extends: if [ -n "$EXISTING_PR" ]; then echo "Updating existing PR #${EXISTING_PR}" github_api -X PATCH \ - -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "$AUTH_HEADER" \ -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls/${EXISTING_PR}" \ -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" else echo "Creating new PR" github_api -X POST \ - -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "$AUTH_HEADER" \ -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls" \ -d "$(jq -n \ @@ -163,5 +170,3 @@ extends: fi displayName: 'Create or update GitHub PR' condition: and(succeeded(), eq(variables.HasChanges, 'true')) - env: - GITHUB_TOKEN: $(GitHubToken) From f206d7d939dff038975d53b6c5bfbd8e6bb17be7 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 16:33:01 -0800 Subject: [PATCH 04/30] Extract push + GitHub PR steps into a reusable template --- .../azure-pipelines/bump-decoupled-deps.yaml | 75 ++-------------- .../templates/push-and-create-github-pr.yaml | 86 +++++++++++++++++++ 2 files changed, 91 insertions(+), 70 deletions(-) create mode 100644 common/config/azure-pipelines/templates/push-and-create-github-pr.yaml diff --git a/common/config/azure-pipelines/bump-decoupled-deps.yaml b/common/config/azure-pipelines/bump-decoupled-deps.yaml index 629cb6108a..b0a1ea613c 100644 --- a/common/config/azure-pipelines/bump-decoupled-deps.yaml +++ b/common/config/azure-pipelines/bump-decoupled-deps.yaml @@ -100,73 +100,8 @@ extends: displayName: 'Generate change files' condition: and(succeeded(), eq(variables.HasChanges, 'true')) - - bash: | - set -e - git push origin $(BranchName) --force - displayName: 'Push branch' - condition: and(succeeded(), eq(variables.HasChanges, 'true')) - - - bash: | - set -e - - # Derive owner/repo from the git remote - REPO_SLUG=$(git remote get-url origin | sed -E 's#.*github\.com[:/](.+/[^.]+)(\.git)?$#\1#') - echo "Repository: ${REPO_SLUG}" - - # Extract the authorization header that AzDO configured via persistCredentials - AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') - if [ -z "$AUTH_HEADER" ]; then - echo "##[error]Could not extract authorization header from git config" - exit 1 - fi - - PR_TITLE="$(CommitMessage)" - PR_BODY="Automated PR to bump decoupled local dependencies to the latest published versions." - API_BASE="https://api.github.com/repos/${REPO_SLUG}" - - # Helper to call the GitHub API and fail with a visible error - github_api() { - local RESPONSE HTTP_CODE - RESPONSE=$(curl -s -w "\n%{http_code}" "$@") - HTTP_CODE=$(echo "$RESPONSE" | tail -n1) - BODY=$(echo "$RESPONSE" | sed '$d') - - if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then - echo "$BODY" - else - echo "::error::GitHub API returned HTTP ${HTTP_CODE}:" >&2 - echo "$BODY" >&2 - return 1 - fi - } - - # Check if a PR already exists for this branch - OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) - EXISTING_PR=$(github_api \ - -H "$AUTH_HEADER" \ - -H "Accept: application/vnd.github+json" \ - "${API_BASE}/pulls?head=${OWNER}:$(BranchName)&state=open" \ - | jq '.[0].number // empty') - - if [ -n "$EXISTING_PR" ]; then - echo "Updating existing PR #${EXISTING_PR}" - github_api -X PATCH \ - -H "$AUTH_HEADER" \ - -H "Accept: application/vnd.github+json" \ - "${API_BASE}/pulls/${EXISTING_PR}" \ - -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" - else - echo "Creating new PR" - github_api -X POST \ - -H "$AUTH_HEADER" \ - -H "Accept: application/vnd.github+json" \ - "${API_BASE}/pulls" \ - -d "$(jq -n \ - --arg title "$PR_TITLE" \ - --arg body "$PR_BODY" \ - --arg head "$(BranchName)" \ - --arg base "main" \ - '{title: $title, body: $body, head: $head, base: $base}')" - fi - displayName: 'Create or update GitHub PR' - condition: and(succeeded(), eq(variables.HasChanges, 'true')) + - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self + parameters: + BranchName: $(BranchName) + PrTitle: $(CommitMessage) + PrDescription: 'Automated PR to bump decoupled local dependencies to the latest published versions.' diff --git a/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml new file mode 100644 index 0000000000..cf00c3740a --- /dev/null +++ b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml @@ -0,0 +1,86 @@ +parameters: + - name: BranchName + type: string + - name: PrTitle + type: string + - name: PrDescription + type: string + default: '' + - name: TargetBranch + type: string + default: 'main' + - name: HasChangesVariableName + type: string + default: 'HasChanges' + +steps: + - bash: | + set -e + git push origin ${{ parameters.BranchName }} --force + displayName: 'Push branch' + condition: and(succeeded(), eq(variables['${{ parameters.HasChangesVariableName }}'], 'true')) + + - bash: | + set -e + + # Derive owner/repo from the git remote + REPO_SLUG=$(git remote get-url origin | sed -E 's#.*github\.com[:/](.+/[^.]+)(\.git)?$#\1#') + echo "Repository: ${REPO_SLUG}" + + # Extract the authorization header that AzDO configured via persistCredentials + AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') + if [ -z "$AUTH_HEADER" ]; then + echo "##[error]Could not extract authorization header from git config. Ensure persistCredentials is enabled on the checkout step." + exit 1 + fi + + PR_TITLE="${{ parameters.PrTitle }}" + PR_BODY="${{ parameters.PrDescription }}" + API_BASE="https://api.github.com/repos/${REPO_SLUG}" + + # Helper to call the GitHub API and fail with a visible error + github_api() { + local RESPONSE HTTP_CODE + RESPONSE=$(curl -s -w "\n%{http_code}" "$@") + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | sed '$d') + + if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then + echo "$BODY" + else + echo "::error::GitHub API returned HTTP ${HTTP_CODE}:" >&2 + echo "$BODY" >&2 + return 1 + fi + } + + # Check if a PR already exists for this branch + OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) + EXISTING_PR=$(github_api \ + -H "$AUTH_HEADER" \ + -H "Accept: application/vnd.github+json" \ + "${API_BASE}/pulls?head=${OWNER}:${{ parameters.BranchName }}&state=open" \ + | jq '.[0].number // empty') + + if [ -n "$EXISTING_PR" ]; then + echo "Updating existing PR #${EXISTING_PR}" + github_api -X PATCH \ + -H "$AUTH_HEADER" \ + -H "Accept: application/vnd.github+json" \ + "${API_BASE}/pulls/${EXISTING_PR}" \ + -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" + else + echo "Creating new PR" + github_api -X POST \ + -H "$AUTH_HEADER" \ + -H "Accept: application/vnd.github+json" \ + "${API_BASE}/pulls" \ + -d "$(jq -n \ + --arg title "$PR_TITLE" \ + --arg body "$PR_BODY" \ + --arg head "${{ parameters.BranchName }}" \ + --arg base "${{ parameters.TargetBranch }}" \ + '{title: $title, body: $body, head: $head, base: $base}')" + fi + displayName: 'Create or update GitHub PR' + condition: and(succeeded(), eq(variables['${{ parameters.HasChangesVariableName }}'], 'true')) From c38478017a224b52aa53f3c5b086d6a0b93569ae Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 18:28:20 -0800 Subject: [PATCH 05/30] Address PR review: sanitize inputs, protect credentials, add security comments --- .../templates/push-and-create-github-pr.yaml | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml index cf00c3740a..d4c77f0561 100644 --- a/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml +++ b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml @@ -14,6 +14,8 @@ parameters: default: 'HasChanges' steps: + # Force-push the branch. This is safe because the branch (e.g. "automated/bump-decoupled-deps") + # is exclusively owned by this pipeline and is never manually committed to. - bash: | set -e git push origin ${{ parameters.BranchName }} --force @@ -23,64 +25,90 @@ steps: - bash: | set -e - # Derive owner/repo from the git remote + # ── Resolve the GitHub owner/repo from the git remote URL ── + # Handles both HTTPS (https://github.com/owner/repo.git) and SSH (git@github.com:owner/repo.git) URLs. REPO_SLUG=$(git remote get-url origin | sed -E 's#.*github\.com[:/](.+/[^.]+)(\.git)?$#\1#') echo "Repository: ${REPO_SLUG}" + OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) - # Extract the authorization header that AzDO configured via persistCredentials + # ── Extract credentials from the AzDO-managed git config ── + # When "persistCredentials: true" is set on the checkout step, AzDO injects an + # "http..extraheader" git config entry containing an "AUTHORIZATION: basic " + # header for the GitHub service connection. We reuse this for GitHub API calls so that + # no additional secrets or PATs need to be configured. AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') if [ -z "$AUTH_HEADER" ]; then echo "##[error]Could not extract authorization header from git config. Ensure persistCredentials is enabled on the checkout step." exit 1 fi - PR_TITLE="${{ parameters.PrTitle }}" - PR_BODY="${{ parameters.PrDescription }}" + # ── Write credentials to a temporary curl config file ── + # This avoids passing the auth token as a command-line argument, which would be + # visible in process listings (e.g. "ps aux") and could leak into logs. + CURL_CONFIG=$(mktemp) + trap 'rm -f "$CURL_CONFIG"' EXIT + echo "-H \"${AUTH_HEADER}\"" > "$CURL_CONFIG" + echo '-H "Accept: application/vnd.github+json"' >> "$CURL_CONFIG" + API_BASE="https://api.github.com/repos/${REPO_SLUG}" - # Helper to call the GitHub API and fail with a visible error + # ── GitHub API helper ── + # Calls the GitHub API using the temporary curl config file for auth headers. + # On success (2xx), prints the response body to stdout. + # On failure, prints the HTTP status and error body to stderr and returns non-zero. github_api() { - local RESPONSE HTTP_CODE - RESPONSE=$(curl -s -w "\n%{http_code}" "$@") + local RESPONSE HTTP_CODE BODY + RESPONSE=$(curl -s -w "\n%{http_code}" -K "$CURL_CONFIG" "$@") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then echo "$BODY" else - echo "::error::GitHub API returned HTTP ${HTTP_CODE}:" >&2 + echo "##[error]GitHub API returned HTTP ${HTTP_CODE}:" >&2 echo "$BODY" >&2 return 1 fi } - # Check if a PR already exists for this branch - OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) + # ── Check for an existing open PR from this branch ── + # The GitHub "List pull requests" API filters by "head=OWNER:BRANCH" to find any + # open PR already targeting this branch. If one exists, we update it instead of + # creating a duplicate. EXISTING_PR=$(github_api \ - -H "$AUTH_HEADER" \ - -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls?head=${OWNER}:${{ parameters.BranchName }}&state=open" \ | jq '.[0].number // empty') if [ -n "$EXISTING_PR" ]; then + # ── Update existing PR ── + # Only the description is updated; the title is left as-is since the branch was + # already force-pushed with the new commits above. echo "Updating existing PR #${EXISTING_PR}" github_api -X PATCH \ - -H "$AUTH_HEADER" \ - -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls/${EXISTING_PR}" \ - -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" + -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" > /dev/null else + # ── Create new PR ── + # jq --arg safely handles JSON escaping of the title and body, so special + # characters (quotes, newlines, etc.) in the parameter values are safe. echo "Creating new PR" github_api -X POST \ - -H "$AUTH_HEADER" \ - -H "Accept: application/vnd.github+json" \ "${API_BASE}/pulls" \ -d "$(jq -n \ --arg title "$PR_TITLE" \ --arg body "$PR_BODY" \ --arg head "${{ parameters.BranchName }}" \ --arg base "${{ parameters.TargetBranch }}" \ - '{title: $title, body: $body, head: $head, base: $base}')" + '{title: $title, body: $body, head: $head, base: $base}')" > /dev/null fi displayName: 'Create or update GitHub PR' condition: and(succeeded(), eq(variables['${{ parameters.HasChangesVariableName }}'], 'true')) + # Pass PR title and description as environment variables rather than using + # ${{ }} template expansion inside the script. Template expansion would + # substitute the raw string into the Bash source code, which breaks if the + # value contains quotes or other shell metacharacters. Environment variables + # are set by the AzDO agent outside of the shell, so they are safe regardless + # of content. + env: + PR_TITLE: ${{ parameters.PrTitle }} + PR_BODY: ${{ parameters.PrDescription }} From 0ac60c35dc3d9bc4f9c8f985aa1383ebbb5e5065 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 23:37:25 -0800 Subject: [PATCH 06/30] Rename to npm-post-publish, publish api artifact, add API docs update stage --- .../azure-pipelines/bump-decoupled-deps.yaml | 107 -------- .../azure-pipelines/npm-post-publish.yaml | 243 ++++++++++++++++++ .../azure-pipelines/npm-publish-rush.yaml | 3 + .../config/azure-pipelines/npm-publish.yaml | 3 + .../templates/post-publish.yaml | 5 + 5 files changed, 254 insertions(+), 107 deletions(-) delete mode 100644 common/config/azure-pipelines/bump-decoupled-deps.yaml create mode 100644 common/config/azure-pipelines/npm-post-publish.yaml diff --git a/common/config/azure-pipelines/bump-decoupled-deps.yaml b/common/config/azure-pipelines/bump-decoupled-deps.yaml deleted file mode 100644 index b0a1ea613c..0000000000 --- a/common/config/azure-pipelines/bump-decoupled-deps.yaml +++ /dev/null @@ -1,107 +0,0 @@ -parameters: - - name: delayMinutes - displayName: 'Minutes to wait for packages to propagate before running' - type: number - default: 5 - -variables: - - name: FORCE_COLOR - value: 1 - - name: BranchName - value: 'automated/bump-decoupled-deps' - - name: CommitMessage - value: 'chore: bump decoupled local dependencies' - -resources: - pipelines: - - pipeline: npmPublish - source: 'rushstack NPM Publish' - trigger: - branches: - include: - - main - - pipeline: npmPublishRush - source: 'rushstack NPM Publish (rush)' - trigger: - branches: - include: - - main - repositories: - - repository: 1esPipelines - type: git - name: 1ESPipelineTemplates/1ESPipelineTemplates - ref: refs/tags/release - -extends: - template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines - parameters: - pool: - name: Azure-Pipelines-1ESPT-ExDShared - os: windows - stages: - - stage: - jobs: - - job: - pool: - name: publish-rushstack - os: linux - steps: - - checkout: self - persistCredentials: true - - - bash: | - echo "Waiting ${{ parameters.delayMinutes }} minute(s) for packages to propagate to npm..." - sleep $(( ${{ parameters.delayMinutes }} * 60 )) - displayName: 'Wait for packages to propagate' - - - template: /common/config/azure-pipelines/templates/install-node.yaml@self - - - script: 'git config --local user.email rushbot@users.noreply.github.com' - displayName: 'git config email' - - - script: 'git config --local user.name Rushbot' - displayName: 'git config name' - - - script: 'node common/scripts/install-run-rush.js install' - displayName: 'Rush Install' - - - script: 'node common/scripts/install-run-rush.js build --to repo-toolbox --verbose' - displayName: 'Rush Build (repo-toolbox)' - - - script: 'node repo-scripts/repo-toolbox/lib-commonjs/start.js bump-decoupled-local-dependencies' - displayName: 'Bump decoupled local dependencies' - - - script: 'node common/scripts/install-run-rush.js update' - displayName: 'Rush Update' - - - bash: | - set -e - - if git diff --quiet; then - echo "No changes detected. Skipping commit and PR." - echo "##vso[task.setvariable variable=HasChanges]false" - exit 0 - fi - - echo "##vso[task.setvariable variable=HasChanges]true" - - git checkout -B $(BranchName) - git add --all - git commit -m "$(CommitMessage)" - displayName: 'Commit dependency changes' - - - bash: | - set -e - - node common/scripts/install-run-rush.js change \ - --bulk \ - --bump-type none \ - --commit-message "chore: generate change files for decoupled dependency bump" - displayName: 'Generate change files' - condition: and(succeeded(), eq(variables.HasChanges, 'true')) - - - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self - parameters: - BranchName: $(BranchName) - PrTitle: $(CommitMessage) - PrDescription: 'Automated PR to bump decoupled local dependencies to the latest published versions.' diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml new file mode 100644 index 0000000000..7a77c321ec --- /dev/null +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -0,0 +1,243 @@ +parameters: + - name: delayMinutes + displayName: 'Minutes to wait for packages to propagate before running' + type: number + default: 5 + +variables: + - name: FORCE_COLOR + value: 1 + +resources: + pipelines: + - pipeline: npmPublish + source: 'rushstack NPM Publish' + trigger: + branches: + include: + - main + - pipeline: npmPublishRush + source: 'rushstack NPM Publish (rush)' + trigger: + branches: + include: + - main + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + os: windows + stages: + # ────────────────────────────────────────────────────────────────────────── + # Stage 1: Bump decoupled local dependencies + # ────────────────────────────────────────────────────────────────────────── + - stage: BumpDecoupledDeps + displayName: 'Bump decoupled local dependencies' + variables: + BranchName: 'automated/bump-decoupled-deps' + CommitMessage: 'chore: bump decoupled local dependencies' + jobs: + - job: + pool: + name: publish-rushstack + os: linux + steps: + - checkout: self + persistCredentials: true + + - bash: | + echo "Waiting ${{ parameters.delayMinutes }} minute(s) for packages to propagate to npm..." + sleep $(( ${{ parameters.delayMinutes }} * 60 )) + displayName: 'Wait for packages to propagate' + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + - script: 'git config --local user.email rushbot@users.noreply.github.com' + displayName: 'git config email' + + - script: 'git config --local user.name Rushbot' + displayName: 'git config name' + + - script: 'node common/scripts/install-run-rush.js install' + displayName: 'Rush Install' + + - script: 'node common/scripts/install-run-rush.js build --to repo-toolbox --verbose' + displayName: 'Rush Build (repo-toolbox)' + + - script: 'node repo-scripts/repo-toolbox/lib-commonjs/start.js bump-decoupled-local-dependencies' + displayName: 'Bump decoupled local dependencies' + + - script: 'node common/scripts/install-run-rush.js update' + displayName: 'Rush Update' + + - bash: | + set -e + + if git diff --quiet; then + echo "No changes detected. Skipping commit and PR." + echo "##vso[task.setvariable variable=HasChanges]false" + exit 0 + fi + + echo "##vso[task.setvariable variable=HasChanges]true" + + git checkout -B $(BranchName) + git add --all + git commit -m "$(CommitMessage)" + displayName: 'Commit dependency changes' + + - bash: | + set -e + + node common/scripts/install-run-rush.js change \ + --bulk \ + --bump-type none \ + --commit-message "chore: generate change files for decoupled dependency bump" + displayName: 'Generate change files' + condition: and(succeeded(), eq(variables.HasChanges, 'true')) + + - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self + parameters: + BranchName: $(BranchName) + PrTitle: $(CommitMessage) + PrDescription: 'Automated PR to bump decoupled local dependencies to the latest published versions.' + + # ────────────────────────────────────────────────────────────────────────── + # Stage 2: Update API documentation on rushstack-websites + # ────────────────────────────────────────────────────────────────────────── + - stage: UpdateApiDocs + displayName: 'Update API documentation' + dependsOn: [] # Run in parallel with BumpDecoupledDeps + variables: + BranchName: 'automated/update-api-docs' + CommitMessage: 'docs: update API documentation' + jobs: + - job: + pool: + name: publish-rushstack + os: linux + steps: + - checkout: self + persistCredentials: true + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + # Download the api artifact from the triggering publish pipeline. + # AzDO automatically resolves which pipeline resource triggered this run. + - task: DownloadPipelineArtifact@2 + displayName: 'Download API review files' + inputs: + artifact: api + path: $(Pipeline.Workspace)/api + + # Install and build only api-documenter, which is needed to generate + # the markdown output from the *.api.json files. + - script: 'node common/scripts/install-run-rush.js install' + displayName: 'Rush Install' + + - script: 'node common/scripts/install-run-rush.js build --to @microsoft/api-documenter --verbose' + displayName: 'Rush Build (api-documenter)' + + # Run api-documenter to generate markdown files from the *.api.json inputs. + - script: 'node apps/api-documenter/bin/api-documenter markdown --input-folder $(Pipeline.Workspace)/api --output-folder $(Pipeline.Workspace)/api-markdown' + displayName: 'Generate API markdown' + + # Clone the rushstack-websites repo, update the API docs folder, and + # create or update a PR with the changes. + - bash: | + set -e + + # ── Extract credentials from git config ── + # persistCredentials injects an authorization header we can reuse for + # cloning the websites repo and for GitHub API calls. + AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') + if [ -z "$AUTH_HEADER" ]; then + echo "##[error]Could not extract authorization header from git config." + exit 1 + fi + + WEBSITES_REPO="https://github.com/microsoft/rushstack-websites.git" + WEBSITES_DIR="$(Pipeline.Workspace)/rushstack-websites" + + # Clone the websites repo using the same credentials + git -c "http.extraheader=$AUTH_HEADER" clone --depth 1 "$WEBSITES_REPO" "$WEBSITES_DIR" + cd "$WEBSITES_DIR" + + git config --local user.email rushbot@users.noreply.github.com + git config --local user.name Rushbot + + # ── Update the API docs folder ── + # Clear the existing pages and replace with freshly generated markdown. + API_DOCS_DIR="websites/api.rushstack.io/docs/pages" + rm -rf "$API_DOCS_DIR" + mkdir -p "$API_DOCS_DIR" + cp -r "$(Pipeline.Workspace)/api-markdown/." "$API_DOCS_DIR/" + + # ── Check for changes and commit ── + if git diff --quiet && [ -z "$(git ls-files --others --exclude-standard)" ]; then + echo "No API documentation changes detected." + echo "##vso[task.setvariable variable=HasChanges]false" + exit 0 + fi + + echo "##vso[task.setvariable variable=HasChanges]true" + + git checkout -B $(BranchName) + git add --all + git commit -m "$(CommitMessage)" + + # ── Push and create/update PR ── + git -c "http.extraheader=$AUTH_HEADER" push origin $(BranchName) --force + + REPO_SLUG="microsoft/rushstack-websites" + API_BASE="https://api.github.com/repos/${REPO_SLUG}" + + # Helper to call the GitHub API and fail with a visible error + github_api() { + local CURL_CFG RESPONSE HTTP_CODE BODY + CURL_CFG=$(mktemp) + trap 'rm -f "$CURL_CFG"' RETURN + echo "-H \"${AUTH_HEADER}\"" > "$CURL_CFG" + echo '-H "Accept: application/vnd.github+json"' >> "$CURL_CFG" + + RESPONSE=$(curl -s -w "\n%{http_code}" -K "$CURL_CFG" "$@") + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | sed '$d') + + if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then + echo "$BODY" + else + echo "##[error]GitHub API returned HTTP ${HTTP_CODE}:" >&2 + echo "$BODY" >&2 + return 1 + fi + } + + EXISTING_PR=$(github_api \ + "${API_BASE}/pulls?head=microsoft:$(BranchName)&state=open" \ + | jq '.[0].number // empty') + + if [ -n "$EXISTING_PR" ]; then + echo "Updating existing PR #${EXISTING_PR}" + github_api -X PATCH \ + "${API_BASE}/pulls/${EXISTING_PR}" \ + -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" > /dev/null + else + echo "Creating new PR" + github_api -X POST \ + "${API_BASE}/pulls" \ + -d "$(jq -n \ + --arg title "$(CommitMessage)" \ + --arg body "Automated PR to update API reference documentation from the latest published packages." \ + --arg head "$(BranchName)" \ + --arg base "main" \ + '{title: $title, body: $body, head: $head, base: $base}')" > /dev/null + fi + displayName: 'Update rushstack-websites and create PR' diff --git a/common/config/azure-pipelines/npm-publish-rush.yaml b/common/config/azure-pipelines/npm-publish-rush.yaml index ee40eec3c8..70727beb73 100644 --- a/common/config/azure-pipelines/npm-publish-rush.yaml +++ b/common/config/azure-pipelines/npm-publish-rush.yaml @@ -42,6 +42,9 @@ extends: - output: pipelineArtifact targetPath: $(Build.ArtifactStagingDirectory)/packages artifactName: packages + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/api + artifactName: api steps: - checkout: self persistCredentials: true diff --git a/common/config/azure-pipelines/npm-publish.yaml b/common/config/azure-pipelines/npm-publish.yaml index dfb163c14b..2b589c4a73 100644 --- a/common/config/azure-pipelines/npm-publish.yaml +++ b/common/config/azure-pipelines/npm-publish.yaml @@ -42,6 +42,9 @@ extends: - output: pipelineArtifact targetPath: $(Build.ArtifactStagingDirectory)/packages artifactName: packages + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/api + artifactName: api steps: - checkout: self persistCredentials: true diff --git a/common/config/azure-pipelines/templates/post-publish.yaml b/common/config/azure-pipelines/templates/post-publish.yaml index c25ab635df..f3069262fb 100644 --- a/common/config/azure-pipelines/templates/post-publish.yaml +++ b/common/config/azure-pipelines/templates/post-publish.yaml @@ -3,3 +3,8 @@ steps: displayName: 'Record Published Versions' - script: 'node repo-scripts/repo-toolbox/lib-commonjs/start.js collect-json-schemas --output-path $(Build.ArtifactStagingDirectory)/json-schemas' displayName: 'Collect JSON Schemas' + - bash: | + set -e + mkdir -p "$(Build.ArtifactStagingDirectory)/api" + cp common/temp/api/*.api.json "$(Build.ArtifactStagingDirectory)/api/" + displayName: 'Collect API review files' From 86170f5f67acaaafaa85d7c0d73ff854679f6087 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 23:43:53 -0800 Subject: [PATCH 07/30] Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- .../azure-pipelines/npm-post-publish.yaml | 93 +++++-------------- .../templates/push-and-create-github-pr.yaml | 5 + 2 files changed, 30 insertions(+), 68 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 7a77c321ec..159da635f1 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -27,6 +27,11 @@ resources: type: git name: 1ESPipelineTemplates/1ESPipelineTemplates ref: refs/tags/release + - repository: rushstackWebsites + type: github + name: microsoft/rushstack-websites + endpoint: pipelinesMicrosoftRushstack + ref: refs/heads/main extends: template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines @@ -124,9 +129,16 @@ extends: name: publish-rushstack os: linux steps: + # Check out both repos. AzDO places them in subdirectories named after the + # repo alias when multiple checkouts are used: + # $(Pipeline.Workspace)/s/self (rushstack) + # $(Pipeline.Workspace)/s/rushstackWebsites (rushstack-websites) - checkout: self persistCredentials: true + - checkout: rushstackWebsites + persistCredentials: true + - template: /common/config/azure-pipelines/templates/install-node.yaml@self # Download the api artifact from the triggering publish pipeline. @@ -141,46 +153,31 @@ extends: # the markdown output from the *.api.json files. - script: 'node common/scripts/install-run-rush.js install' displayName: 'Rush Install' + workingDirectory: $(Pipeline.Workspace)/s/self - script: 'node common/scripts/install-run-rush.js build --to @microsoft/api-documenter --verbose' displayName: 'Rush Build (api-documenter)' + workingDirectory: $(Pipeline.Workspace)/s/self # Run api-documenter to generate markdown files from the *.api.json inputs. - script: 'node apps/api-documenter/bin/api-documenter markdown --input-folder $(Pipeline.Workspace)/api --output-folder $(Pipeline.Workspace)/api-markdown' displayName: 'Generate API markdown' + workingDirectory: $(Pipeline.Workspace)/s/self - # Clone the rushstack-websites repo, update the API docs folder, and - # create or update a PR with the changes. + # Update the API docs folder in rushstack-websites and commit. - bash: | set -e - # ── Extract credentials from git config ── - # persistCredentials injects an authorization header we can reuse for - # cloning the websites repo and for GitHub API calls. - AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') - if [ -z "$AUTH_HEADER" ]; then - echo "##[error]Could not extract authorization header from git config." - exit 1 - fi - - WEBSITES_REPO="https://github.com/microsoft/rushstack-websites.git" - WEBSITES_DIR="$(Pipeline.Workspace)/rushstack-websites" - - # Clone the websites repo using the same credentials - git -c "http.extraheader=$AUTH_HEADER" clone --depth 1 "$WEBSITES_REPO" "$WEBSITES_DIR" - cd "$WEBSITES_DIR" - git config --local user.email rushbot@users.noreply.github.com git config --local user.name Rushbot - # ── Update the API docs folder ── # Clear the existing pages and replace with freshly generated markdown. API_DOCS_DIR="websites/api.rushstack.io/docs/pages" rm -rf "$API_DOCS_DIR" mkdir -p "$API_DOCS_DIR" cp -r "$(Pipeline.Workspace)/api-markdown/." "$API_DOCS_DIR/" - # ── Check for changes and commit ── + # Check for changes (tracked and untracked) if git diff --quiet && [ -z "$(git ls-files --others --exclude-standard)" ]; then echo "No API documentation changes detected." echo "##vso[task.setvariable variable=HasChanges]false" @@ -192,52 +189,12 @@ extends: git checkout -B $(BranchName) git add --all git commit -m "$(CommitMessage)" + displayName: 'Update API docs and commit' + workingDirectory: $(Pipeline.Workspace)/s/rushstackWebsites - # ── Push and create/update PR ── - git -c "http.extraheader=$AUTH_HEADER" push origin $(BranchName) --force - - REPO_SLUG="microsoft/rushstack-websites" - API_BASE="https://api.github.com/repos/${REPO_SLUG}" - - # Helper to call the GitHub API and fail with a visible error - github_api() { - local CURL_CFG RESPONSE HTTP_CODE BODY - CURL_CFG=$(mktemp) - trap 'rm -f "$CURL_CFG"' RETURN - echo "-H \"${AUTH_HEADER}\"" > "$CURL_CFG" - echo '-H "Accept: application/vnd.github+json"' >> "$CURL_CFG" - - RESPONSE=$(curl -s -w "\n%{http_code}" -K "$CURL_CFG" "$@") - HTTP_CODE=$(echo "$RESPONSE" | tail -n1) - BODY=$(echo "$RESPONSE" | sed '$d') - - if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then - echo "$BODY" - else - echo "##[error]GitHub API returned HTTP ${HTTP_CODE}:" >&2 - echo "$BODY" >&2 - return 1 - fi - } - - EXISTING_PR=$(github_api \ - "${API_BASE}/pulls?head=microsoft:$(BranchName)&state=open" \ - | jq '.[0].number // empty') - - if [ -n "$EXISTING_PR" ]; then - echo "Updating existing PR #${EXISTING_PR}" - github_api -X PATCH \ - "${API_BASE}/pulls/${EXISTING_PR}" \ - -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" > /dev/null - else - echo "Creating new PR" - github_api -X POST \ - "${API_BASE}/pulls" \ - -d "$(jq -n \ - --arg title "$(CommitMessage)" \ - --arg body "Automated PR to update API reference documentation from the latest published packages." \ - --arg head "$(BranchName)" \ - --arg base "main" \ - '{title: $title, body: $body, head: $head, base: $base}')" > /dev/null - fi - displayName: 'Update rushstack-websites and create PR' + - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self + parameters: + BranchName: $(BranchName) + PrTitle: $(CommitMessage) + PrDescription: 'Automated PR to update API reference documentation from the latest published packages.' + WorkingDirectory: $(Pipeline.Workspace)/s/rushstackWebsites diff --git a/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml index d4c77f0561..2aa09ac32d 100644 --- a/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml +++ b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml @@ -12,6 +12,9 @@ parameters: - name: HasChangesVariableName type: string default: 'HasChanges' + - name: WorkingDirectory + type: string + default: '$(Build.SourcesDirectory)' steps: # Force-push the branch. This is safe because the branch (e.g. "automated/bump-decoupled-deps") @@ -21,6 +24,7 @@ steps: git push origin ${{ parameters.BranchName }} --force displayName: 'Push branch' condition: and(succeeded(), eq(variables['${{ parameters.HasChangesVariableName }}'], 'true')) + workingDirectory: ${{ parameters.WorkingDirectory }} - bash: | set -e @@ -109,6 +113,7 @@ steps: # value contains quotes or other shell metacharacters. Environment variables # are set by the AzDO agent outside of the shell, so they are safe regardless # of content. + workingDirectory: ${{ parameters.WorkingDirectory }} env: PR_TITLE: ${{ parameters.PrTitle }} PR_BODY: ${{ parameters.PrDescription }} From 1e5760cbb590accf82fba6413746560a9b829e33 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sat, 21 Feb 2026 23:54:14 -0800 Subject: [PATCH 08/30] Extract api artifact publishing to separate branch --- common/config/azure-pipelines/npm-publish-rush.yaml | 3 --- common/config/azure-pipelines/npm-publish.yaml | 3 --- common/config/azure-pipelines/templates/post-publish.yaml | 5 ----- 3 files changed, 11 deletions(-) diff --git a/common/config/azure-pipelines/npm-publish-rush.yaml b/common/config/azure-pipelines/npm-publish-rush.yaml index 70727beb73..ee40eec3c8 100644 --- a/common/config/azure-pipelines/npm-publish-rush.yaml +++ b/common/config/azure-pipelines/npm-publish-rush.yaml @@ -42,9 +42,6 @@ extends: - output: pipelineArtifact targetPath: $(Build.ArtifactStagingDirectory)/packages artifactName: packages - - output: pipelineArtifact - targetPath: $(Build.ArtifactStagingDirectory)/api - artifactName: api steps: - checkout: self persistCredentials: true diff --git a/common/config/azure-pipelines/npm-publish.yaml b/common/config/azure-pipelines/npm-publish.yaml index 2b589c4a73..dfb163c14b 100644 --- a/common/config/azure-pipelines/npm-publish.yaml +++ b/common/config/azure-pipelines/npm-publish.yaml @@ -42,9 +42,6 @@ extends: - output: pipelineArtifact targetPath: $(Build.ArtifactStagingDirectory)/packages artifactName: packages - - output: pipelineArtifact - targetPath: $(Build.ArtifactStagingDirectory)/api - artifactName: api steps: - checkout: self persistCredentials: true diff --git a/common/config/azure-pipelines/templates/post-publish.yaml b/common/config/azure-pipelines/templates/post-publish.yaml index f3069262fb..c25ab635df 100644 --- a/common/config/azure-pipelines/templates/post-publish.yaml +++ b/common/config/azure-pipelines/templates/post-publish.yaml @@ -3,8 +3,3 @@ steps: displayName: 'Record Published Versions' - script: 'node repo-scripts/repo-toolbox/lib-commonjs/start.js collect-json-schemas --output-path $(Build.ArtifactStagingDirectory)/json-schemas' displayName: 'Collect JSON Schemas' - - bash: | - set -e - mkdir -p "$(Build.ArtifactStagingDirectory)/api" - cp common/temp/api/*.api.json "$(Build.ArtifactStagingDirectory)/api/" - displayName: 'Collect API review files' From b7045fa5f1e0cf2aeb02e8e07e0a457fee2f29a6 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 14:22:01 -0800 Subject: [PATCH 09/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- .../azure-pipelines/npm-post-publish.yaml | 25 +++---------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 159da635f1..5d0ad1074d 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -129,13 +129,6 @@ extends: name: publish-rushstack os: linux steps: - # Check out both repos. AzDO places them in subdirectories named after the - # repo alias when multiple checkouts are used: - # $(Pipeline.Workspace)/s/self (rushstack) - # $(Pipeline.Workspace)/s/rushstackWebsites (rushstack-websites) - - checkout: self - persistCredentials: true - - checkout: rushstackWebsites persistCredentials: true @@ -149,20 +142,10 @@ extends: artifact: api path: $(Pipeline.Workspace)/api - # Install and build only api-documenter, which is needed to generate - # the markdown output from the *.api.json files. - - script: 'node common/scripts/install-run-rush.js install' - displayName: 'Rush Install' - workingDirectory: $(Pipeline.Workspace)/s/self - - - script: 'node common/scripts/install-run-rush.js build --to @microsoft/api-documenter --verbose' - displayName: 'Rush Build (api-documenter)' - workingDirectory: $(Pipeline.Workspace)/s/self - - # Run api-documenter to generate markdown files from the *.api.json inputs. - - script: 'node apps/api-documenter/bin/api-documenter markdown --input-folder $(Pipeline.Workspace)/api --output-folder $(Pipeline.Workspace)/api-markdown' + # Install api-documenter from the package feed (just published) and + # generate markdown from the *.api.json inputs. + - script: 'npx @microsoft/api-documenter@latest markdown --input-folder $(Pipeline.Workspace)/api --output-folder $(Pipeline.Workspace)/api-markdown' displayName: 'Generate API markdown' - workingDirectory: $(Pipeline.Workspace)/s/self # Update the API docs folder in rushstack-websites and commit. - bash: | @@ -190,11 +173,9 @@ extends: git add --all git commit -m "$(CommitMessage)" displayName: 'Update API docs and commit' - workingDirectory: $(Pipeline.Workspace)/s/rushstackWebsites - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self parameters: BranchName: $(BranchName) PrTitle: $(CommitMessage) PrDescription: 'Automated PR to update API reference documentation from the latest published packages.' - WorkingDirectory: $(Pipeline.Workspace)/s/rushstackWebsites From 8d8bac6c025596d9b616e8bee2ef46f7ce2624b6 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 14:26:06 -0800 Subject: [PATCH 10/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- .../azure-pipelines/npm-post-publish.yaml | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 5d0ad1074d..472150049a 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -40,11 +40,27 @@ extends: name: Azure-Pipelines-1ESPT-ExDShared os: windows stages: + # ────────────────────────────────────────────────────────────────────────── + # Stage 0: Wait for packages to propagate to the npm registry + # ────────────────────────────────────────────────────────────────────────── + - stage: WaitForPropagation + displayName: 'Wait for npm propagation' + jobs: + - job: + pool: server + timeoutInMinutes: 120 + steps: + - task: Delay@1 + displayName: 'Wait ${{ parameters.delayMinutes }} minute(s)' + inputs: + delayForMinutes: '${{ parameters.delayMinutes }}' + # ────────────────────────────────────────────────────────────────────────── # Stage 1: Bump decoupled local dependencies # ────────────────────────────────────────────────────────────────────────── - stage: BumpDecoupledDeps displayName: 'Bump decoupled local dependencies' + dependsOn: WaitForPropagation variables: BranchName: 'automated/bump-decoupled-deps' CommitMessage: 'chore: bump decoupled local dependencies' @@ -57,11 +73,6 @@ extends: - checkout: self persistCredentials: true - - bash: | - echo "Waiting ${{ parameters.delayMinutes }} minute(s) for packages to propagate to npm..." - sleep $(( ${{ parameters.delayMinutes }} * 60 )) - displayName: 'Wait for packages to propagate' - - template: /common/config/azure-pipelines/templates/install-node.yaml@self - script: 'git config --local user.email rushbot@users.noreply.github.com' @@ -119,7 +130,7 @@ extends: # ────────────────────────────────────────────────────────────────────────── - stage: UpdateApiDocs displayName: 'Update API documentation' - dependsOn: [] # Run in parallel with BumpDecoupledDeps + dependsOn: WaitForPropagation variables: BranchName: 'automated/update-api-docs' CommitMessage: 'docs: update API documentation' From 8c803efc427a2b3af3d8c0f6e68cfeaef4b67cbe Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 16:20:28 -0800 Subject: [PATCH 11/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 472150049a..af904db63e 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -8,6 +8,11 @@ variables: - name: FORCE_COLOR value: 1 +# This pipeline is triggered only by pipeline resources (npm publish pipelines), +# not by CI pushes or PR builds. +trigger: none +pr: none + resources: pipelines: - pipeline: npmPublish From 63137c08ee0cbd7fcb98b04fc4343301c3959009 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 16:25:14 -0800 Subject: [PATCH 12/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index af904db63e..54d10904f1 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -4,6 +4,8 @@ parameters: type: number default: 5 +name: 'Post-publish $(Date:yyyyMMdd).$(Rev:r) (triggered by $(resources.triggeringAlias))' + variables: - name: FORCE_COLOR value: 1 From a33d3cee37922d15a516b74487502f39aca34c71 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 16:55:48 -0800 Subject: [PATCH 13/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 54d10904f1..2a6fc66398 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -37,7 +37,7 @@ resources: - repository: rushstackWebsites type: github name: microsoft/rushstack-websites - endpoint: pipelinesMicrosoftRushstack + endpoint: GitHubProjects ref: refs/heads/main extends: From 165235022ec13ac03ed523a2013ae500056a6031 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 16:56:46 -0800 Subject: [PATCH 14/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 2a6fc66398..ca77e15ff9 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -43,6 +43,10 @@ resources: extends: template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: + sdl: + sourceRepositoriesToScan: + exclude: + - repository: rushstackWebsites pool: name: Azure-Pipelines-1ESPT-ExDShared os: windows From 10dade8a50ab551d3ea1957e504d5d625d23471e Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 16:58:59 -0800 Subject: [PATCH 15/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index ca77e15ff9..6e045e6058 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -46,6 +46,7 @@ extends: sdl: sourceRepositoriesToScan: exclude: + - repository: self - repository: rushstackWebsites pool: name: Azure-Pipelines-1ESPT-ExDShared @@ -58,6 +59,7 @@ extends: displayName: 'Wait for npm propagation' jobs: - job: + displayName: 'Delay' pool: server timeoutInMinutes: 120 steps: @@ -77,6 +79,7 @@ extends: CommitMessage: 'chore: bump decoupled local dependencies' jobs: - job: + displayName: 'Bump and create PR' pool: name: publish-rushstack os: linux @@ -147,6 +150,7 @@ extends: CommitMessage: 'docs: update API documentation' jobs: - job: + displayName: 'Generate docs and create PR' pool: name: publish-rushstack os: linux From 27973442014f75747f784a2a92623679dbdc6707 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 17:01:33 -0800 Subject: [PATCH 16/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 6e045e6058..e0efce24bf 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -79,7 +79,7 @@ extends: CommitMessage: 'chore: bump decoupled local dependencies' jobs: - job: - displayName: 'Bump and create PR' + displayName: 'Bump decoupled dependencies and create PR' pool: name: publish-rushstack os: linux @@ -150,7 +150,7 @@ extends: CommitMessage: 'docs: update API documentation' jobs: - job: - displayName: 'Generate docs and create PR' + displayName: 'Update API docs and create PR' pool: name: publish-rushstack os: linux From 0ac30e765e0b80ef8f08637b23c958dce9caa931 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 17:02:39 -0800 Subject: [PATCH 17/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index e0efce24bf..291a3632f0 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -46,7 +46,6 @@ extends: sdl: sourceRepositoriesToScan: exclude: - - repository: self - repository: rushstackWebsites pool: name: Azure-Pipelines-1ESPT-ExDShared From 728b415a561462c6e7448934165fbd38c735da09 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 17:52:21 -0800 Subject: [PATCH 18/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 291a3632f0..fc0023e5ff 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -20,12 +20,14 @@ resources: - pipeline: npmPublish source: 'rushstack NPM Publish' trigger: + enabled: true branches: include: - main - pipeline: npmPublishRush source: 'rushstack NPM Publish (rush)' trigger: + enabled: true branches: include: - main @@ -46,6 +48,7 @@ extends: sdl: sourceRepositoriesToScan: exclude: + - repository: self - repository: rushstackWebsites pool: name: Azure-Pipelines-1ESPT-ExDShared From 59b9867740165790cede12a0f35b2ceb291c490f Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 17:54:59 -0800 Subject: [PATCH 19/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index fc0023e5ff..9ad21629ef 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -48,7 +48,6 @@ extends: sdl: sourceRepositoriesToScan: exclude: - - repository: self - repository: rushstackWebsites pool: name: Azure-Pipelines-1ESPT-ExDShared From 8963a0e7ec07e1a69dde1e5ffc896153d9c55066 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 18:03:14 -0800 Subject: [PATCH 20/30] Only install to repo-toolbox. --- common/config/azure-pipelines/npm-post-publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 9ad21629ef..8422ab4b36 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -96,7 +96,7 @@ extends: - script: 'git config --local user.name Rushbot' displayName: 'git config name' - - script: 'node common/scripts/install-run-rush.js install' + - script: 'node common/scripts/install-run-rush.js install --to repo-toolbox' displayName: 'Rush Install' - script: 'node common/scripts/install-run-rush.js build --to repo-toolbox --verbose' From 7bbe316baa47c437f462b2d75e1f526d0588fbeb Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 18:26:35 -0800 Subject: [PATCH 21/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 8422ab4b36..d5b4f3dd70 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -19,18 +19,10 @@ resources: pipelines: - pipeline: npmPublish source: 'rushstack NPM Publish' - trigger: - enabled: true - branches: - include: - - main + trigger: true - pipeline: npmPublishRush source: 'rushstack NPM Publish (rush)' - trigger: - enabled: true - branches: - include: - - main + trigger: true repositories: - repository: 1esPipelines type: git From d5645af6de32f750c11aa44deccb8584b178f405 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 18:29:13 -0800 Subject: [PATCH 22/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index d5b4f3dd70..286cff555c 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -19,10 +19,16 @@ resources: pipelines: - pipeline: npmPublish source: 'rushstack NPM Publish' - trigger: true + trigger: + branches: + include: + - refs/heads/main - pipeline: npmPublishRush source: 'rushstack NPM Publish (rush)' - trigger: true + trigger: + branches: + include: + - refs/heads/main repositories: - repository: 1esPipelines type: git From a204dddfd3b891611ee9c62ae1fba6bf555a9780 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 18:33:31 -0800 Subject: [PATCH 23/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 286cff555c..0a4300e45a 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -19,12 +19,14 @@ resources: pipelines: - pipeline: npmPublish source: 'rushstack NPM Publish' + branch: refs/heads/main trigger: branches: include: - refs/heads/main - pipeline: npmPublishRush source: 'rushstack NPM Publish (rush)' + branch: refs/heads/main trigger: branches: include: From b4be87423729b1c0ec52ea617b01e4b86ab8b0a9 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 18:34:48 -0800 Subject: [PATCH 24/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 0a4300e45a..e058cf45ea 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -20,17 +20,11 @@ resources: - pipeline: npmPublish source: 'rushstack NPM Publish' branch: refs/heads/main - trigger: - branches: - include: - - refs/heads/main + trigger: true - pipeline: npmPublishRush source: 'rushstack NPM Publish (rush)' branch: refs/heads/main - trigger: - branches: - include: - - refs/heads/main + trigger: true repositories: - repository: 1esPipelines type: git From 4b5069d2b288b27b4559d901a462f96f4afc61c0 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 18:59:43 -0800 Subject: [PATCH 25/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- common/config/azure-pipelines/npm-post-publish.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index e058cf45ea..947bc75afc 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -19,12 +19,16 @@ resources: pipelines: - pipeline: npmPublish source: 'rushstack NPM Publish' - branch: refs/heads/main - trigger: true + trigger: + branches: + include: + - main - pipeline: npmPublishRush source: 'rushstack NPM Publish (rush)' - branch: refs/heads/main - trigger: true + trigger: + branches: + include: + - main repositories: - repository: 1esPipelines type: git From ba040aa507e0fb8a8d9a1703eb1709781910fc47 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 19:01:06 -0800 Subject: [PATCH 26/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- .../config/azure-pipelines/npm-post-publish.yaml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 947bc75afc..56ff9798ae 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -20,15 +20,17 @@ resources: - pipeline: npmPublish source: 'rushstack NPM Publish' trigger: + enabled: true branches: include: - - main - - pipeline: npmPublishRush - source: 'rushstack NPM Publish (rush)' - trigger: - branches: - include: - - main + - refs/heads/main + # - pipeline: npmPublishRush + # source: 'rushstack NPM Publish (rush)' + # trigger: + # enabled: true + # branches: + # include: + # - refs/heads/main repositories: - repository: 1esPipelines type: git From d3bb56408229847e459ad0f332c40c2388a25cc9 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 19:07:14 -0800 Subject: [PATCH 27/30] fixup! Rename to npm-post-publish, add api artifact, add API docs update stage using multi-repo checkout --- .../config/azure-pipelines/npm-post-publish.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 56ff9798ae..135d010f90 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -24,13 +24,13 @@ resources: branches: include: - refs/heads/main - # - pipeline: npmPublishRush - # source: 'rushstack NPM Publish (rush)' - # trigger: - # enabled: true - # branches: - # include: - # - refs/heads/main + - pipeline: npmPublishRush + source: 'rushstack NPM Publish (rush)' + trigger: + enabled: true + branches: + include: + - refs/heads/main repositories: - repository: 1esPipelines type: git From f62258a6d6d025affd401c5a6905d98cbca1bb0d Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Sun, 22 Feb 2026 21:36:40 -0800 Subject: [PATCH 28/30] TEMP: download api artifact from latest npmPublish for testing --- common/config/azure-pipelines/npm-post-publish.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index 135d010f90..f393f3029f 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -166,6 +166,10 @@ extends: - task: DownloadPipelineArtifact@2 displayName: 'Download API review files' inputs: + source: specific + project: GitHubProjects + pipeline: 'rushstack NPM Publish' + runVersion: latest artifact: api path: $(Pipeline.Workspace)/api From a4467e5f2bf519f468406ccea714ae0cef98c81e Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 23 Feb 2026 10:52:26 -0800 Subject: [PATCH 29/30] Use api-documenter-docusaurus-plugin. --- .../azure-pipelines/npm-post-publish.yaml | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index f393f3029f..f8bf3c1132 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -161,6 +161,14 @@ extends: - template: /common/config/azure-pipelines/templates/install-node.yaml@self + # Build the custom Docusaurus plugin for api-documenter in the + # rushstack-websites repo. + - script: 'node common/scripts/install-run-rush.js install' + displayName: 'Rush Install (rushstack-websites)' + + - script: 'node common/scripts/install-run-rush.js build --to-except api.rushstack.io --verbose' + displayName: 'Rush Build to-except api.rushstack.io (rushstack-websites)' + # Download the api artifact from the triggering publish pipeline. # AzDO automatically resolves which pipeline resource triggered this run. - task: DownloadPipelineArtifact@2 @@ -173,10 +181,12 @@ extends: artifact: api path: $(Pipeline.Workspace)/api - # Install api-documenter from the package feed (just published) and - # generate markdown from the *.api.json inputs. - - script: 'npx @microsoft/api-documenter@latest markdown --input-folder $(Pipeline.Workspace)/api --output-folder $(Pipeline.Workspace)/api-markdown' - displayName: 'Generate API markdown' + # Run api-documenter with the Docusaurus plugin from the + # api.rushstack.io project directory so it picks up + # config/api-documenter.json. + - script: 'npx @microsoft/api-documenter@latest generate --input-folder $(Pipeline.Workspace)/api --output-folder ./docs/pages' + displayName: 'Generate API documentation' + workingDirectory: websites/api.rushstack.io # Update the API docs folder in rushstack-websites and commit. - bash: | @@ -185,11 +195,8 @@ extends: git config --local user.email rushbot@users.noreply.github.com git config --local user.name Rushbot - # Clear the existing pages and replace with freshly generated markdown. - API_DOCS_DIR="websites/api.rushstack.io/docs/pages" - rm -rf "$API_DOCS_DIR" - mkdir -p "$API_DOCS_DIR" - cp -r "$(Pipeline.Workspace)/api-markdown/." "$API_DOCS_DIR/" + # Move the generated nav data file to the expected location. + mv websites/api.rushstack.io/docs/api_nav.json websites/api.rushstack.io/data/api_nav.json # Check for changes (tracked and untracked) if git diff --quiet && [ -z "$(git ls-files --others --exclude-standard)" ]; then From 43b9ba87918aee4515fe2bce20320cdbcd41ee84 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 23 Feb 2026 11:02:42 -0800 Subject: [PATCH 30/30] fixup! Use api-documenter-docusaurus-plugin. --- common/config/azure-pipelines/npm-post-publish.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml index f8bf3c1132..61be013516 100644 --- a/common/config/azure-pipelines/npm-post-publish.yaml +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -160,6 +160,8 @@ extends: persistCredentials: true - template: /common/config/azure-pipelines/templates/install-node.yaml@self + parameters: + NodeMajorVersion: 24 # Build the custom Docusaurus plugin for api-documenter in the # rushstack-websites repo.