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
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Change

Describe the problem and resulting behavior. Target `next` and use a Conventional Commit title, for example `fix(cli): handle missing snapshots`.

## Validation

List the relevant checks and their results.

## Release impact

Describe any compatibility change. Tagging or publishing requires Omer's explicit approval; a PR is not release approval.
159 changes: 30 additions & 129 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,142 +1,43 @@
name: Continuous Integration
on: pull_request

on:
pull_request:
branches: [next]
push:
branches: [next]
permissions:
id-token: write
contents: read
actions: read
checks: write
pull-requests: write

concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build
verify:
name: Verify (Node ${{ matrix.node }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [20.x, 22.x, 24.x]
node: [22, 24, 26]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Use Node ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4

- uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm build

lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22.x'

- name: Install pnpm
uses: pnpm/action-setup@v4
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9.15.4

- uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Lint
run: pnpm lint

test:
name: Unit Tests
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm lint
- run: pnpm test
- run: pnpm test:e2e
ci:
name: CI
if: always()
needs: [verify]
runs-on: ubuntu-latest
strategy:
matrix:
project: ['cli', 'governance', 'changesets', 'json-schema-differ', 'types']
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22.x'

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4

- uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm build

- name: Create Coverage Directory
run: mkdir -p ${{ github.workspace }}/coverage

- name: Test
run: pnpm lerna run test --scope @contractual/${{ matrix.project }} --stream
continue-on-error: true
- name: Require every verification job
env:
COVERAGE_DIR: ${{ github.workspace }}/coverage
COVERAGE_FILE: coverage-${{ matrix.project }}.xml

e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: [build]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22.x'

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4

- uses: actions/cache@v4
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm build

- name: Run E2E Tests
run: pnpm test:e2e
RESULT: ${{ needs.verify.result }}
run: test "$RESULT" = success
2 changes: 1 addition & 1 deletion .github/workflows/e2e-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
fail-fast: false
matrix:
e2e-project: ['cli-basic', 'cli-lifecycle', 'packages-import']
node-version: [20.x, 22.x, 24.x]
node-version: [22.x, 24.x, 26.x]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
39 changes: 39 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Pull request title
on:
pull_request:
branches: [next]
types: [opened, edited, synchronize, reopened, ready_for_review]
permissions:
pull-requests: read
jobs:
title:
name: PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ github.token }}
with:
types: |
feat
fix
docs
style
refactor
perf
test
build
ci
chore
revert
scopes: |
cli
changesets
types
governance
differs\.core
differs\.json-schema
differs\.openapi
\*
requireScope: false
subjectPattern: '^\S[^\r\n]*$'
143 changes: 55 additions & 88 deletions .github/workflows/publish-packages.yml
Original file line number Diff line number Diff line change
@@ -1,106 +1,73 @@
name: Publish Packages
env:
CI: true

permissions:
id-token: write
contents: write

on:
workflow_dispatch:
inputs:
dist_tag:
description: 'Distribution Tag'
type: choice
options:
- 'next'
- 'latest'
- 'rc'
- 'dev'
- 'alpha'
- 'beta'
commit:
description: Full reviewed commit SHA on next, explicitly approved by Omer
required: true
default: 'next'
target_branch:
description: 'Target branch to release from'
type: string
dist_tag:
description: Approved npm distribution tag
type: choice
options:
- 'next'
- 'master'
options: [dev, next, rc, alpha, beta, latest]
default: dev
required: true
default: 'next'

permissions:
id-token: write
contents: read
concurrency:
group: release
cancel-in-progress: false
jobs:
publish:
name: Publish to NPM
if: github.ref == 'refs/heads/next'
environment: release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.target_branch }}
ref: ${{ inputs.commit }}
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: https://registry.npmjs.org/
scope: '@contractual'
always-auth: true

- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Verify approved commit belongs to next
env:
APPROVED_COMMIT: ${{ inputs.commit }}
run: |
[[ "$APPROVED_COMMIT" =~ ^[0-9a-f]{40}$ ]]
test "$(git rev-parse HEAD)" = "$APPROVED_COMMIT"
git merge-base --is-ancestor HEAD origin/next
- uses: pnpm/action-setup@v4
with:
version: 9.15.4

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm lerna run build

- name: Capture Versions for Report
run: |
echo "## Publishing to NPM" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Registry:** \`https://registry.npmjs.org/\`" >> $GITHUB_STEP_SUMMARY
echo "**Dist Tag:** \`${{ github.event.inputs.dist_tag }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${{ github.event.inputs.target_branch }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Packages:" >> $GITHUB_STEP_SUMMARY
lerna ls --json | jq -r '.[] | "- **\(.name)** -> `v\(.version)`"' >> $GITHUB_STEP_SUMMARY

- name: Publish Packages
run: |
npx lerna publish from-package --yes \
--dist-tag ${{ github.event.inputs.dist_tag }} \
--no-git-reset
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org/
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm lint
- run: pnpm test
- run: pnpm test:e2e
- name: Check npm authorization and package metadata
env:
DIST_TAG: ${{ inputs.dist_tag }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Generate Success Summary
if: success()
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Publish Successful" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "All packages have been successfully published to npm!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Installation command:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "npm install @contractual/cli@${{ github.event.inputs.dist_tag }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY

- name: Generate Failure Summary
if: failure()
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Publish Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The publish step failed. Check the logs above for details." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Common issues:**" >> $GITHUB_STEP_SUMMARY
echo "- Version already exists in npm registry" >> $GITHUB_STEP_SUMMARY
echo "- Authentication token is invalid or expired" >> $GITHUB_STEP_SUMMARY
echo "- Network connectivity issues" >> $GITHUB_STEP_SUMMARY
case "$DIST_TAG" in dev|next|rc|alpha|beta|latest) ;; *) exit 1 ;; esac
test -n "$NODE_AUTH_TOKEN"
npm_user="$(npm whoami --registry=https://registry.npmjs.org/)"
package_access="$(npm access list packages "$npm_user" --json)"
for manifest in packages/*/package.json; do
if jq -e '.private == true' "$manifest" > /dev/null; then continue; fi
package_name="$(jq -r '.name' "$manifest")"
jq -e '.repository.url == "https://github.com/codotech/contractual.git" and .publishConfig.access == "public"' "$manifest" > /dev/null
jq -e --arg name "$package_name" '.[$name] == "read-write"' <<< "$package_access" > /dev/null
if [ "$DIST_TAG" = latest ]; then
jq -e '.version | contains("-") | not' "$manifest" > /dev/null
fi
echo "$package_name: publishing preflight passed ($DIST_TAG)"
done
- name: Publish approved versions (does not create Git tags)
env:
DIST_TAG: ${{ inputs.dist_tag }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: pnpm exec lerna publish from-package --yes --dist-tag "$DIST_TAG" --no-git-reset
Loading
Loading