Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions .github/workflows/on-push-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,67 @@ 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-changes:
runs-on: ubuntu-latest
outputs:
v20111101: ${{ steps.filter.outputs.v20111101 }}
v20250224: ${{ steps.filter.outputs.v20250224 }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
v20111101:
- 'v20111101/**'
v20250224:
- 'v20250224/**'

# Publish and release for each version conditionally
# Only runs if [skip-publish] flag is NOT present AND files for that version were modified

publish-v20111101:
needs: check-skip-publish
if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, 'v20111101')
needs: [check-skip-publish, detect-changes]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20111101 == 'true'
uses: ./.github/workflows/publish.yml
with:
version_directory: v20111101
secrets: inherit

release-v20111101:
needs: [check-skip-publish, publish-v20111101]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, 'v20111101')
needs: [check-skip-publish, detect-changes, publish-v20111101]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20111101 == 'true'
uses: ./.github/workflows/release.yml
with:
version_directory: v20111101
secrets: inherit

# Gate job to handle serial ordering when v20111101 is modified
# Uses always() to run even if release-v20111101 is skipped, allowing downstream jobs to proceed
# This ensures v20250224 can run when only v20250224 is modified, while still maintaining
# serial ordering when both versions are modified
# Depends on release-v20111101 to enforce serial ordering (waits for v20111101 to complete)
# Uses always() to continue even when release-v20111101 is skipped (when v20111101 wasn't modified)
# This ensures: v20111101 publishes first (serially) → then v20250224 publishes (serially)
gate-v20111101-complete:
runs-on: ubuntu-latest
needs: [check-skip-publish, release-v20111101]
needs: [check-skip-publish, detect-changes, release-v20111101]
if: always() && needs.check-skip-publish.outputs.skip_publish == 'false'
steps:
- name: Gate complete - ready for v20250224
run: echo "v20111101 release workflow complete (or skipped)"
- name: Gate reached - v20111101 release complete (or skipped)
run: echo "Ready to proceed with v20250224 publication"

publish-v20250224:
needs: [check-skip-publish, gate-v20111101-complete]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, 'v20250224')
needs: [check-skip-publish, detect-changes, gate-v20111101-complete]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20250224 == 'true'
uses: ./.github/workflows/publish.yml
with:
version_directory: v20250224
secrets: inherit

release-v20250224:
needs: [check-skip-publish, publish-v20250224]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, 'v20250224')
needs: [check-skip-publish, detect-changes, publish-v20250224]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20250224 == 'true'
uses: ./.github/workflows/release.yml
with:
version_directory: v20250224
Expand Down
83 changes: 62 additions & 21 deletions docs/Adding-a-New-API-Version.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,36 @@ This ensures when multiple versions are generated, changelog entries appear in o

### 2.4 Update on-push-master.yml

This workflow automatically triggers publish and release jobs when version directories are pushed to master. Since individual version jobs use conditional `if` statements based on path changes, you need to add new conditional jobs for your new version.
This workflow automatically triggers publish and release jobs when version directories are pushed to master. The workflow uses path-based detection (via `dorny/paths-filter`) to determine which versions were modified, then conditionally runs the appropriate publish/release jobs in serial order.

**Location 1: Path trigger**
**Location 1: Update detect-changes job with new version filter**

In the `detect-changes` job's filter section, add your new version:

```yaml
detect-changes:
runs-on: ubuntu-latest
outputs:
v20111101: ${{ steps.filter.outputs.v20111101 }}
v20250224: ${{ steps.filter.outputs.v20250224 }}
v20300101: ${{ steps.filter.outputs.v20300101 }} # NEW output
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
v20111101:
- 'v20111101/**'
v20250224:
- 'v20250224/**'
v20300101: # NEW filter
- 'v20300101/**'
```

This is **critical**: Without this, the path detection won't work for your new version, and the publish/release jobs won't trigger when it's modified.

**Location 2: Add path trigger**

In the `on.push.paths` section, add a new path for your version:

Expand All @@ -205,55 +232,68 @@ on:

This ensures the workflow triggers when changes to your version directory are pushed to master.

**Location 2: Add publish job for new version**
**Location 3: Add publish job for new version**

Add a new publish job for your version (copy and modify the existing v20250224 jobs):

```yaml
publish-v20300101:
runs-on: ubuntu-latest
needs: [check-skip-publish, gate-v20250224-complete] # Gate waits for previous version
if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, 'v20300101')
uses: ./.github/workflows/publish.yml@master
needs: [check-skip-publish, detect-changes, gate-v20250224-complete]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20300101 == 'true'
uses: ./.github/workflows/publish.yml
with:
version_directory: v20300101
secrets: inherit
```

**Location 3: Add release job for new version**
**Important**: The `needs` array must include the **previous version's gate job** to enforce serial ordering. This ensures v20250224 finishes before v20300101 starts publishing.

**Location 4: Add release job for new version**

Add a new release job for your version:

```yaml
release-v20300101:
runs-on: ubuntu-latest
needs: [check-skip-publish, publish-v20300101]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && contains(github.event.head_commit.modified, 'v20300101')
uses: ./.github/workflows/release.yml@master
needs: [check-skip-publish, detect-changes, publish-v20300101]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20300101 == 'true'
uses: ./.github/workflows/release.yml
with:
version_directory: v20300101
secrets: inherit
```

**Location 4: Add gate job for previous version**
**Location 5: Add gate job for previous version**

Add a new gate job after the previous version's release to handle serial ordering:

```yaml
gate-v20250224-complete:
runs-on: ubuntu-latest
needs: [check-skip-publish, release-v20250224]
needs: [check-skip-publish, detect-changes, release-v20250224]
if: always() && needs.check-skip-publish.outputs.skip_publish == 'false'
steps:
- name: Gate complete - ready for v20300101
run: echo "v20250224 release workflow complete (or skipped)"
- name: Gate reached - v20250224 release complete (or skipped)
run: echo "Ready to proceed with v20300101 publication"
```

**Important Notes**:
- Each publish job depends on the **previous version's gate job** to maintain serial ordering
- Each release job depends on its corresponding publish job
- Gate jobs use the `always()` condition so they run even when intermediate jobs are skipped
- This prevents npm registry race conditions and ensures correct behavior whether one or multiple versions are modified
**Critical implementation details**:

1. **Each publish job** depends on the **previous version's gate job** (not the previous release directly)
- This prevents race conditions when multiple versions are modified
- Ensures strict serial ordering at the npm registry level

2. **Each release job** depends on its corresponding publish job
- Ensures publication completes before creating release

3. **Each gate job** uses `needs: [check-skip-publish, detect-changes, release-v<VERSION>]`
- Waits for the previous version's release to complete
- The `if: always()` condition ensures the gate continues running even when the release job is **skipped**
- This is crucial: when the previous version isn't modified, its release is skipped, but the gate still runs and unblocks the next version

4. **Each publish/release if condition** uses `needs.detect-changes.outputs.v<VERSION> == 'true'`
- This is more reliable than the older `contains()` pattern
- Uses the path-filter outputs to determine which versions changed
- Prevents false publishes when only docs change

### 2.5 Verify Workflow Syntax

Expand Down Expand Up @@ -434,6 +474,7 @@ Use this checklist to verify you've completed all steps:
- [ ] Updated `.github/workflows/openapi-generate-and-push.yml` with version-to-config mapping in Setup job
- [ ] Updated `.github/changelog_manager.rb` with new version in `API_VERSION_ORDER` array
- [ ] Updated `.github/workflows/on-push-master.yml` path triggers with `v20300101/**`
- [ ] Updated `detect-changes` job in `.github/workflows/on-push-master.yml` with new version output and filter
- [ ] Updated `.github/workflows/on-push-master.yml` with new publish job for v20300101
- [ ] Updated `.github/workflows/on-push-master.yml` with new release job for v20300101
- [ ] Updated `.github/workflows/on-push-master.yml` with new gate job for previous version (v20250224)
Expand Down
20 changes: 11 additions & 9 deletions docs/Workflow-and-Configuration-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,12 @@ 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. Check-skip-publish job detects if `[skip-publish]` flag is in commit message
2. For each version with path changes (v20111101/**, v20250224/**):
- Publish job: Call `publish.yml` with version-specific directory
- Release job: Call `release.yml` after publish completes
3. Path-based matrix execution ensures only modified versions are published
1. Detect-changes job uses `dorny/paths-filter@v2` to identify which version directories changed (v20111101/**, v20250224/**)
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)
- Release job: Call `release.yml` after publish completes (only if paths modified)
4. Path-based filtering ensures only modified versions are published, never in parallel

**Serialization Chain** (for race condition prevention):
- v20111101 publish runs first (depends on check-skip-publish)
Expand Down Expand Up @@ -293,11 +294,12 @@ publish:
**Serial Approach** (Explicit, safe, maintainable):
```yaml
publish-v20111101:
if: skip_publish == false && contains(modified, 'v20111101')
needs: [check-skip-publish, detect-changes]
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20111101 == 'true'

publish-v20250224:
needs: [gate-v20111101-complete] # Must wait
if: skip_publish == false && contains(modified, 'v20250224')
needs: [check-skip-publish, detect-changes, gate-v20111101-complete] # Must wait for gate
if: needs.check-skip-publish.outputs.skip_publish == 'false' && needs.detect-changes.outputs.v20250224 == 'true'
```

**Advantages**:
Expand Down Expand Up @@ -382,7 +384,7 @@ Include `[skip-publish]` in commit message to prevent publish/release for this p
```yaml
gate-v20111101-complete:
runs-on: ubuntu-latest
needs: [check-skip-publish, release-v20111101]
needs: [check-skip-publish, detect-changes, release-v20111101]
if: always() && needs.check-skip-publish.outputs.skip_publish == 'false'
steps:
- name: Gate complete - ready for v20250224
Expand Down