Version Packages (#597) #961
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Detect which files changed to enable path-based filtering | |
| changes: | |
| name: Detect changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| nix: ${{ steps.filter.outputs.nix }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Check for Nix-related changes | |
| uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| nix: | |
| - 'flake.nix' | |
| - 'flake.lock' | |
| - 'package.json' | |
| - 'pnpm-lock.yaml' | |
| - 'scripts/update-flake.sh' | |
| - '.github/workflows/ci.yml' | |
| test_pr: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build project | |
| run: pnpm run build | |
| - name: Run tests | |
| run: pnpm test | |
| - name: Upload test coverage | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report-pr | |
| path: coverage/ | |
| retention-days: 7 | |
| test_matrix: | |
| name: Test (${{ matrix.label }}) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| if: github.event_name != 'pull_request' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| shell: bash | |
| label: linux-bash | |
| - os: macos-latest | |
| shell: bash | |
| label: macos-bash | |
| - os: windows-latest | |
| shell: pwsh | |
| label: windows-pwsh | |
| defaults: | |
| run: | |
| shell: ${{ matrix.shell }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'pnpm' | |
| - name: Print environment diagnostics | |
| run: | | |
| node -p "JSON.stringify({ platform: process.platform, arch: process.arch, shell: process.env.SHELL || process.env.ComSpec || '' })" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build project | |
| run: pnpm run build | |
| - name: Run tests | |
| run: pnpm test | |
| - name: Upload test coverage | |
| if: matrix.os == 'ubuntu-latest' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report-main | |
| path: coverage/ | |
| retention-days: 7 | |
| lint: | |
| name: Lint & Type Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build project | |
| run: pnpm run build | |
| - name: Type check | |
| run: pnpm exec tsc --noEmit | |
| - name: Lint | |
| run: pnpm lint | |
| - name: Check for build artifacts | |
| run: | | |
| if [ ! -d "dist" ]; then | |
| echo "Error: dist directory not found after build" | |
| exit 1 | |
| fi | |
| if [ ! -f "dist/cli/index.js" ]; then | |
| echo "Error: CLI entry point not found" | |
| exit 1 | |
| fi | |
| nix-flake-validate: | |
| name: Nix Flake Validation | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: changes | |
| if: needs.changes.outputs.nix == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install Nix | |
| uses: DeterminateSystems/nix-installer-action@v13 | |
| - name: Setup Nix cache | |
| uses: DeterminateSystems/magic-nix-cache-action@v8 | |
| - name: Build with Nix | |
| run: nix build | |
| - name: Verify build output | |
| run: | | |
| if [ ! -e "result" ]; then | |
| echo "Error: Nix build output 'result' symlink not found" | |
| exit 1 | |
| fi | |
| if [ ! -f "result/bin/openspec" ]; then | |
| echo "Error: openspec binary not found in build output" | |
| exit 1 | |
| fi | |
| echo "✅ Build output verified" | |
| - name: Test binary execution | |
| run: | | |
| VERSION=$(nix run . -- --version) | |
| echo "OpenSpec version: $VERSION" | |
| if [ -z "$VERSION" ]; then | |
| echo "Error: Version command returned empty output" | |
| exit 1 | |
| fi | |
| echo "✅ Binary execution successful" | |
| - name: Validate update script | |
| run: | | |
| echo "Testing update-flake.sh script..." | |
| bash scripts/update-flake.sh | |
| echo "✅ Update script executed successfully" | |
| - name: Check flake.nix modifications | |
| run: | | |
| if git diff --quiet flake.nix; then | |
| echo "⚠️ Warning: flake.nix was not modified by update script" | |
| else | |
| echo "✅ flake.nix was updated by script" | |
| git diff flake.nix | |
| fi | |
| - name: Restore flake.nix | |
| if: always() | |
| run: git checkout -- flake.nix || true | |
| validate-changesets: | |
| name: Validate Changesets | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Validate changesets | |
| run: | | |
| if command -v changeset &> /dev/null; then | |
| pnpm exec changeset status --since=origin/main | |
| else | |
| echo "Changesets not configured, skipping validation" | |
| fi | |
| required-checks-pr: | |
| name: All checks passed | |
| runs-on: ubuntu-latest | |
| needs: [test_pr, lint, nix-flake-validate] | |
| if: always() && github.event_name == 'pull_request' | |
| steps: | |
| - name: Verify all checks passed | |
| run: | | |
| if [[ "${{ needs.test_pr.result }}" != "success" ]]; then | |
| echo "Test job failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.lint.result }}" != "success" ]]; then | |
| echo "Lint job failed" | |
| exit 1 | |
| fi | |
| # Nix validation may be skipped if no Nix-related files changed | |
| if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then | |
| echo "Nix flake validation job failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then | |
| echo "Nix flake validation skipped (no Nix-related changes)" | |
| fi | |
| echo "All required checks passed!" | |
| required-checks-main: | |
| name: All checks passed | |
| runs-on: ubuntu-latest | |
| needs: [test_matrix, lint, nix-flake-validate] | |
| if: always() && github.event_name != 'pull_request' | |
| steps: | |
| - name: Verify all checks passed | |
| run: | | |
| if [[ "${{ needs.test_matrix.result }}" != "success" ]]; then | |
| echo "Matrix test job failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.lint.result }}" != "success" ]]; then | |
| echo "Lint job failed" | |
| exit 1 | |
| fi | |
| # Nix validation may be skipped if no Nix-related files changed | |
| if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then | |
| echo "Nix flake validation job failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then | |
| echo "Nix flake validation skipped (no Nix-related changes)" | |
| fi | |
| echo "All required checks passed!" |