Skip to content

refactor: remove all as type assertions from source code #1589

refactor: remove all as type assertions from source code

refactor: remove all as type assertions from source code #1589

name: Validate
on:
push:
branches:
- main
pull_request:
types: [opened, edited, synchronize, reopened]
branches:
- main
workflow_dispatch:
workflow_call:
permissions:
contents: read
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
ARCHGATE_TELEMETRY: "0"
jobs:
validate:
name: Lint, Test & Check
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
- name: Restore Bun Package Cache
id: restore-bun-cache
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: /home/runner/.bun/install/cache
key: bun-packages-${{ runner.os }}-v1-${{ hashFiles('bun.lock') }}
- uses: ./.github/actions/setup-bun-project
with:
cache: "true"
cache-base: main
- name: Validate commit messages
if: github.event_name == 'pull_request'
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: echo "$PR_TITLE" | bun run commitlint
- name: Check llms-full.txt is up to date
run: |
bun run docs/scripts/generate-llms-full.ts
git diff --exit-code docs/public/llms-full.txt || {
echo "::error::docs/public/llms-full.txt is out of date. Run 'bun run docs/scripts/generate-llms-full.ts' and commit the result."
exit 1
}
- name: Validate
id: validate
run: bun run validate:coverage
- name: Upload coverage
if: always() && steps.validate.outcome == 'success'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: coverage-linux
path: coverage/lcov.info
retention-days: 1
- name: Save Bun Cache
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
if: steps.validate.outcome == 'success' && steps.restore-bun-cache.outputs.cache-hit != 'true'
with:
path: /home/runner/.bun/install/cache
key: ${{ steps.restore-bun-cache.outputs.cache-primary-key }}
shim-changes:
name: Detect Shim Changes
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
outputs:
shims_changed: ${{ steps.changes.outputs.shims_changed }}
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
- name: Check for shim changes
id: changes
env:
# Passed via env, not inlined into the script, to avoid template-injection
# (zizmor: code injection via template expansion).
BASE_REF: ${{ github.base_ref }}
run: |
# Detect changes to shim source code AND workflow files that configure
# shim test/publish infrastructure (e.g., action version bumps, runtime
# version changes). Without checking workflow files, a Renovate PR that
# bumps Ruby 3.3→3.4 in the shim-tests job would skip tests entirely.
PATHS=(shims/ .github/workflows/publish-shims.yml .github/workflows/code-pull-request.yml)
if [ "${{ github.event_name }}" = "pull_request" ]; then
CHANGED=$(git diff --name-only "origin/$BASE_REF...HEAD" -- "${PATHS[@]}" || true)
else
CHANGED=$(git diff --name-only HEAD~1 -- "${PATHS[@]}" || true)
fi
if [ -n "$CHANGED" ]; then
echo "shims_changed=true" >> "$GITHUB_OUTPUT"
else
echo "shims_changed=false" >> "$GITHUB_OUTPUT"
fi
shim-tests:
name: Shim Tests (${{ matrix.shim }})
runs-on: ubuntu-latest
timeout-minutes: 10
needs: shim-changes
if: needs.shim-changes.outputs.shims_changed == 'true'
strategy:
fail-fast: false
matrix:
shim: [npm, pypi, go, maven, nuget, rubygem]
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
# --- npm (Node.js pre-installed on ubuntu-latest) ---
- name: Test npm shim
if: matrix.shim == 'npm'
run: node --test shims/npm/test/archgate.test.cjs
# --- PyPI ---
- name: Setup Python
if: matrix.shim == 'pypi'
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: "3.12"
- name: Test PyPI shim
if: matrix.shim == 'pypi'
working-directory: shims/pypi
run: python -m unittest discover tests/
# --- Go ---
- name: Setup Go
if: matrix.shim == 'go'
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version: "1.21"
cache-dependency-path: shims/go/go.sum
- name: Test Go shim
if: matrix.shim == 'go'
working-directory: shims/go
run: go test ./...
# --- Maven ---
- name: Setup Java
if: matrix.shim == 'maven'
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5
with:
distribution: temurin
java-version: "11"
- name: Test Maven shim
if: matrix.shim == 'maven'
working-directory: shims/maven
run: mvn test -B
# --- NuGet ---
- name: Setup .NET
if: matrix.shim == 'nuget'
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5
with:
dotnet-version: "8.0.x"
- name: Test NuGet shim
if: matrix.shim == 'nuget'
working-directory: shims/nuget/tests/Archgate.Tool.Tests
run: dotnet test
# --- RubyGem ---
- name: Setup Ruby
if: matrix.shim == 'rubygem'
uses: ruby/setup-ruby@9eb537ca036ebaed86729dcb9309076e4c5c3b74 # v1.314.0
with:
ruby-version: "4.0.5"
- name: Test RubyGem shim
if: matrix.shim == 'rubygem'
working-directory: shims/rubygem
run: bundle install --jobs 4 && bundle exec ruby test/test_shim.rb
smoke-windows:
name: Smoke Test (Windows)
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
uses: ./.github/workflows/smoke-test-windows.yml
smoke-linux:
name: Smoke Test (Linux)
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
uses: ./.github/workflows/smoke-test-linux.yml
# Uploads findings to the Security tab (GitHub Advanced Security, free for
# public repos) rather than failing the build — there's an existing
# unreviewed findings backlog across several workflow files. Once that's
# triaged, this can be promoted to a hard gate via code-scanning merge
# protection (repo Settings, not this workflow).
zizmor:
name: Zizmor (Workflow Security)
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
permissions:
contents: read # actions/checkout
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Run zizmor
# Fork PRs get a read-only GITHUB_TOKEN regardless of the
# `permissions:` above, so SARIF upload would fail — fall back to
# console-only output and don't let that (or the pre-existing
# findings backlog) fail the gate for external contributors.
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
continue-on-error: ${{ github.event.pull_request.head.repo.fork == true }}
with:
config: zizmor.yml
advanced-security: ${{ github.event.pull_request.head.repo.fork != true }}
# Validates workflow schema (zizmor covers security patterns only). See CI-002.
actionlint:
name: Actionlint (Workflow Schema)
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
permissions:
contents: read # actions/checkout
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- name: Install actionlint
# Pinned script commit + pinned version, not `latest` — see CI-002.
run: |
bash <(curl -fsSL "https://raw.githubusercontent.com/rhysd/actionlint/011a6d15e749bb3f2d771eed9c7aa0e7e3e10ee7/scripts/download-actionlint.bash") 1.7.12
- name: Run actionlint
run: ./actionlint -color
coverage:
name: Coverage Report
runs-on: ubuntu-latest
if: always() && needs.validate.result == 'success'
needs: [validate, smoke-windows]
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Download Linux coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: coverage-linux
path: coverage-linux
- name: Download Windows coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: coverage-windows
path: coverage-windows
continue-on-error: true
- name: Merge coverage and generate report
id: coverage-report
uses: ./.github/actions/coverage-report
with:
min-coverage: "90"
github-token: ${{ github.token }}
event-name: ${{ github.event_name }}
pr-number: ${{ github.event.pull_request.number }}
is-fork: ${{ github.event.pull_request.head.repo.fork }}
run-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Upload coverage report
if: always() && steps.coverage-report.outcome == 'success'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: coverage-report
path: ${{ steps.coverage-report.outputs.html-report-path }}
retention-days: 30
- name: Enforce coverage threshold
if: always() && steps.coverage-report.outcome == 'success'
run: |
COVERAGE="${{ steps.coverage-report.outputs.coverage }}"
MIN_COVERAGE=90
BELOW=$(awk "BEGIN{print ($COVERAGE < $MIN_COVERAGE) ? 1 : 0}")
if [ "$BELOW" = "1" ]; then
echo "::error::Code coverage is ${COVERAGE}%, which is below the minimum threshold of ${MIN_COVERAGE}%."
exit 1
fi
echo "Coverage ${COVERAGE}% meets the minimum threshold of ${MIN_COVERAGE}%."
# Gate job — single required status check for branch protection.
status:
name: Validate Code
runs-on: ubuntu-latest
if: always()
needs:
[
validate,
shim-changes,
shim-tests,
smoke-windows,
smoke-linux,
zizmor,
actionlint,
coverage,
]
steps:
- name: Check job results
run: |
# shim-tests is skipped when no shim files changed — treat skipped as success.
SHIM_OK="${{ needs.shim-tests.result }}"
if [[ "$SHIM_OK" == "skipped" ]]; then SHIM_OK="success"; fi
if [[ "${{ needs.validate.result }}" != "success" ]] || \
[[ "$SHIM_OK" != "success" ]] || \
[[ "${{ needs.smoke-windows.result }}" != "success" ]] || \
[[ "${{ needs.smoke-linux.result }}" != "success" ]] || \
[[ "${{ needs.zizmor.result }}" != "success" ]] || \
[[ "${{ needs.actionlint.result }}" != "success" ]] || \
[[ "${{ needs.coverage.result }}" != "success" ]]; then
echo "::error::One or more jobs failed:"
echo " validate: ${{ needs.validate.result }}"
echo " shim-tests: ${{ needs.shim-tests.result }}"
echo " smoke-windows: ${{ needs.smoke-windows.result }}"
echo " smoke-linux: ${{ needs.smoke-linux.result }}"
echo " zizmor: ${{ needs.zizmor.result }}"
echo " actionlint: ${{ needs.actionlint.result }}"
echo " coverage: ${{ needs.coverage.result }}"
exit 1
fi
echo "All checks passed."