mirror of
https://github.com/mvanhorn/cli-printing-press.git
synced 2026-09-14 15:38:08 +08:00
102578c08c
* fix(cli): make go install work on Go 1.27 Pin github.com/enetx/http to v1.0.29 so enetx/http2's go1.27-tagged DisableClientPriority read compiles. Floor the same version in generated go.mod files so regen-merge cannot reintroduce v1.0.28. Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * test(cli): cover browser-transport go.mod pin under Go 1.27 Add a browser-chrome-h2 golden/generated-output fixture for the emitted enetx/http pin, and compile the affected generated modules — including the go1.27-tagged http2 source — instead of string-matching go.mod. Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com>
381 lines
13 KiB
YAML
381 lines
13 KiB
YAML
name: CI
|
|
|
|
on:
|
|
pull_request:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
lint:
|
|
name: go-lint
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Check whether lint validations are needed
|
|
id: changes
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
git fetch --no-tags --prune origin "${{ github.base_ref }}"
|
|
mapfile -t changed < <(git diff --name-only --diff-filter=ACMR "origin/${{ github.base_ref }}...HEAD")
|
|
|
|
echo "Changed files:"
|
|
printf ' %s\n' "${changed[@]}"
|
|
|
|
needs_lint=false
|
|
needs_skill_docs=false
|
|
for file in "${changed[@]}"; do
|
|
case "$file" in
|
|
*.go|go.mod|go.sum|.golangci.yml|.github/workflows/lint.yml)
|
|
needs_lint=true
|
|
;;
|
|
esac
|
|
|
|
case "$file" in
|
|
skills/*|docs/SKILLS.md|.github/scripts/validate-skill-docs.sh|.github/workflows/lint.yml)
|
|
needs_skill_docs=true
|
|
;;
|
|
esac
|
|
|
|
if [[ "$needs_lint" == "true" && "$needs_skill_docs" == "true" ]]; then
|
|
break
|
|
fi
|
|
done
|
|
|
|
echo "needs_lint=$needs_lint" >> "$GITHUB_OUTPUT"
|
|
echo "needs_skill_docs=$needs_skill_docs" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Skip Go lint
|
|
if: steps.changes.outputs.needs_lint != 'true'
|
|
run: |
|
|
echo "Skipping golangci-lint: no Go, module, lint config, or lint workflow files changed."
|
|
|
|
- name: Skip skill docs validation
|
|
if: steps.changes.outputs.needs_skill_docs != 'true'
|
|
run: |
|
|
echo "Skipping skill docs validation: no skill docs, skill guidance, or skill-doc workflow files changed."
|
|
|
|
- name: Validate skill docs
|
|
if: steps.changes.outputs.needs_skill_docs == 'true'
|
|
run: bash .github/scripts/validate-skill-docs.sh
|
|
|
|
# setup-go's bundled cache restores both GOMODCACHE and GOCACHE as one
|
|
# ~1GB tarball; on this repo that adds ~75s of extract time per job.
|
|
# The lint job sees little payoff from a warm GOCACHE (golangci-lint
|
|
# has its own 1 MB analyzer cache that's already hit cleanly), so we
|
|
# skip the bundled cache and restore only the module cache manually.
|
|
- uses: actions/setup-go@v6
|
|
if: steps.changes.outputs.needs_lint == 'true'
|
|
with:
|
|
go-version-file: go.mod
|
|
cache: false
|
|
|
|
- name: Cache Go modules
|
|
if: steps.changes.outputs.needs_lint == 'true'
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: lint-gomodcache-${{ runner.os }}-${{ hashFiles('go.sum') }}
|
|
restore-keys: |
|
|
lint-gomodcache-${{ runner.os }}-
|
|
|
|
- uses: golangci/golangci-lint-action@v9
|
|
if: steps.changes.outputs.needs_lint == 'true'
|
|
with:
|
|
version: v2.11.4
|
|
verify: false
|
|
|
|
test-changes:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
outputs:
|
|
needs_tests: ${{ steps.changes.outputs.needs_tests }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Check whether Go tests are needed
|
|
id: changes
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
echo "Delegating Go tests to Main CI for main-targeted PRs."
|
|
echo "needs_tests=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
git fetch --no-tags --prune origin "${{ github.base_ref }}"
|
|
mapfile -t changed < <(git diff --name-only --diff-filter=ACMR "origin/${{ github.base_ref }}...HEAD")
|
|
|
|
echo "Changed files:"
|
|
printf ' %s\n' "${changed[@]}"
|
|
|
|
needs_tests=false
|
|
for file in "${changed[@]}"; do
|
|
case "$file" in
|
|
.github/workflows/lint.yml|go.mod|go.sum|cmd/*|internal/*|scripts/*|testdata/*)
|
|
needs_tests=true
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo "needs_tests=$needs_tests" >> "$GITHUB_OUTPUT"
|
|
|
|
test-shard:
|
|
name: test (${{ matrix.shard }})
|
|
runs-on: ubuntu-latest
|
|
needs: test-changes
|
|
if: needs.test-changes.outputs.needs_tests == 'true'
|
|
timeout-minutes: 10
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- shard: generator
|
|
- shard: pipeline
|
|
- shard: cli
|
|
- shard: rest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-go@v6
|
|
with:
|
|
go-version-file: go.mod
|
|
cache: true
|
|
cache-dependency-path: go.sum
|
|
|
|
- name: Run Go tests
|
|
shell: bash
|
|
run: |
|
|
set -o pipefail
|
|
|
|
case "${{ matrix.shard }}" in
|
|
generator)
|
|
packages=(./internal/generator/...)
|
|
;;
|
|
pipeline)
|
|
packages=(./internal/pipeline/...)
|
|
;;
|
|
cli)
|
|
packages=(./internal/cli/...)
|
|
;;
|
|
rest)
|
|
mapfile -t packages < <(go list ./... | grep -Ev '/internal/(generator|pipeline|cli)(/|$)')
|
|
;;
|
|
*)
|
|
echo "unknown test shard: ${{ matrix.shard }}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
printf 'Testing packages:\n'
|
|
printf ' %s\n' "${packages[@]}"
|
|
|
|
go test -short -json -timeout 12m "${packages[@]}" 2>&1 | tee /tmp/go-test.json
|
|
status=${PIPESTATUS[0]}
|
|
|
|
python3 - /tmp/go-test.json <<'PY'
|
|
import json
|
|
import sys
|
|
|
|
packages = {}
|
|
tests = 0
|
|
with open(sys.argv[1]) as events:
|
|
for line in events:
|
|
try:
|
|
event = json.loads(line)
|
|
except Exception:
|
|
continue
|
|
if event.get("Action") == "pass" and event.get("Test"):
|
|
tests += 1
|
|
if event.get("Action") in {"pass", "fail"} and event.get("Test") is None:
|
|
packages[event["Package"]] = event.get("Elapsed", 0)
|
|
|
|
print("Slowest Go packages:")
|
|
for pkg, elapsed in sorted(packages.items(), key=lambda item: -item[1])[:15]:
|
|
print(f"{elapsed:6.1f}s {pkg}")
|
|
print(f"test_pass_events {tests}")
|
|
PY
|
|
|
|
exit "$status"
|
|
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
needs:
|
|
- test-changes
|
|
- test-shard
|
|
if: ${{ always() }}
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Skip Go tests
|
|
if: needs.test-changes.outputs.needs_tests != 'true'
|
|
run: |
|
|
echo "Skipping Go tests in CI: no relevant changes, or this main-targeted PR is covered by Main CI."
|
|
|
|
- name: Check test shards
|
|
if: needs.test-changes.outputs.needs_tests == 'true'
|
|
shell: bash
|
|
run: |
|
|
if [[ "${{ needs.test-shard.result }}" != "success" ]]; then
|
|
echo "A test shard failed or was cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
echo "All test shards passed."
|
|
|
|
generated-test-changes:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
outputs:
|
|
needs_full: ${{ steps.changes.outputs.needs_full }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Check whether generated compile tests are needed
|
|
id: changes
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ "${{ github.base_ref }}" == "main" ]]; then
|
|
echo "Delegating generated compile tests to Main CI for main-targeted PRs."
|
|
echo "needs_full=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
git fetch --no-tags --prune origin "${{ github.base_ref }}"
|
|
mapfile -t changed < <(git diff --name-only --diff-filter=ACMR "origin/${{ github.base_ref }}...HEAD")
|
|
|
|
echo "Changed files:"
|
|
printf ' %s\n' "${changed[@]}"
|
|
|
|
needs_full=false
|
|
for file in "${changed[@]}"; do
|
|
case "$file" in
|
|
.github/workflows/lint.yml|go.mod|go.sum|cmd/*|internal/cli/*|internal/generator/*|internal/openapi/*|internal/pipeline/*|internal/spec/*|testdata/*)
|
|
needs_full=true
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo "needs_full=$needs_full" >> "$GITHUB_OUTPUT"
|
|
|
|
generated-test-shard:
|
|
name: generated-test (${{ matrix.shard }})
|
|
runs-on: ubuntu-latest
|
|
needs: generated-test-changes
|
|
if: needs.generated-test-changes.outputs.needs_full == 'true'
|
|
timeout-minutes: 15
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- shard: h3
|
|
packages: ./internal/generator
|
|
pattern: ^(TestGenerateBrowserChromeH3Transport|TestGenerateBrowserChromeTransport|TestGenerateCookieHTMLDefaultsBrowserChromeTransport)$
|
|
- shard: generator
|
|
packages: ./internal/generator
|
|
pattern: ^(TestGenerateProjectsCompile|TestGenerateCliutilPackage|TestGenerateFreshnessHelperEmitted|TestGenerateShareEmittedWhenEnabled|TestGenerateAgentContextCommand|TestGenerateHTMLExtractionEndpoint|TestGenerateHTMLExtractionEmbeddedJSONMode|TestGenerateHTMLExtractionPerModeGating|TestGenerateStoreWithBatchResourceDoesNotDuplicateUpsertBatch|TestGenerateStoreUpsertBatchDispatchesToTypedTable|TestGenerateStoreBackfillsIndexedColumnsOnUpgrade|TestGenerateStoreQuotesNumericTableAndDerivedIdentifiers|TestGeneratedOutput_PromotedCommandCompiles|TestGeneratedHelpers_AuthWithKeyURL_Compiles|TestGenerate_CookieAuthUsesBrowserTemplate|TestGenerate_ComposedAuthUsesBrowserTemplate|TestJSONStringParamRejectsInvalidValueBeforeClient|TestGenerateGraphQLBFFUsesSemanticCommandSurface|TestGenerateWhichFallsBackToCommandTree|TestGenerateDependentSyncCompiles|TestGenerateDependentSyncReservedWordCompiles|TestGeneratedSyncTreatsAccessDeniedAsWarning|TestGenerateGraphQLCompiles|TestGenerateMCPCodeOrchestrationEmitsSearchExecute|TestGenerateMCPIntentsEmittedWhenDeclared|TestGenerateMCPEndpointToolsHiddenSuppressesEndpointTools|TestGenerateMCPMainRemoteRuntime|TestGenerateMCPMainRemoteCompiles)$
|
|
- shard: openapi
|
|
packages: ./internal/openapi
|
|
pattern: ^(TestGenerateFromOpenAPICompiles)$
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-go@v6
|
|
with:
|
|
go-version-file: go.mod
|
|
cache: true
|
|
cache-dependency-path: go.sum
|
|
|
|
- name: Run generated compile tests
|
|
shell: bash
|
|
run: |
|
|
set -o pipefail
|
|
|
|
read -r -a packages <<< "${{ matrix.packages }}"
|
|
|
|
printf 'Testing packages:\n'
|
|
printf ' %s\n' "${packages[@]}"
|
|
echo 'Test pattern: ${{ matrix.pattern }}'
|
|
|
|
go test -json -timeout 12m -run '${{ matrix.pattern }}' "${packages[@]}" 2>&1 | tee /tmp/go-test-generated.json
|
|
status=${PIPESTATUS[0]}
|
|
|
|
python3 - /tmp/go-test-generated.json <<'PY'
|
|
import json
|
|
import sys
|
|
|
|
packages = {}
|
|
tests = 0
|
|
with open(sys.argv[1]) as events:
|
|
for line in events:
|
|
try:
|
|
event = json.loads(line)
|
|
except Exception:
|
|
continue
|
|
if event.get("Action") == "pass" and event.get("Test"):
|
|
tests += 1
|
|
if event.get("Action") in {"pass", "fail"} and event.get("Test") is None:
|
|
packages[event["Package"]] = event.get("Elapsed", 0)
|
|
|
|
print("Slowest Go packages:")
|
|
for pkg, elapsed in sorted(packages.items(), key=lambda item: -item[1])[:15]:
|
|
print(f"{elapsed:6.1f}s {pkg}")
|
|
print(f"test_pass_events {tests}")
|
|
PY
|
|
|
|
exit "$status"
|
|
|
|
generated-test:
|
|
runs-on: ubuntu-latest
|
|
needs:
|
|
- generated-test-changes
|
|
- generated-test-shard
|
|
if: ${{ always() }}
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Skip generated compile tests
|
|
if: needs.generated-test-changes.outputs.needs_full != 'true'
|
|
run: |
|
|
echo "Skipping generated compile tests in CI: no relevant changes, or this main-targeted PR is covered by Main CI."
|
|
|
|
- name: Check generated compile shards
|
|
if: needs.generated-test-changes.outputs.needs_full == 'true'
|
|
shell: bash
|
|
run: |
|
|
if [[ "${{ needs.generated-test-shard.result }}" != "success" ]]; then
|
|
echo "A generated compile shard failed or was cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
echo "All generated compile shards passed."
|
|
|
|
skill-docs:
|
|
name: skill-docs
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Compatibility check
|
|
run: |
|
|
echo "Skill docs validation runs inside go-lint."
|