Skip to content

fix: exempt dependency manifests from sharedGlobals global invalidation #368

fix: exempt dependency manifests from sharedGlobals global invalidation

fix: exempt dependency manifests from sharedGlobals global invalidation #368

Workflow file for this run

name: CI
env:
DEBUG: napi:*
APP_NAME: domino
MACOSX_DEPLOYMENT_TARGET: '10.13'
CARGO_INCREMENTAL: '1'
'on':
push:
branches:
- main
tags-ignore:
- '**'
paths-ignore:
- '**/*.md'
- LICENSE
- '**/*.gitignore'
- .editorconfig
- docs/**
pull_request:
types:
- opened
- synchronize
- reopened
- edited
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: 24
cache: yarn
- name: Install Rust toolchain
run: rustup show
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Oxlint
run: yarn lint
- name: Cargo fmt
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy
- name: Test publish-preview script
run: node --test tests/publish-preview.test.js
verify-pr-title:
name: Verify PR title
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Validate conventional commit format
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
TITLE="$PR_TITLE"
PATTERN="^(feat|fix|chore|ci|docs|refactor|test|perf|build|style|revert)(\(.+\))?(!)?: .+"
if [[ ! "$TITLE" =~ $PATTERN ]]; then
echo "::error::PR title must follow conventional commits format."
echo ""
echo "Expected: <type>(<optional scope>): <description>"
echo "Got: $TITLE"
echo ""
echo "Allowed types: feat, fix, chore, ci, docs, refactor, test, perf, build, style, revert"
echo "Examples:"
echo " feat: add new parser"
echo " fix(resolver): handle circular imports"
echo " feat!: redesign API"
exit 1
fi
echo "PR title is valid: $TITLE"
build:
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: yarn build --target x86_64-apple-darwin
- host: windows-latest
build: yarn build --target x86_64-pc-windows-msvc
target: x86_64-pc-windows-msvc
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
build: yarn build --target x86_64-unknown-linux-gnu --use-napi-cross
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
build: yarn build --target x86_64-unknown-linux-musl -x
- host: macos-latest
target: aarch64-apple-darwin
build: yarn build --target aarch64-apple-darwin
- host: ubuntu-latest
target: aarch64-unknown-linux-musl
build: yarn build --target aarch64-unknown-linux-musl -x
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
build: yarn build --target aarch64-unknown-linux-gnu --use-napi-cross
name: stable - ${{ matrix.settings.target }} - node@22
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: 24
cache: yarn
- name: Install Rust toolchain
run: |
rustup show
rustup target add ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@v4
if: ${{ !contains(matrix.settings.target, 'linux-gnu') }}
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
~/.napi-rs
.cargo-cache
target/
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
# NO cargo cache for Linux GNU - cross builds in Docker with different GLIBC
# Caching host-compiled dependencies would contaminate cross build with wrong GLIBC version
# - name: Cache cargo (no target for Linux GNU)
# uses: actions/cache@v4
# if: ${{ contains(matrix.settings.target, 'linux-gnu') }}
# with:
# path: |
# ~/.cargo/registry/index/
# ~/.cargo/registry/cache/
# ~/.cargo/git/db/
# ~/.napi-rs
# .cargo-cache
# key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
- name: Install cross
uses: taiki-e/install-action@v2
if: ${{ contains(matrix.settings.target, 'linux-gnu') }}
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tool: cross
- uses: mlugg/setup-zig@v2
if: ${{ contains(matrix.settings.target, 'musl') }}
with:
version: 0.14.1
- name: Install cargo-zigbuild
uses: taiki-e/install-action@v2
if: ${{ contains(matrix.settings.target, 'musl') }}
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tool: cargo-zigbuild
- name: Setup toolchain
run: ${{ matrix.settings.setup }}
if: ${{ matrix.settings.setup }}
shell: bash
- name: Install cross-compilation dependencies
if: ${{ contains(matrix.settings.target, 'linux') && matrix.settings.host == 'ubuntu-latest' }}
run: |
sudo apt-get update
sudo apt-get install -y build-essential pkg-config perl
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build native addon
env:
PKG_CONFIG_ALLOW_CROSS: 1
run: ${{ matrix.settings.build }}
shell: bash
- name: Build binary executable
env:
PKG_CONFIG_ALLOW_CROSS: 1
run: |
if [[ "${{ matrix.settings.target }}" == *"windows"* ]]; then
cargo build --release --target ${{ matrix.settings.target }} --bin domino
BINARY_SOURCE="target/${{ matrix.settings.target }}/release/domino.exe"
BINARY_DEST="domino-${{ matrix.settings.target }}.exe"
elif [[ "${{ matrix.settings.target }}" == *"linux-gnu"* ]]; then
# Use cross to build with older GLIBC version (same approach as oxc)
# Clean everything to avoid contamination from host-compiled dependencies
rm -rf target/${{ matrix.settings.target }}
rm -rf ~/.cargo/registry/cache
rm -rf ~/.cargo/git/checkouts
cross build --release --target=${{ matrix.settings.target }} --bin domino
BINARY_SOURCE="target/${{ matrix.settings.target }}/release/domino"
BINARY_DEST="domino-${{ matrix.settings.target }}"
# Verify GLIBC requirement
echo "Checking GLIBC requirement for binary:"
objdump -T "$BINARY_SOURCE" | grep GLIBC | sed 's/.*GLIBC_\([.0-9]*\).*/\1/g' | sort -V | tail -1 || echo "No GLIBC symbols found"
elif [[ "${{ matrix.settings.target }}" == *"musl"* ]]; then
# Use cargo-zigbuild for musl targets (same approach as oxc)
cargo zigbuild --release --target=${{ matrix.settings.target }} --bin domino
BINARY_SOURCE="target/${{ matrix.settings.target }}/release/domino"
BINARY_DEST="domino-${{ matrix.settings.target }}"
else
cargo build --release --target ${{ matrix.settings.target }} --bin domino
BINARY_SOURCE="target/${{ matrix.settings.target }}/release/domino"
BINARY_DEST="domino-${{ matrix.settings.target }}"
fi
# Copy binary to repo root with target suffix (like oxc: domino-{target} or domino-{target}.exe)
cp "$BINARY_SOURCE" "$BINARY_DEST"
echo "BINARY_PATH=$BINARY_DEST" >> $GITHUB_ENV
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v5
with:
name: bindings-${{ matrix.settings.target }}
path: |
${{ env.APP_NAME }}.*.node
${{ env.APP_NAME }}.*.wasm
${{ env.BINARY_PATH }}
if-no-files-found: error
test-macOS-windows-binding:
name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
settings:
- host: windows-latest
target: x86_64-pc-windows-msvc
architecture: x64
- host: macos-latest
target: aarch64-apple-darwin
architecture: arm64
- host: macos-latest
target: x86_64-apple-darwin
architecture: x64
node:
- '20'
- '22'
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v6
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
architecture: ${{ matrix.settings.architecture }}
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Download artifacts
uses: actions/download-artifact@v6
with:
name: bindings-${{ matrix.settings.target }}
path: .
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
run: yarn test
test-linux-binding:
name: Test ${{ matrix.target }} - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
node:
- '20'
- '22'
runs-on: ${{ contains(matrix.target, 'aarch64') && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v6
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
cache: yarn
- name: Output docker params
id: docker
run: |
node -e "
if ('${{ matrix.target }}'.startsWith('aarch64')) {
console.log('PLATFORM=linux/arm64')
} else if ('${{ matrix.target }}'.startsWith('armv7')) {
console.log('PLATFORM=linux/arm/v7')
} else {
console.log('PLATFORM=linux/amd64')
}
" >> $GITHUB_OUTPUT
node -e "
if ('${{ matrix.target }}'.endsWith('-musl')) {
console.log('IMAGE=node:${{ matrix.node }}-alpine')
} else {
console.log('IMAGE=node:${{ matrix.node }}-slim')
}
" >> $GITHUB_OUTPUT
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Download artifacts
uses: actions/download-artifact@v6
with:
name: bindings-${{ matrix.target }}
path: .
- name: List packages
run: ls -R .
shell: bash
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
if: ${{ contains(matrix.target, 'armv7') }}
with:
platforms: all
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
if: ${{ contains(matrix.target, 'armv7') }}
- name: Test bindings
uses: addnab/docker-run-action@v3
with:
image: ${{ steps.docker.outputs.IMAGE }}
options: '-v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }} --platform ${{ steps.docker.outputs.PLATFORM }}'
run: |
# Reinstall dependencies inside container to get correct platform binaries
# Host installed GNU binaries, but Alpine/musl needs musl binaries
# This allows Yarn to re-evaluate optionalDependencies for the current platform
yarn install
yarn test
save-pr-metadata:
name: Save PR metadata
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Save PR number and head SHA
run: |
echo '{"pr_number": "${{ github.event.pull_request.number }}", "head_sha": "${{ github.event.pull_request.head.sha }}"}' > pr-metadata.json
- uses: actions/upload-artifact@v5
with:
name: pr-metadata
path: pr-metadata.json
publish:
name: Publish
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
needs:
- lint
- test-macOS-windows-binding
- test-linux-binding
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
- name: Setup node
uses: actions/setup-node@v6
with:
node-version: 24
cache: yarn
registry-url: https://registry.npmjs.org/
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Download all artifacts
uses: actions/download-artifact@v6
with:
path: artifacts
- name: Determine version bump
id: version
run: |
COMMIT_MSG=$(git log -1 --pretty=%s)
if echo "$COMMIT_MSG" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+$"; then
echo "Current commit is a version commit, skipping bump"
echo "is_release=true" >> $GITHUB_OUTPUT
exit 0
fi
echo "is_release=false" >> $GITHUB_OUTPUT
LAST_TAG=$(git describe --tags --abbrev=0 --match "v[0-9]*" 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
LAST_TAG=$(git describe --tags --abbrev=0 --match "[0-9]*" 2>/dev/null || echo "")
fi
if [ -z "$LAST_TAG" ]; then
echo "No previous tags found, using all commits"
SUBJECTS=$(git log --format="%s" --no-merges)
BODIES=$(git log --format="%b" --no-merges)
else
echo "Last tag: $LAST_TAG"
SUBJECTS=$(git log "${LAST_TAG}..HEAD" --format="%s" --no-merges)
BODIES=$(git log "${LAST_TAG}..HEAD" --format="%b" --no-merges)
fi
echo "=== Commits since last tag ==="
echo "$SUBJECTS"
echo "=== End commits ==="
BUMP="patch"
BUMP_REASON="default (no feat: or breaking changes detected)"
if echo "$SUBJECTS" | grep -qE "^[a-z]+(\(.+\))?!:"; then
BUMP="major"
BREAKING_SUBJECT=$(echo "$SUBJECTS" | grep -E "^[a-z]+(\(.+\))?!:" | head -1)
BUMP_REASON="breaking change in commit subject: ${BREAKING_SUBJECT}"
elif echo "$BODIES" | grep -qE "^BREAKING[ -]CHANGE:"; then
BUMP="major"
BUMP_REASON="BREAKING CHANGE footer found in commit body"
elif echo "$SUBJECTS" | grep -qE "^feat(\(.+\))?:"; then
BUMP="minor"
BUMP_REASON="feat: commit detected"
fi
echo ""
echo "##################################################"
echo "# Version bump: $BUMP"
echo "# Reason: $BUMP_REASON"
echo "##################################################"
if [ "$BUMP" = "major" ]; then
CURRENT_VERSION=$(node -p "require('./package.json').version")
NEXT_MAJOR=$((${CURRENT_VERSION%%.*} + 1)).0.0
echo ""
echo "::warning::MAJOR version bump detected: ${CURRENT_VERSION} → ${NEXT_MAJOR}"
echo "::warning::Triggered by: ${BUMP_REASON}"
echo "::warning::If this is unintentional, check commit messages for accidental '!:' suffix or 'BREAKING CHANGE:' footer"
fi
echo "bump=$BUMP" >> $GITHUB_OUTPUT
- name: Bump version
id: bump
if: steps.version.outputs.is_release != 'true'
run: |
npm version ${{ steps.version.outputs.bump }} --no-git-tag-version --ignore-scripts
node scripts/sync-cargo-version.js
NEW_VERSION=$(node -p "require('./package.json').version")
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "Bumped to $NEW_VERSION"
- name: Generate packages
if: steps.version.outputs.is_release != 'true'
run: node scripts/generate-packages.js
- name: List packages
if: steps.version.outputs.is_release != 'true'
run: ls -R ./npm
shell: bash
- name: Publish to npm
if: steps.version.outputs.is_release != 'true'
run: |
PKG_NAME=$(node -p "require('./package.json').name")
PKG_VERSION=$(node -p "require('./package.json').version")
if npm view "${PKG_NAME}@${PKG_VERSION}" version >/dev/null 2>&1; then
echo "Version ${PKG_VERSION} already published, skipping"
exit 0
fi
npm config set provenance true
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Push version commit and tag
if: steps.version.outputs.is_release != 'true'
env:
HUSKY: '0'
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# generate-packages.js bumps optionalDependencies to the new version — refresh lockfile
# so CI (yarn install --frozen-lockfile) does not fail on the version commit.
# Yarn defaults to immutable installs on CI, so allow lockfile updates here.
# Retry yarn install to handle npm registry propagation delay after publish.
for i in 1 2 3 4 5; do
if YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install; then
break
fi
echo "yarn install attempt $i failed, retrying in 15s..."
sleep 15
done
git add package.json Cargo.toml yarn.lock
git commit -m "${{ steps.bump.outputs.new_version }}"
git tag "v${{ steps.bump.outputs.new_version }}"
git push --atomic origin main "v${{ steps.bump.outputs.new_version }}"