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
101 changes: 87 additions & 14 deletions .github/workflows/js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,62 @@ on:
required: false
type: string

concurrency: ${{ github.workflow }}-${{ github.ref }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
# Changeset check - only runs on PRs
# === DETECT CHANGES - determines which jobs should run ===
detect-changes:
name: Detect Changes
runs-on: ubuntu-latest
if: github.event_name != 'workflow_dispatch'
outputs:
mjs-changed: ${{ steps.changes.outputs.mjs-changed }}
js-changed: ${{ steps.changes.outputs.js-changed }}
package-changed: ${{ steps.changes.outputs.package-changed }}
docs-changed: ${{ steps.changes.outputs.docs-changed }}
workflow-changed: ${{ steps.changes.outputs.workflow-changed }}
any-code-changed: ${{ steps.changes.outputs.any-code-changed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Detect changes
id: changes
working-directory: ./js
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: node scripts/detect-code-changes.mjs

# === VERSION CHANGE CHECK ===
# Prohibit manual version changes in package.json - versions should only be changed by CI/CD
version-check:
name: Check for Manual Version Changes
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check for version changes in package.json
working-directory: ./js
env:
GITHUB_HEAD_REF: ${{ github.head_ref }}
GITHUB_BASE_REF: ${{ github.base_ref }}
run: node scripts/check-version.mjs

# === CHANGESET CHECK - only runs on PRs with code changes ===
# Docs-only PRs (./docs folder, markdown files) don't require changesets
changeset-check:
name: Check for Changesets
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
needs: [detect-changes]
if: github.event_name == 'pull_request' && needs.detect-changes.outputs.any-code-changed == 'true'
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -59,6 +107,10 @@ jobs:

- name: Check for changesets
working-directory: ./js
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Skip changeset check for automated version PRs
if [[ "${{ github.head_ref }}" == "changeset-release/"* ]]; then
Expand All @@ -69,12 +121,22 @@ jobs:
# Run changeset validation script
node scripts/validate-changeset.mjs

# Linting and formatting - runs after changeset check on PRs, immediately on main
# === LINT AND FORMAT CHECK ===
# Lint runs independently of changeset-check - it's a fast check that should always run
lint:
name: Lint and Format Check
runs-on: ubuntu-latest
needs: [changeset-check]
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
needs: [detect-changes]
if: |
always() && !cancelled() && (
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch' ||
needs.detect-changes.outputs.mjs-changed == 'true' ||
needs.detect-changes.outputs.js-changed == 'true' ||
needs.detect-changes.outputs.docs-changed == 'true' ||
needs.detect-changes.outputs.package-changed == 'true' ||
needs.detect-changes.outputs.workflow-changed == 'true'
)
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -103,8 +165,9 @@ jobs:
test:
name: Test (Node.js on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: [changeset-check]
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
needs: [detect-changes, changeset-check]
# Run if: push event, OR changeset-check succeeded, OR changeset-check was skipped (docs-only PR)
if: always() && !cancelled() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || needs.changeset-check.result == 'success' || needs.changeset-check.result == 'skipped')
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -135,7 +198,7 @@ jobs:
needs: [lint, test]
# Use always() to ensure this job runs even if changeset-check was skipped
# This is needed because lint/test jobs have a transitive dependency on changeset-check
if: always() && github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success'
if: always() && !cancelled() && github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success'
runs-on: ubuntu-latest
# Permissions required for npm OIDC trusted publishing
permissions:
Expand Down Expand Up @@ -164,11 +227,14 @@ jobs:
- name: Check for changesets
id: check_changesets
working-directory: ./js
run: node scripts/check-changesets.mjs

- name: Merge multiple changesets
if: steps.check_changesets.outputs.has_changesets == 'true' && steps.check_changesets.outputs.changeset_count > 1
working-directory: ./js
run: |
# Count changeset files (excluding README.md and config.json)
CHANGESET_COUNT=$(find .changeset -name "*.md" ! -name "README.md" | wc -l)
echo "Found $CHANGESET_COUNT changeset file(s)"
echo "has_changesets=$([[ $CHANGESET_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "Multiple changesets detected, merging..."
node scripts/merge-changesets.mjs

- name: Version packages and commit to main
if: steps.check_changesets.outputs.has_changesets == 'true'
Expand Down Expand Up @@ -200,7 +266,14 @@ jobs:
# Manual Instant Release - triggered via workflow_dispatch with instant mode
instant-release:
name: Instant Release
if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'instant'
needs: [lint, test]
# Note: always() is required to evaluate the condition when dependencies use always()
if: |
always() && !cancelled() &&
github.event_name == 'workflow_dispatch' &&
github.event.inputs.release_mode == 'instant' &&
needs.lint.result == 'success' &&
needs.test.result == 'success'
runs-on: ubuntu-latest
# Permissions required for npm OIDC trusted publishing
permissions:
Expand Down
Loading
Loading