From 273ad9752ccd32b288bccb437aeea2445b952776 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Wed, 18 Feb 2026 10:15:21 -0700 Subject: [PATCH 1/4] Update workflows with final fixes --- .github/workflows/generate.yml | 4 +- .github/workflows/on-push-master.yml | 3 +- .../workflows/openapi-generate-and-push.yml | 60 ++++++++++--------- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 543ecbc..23cde2e 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -93,9 +93,9 @@ jobs: git config user.name "devexperience" git config user.email "devexperience@mx.com" git add . - git commit -m "Generated API ${{ github.event.inputs.api_version }} SDK for version ${{ steps.bump_version.outputs.version }} + git commit -m "Manually Generated API ${{ github.event.inputs.api_version }} SDK for version ${{ steps.bump_version.outputs.version }} - This pull request was automatically generated by a GitHub Action. + This pull request was automatically generated by generate GitHub Action. API Version: ${{ github.event.inputs.api_version }} SDK Version: ${{ steps.bump_version.outputs.version }} diff --git a/.github/workflows/on-push-master.yml b/.github/workflows/on-push-master.yml index 36ca904..bdfab17 100644 --- a/.github/workflows/on-push-master.yml +++ b/.github/workflows/on-push-master.yml @@ -17,8 +17,9 @@ jobs: steps: - name: Check for [skip-publish] flag in commit message id: check + env: + COMMIT_MSG: ${{ github.event.head_commit.message }} run: | - COMMIT_MSG="${{ github.event.head_commit.message }}" if [[ "$COMMIT_MSG" == *"[skip-publish]"* ]]; then echo "skip_publish=true" >> $GITHUB_OUTPUT echo "🚫 [skip-publish] flag detected - skipping all publish/release jobs" diff --git a/.github/workflows/openapi-generate-and-push.yml b/.github/workflows/openapi-generate-and-push.yml index c0bec5b..9045576 100644 --- a/.github/workflows/openapi-generate-and-push.yml +++ b/.github/workflows/openapi-generate-and-push.yml @@ -3,12 +3,6 @@ name: "OpenAPI: Automated Generate and Push" on: repository_dispatch: types: [generate_publish_release] - workflow_dispatch: - inputs: - payload_json: - description: 'JSON payload (e.g., {"api_versions":"v20111101","version":"patch","commit_sha":"abc123"})' - required: false - type: string jobs: Setup: @@ -20,12 +14,7 @@ jobs: - name: Parse payload id: parse-payload run: | - # Parse workflow_dispatch payload if provided, otherwise use repository_dispatch payload - if [ -n "${{ github.event.inputs.payload_json }}" ]; then - VERSIONS=$(echo '${{ github.event.inputs.payload_json }}' | jq -r '.api_versions // "v20111101"') - else - VERSIONS="${{ github.event.client_payload.api_versions || 'v20111101' }}" - fi + VERSIONS="${{ github.event.client_payload.api_versions || 'v20111101' }}" echo "versions_to_generate=$VERSIONS" >> $GITHUB_OUTPUT - name: Set up matrix @@ -77,13 +66,8 @@ jobs: - name: Bump version id: bump_version run: | - # Parse version from workflow_dispatch or repository_dispatch - if [ -n "${{ github.event.inputs.payload_json }}" ]; then - VERSION=$(echo '${{ github.event.inputs.payload_json }}' | jq -r '.version // "patch"') - else - VERSION="${{ github.event.client_payload.version || 'patch' }}" - fi - NEW_VERSION=$(ruby .github/version.rb "$VERSION" ${{ matrix.config_file }}) + VERSION="${{ github.event.client_payload.version || 'patch' }}" + NEW_VERSION=$(ruby .github/version.rb $VERSION ${{ matrix.config_file }}) echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - name: Clean repo run: ruby .github/clean.rb ${{ matrix.api_version }} @@ -95,12 +79,7 @@ jobs: run: npm install @openapitools/openapi-generator-cli -g - name: Generate SDK run: | - # Parse commit_sha from workflow_dispatch or repository_dispatch - if [ -n "${{ github.event.inputs.payload_json }}" ]; then - COMMIT_SHA=$(echo '${{ github.event.inputs.payload_json }}' | jq -r '.commit_sha // "master"') - else - COMMIT_SHA="${{ github.event.client_payload.commit_sha || 'master' }}" - fi + COMMIT_SHA="${{ github.event.client_payload.commit_sha || 'master' }}" # Versioned spec URLs with commit SHA to avoid GitHub CDN cache race condition # Problem: GitHub's raw.githubusercontent.com CDN caches files for 5 minutes @@ -113,11 +92,16 @@ jobs: -c ${{ matrix.config_file }} \ -t ./openapi/templates \ -o ./${{ matrix.api_version }} - - name: Upload artifacts + - name: Upload SDK artifacts uses: actions/upload-artifact@v4 with: name: generated-${{ matrix.api_version }} path: ./${{ matrix.api_version }} + - name: Upload config artifact + uses: actions/upload-artifact@v4 + with: + name: config-${{ matrix.api_version }} + path: ${{ matrix.config_file }} Process-and-Push: runs-on: ubuntu-latest @@ -128,6 +112,20 @@ jobs: uses: actions/download-artifact@v4 with: path: ./generated + - name: Restore config files from artifacts + run: | + # Config files are bumped in the Generate job (separate runner). + # Restore them here so the version bump persists in the commit. + for dir in ./generated/config-*; do + [ -d "$dir" ] || continue + VERSION=$(basename "$dir" | sed 's/config-//') + CONFIG_FILE="openapi/config-${VERSION}.yml" + cp "$dir"/* "./$CONFIG_FILE" 2>/dev/null || echo "Config not found in $dir" + echo "Restored $CONFIG_FILE" + done + + # Clean up config artifact directories so they don't get committed + rm -rf ./generated/config-* - name: Move generated files and track versions id: track_versions run: | @@ -135,6 +133,12 @@ jobs: for dir in ./generated/generated-*; do VERSION=$(basename "$dir" | sed 's/generated-//') + + # Remove target directory before moving to prevent nesting + if [ -d "./$VERSION" ]; then + rm -rf "./$VERSION" + fi + mv "$dir" "./$VERSION" GENERATED_VERSIONS="$GENERATED_VERSIONS $VERSION" done @@ -170,9 +174,9 @@ jobs: git config user.name "devexperience" git config user.email "devexperience@mx.com" git add . - git commit -m "Generated SDK versions: ${{ needs.Setup.outputs.versions_to_generate }} + git commit -m "Automated Generated SDK versions: ${{ needs.Setup.outputs.versions_to_generate }} - This commit was automatically created by a GitHub Action." + This commit was automatically created by openapi-generate-and-push GitHub Action." - name: Push to master run: git push origin master env: From c8079123630f70eed4aad54f080d4b84e44c2fdf Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Wed, 18 Feb 2026 11:21:58 -0700 Subject: [PATCH 2/4] And some more fixes --- .github/workflows/generate.yml | 3 +- .github/workflows/on-push-master.yml | 30 ++++++++++++-- .../workflows/openapi-generate-and-push.yml | 40 +++++++++++++++++++ .github/workflows/publish.yml | 3 +- .github/workflows/release.yml | 3 +- 5 files changed, 70 insertions(+), 9 deletions(-) diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 23cde2e..a9362fa 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -113,8 +113,7 @@ jobs: status: ${{ job.status }} token: ${{ secrets.GITHUB_TOKEN }} notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" - footer: "<{workflow_url}|View Workflow>" + message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" notify_when: "failure" env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/on-push-master.yml b/.github/workflows/on-push-master.yml index bdfab17..e9aba13 100644 --- a/.github/workflows/on-push-master.yml +++ b/.github/workflows/on-push-master.yml @@ -6,6 +6,8 @@ on: paths: - 'v20111101/**' - 'v20250224/**' + repository_dispatch: + types: [manual_push_to_master] jobs: # Check for skip-publish flag in commit message. This allows skipping publish/release for specific scenarios, @@ -28,9 +30,11 @@ jobs: echo "✅ No skip flag - proceeding with publish/release" fi - # Detect which API versions were modified in this push - # Uses dorny/paths-filter to reliably check which directories changed - # This allows us to run publish/release jobs only for versions that were actually modified + # Detect which API versions were modified + # Uses dorny/paths-filter to check which version directories changed. + # For push events: paths-filter uses github.event.before/after automatically. + # For repository_dispatch events: both push and dispatch target master (same branch), + # so we compare HEAD against HEAD~1 to detect changes from the just-pushed commit. detect-changes: runs-on: ubuntu-latest outputs: @@ -41,6 +45,7 @@ jobs: - uses: dorny/paths-filter@v2 id: filter with: + base: ${{ github.event_name == 'repository_dispatch' && 'HEAD~1' || '' }} filters: | v20111101: - 'v20111101/**' @@ -89,3 +94,22 @@ jobs: with: version_directory: v20250224 secrets: inherit + + # Notify on failure of orchestration jobs (check-skip-publish, detect-changes, delay). + # Publish and release workflows have their own Slack notifications, so we only + # monitor the jobs owned by this workflow to avoid double-alerting. + slack-notification: + runs-on: ubuntu-latest + needs: [check-skip-publish, detect-changes, delay-for-v20250224] + if: always() && (needs.check-skip-publish.result == 'failure' || needs.detect-changes.result == 'failure' || needs.delay-for-v20250224.result == 'failure') + steps: + - name: Slack notification + uses: ravsamhq/notify-slack-action@v2 + with: + status: failure + token: ${{ secrets.GITHUB_TOKEN }} + notification_title: "{repo}: {workflow} workflow" + message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" + notify_when: "failure" + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/openapi-generate-and-push.yml b/.github/workflows/openapi-generate-and-push.yml index 9045576..ea3a42c 100644 --- a/.github/workflows/openapi-generate-and-push.yml +++ b/.github/workflows/openapi-generate-and-push.yml @@ -63,20 +63,25 @@ jobs: ruby-version: 3.1 - name: Validate configuration run: ruby .github/config_validator.rb "${{ matrix.config_file }}" "${{ matrix.api_version }}" + - name: Bump version id: bump_version run: | VERSION="${{ github.event.client_payload.version || 'patch' }}" NEW_VERSION=$(ruby .github/version.rb $VERSION ${{ matrix.config_file }}) echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + - name: Clean repo run: ruby .github/clean.rb ${{ matrix.api_version }} + - name: Copy generator ignore rules run: | mkdir -p ./${{ matrix.api_version }}/ cp .openapi-generator-ignore ./${{ matrix.api_version }}/ + - name: Install openapi-generator-cli run: npm install @openapitools/openapi-generator-cli -g + - name: Generate SDK run: | COMMIT_SHA="${{ github.event.client_payload.commit_sha || 'master' }}" @@ -92,11 +97,13 @@ jobs: -c ${{ matrix.config_file }} \ -t ./openapi/templates \ -o ./${{ matrix.api_version }} + - name: Upload SDK artifacts uses: actions/upload-artifact@v4 with: name: generated-${{ matrix.api_version }} path: ./${{ matrix.api_version }} + - name: Upload config artifact uses: actions/upload-artifact@v4 with: @@ -112,6 +119,7 @@ jobs: uses: actions/download-artifact@v4 with: path: ./generated + - name: Restore config files from artifacts run: | # Config files are bumped in the Generate job (separate runner). @@ -126,6 +134,7 @@ jobs: # Clean up config artifact directories so they don't get committed rm -rf ./generated/config-* + - name: Move generated files and track versions id: track_versions run: | @@ -144,6 +153,7 @@ jobs: done echo "generated_versions=$GENERATED_VERSIONS" >> $GITHUB_OUTPUT + - name: Update CHANGELOG run: | GENERATED_VERSIONS="${{ steps.track_versions.outputs.generated_versions }}" @@ -158,6 +168,7 @@ jobs: # Trim leading/trailing whitespace first VERSIONS_CSV=$(echo "$GENERATED_VERSIONS" | xargs | tr ' ' ',') ruby .github/changelog_manager.rb "$VERSIONS_CSV" + - name: Copy documentation run: | GENERATED_VERSIONS="${{ steps.track_versions.outputs.generated_versions }}" @@ -167,6 +178,7 @@ jobs: cp CHANGELOG.md "./$VERSION/CHANGELOG.md" cp MIGRATION.md "./$VERSION/MIGRATION.md" done + - name: Checkout master run: git checkout master - name: Create commit @@ -181,3 +193,31 @@ jobs: run: git push origin master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # GitHub security feature: pushes using GITHUB_TOKEN don't trigger other workflows. + # We must explicitly trigger on-push-master.yml using a GitHub App token. + - name: Generate access token + id: generate_token + uses: tibdex/github-app-token@v1 + with: + app_id: ${{ secrets.PAPI_SDK_APP_ID }} + installation_id: ${{ secrets.PAPI_SDK_INSTALLATION_ID }} + private_key: ${{ secrets.PAPI_SDK_PRIVATE_KEY }} + + - name: Trigger publish and release workflow + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ steps.generate_token.outputs.token }} + event-type: manual_push_to_master + + - name: Slack notification + uses: ravsamhq/notify-slack-action@v2 + if: always() + with: + status: ${{ job.status }} + token: ${{ secrets.GITHUB_TOKEN }} + notification_title: "{repo}: {workflow} workflow" + message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" + notify_when: "failure" + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b69c8c4..b801f3a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,8 +40,7 @@ jobs: status: ${{ job.status }} token: ${{ secrets.GITHUB_TOKEN }} notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" - footer: "<{workflow_url}|View Workflow>" + message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" notify_when: "failure" env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c1236f1..8c095de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,8 +42,7 @@ jobs: status: ${{ job.status }} token: ${{ secrets.GITHUB_TOKEN }} notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>" - footer: "<{workflow_url}|View Workflow>" + message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" notify_when: "failure" env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} From e331682fa35ef1020931497b0f94a56d5c55e056 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Wed, 18 Feb 2026 11:40:08 -0700 Subject: [PATCH 3/4] Update docs --- .github/workflows/on-push-master.yml | 2 +- .../workflows/openapi-generate-and-push.yml | 2 +- docs/Adding-a-New-API-Version.md | 8 ++- docs/Multi-Version-SDK-Flow.md | 6 +- docs/Troubleshooting-Guide.md | 63 ++++++++++++++++- docs/Workflow-and-Configuration-Reference.md | 68 ++++++++++++++++--- 6 files changed, 130 insertions(+), 19 deletions(-) diff --git a/.github/workflows/on-push-master.yml b/.github/workflows/on-push-master.yml index e9aba13..aaee735 100644 --- a/.github/workflows/on-push-master.yml +++ b/.github/workflows/on-push-master.yml @@ -7,7 +7,7 @@ on: - 'v20111101/**' - 'v20250224/**' repository_dispatch: - types: [manual_push_to_master] + types: [automated_push_to_master] jobs: # Check for skip-publish flag in commit message. This allows skipping publish/release for specific scenarios, diff --git a/.github/workflows/openapi-generate-and-push.yml b/.github/workflows/openapi-generate-and-push.yml index ea3a42c..5b83844 100644 --- a/.github/workflows/openapi-generate-and-push.yml +++ b/.github/workflows/openapi-generate-and-push.yml @@ -208,7 +208,7 @@ jobs: uses: peter-evans/repository-dispatch@v2 with: token: ${{ steps.generate_token.outputs.token }} - event-type: manual_push_to_master + event-type: automated_push_to_master - name: Slack notification uses: ravsamhq/notify-slack-action@v2 diff --git a/docs/Adding-a-New-API-Version.md b/docs/Adding-a-New-API-Version.md index 02b1af1..b713aac 100644 --- a/docs/Adding-a-New-API-Version.md +++ b/docs/Adding-a-New-API-Version.md @@ -2,7 +2,7 @@ **Document Purpose**: Step-by-step guide for adding support for a new API version (e.g., `v20300101`) to the mx-platform-node repository. -**Last Updated**: January 29, 2026 +**Last Updated**: February 18, 2026 **Time to Complete**: 30-45 minutes **Prerequisites**: Familiarity with the multi-version architecture (see [Multi-Version-SDK-Flow.md](Multi-Version-SDK-Flow.md)) @@ -152,6 +152,8 @@ version_directory: This workflow is automatically triggered by the OpenAPI repository to generate and push SDKs for all versions in parallel. +**Note**: The existing infrastructure handles config file artifact upload/download between Generate and Process-and-Push jobs automatically. You only need to add the version-to-config mapping below — the artifact pipeline will pick up your new config file without additional changes. + **Location 1: Version-to-config mapping** In the `Setup` job's `Set up matrix` step, find the section with the version-to-config mapping and add an `elif` branch for your new version: @@ -228,9 +230,11 @@ on: - 'v20111101/**' - 'v20250224/**' - 'v20300101/**' # NEW + repository_dispatch: + types: [automated_push_to_master] # No changes needed here ``` -This ensures the workflow triggers when changes to your version directory are pushed to master. +This ensures the workflow triggers when changes to your version directory are pushed to master. The `repository_dispatch` trigger does not need modification — it is used by `openapi-generate-and-push.yml` to trigger this workflow after automated pushes, and works regardless of which version directories changed. **Location 3: Add publish job for new version** diff --git a/docs/Multi-Version-SDK-Flow.md b/docs/Multi-Version-SDK-Flow.md index feb9cc2..0fe10d2 100644 --- a/docs/Multi-Version-SDK-Flow.md +++ b/docs/Multi-Version-SDK-Flow.md @@ -2,7 +2,7 @@ **Document Purpose**: Quick-reference guide to the multi-version SDK generation, publishing, and release system. This is your entry point to understanding how the system works. -**Last Updated**: January 28, 2026 +**Last Updated**: February 18, 2026 **Read Time**: 5-10 minutes **Audience**: Anyone joining the team or needing a system overview @@ -37,7 +37,7 @@ OpenAPI spec changes → `openapi-generate-and-push.yml` generates SDK → commi **What Happens**: 1. `openapi-generate-and-push.yml` generates all specified versions in parallel 2. All generated files committed to master -3. `on-push-master.yml` automatically triggered by the push +3. `openapi-generate-and-push.yml` sends a `repository_dispatch` event (`automated_push_to_master`) to trigger `on-push-master.yml` (required because `GITHUB_TOKEN` pushes don't trigger other workflows) 4. `on-push-master.yml` handles serial publish/release with version gating **Key Details**: See [Workflow-and-Configuration-Reference.md](Workflow-and-Configuration-Reference.md#flow-1-automatic-multi-version-generation-repository-dispatch) @@ -83,7 +83,7 @@ sequenceDiagram Gen->>Push: Commit to master
Update CHANGELOG.md deactivate Gen - Push->>+OnPush: Push event triggers + Push->>+OnPush: repository_dispatch
(automated_push_to_master) OnPush->>OnPush: Check skip-publish flag OnPush->>OnPush: Serial: v20111101 publish OnPush->>npm: npm publish v2.x.x diff --git a/docs/Troubleshooting-Guide.md b/docs/Troubleshooting-Guide.md index 0764c4b..d59aa02 100644 --- a/docs/Troubleshooting-Guide.md +++ b/docs/Troubleshooting-Guide.md @@ -2,7 +2,7 @@ **Document Purpose**: Quick reference for diagnosing and fixing issues in the multi-version SDK generation, publishing, and release workflows. -**Last Updated**: January 29, 2026 +**Last Updated**: February 18, 2026 **Audience**: Developers debugging workflow failures --- @@ -289,6 +289,33 @@ fatal: A release with this tag already exists --- +### Generated Files Placed in Nested Subdirectory + +**Symptom**: After automated generation, SDK files appear at `v20111101/generated-v20111101/api.ts` instead of `v20111101/api.ts` + +**Cause**: The `Process-and-Push` job in `openapi-generate-and-push.yml` downloads generated artifacts and moves them into the version directory. If the version directory already exists (from a prior commit), `mv` places the source *inside* the existing directory as a subdirectory rather than replacing it. + +**Solution**: Already fixed in `openapi-generate-and-push.yml`. The workflow now runs `rm -rf ./$VERSION` before `mv` to ensure the target directory doesn't exist, so the move replaces rather than nests. If you see this issue, verify the workflow includes the `rm -rf` step before the `mv` command in the Process-and-Push job. + +--- + +### Version Bump Not Applied During Automated Generation + +**Symptom**: Automated generation completes but the version in `package.json` didn't increment (stays at the previous version) + +**Cause**: The `version.rb` script argument was quoted incorrectly in the workflow. Passing `"$VERSION"` (with surrounding quotes in the shell script) causes bash to pass the literal string `$VERSION` instead of its value, so `version.rb` receives an unrecognized bump type and silently fails. + +**Solution**: Already fixed in `openapi-generate-and-push.yml`. The `$VERSION` variable is now passed unquoted to `version.rb`. If you see this issue, verify the workflow calls `version.rb` with `$VERSION` (not `"$VERSION"`): +```bash +# Correct +NEW_VERSION=$(ruby .github/version.rb $VERSION ${{ matrix.config_file }}) + +# Wrong — passes literal string +NEW_VERSION=$(ruby .github/version.rb "$VERSION" ${{ matrix.config_file }}) +``` + +--- + ### Workflow Not Triggering on Push **Symptom**: Merged a PR with changes to `v20111101/` directory, but `on-push-master.yml` didn't run @@ -298,6 +325,7 @@ fatal: A release with this tag already exists - Changes were not actually in the version directory - Commit was made to wrong branch - Workflow file has syntax error +- (Automated flow only) The push was made with `GITHUB_TOKEN`, which does not trigger `push` events for other workflows **Solutions**: 1. Verify path filter syntax is correct: @@ -308,6 +336,8 @@ fatal: A release with this tag already exists paths: - 'v20111101/**' # Correct format - 'v20250224/**' + repository_dispatch: + types: [automated_push_to_master] ``` 2. Check what files were actually changed: ```bash @@ -322,6 +352,7 @@ fatal: A release with this tag already exists ```bash ruby -e "require 'yaml'; puts YAML.load(File.read('.github/workflows/on-push-master.yml'))" ``` +5. **For automated flows**: Verify that `openapi-generate-and-push.yml` sends a `repository_dispatch` event after pushing. The `push` trigger only works for manual PR merges. Automated pushes from workflows use `GITHUB_TOKEN`, which does not trigger other workflows — the generate workflow must send an explicit `repository_dispatch` (type: `automated_push_to_master`) using a GitHub App token. --- @@ -347,6 +378,36 @@ git commit -m "Migrate SDK structure skip-publish" --- +### Skip-Publish Check Fails with Bash Error + +**Symptom**: The `check-skip-publish` step in `on-push-master.yml` errors with something like `SDK: command not found` (exit code 127), and downstream jobs skip unexpectedly + +**Cause**: The commit message contains double quotes (e.g., `Revert "Generated SDK versions: v20111101"`). If the workflow uses inline `${{ }}` interpolation to assign the commit message, the inner quotes close the outer quotes in bash, causing the remaining text to be interpreted as commands. + +**Example of broken pattern**: +```yaml +# BROKEN - double quotes in commit message break this +COMMIT_MSG="${{ github.event.head_commit.message }}" +``` + +**Solution**: The workflow should use an `env:` block to pass the commit message safely: +```yaml +- name: Check for [skip-publish] flag in commit message + id: check + env: + COMMIT_MSG: ${{ github.event.head_commit.message }} + run: | + if [[ "$COMMIT_MSG" == *"[skip-publish]"* ]]; then + echo "skip_publish=true" >> $GITHUB_OUTPUT + else + echo "skip_publish=false" >> $GITHUB_OUTPUT + fi +``` + +This fix is already applied to `on-push-master.yml`. If you see this error, verify that the workflow is using the `env:` block pattern and not inline interpolation. + +--- + ### Version.rb Script Errors #### Error: "Version directory parameter required" diff --git a/docs/Workflow-and-Configuration-Reference.md b/docs/Workflow-and-Configuration-Reference.md index 8090f04..2ceb769 100644 --- a/docs/Workflow-and-Configuration-Reference.md +++ b/docs/Workflow-and-Configuration-Reference.md @@ -2,7 +2,7 @@ **Document Purpose**: Detailed technical reference for the multi-version SDK generation, publishing, and release workflows. Covers implementation details, configuration files, and system architecture. -**Last Updated**: January 29, 2026 +**Last Updated**: February 18, 2026 **Audience**: Developers who need to understand or modify the implementation --- @@ -81,14 +81,21 @@ strategy: 6. **Upload Artifacts** - Upload generated SDK to workflow artifact storage + - Upload bumped config file as separate artifact (config file version bump happens on Generate runner, but Process-and-Push runs on a different runner with a fresh checkout — without this, the version bump would be lost) - Allows atomic multi-version commit after all matrix jobs complete #### Step 3: Post-Generation Processing (After All Matrix Jobs Complete) 1. **Download Artifacts** - Retrieve generated SDKs for all versions from artifact storage + - Retrieve config file artifacts and restore them to `openapi/` directory + - Clean up config artifact directories (`rm -rf ./generated/config-*`) to prevent them from being committed -2. **Track Generated Versions** +2. **Move Generated Files to Version Directories** + - Remove existing version directory contents before moving: `rm -rf ./$VERSION` then `mv` generated files into place + - This prevents the generated files from being placed in a nested subdirectory (e.g., `v20111101/generated-v20111101/` instead of `v20111101/`) + +3. **Track Generated Versions** - Record which directories were actually generated - Used by CHANGELOG automation to add entries only for generated versions @@ -129,7 +136,11 @@ strategy: #### Step 5: Automatic Publish and Release (via on-push-master.yml) -**Architecture**: After `Process-and-Push` completes and pushes to master, the automatic `on-push-master.yml` workflow is triggered by GitHub's push event. +**Architecture**: After `Process-and-Push` completes and pushes to master, it explicitly triggers `on-push-master.yml` via a `repository_dispatch` event (type: `automated_push_to_master`). + +**Why `repository_dispatch` instead of relying on the push event?** GitHub's security model prevents workflows triggered by `GITHUB_TOKEN` from triggering other workflows. Since `openapi-generate-and-push.yml` pushes to master using `GITHUB_TOKEN`, that push does **not** trigger `on-push-master.yml`'s `push` event. To solve this, `openapi-generate-and-push.yml` generates a GitHub App token (via `tibdex/github-app-token@v1`) and uses it to send a `repository_dispatch` event (via `peter-evans/repository-dispatch@v2`), which does trigger `on-push-master.yml`. + +**Note**: The `push` trigger on `on-push-master.yml` still exists and works for manual PR merges — only automated pushes from workflows need the `repository_dispatch` workaround. **Why This Architecture?** - Separates concerns: `openapi-generate-and-push.yml` owns generation, `on-push-master.yml` owns publishing @@ -137,7 +148,7 @@ strategy: - Prevents duplicate publishes: Manual generate.yml + PR merge only triggers publish once (via on-push-master.yml) **Process** (handled by `on-push-master.yml`): -1. Detect-changes job uses `dorny/paths-filter@v2` to identify which version directories changed (v20111101/**, v20250224/**) +1. Detect-changes job uses `dorny/paths-filter@v2` to identify which version directories changed (v20111101/**, v20250224/**). For `repository_dispatch` events, uses `base: HEAD~1` to compare against the previous commit (push events use default `before`/`after` automatically). 2. Check-skip-publish job detects if `[skip-publish]` flag is in commit message 3. For each version with path changes (output by detect-changes): - Publish job: Call `publish.yml` with version-specific directory (only if paths modified) @@ -339,8 +350,13 @@ publish-v20250224: -### Trigger -Push to `master` branch with changes in version-specific directories (`v20111101/**` or `v20250224/**`) +### Triggers + +`on-push-master.yml` responds to two trigger types: +1. **`push`** — activated when changes are pushed to `master` (e.g., PR merges) +2. **`repository_dispatch`** (type: `automated_push_to_master`) — activated by `openapi-generate-and-push.yml` after it pushes generated SDK files to master (needed because `GITHUB_TOKEN` pushes don't trigger `push` events for other workflows) + +Both triggers require changes in version-specific directories (`v20111101/**` or `v20250224/**`) to proceed to publishing. ### Skip-Publish Safety Mechanism Include `[skip-publish]` in commit message to prevent publish/release for this push. @@ -358,15 +374,21 @@ Include `[skip-publish]` in commit message to prevent publish/release for this p **Job**: `check-skip-publish` ```yaml -- name: Check for skip-publish flag +- name: Check for [skip-publish] flag in commit message + id: check + env: + COMMIT_MSG: ${{ github.event.head_commit.message }} run: | - if [[ "${{ github.event.head_commit.message }}" == *"[skip-publish]"* ]]; then + if [[ "$COMMIT_MSG" == *"[skip-publish]"* ]]; then echo "skip_publish=true" >> $GITHUB_OUTPUT + echo "🚫 [skip-publish] flag detected - skipping all publish/release jobs" else echo "skip_publish=false" >> $GITHUB_OUTPUT + echo "✅ No skip flag - proceeding with publish/release" fi ``` +- Uses `env:` block to safely pass commit message (avoids bash errors when commit messages contain double quotes — e.g., `Revert "Generated SDK versions: v20111101"` would break inline `${{ }}` interpolation) - Parses HEAD commit message - Sets output: `skip_publish` = true/false - Used by subsequent jobs to determine execution @@ -454,6 +476,22 @@ If v20250224 jobs depended directly on v20111101's publish job, the workflow wou --- +## Slack Failure Notifications + +All workflows send Slack notifications on failure to the channel configured via `SLACK_WEBHOOK_URL`. Notifications include a clickable link to the specific failed workflow run URL for quick diagnosis. + +| Workflow | Notification Scope | +|----------|--------------------| +| `openapi-generate-and-push.yml` | Generate job failures, Process-and-Push job failures | +| `on-push-master.yml` | Orchestration job failures (check-skip-publish, detect-changes, delay). Publish/release jobs have their own notifications via `publish.yml` and `release.yml`. | +| `generate.yml` | Generation failures | +| `publish.yml` | Publish failures | +| `release.yml` | Release failures | + +**Message format**: The workflow name in Slack messages links directly to the failed run URL, making it easy to jump straight to the failing step without navigating through the GitHub Actions UI. + +--- + ## Supporting Scripts ### version.rb - Multi-Version Support @@ -643,8 +681,12 @@ on: # - 'openapi/**' (config changes alone) # - 'docs/**' (documentation changes) # - 'README.md' (root documentation) + repository_dispatch: + types: [automated_push_to_master] # Triggered by openapi-generate-and-push.yml ``` +The `repository_dispatch` trigger is required because automated pushes from `openapi-generate-and-push.yml` use `GITHUB_TOKEN`, which does not trigger `push` events for other workflows (GitHub security feature). The generate workflow sends this dispatch explicitly using a GitHub App token. + **Benefits**: - Enhancement PRs (docs only) don't trigger publish - Workflow file changes don't trigger publish @@ -680,6 +722,8 @@ The repository uses **semantic versioning with major version = API version**: | `NPM_AUTH_TOKEN` | publish.yml | Authenticate to npm registry for publishing | | `GITHUB_TOKEN` | All workflows | GitHub API access (auto-provided by GitHub Actions) | | `SLACK_WEBHOOK_URL` | All workflows | Send failure notifications to Slack | +| `APP_ID` | openapi-generate-and-push.yml | GitHub App ID for generating tokens that can trigger cross-workflow events | +| `APP_PRIVATE_KEY` | openapi-generate-and-push.yml | GitHub App private key (used with `tibdex/github-app-token@v1` to create tokens for `repository_dispatch`) | ### Environment Setup @@ -706,13 +750,15 @@ openapi-generate-and-push.yml: Triggered ├─ Download artifacts ├─ Update CHANGELOG.md ├─ Commit to master - ├─ Push to master (triggers on-push-master.yml) + ├─ Push to master + ├─ Send repository_dispatch (automated_push_to_master) ↓ -on-push-master.yml: Triggered (push event) +on-push-master.yml: Triggered (repository_dispatch) ├─ check-skip-publish: Verify no [skip-publish] flag + ├─ detect-changes: paths-filter with base: HEAD~1 ├─ publish-v20111101: npm publish (path filter matched) ├─ release-v20111101: Create tag v2.0.1 (after publish) - ├─ publish-v20250224: npm publish (serialized, after v20111101 release) + ├─ publish-v20250224: npm publish (serialized, after delay) ├─ release-v20250224: Create tag v3.0.1 (after publish) ↓ Result: Both versions published and released sequentially, CHANGELOG updated From 9f2d03b772c2ba58f3d8b020377a0962eb665103 Mon Sep 17 00:00:00 2001 From: Genevieve Nuebel Date: Wed, 18 Feb 2026 11:49:46 -0700 Subject: [PATCH 4/4] Fix indent --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c095de..d45ebb0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: status: ${{ job.status }} token: ${{ secrets.GITHUB_TOKEN }} notification_title: "{repo}: {workflow} workflow" - message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" + message_format: "{emoji} *<{workflow_url}|{workflow}>* {status_message} in <{repo_url}|{repo}>" notify_when: "failure" env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}