mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-03 07:18:03 +01:00
Merge origin/main (v1.91.106.0, #3209) into capy/next-wave; keep 1.91.107.0
Resolves the setup-hook harness conflict (keep _setup_ready_line, take main's gstack_canonical_claude_root slice) and treats main's new _gstack_bun_below status 2 (unparseable) as not satisfying a >= pin in the installer's jq fallback. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
commit
daf9f1b450
144 files changed
+8252
-712
No files matched your search
@@ -133,7 +133,7 @@ jobs:
|
||||
CONTAINER
|
||||
- name: Retain source seals and native smoke evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: native-arm-setup-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: ${{ runner.temp }}/arm-evidence/
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Record the requalification trigger inputs of this source commit
|
||||
run: bun run scripts/cso-requalification.ts triggers > requalification.json
|
||||
- if: github.event_name == 'workflow_dispatch'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: cso-requalification-triggers
|
||||
path: requalification.json
|
||||
@@ -276,7 +276,7 @@ jobs:
|
||||
--arg commit "$GITHUB_SHA" --arg workflow "$workflow" --arg sbom "$sbom_digest" \
|
||||
--arg provenance "$provenance_digest" --argjson versions "$CSO_VERSIONS" \
|
||||
'{schemaVersion:1,helperAbi:3,state:"staged",buildRevision:$buildRevision,runtimeId:$runtimeId,image:$image,platform:$platform,stack:$stack,versions:$versions,sourceCommit:$commit,workflow:$workflow,sbomDigest:$sbom,provenanceDigest:$provenance,verifiedProvenance:true,qualification:"pending native and private release gates; no automatic promotion"}' > staged-image.json
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: cso-staged-${{ matrix.stack }}-${{ matrix.arch }}
|
||||
path: |
|
||||
@@ -309,12 +309,12 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: cso-staged-${{ matrix.stack }}-${{ matrix.arch }}
|
||||
path: staged-application
|
||||
- if: matrix.stack == 'rails'
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: cso-staged-postgresql-${{ matrix.arch }}
|
||||
path: staged-postgresql
|
||||
@@ -366,7 +366,7 @@ jobs:
|
||||
bun run scripts/cso-native-evidence.ts --stack "$CSO_STACK" --platform "$CSO_PLATFORM" \
|
||||
--junit native-tests.junit.xml --staged staged-application/staged-image.json \
|
||||
--output qualification-evidence.json
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: cso-qualification-gates-${{ matrix.stack }}-${{ matrix.arch }}
|
||||
path: |
|
||||
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
Validation: runtime promotion contracts, distribution contracts, compiled CSO helper build, candidate attestation verification, and exact committed-byte comparison.
|
||||
EOF
|
||||
gh pr create --base main --head "$branch" --title "Promote qualified CSO runtime catalog" --body-file pr-body.md
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: cso-runtime-catalog-candidate
|
||||
path: |
|
||||
|
||||
@@ -150,7 +150,7 @@ jobs:
|
||||
--evidence-root qualification-evidence \
|
||||
--output runtime-catalog.proof.json
|
||||
rm runtime-catalog.proof.json
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: cso-qualified-runtime-statements
|
||||
path: |
|
||||
|
||||
@@ -253,7 +253,7 @@ jobs:
|
||||
printf '%s\n' "$CSO_UPSTREAM" > upstream-evidence.json
|
||||
printf '%s\n' "$CSO_SBOM_GENERATOR" > sbom-generator-evidence.json
|
||||
sha256sum "$output" staged-profile.json version.sha256 declared-assets.json public-image.json sbom.spdx.json provenance-verification.json sbom-verification.json upstream-evidence.json sbom-generator-evidence.json upstream-base-*-verification.json sbom-generator-*-verification.json > evidence.sha256
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: cso-scanner-profile-${{ matrix.scanner }}-${{ matrix.arch }}
|
||||
path: |
|
||||
@@ -290,7 +290,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
pattern: cso-scanner-profile-*
|
||||
path: qualified-artifacts
|
||||
@@ -305,7 +305,7 @@ jobs:
|
||||
image_prefix="ghcr.io/${GITHUB_REPOSITORY,,}/cso-scanners/"
|
||||
bun run scripts/cso-scanner-catalog.ts assemble qualified-fragments lib/cso/scanner-images/catalog.json catalog-proposal.json --revision "$revision" --source-commit "$GITHUB_SHA" --workflow "$workflow" --image-prefix "$image_prefix"
|
||||
bun run scripts/cso-scanner-catalog.ts validate catalog-proposal.json
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: cso-scanner-catalog-proposal
|
||||
path: catalog-proposal.json
|
||||
@@ -330,7 +330,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: cso-scanner-catalog-proposal
|
||||
path: promotion
|
||||
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
|
||||
- name: Upload the sweep report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: ship-measure-sweep-report
|
||||
path: |
|
||||
@@ -191,7 +191,7 @@ jobs:
|
||||
|
||||
- name: Upload the sweep captures
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: ship-measure-sweep-captures
|
||||
include-hidden-files: true
|
||||
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
echo "slices=$(jq -c '[range(1; .sliceCount + 1)]' /tmp/marathon-plan/manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
echo "slice_timeouts=$(jq -ec '[0] + .plan.sliceCiTimeoutMinutes' /tmp/marathon-plan/manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: marathon-plan
|
||||
path: /tmp/marathon-plan/manifest.json
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
- name: Register gstack skills for PTY tests
|
||||
uses: ./.github/actions/register-gstack-skills
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: marathon-plan
|
||||
path: /tmp/marathon-plan
|
||||
@@ -215,7 +215,7 @@ jobs:
|
||||
|
||||
- name: Upload slice results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: marathon-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
path: /tmp/marathon-slice-results
|
||||
@@ -223,7 +223,7 @@ jobs:
|
||||
|
||||
- name: Upload native capture evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: native-captures-${{ env.EVALS_RUN_ID }}
|
||||
include-hidden-files: true
|
||||
@@ -237,7 +237,7 @@ jobs:
|
||||
|
||||
- name: Upload shard logs on failure
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: marathon-logs-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
include-hidden-files: true
|
||||
@@ -270,12 +270,12 @@ jobs:
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: marathon-plan
|
||||
path: /tmp/marathon-report
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
pattern: marathon-slice-*
|
||||
path: /tmp/marathon-report
|
||||
@@ -314,7 +314,7 @@ jobs:
|
||||
|
||||
- name: Upload the marathon report
|
||||
if: always() && (steps.reconcile.outputs.exit != '0' || needs.eval-slices.result != 'success')
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: marathon-report-a${{ github.run_attempt }}
|
||||
path: /tmp/marathon-report.md
|
||||
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
echo "slice_timeouts=$(jq -ec '[0] + .plan.sliceCiTimeoutMinutes' /tmp/paid-plan/manifest.json)"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-plan
|
||||
path: /tmp/paid-plan/manifest.json
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
echo "slices=$(jq -c '[range(1; .sliceCount + 1)]' /tmp/gate-census-plan/manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
echo "slice_timeouts=$(jq -ec '[0] + .plan.sliceCiTimeoutMinutes' /tmp/gate-census-plan/manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: gate-census-plan
|
||||
path: /tmp/gate-census-plan/manifest.json
|
||||
@@ -227,7 +227,7 @@ jobs:
|
||||
|
||||
- name: Upload canary results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: schema-canary-a${{ github.run_attempt }}
|
||||
path: /tmp/schema-canary-results
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
- name: Register gstack skills for PTY tests
|
||||
uses: ./.github/actions/register-gstack-skills
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: paid-plan
|
||||
path: /tmp/paid-plan
|
||||
@@ -338,7 +338,7 @@ jobs:
|
||||
|
||||
- name: Upload slice results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
path: /tmp/paid-slice-results
|
||||
@@ -346,7 +346,7 @@ jobs:
|
||||
|
||||
- name: Upload native capture evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: native-captures-${{ env.EVALS_RUN_ID }}
|
||||
include-hidden-files: true
|
||||
@@ -362,7 +362,7 @@ jobs:
|
||||
# longer reds its runner, but its full log is the diagnosis evidence.
|
||||
- name: Upload shard logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-logs-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
include-hidden-files: true
|
||||
@@ -409,7 +409,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: paid-plan
|
||||
path: ${{ runner.temp }}/paid-plan
|
||||
@@ -477,7 +477,7 @@ jobs:
|
||||
|
||||
- name: Upload slice results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
path: ${{ runner.temp }}/paid-slice-results
|
||||
@@ -485,7 +485,7 @@ jobs:
|
||||
|
||||
- name: Upload native capture evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: native-captures-${{ env.EVALS_RUN_ID }}
|
||||
include-hidden-files: true
|
||||
@@ -499,7 +499,7 @@ jobs:
|
||||
|
||||
- name: Upload shard logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-logs-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
include-hidden-files: true
|
||||
@@ -559,7 +559,7 @@ jobs:
|
||||
|
||||
- run: bun run build
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: gate-census-plan
|
||||
path: /tmp/gate-census-plan
|
||||
@@ -601,7 +601,7 @@ jobs:
|
||||
|
||||
- name: Upload census results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: gate-census-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
path: /tmp/gate-census-results
|
||||
@@ -609,7 +609,7 @@ jobs:
|
||||
|
||||
- name: Upload native capture evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: native-captures-${{ env.EVALS_RUN_ID }}
|
||||
include-hidden-files: true
|
||||
@@ -647,24 +647,24 @@ jobs:
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: paid-plan
|
||||
path: /tmp/paid-report
|
||||
|
||||
# One directory per attempt-scoped slice artifact (no merge): shard
|
||||
# records never overwrite each other and the first attempt decides.
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
pattern: paid-slice-*
|
||||
path: /tmp/paid-report
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: gate-census-plan
|
||||
path: /tmp/gate-census-report
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
pattern: gate-census-[0-9]*
|
||||
path: /tmp/gate-census-report
|
||||
@@ -705,7 +705,7 @@ jobs:
|
||||
|
||||
- name: Upload trial outcomes for pass-rate history
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: trial-outcomes-periodic-a${{ github.run_attempt }}
|
||||
path: |
|
||||
@@ -715,7 +715,7 @@ jobs:
|
||||
|
||||
- name: Upload gate census trial outcomes for pass-rate history
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: trial-outcomes-gate-census-a${{ github.run_attempt }}
|
||||
path: |
|
||||
@@ -824,7 +824,7 @@ jobs:
|
||||
|
||||
- name: Upload the census report
|
||||
if: always() && (steps.reconcile.outputs.exit != '0' || steps.gate-reconcile.outputs.exit != '0' || steps.pass-rates.outputs.exit != '0' || needs.eval-slices.result != 'success' || !contains(fromJSON('["success","skipped"]'), needs.eval-codex-slices.result) || needs.gate-census.result != 'success')
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: census-report-a${{ github.run_attempt }}
|
||||
path: /tmp/census-report.md
|
||||
|
||||
+13
-13
@@ -222,7 +222,7 @@ jobs:
|
||||
|| echo "- Receipt recovery crashed; reuse stays off this run" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Hand the receipt store to plan-slices
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: receipt-store
|
||||
path: /tmp/gstack-eval-input-cache
|
||||
@@ -291,7 +291,7 @@ jobs:
|
||||
- name: Download this PR's receipt store
|
||||
if: github.event_name == 'pull_request' || inputs.pr_receipts != ''
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: receipt-store
|
||||
path: /tmp/gstack-eval-input-cache
|
||||
@@ -329,7 +329,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
run: mkdir -p /tmp/paid-plan/store && cp -a /tmp/gstack-eval-input-cache/. /tmp/paid-plan/store/
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-plan
|
||||
path: |
|
||||
@@ -404,7 +404,7 @@ jobs:
|
||||
- name: Register gstack skills for PTY smokes
|
||||
uses: ./.github/actions/register-gstack-skills
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: paid-plan
|
||||
path: /tmp/paid-plan
|
||||
@@ -460,7 +460,7 @@ jobs:
|
||||
# attempt and never replace (or collide with) the first attempt's.
|
||||
- name: Upload slice results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
path: /tmp/paid-slice-results
|
||||
@@ -468,7 +468,7 @@ jobs:
|
||||
|
||||
- name: Upload native capture evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: native-captures-${{ env.EVALS_RUN_ID }}
|
||||
include-hidden-files: true
|
||||
@@ -486,7 +486,7 @@ jobs:
|
||||
# longer reds its runner, but its full log is the diagnosis evidence.
|
||||
- name: Upload shard logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: paid-logs-slice-${{ matrix.slice }}-a${{ github.run_attempt }}
|
||||
include-hidden-files: true
|
||||
@@ -528,7 +528,7 @@ jobs:
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: paid-plan
|
||||
path: /tmp/paid-report
|
||||
@@ -536,7 +536,7 @@ jobs:
|
||||
# One directory per attempt-scoped slice artifact (no merge): shard
|
||||
# records can never overwrite each other, and the report keeps the
|
||||
# first attempt's verdict.
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
pattern: paid-slice-*
|
||||
path: /tmp/paid-report
|
||||
@@ -583,7 +583,7 @@ jobs:
|
||||
|
||||
- name: Upload reconciliation output for the comment job
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: report-verdict-a${{ github.run_attempt }}
|
||||
path: |
|
||||
@@ -596,7 +596,7 @@ jobs:
|
||||
|
||||
- name: Upload trial outcomes for pass-rate history
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: trial-outcomes-pr-a${{ github.run_attempt }}
|
||||
path: /tmp/paid-report/trial-outcomes.jsonl
|
||||
@@ -622,12 +622,12 @@ jobs:
|
||||
# `issues` permission, not `pull-requests` (#1802 CI fix).
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: paid-plan
|
||||
path: /tmp/paid-report
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: report-verdict-a${{ github.run_attempt }}
|
||||
path: /tmp/verdict
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
run: bun scripts/model-policy-freshness.ts
|
||||
- name: Preserve evidence report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: model-policy-freshness-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: ${{ runner.temp }}/model-policy-freshness.json
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
- name: Install pinned dependencies
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
run: ./.github/scripts/run-cookie-native-qualification.ps1 -OutputRoot "$env:RUNNER_TEMP"
|
||||
- name: Preserve qualification evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: cookie-native-qualification
|
||||
path: ${{ runner.temp }}/cookie-native-qualification-*/
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
- name: Configure git identity (required by tests that init temp repos)
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
exit "$status"
|
||||
- name: Upload diagnostic logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: windows-native-diagnostics
|
||||
path: ${{ runner.temp }}/gstack-free-test-*.log
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
if: inputs.mode == 'dia-launch-comparison'
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
run: bun --no-env-file --no-install --no-macros --config=/dev/null .github/scripts/run-dia-native-qualification.ts --launch-comparison "$COMPARISON_RUNTIME"
|
||||
- name: Preserve only the sanitized qualification receipt
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
|
||||
with:
|
||||
name: ${{ inputs.mode == 'dia-gui-readiness' && 'dia-gui-readiness' || inputs.mode == 'dia-launch-comparison' && format('dia-launch-comparison-{0}', matrix.runtime) || 'dia-native-qualification' }}
|
||||
path: ${{ runner.temp }}/dia-native-qualification.json
|
||||
|
||||
@@ -35,18 +35,18 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
|
||||
- uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: true
|
||||
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: scorecard-sarif
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
- uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
||||
- uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -2,6 +2,7 @@ name: Version Gate
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'VERSION'
|
||||
- 'CHANGELOG.md'
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
run: |
|
||||
matrix=$(bun run scripts/test-free-shards.ts --windows-only --ci-plan "$RUNNER_TEMP/windows-plan.json" --shards 6)
|
||||
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: windows-plan
|
||||
path: ${{ runner.temp }}/windows-plan.json
|
||||
@@ -84,11 +84,11 @@ jobs:
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: windows-plan
|
||||
path: ${{ runner.temp }}
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
|
||||
- name: Upload strict shard result
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: windows-result-${{ matrix.shard }}
|
||||
path: ${{ runner.temp }}/windows-results/*.json
|
||||
@@ -153,7 +153,7 @@ jobs:
|
||||
# not causes, so complete shard logs are kept on every run.
|
||||
- name: Upload full shard logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: windows-free-test-shard-logs-${{ matrix.shard }}
|
||||
path: |
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
|
||||
- name: Upload flake ledger
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
with:
|
||||
name: flake-ledger-windows-${{ matrix.shard }}
|
||||
path: ${{ runner.temp }}/flake-ledger.jsonl
|
||||
@@ -191,11 +191,11 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
name: windows-plan
|
||||
path: ${{ runner.temp }}
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
|
||||
with:
|
||||
pattern: windows-result-*
|
||||
merge-multiple: true
|
||||
@@ -214,7 +214,7 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
- name: Prepare the same inputs as a Windows shard
|
||||
@@ -240,7 +240,7 @@ jobs:
|
||||
if: always()
|
||||
shell: bash
|
||||
run: cp scripts/free-test-durations.json "$RUNNER_TEMP/free-test-durations-windows.json"
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
||||
if: always()
|
||||
with:
|
||||
name: free-test-durations-windows
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
name: Windows Pregate E2E
|
||||
|
||||
# Native proof for #3197 on windows-latest: Bun on Windows cannot execute an
|
||||
# extensionless shebang bin (bin/gstack-wtree, gstack-slug, gstack-redact),
|
||||
# so every TypeScript caller goes through lib/script-invocation.ts, which
|
||||
# hands bash bins to Git Bash and bun bins to Bun. This job drives the real
|
||||
# CLIs from TypeScript entry points against a fixture repository:
|
||||
# - the resolver finds Git Bash from `git --exec-path`;
|
||||
# - gstack-restamp --dry-run fingerprints the tree and stamps;
|
||||
# - gstack-regen check (scratch worktree from the fingerprint, the entry's
|
||||
# command through `bash -c`) and write (the no-scratch path);
|
||||
# - gstack-evidence records a content fingerprint, its command through bash -c;
|
||||
# - gstack-gate-diff records a candidate with a tree id, not `+nowtree`;
|
||||
# - a hook invocation is timed cold and warm (the cached resolution);
|
||||
# - a missing GSTACK_GIT_BASH refuses with BASH_UNAVAILABLE, not `()`;
|
||||
# - the same journey under a pinned, checksum-verified PortableGit found
|
||||
# only through `git --exec-path`.
|
||||
# `gstack-pregate run` joins this job in the follow-up that migrates the
|
||||
# pregate consumers (item 10b).
|
||||
#
|
||||
# Runner: GitHub-hosted free windows-latest. ~4-6 min.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'lib/script-invocation.ts'
|
||||
- 'lib/regen.ts'
|
||||
- 'lib/restamp.ts'
|
||||
- 'lib/gbrain-exec.ts'
|
||||
- 'lib/gate-diff/**'
|
||||
- 'lib/pregate/**'
|
||||
- 'lib/result-codes.ts'
|
||||
- 'bin/gstack-wtree'
|
||||
- 'bin/gstack-slug'
|
||||
- 'bin/gstack-path-spelling.sh'
|
||||
- 'bin/gstack-restamp'
|
||||
- 'bin/gstack-regen'
|
||||
- 'bin/gstack-evidence'
|
||||
- 'bin/gstack-gate-diff'
|
||||
- 'bin/gstack-redact'
|
||||
- 'hosts/claude/hooks/**'
|
||||
- '.github/workflows/windows-pregate-e2e.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: windows-pregate-e2e-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
PORTABLE_GIT_VERSION: 2.56.0.windows.2
|
||||
PORTABLE_GIT_FILE: PortableGit-2.56.0.2-64-bit.7z.exe
|
||||
PORTABLE_GIT_SHA256: 075e158ef8e1f0ab80b347e245405d3eca735c2dc88fd8e032e137d0ca61f61b
|
||||
|
||||
jobs:
|
||||
windows-pregate:
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config --global user.email "windows-pregate-e2e@gstack.test"
|
||||
git config --global user.name "Windows Pregate E2E"
|
||||
git config --global init.defaultBranch main
|
||||
git config --global commit.gpgsign false
|
||||
shell: bash
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
shell: bash
|
||||
|
||||
- name: Build the fixture repository
|
||||
# A VERSION + CHANGELOG + ship policy + generated-file registry, a
|
||||
# bare origin and a feature branch with an [Unreleased] entry.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
T="$RUNNER_TEMP/pregate-e2e"
|
||||
rm -rf "$T"; mkdir -p "$T/home"
|
||||
git init -q --bare -b main "$T/origin.git"
|
||||
git init -q -b main "$T/work"
|
||||
cd "$T/work"
|
||||
mkdir -p generated .gstack
|
||||
echo 1.2.3.0 > VERSION
|
||||
printf '{ "name": "fixture", "version": "1.2.3" }\n' > package.json
|
||||
printf '%s\n' "const fs=require('fs');const v=fs.readFileSync('VERSION','utf8').trim();fs.writeFileSync('generated/digest.md','# digest v'+v+'\\n');" > gen.js
|
||||
node gen.js
|
||||
printf '# Changelog\n\n## [1.2.3.0] - 2026-10-01\n\n- base release\n' > CHANGELOG.md
|
||||
cat > .gstack/ship-policy.json <<'JSON'
|
||||
{ "$schema": "https://github.com/garrytan/gstack/docs/ship-policy.md#schema-v1", "bump": "patch", "queue_mode": "stamp-at-merge", "release_tool": "node gen.js", "release_outputs": ["generated/**"], "stamp_paths": [], "changelog": "CHANGELOG.md", "history": "squash-ok", "stamp_sensitive_gates": [] }
|
||||
JSON
|
||||
cat > .gstack/generated.json <<'JSON'
|
||||
{ "$schema": "https://github.com/garrytan/gstack/docs/pregate.md#generated-v1", "entries": [ { "id": "digest", "command": "node gen.js", "outputs": ["generated/**"], "inputs": ["VERSION", "gen.js"] } ] }
|
||||
JSON
|
||||
git add -A && git commit -qm base
|
||||
git remote add origin "$T/origin.git" && git push -q origin main && git remote set-head origin main
|
||||
git checkout -qb feature
|
||||
echo feature > feature.txt
|
||||
printf '# Changelog\n\n## [Unreleased]\n\n- feature change\n\n## [1.2.3.0] - 2026-10-01\n\n- base release\n' > CHANGELOG.md
|
||||
git add -A && git commit -qm feature
|
||||
shell: bash
|
||||
|
||||
- name: The resolver finds the runner's Git Bash from git --exec-path
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git --version
|
||||
OUT=$(bun -e 'import { resolveWindowsBash } from "./lib/script-invocation"; const r = resolveWindowsBash(); console.log(JSON.stringify(r)); process.exit(r.ok ? 0 : 1);')
|
||||
echo "$OUT"
|
||||
echo "$OUT" | grep -q '"source":"git --exec-path"' || (echo "Git Bash was not found through git --exec-path" && exit 1)
|
||||
echo "$OUT" | grep -qiE '"bash":"[^"]*/(usr/)?bin/bash\.exe"' || (echo "the resolved bash is not a Git Bash bash.exe" && exit 1)
|
||||
shell: bash
|
||||
|
||||
- name: A hook invocation, timed cold and warm (cached Git Bash resolution)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
T="$RUNNER_TEMP/hook-timing"
|
||||
rm -rf "$T"; mkdir -p "$T"
|
||||
PAYLOAD='{"session_id":"e2e","hook_event_name":"PostToolUse","tool_name":"AskUserQuestion","tool_use_id":"TOOL_ID","tool_input":{"questions":[{"question":"Ship it?","options":[{"label":"Ship now (recommended)"},{"label":"Hold"}]}]},"tool_response":{"answers":[{"option_label":"Ship now"}]}}'
|
||||
run_hook() {
|
||||
local start end
|
||||
start=$(date +%s%3N)
|
||||
printf '%s' "${PAYLOAD/TOOL_ID/$1}" | (cd "$T" && GSTACK_STATE_ROOT="$T" GSTACK_QUESTION_LOG_NO_DERIVE=1 bun "$GITHUB_WORKSPACE/hosts/claude/hooks/question-log-hook.ts")
|
||||
end=$(date +%s%3N)
|
||||
echo $((end - start))
|
||||
}
|
||||
COLD=$(run_hook toolu_cold)
|
||||
test -f "$T/cache/windows-bash.json" || (echo "the hook did not cache its Git Bash resolution" && exit 1)
|
||||
cat "$T/cache/windows-bash.json"
|
||||
WARM=$(run_hook toolu_warm)
|
||||
echo "question-log-hook: cold ${COLD} ms, warm ${WARM} ms"
|
||||
echo "### question-log-hook on windows-latest: cold ${COLD} ms, warm ${WARM} ms" >> "$GITHUB_STEP_SUMMARY"
|
||||
LOGS=$(find "$T/projects" -name question-log.jsonl | head -n 1)
|
||||
test -n "$LOGS" || (echo "the hook wrote no question-log.jsonl" && exit 1)
|
||||
test "$(wc -l < "$LOGS")" -eq 2 || (echo "expected two logged events" && exit 1)
|
||||
test ! -s "$T/hook-errors.log" || { cat "$T/hook-errors.log"; echo "the hook logged errors"; exit 1; }
|
||||
shell: bash
|
||||
|
||||
- name: A missing GSTACK_GIT_BASH refuses with BASH_UNAVAILABLE and names every candidate
|
||||
run: |
|
||||
set -uo pipefail
|
||||
T="$RUNNER_TEMP/pregate-e2e"
|
||||
cd "$T/work"
|
||||
OUT=$(GSTACK_HOME="$T/home" GSTACK_GIT_BASH='C:\no-such-git\bin\bash.exe' bun "$GITHUB_WORKSPACE/bin/gstack-restamp" --base main --allow-repo-commands --next --dry-run 2>&1) && CODE=0 || CODE=$?
|
||||
echo "$OUT" | tail -n 3
|
||||
test "$CODE" -ne 0 || (echo "restamp passed without a bash" && exit 1)
|
||||
echo "$OUT" | grep -q 'cannot fingerprint the working tree (gstack-wtree could not start: gstack: no Git Bash found' || (echo "the refusal does not say why" && exit 1)
|
||||
echo "$OUT" | grep -q 'GSTACK_GIT_BASH C:/no-such-git/bin/bash.exe: does not exist' || (echo "the refusal does not list the override" && exit 1)
|
||||
echo "$OUT" | grep -q '(BASH_UNAVAILABLE)' || (echo "the refusal has no result code" && exit 1)
|
||||
shell: bash
|
||||
|
||||
- name: Download the pinned PortableGit and verify its checksum
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PG="$RUNNER_TEMP/PortableGit"
|
||||
curl -fsSL -o "$RUNNER_TEMP/$PORTABLE_GIT_FILE" "https://github.com/git-for-windows/git/releases/download/v${PORTABLE_GIT_VERSION}/${PORTABLE_GIT_FILE}"
|
||||
echo "$PORTABLE_GIT_SHA256 $RUNNER_TEMP/$PORTABLE_GIT_FILE" | sha256sum -c -
|
||||
"$RUNNER_TEMP/$PORTABLE_GIT_FILE" -o"$(cygpath -w "$PG")" -y
|
||||
test -f "$PG/bin/bash.exe" || (echo "PortableGit has no bin/bash.exe" && exit 1)
|
||||
"$PG/cmd/git.exe" --version
|
||||
shell: bash
|
||||
|
||||
- name: The resolver finds the PortableGit bash through git --exec-path alone
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PG=$(cygpath -u "$RUNNER_TEMP/PortableGit")
|
||||
export PATH="$PG/cmd:$PATH"
|
||||
git --version
|
||||
WANT=$(cygpath -m "$PG/bin/bash.exe")
|
||||
OUT=$(bun -e 'import { resolveWindowsBash } from "./lib/script-invocation"; const r = resolveWindowsBash(); console.log(JSON.stringify(r)); process.exit(r.ok ? 0 : 1);')
|
||||
echo "$OUT"
|
||||
echo "$OUT" | grep -qiF "\"bash\":\"$WANT\"" || (echo "expected $WANT" && exit 1)
|
||||
echo "$OUT" | grep -q '"source":"git --exec-path"' || (echo "PortableGit was not found through git --exec-path" && exit 1)
|
||||
shell: bash
|
||||
|
||||
- name: The fixture journey (restamp, regen, evidence, gate-diff) under the runner's Git and the pinned PortableGit
|
||||
run: |
|
||||
set -euo pipefail
|
||||
journey() {
|
||||
G="$PWD"
|
||||
T="$RUNNER_TEMP/pregate-e2e"
|
||||
export GSTACK_HOME="$T/home" GSTACK_STATE_ROOT="$T/home"
|
||||
cd "$T/work"
|
||||
git reset -q --hard && git clean -fdq
|
||||
rm -rf "$T/home/projects"
|
||||
|
||||
OUT=$(bun "$G/bin/gstack-restamp" --base main --allow-repo-commands --next --dry-run 2>&1) || { echo "$OUT"; echo "gstack-restamp --dry-run failed"; exit 1; }
|
||||
echo "$OUT" | tail -n 8
|
||||
echo "$OUT" | grep -q '^+1\.2\.4\.0$' || (echo "restamp did not stamp VERSION" && exit 1)
|
||||
echo "$OUT" | grep -q '^+# digest v1\.2\.4\.0$' || (echo "restamp did not run the release tool" && exit 1)
|
||||
echo "$OUT" | grep -q 'GSTACK_RESULT: skill=restamp status=complete' || (echo "restamp did not complete" && exit 1)
|
||||
test -z "$(git status --porcelain)" || (echo "--dry-run wrote to the tree" && exit 1)
|
||||
|
||||
OUT=$(bun "$G/bin/gstack-regen" check --allow-repo-commands 2>&1) || { echo "$OUT"; echo "gstack-regen check failed"; exit 1; }
|
||||
echo "$OUT"
|
||||
echo "$OUT" | grep -q '^regen digest: fresh' || (echo "the regen command did not run fresh in the scratch worktree" && exit 1)
|
||||
echo "$OUT" | grep -qE 'GSTACK_RESULT: skill=regen status=complete run=[0-9a-f]{40}$' || (echo "regen check has no tree fingerprint" && exit 1)
|
||||
OUT=$(bun "$G/bin/gstack-regen" write --allow-repo-commands 2>&1) || { echo "$OUT"; echo "gstack-regen write failed"; exit 1; }
|
||||
echo "$OUT" | grep -qE 'GSTACK_RESULT: skill=regen status=complete run=[0-9a-f]{40}$' || (echo "regen write has no tree fingerprint" && exit 1)
|
||||
|
||||
bun "$G/bin/gstack-evidence" run --label tests -- 'echo evidence-ok && test -f VERSION'
|
||||
LEDGER=$(find "$T/home/projects" -name '*-evidence.jsonl' | head -n 1)
|
||||
test -n "$LEDGER" || (echo "no evidence ledger written" && exit 1)
|
||||
tail -n 1 "$LEDGER"
|
||||
tail -n 1 "$LEDGER" | grep -qE '"exit":0,' || (echo "the evidence command did not exit 0 through bash -c" && exit 1)
|
||||
tail -n 1 "$LEDGER" | grep -qE '"wtree":"[0-9a-f]{40}"' || (echo "evidence recorded no content fingerprint" && exit 1)
|
||||
|
||||
set +e
|
||||
OUT=$(bun "$G/bin/gstack-gate-diff" main 2>&1)
|
||||
CODE=$?
|
||||
set -e
|
||||
echo "$OUT" | tail -n 3
|
||||
test "$CODE" -eq 0 || (echo "gstack-gate-diff exited $CODE" && exit 1)
|
||||
! echo "$OUT" | grep -q 'fingerprint unavailable' || (echo "gate-diff could not fingerprint the tree" && exit 1)
|
||||
echo "$OUT" | grep -qE 'candidate=[0-9a-f]{12}\+[0-9a-f]{12} ' || (echo "gate-diff candidate has no tree id" && exit 1)
|
||||
}
|
||||
echo "::group::runner Git for Windows ($(git --version))"
|
||||
(journey)
|
||||
echo "::endgroup::"
|
||||
echo "::group::pinned PortableGit $PORTABLE_GIT_VERSION"
|
||||
PG_CMD=$(cygpath -u "$RUNNER_TEMP/PortableGit/cmd")
|
||||
(export PATH="$PG_CMD:$PATH"; git --version; journey)
|
||||
echo "::endgroup::"
|
||||
shell: bash
|
||||
@@ -18,10 +18,21 @@ name: Windows Setup E2E
|
||||
# had the false positive recovers with the documented
|
||||
# `git pull --ff-only --autostash && ./setup`.
|
||||
#
|
||||
# setup.ps1 under Windows PowerShell 5.1 (powershell.exe, #3130): its cases
|
||||
# in test/setup-ps1.test.ts run with a space in the temp path, and a real
|
||||
# install runs from a checkout path with a space. The held-install job
|
||||
# (#3184) builds a prefix-mode v1.91.101.0 install behind this PR's tree in
|
||||
# three states (clean, dirty-conflicting, already-unmerged): the old updater
|
||||
# must log `HELD hook-check-unavailable`, the PowerShell recovery form that
|
||||
# docs/troubleshooting.md publishes must reach the PR's tree with every
|
||||
# local edit in a rescue ref, the trial and go-back forms must move the
|
||||
# install, and the new updater must then take a later release whose symlink
|
||||
# sorts before its target. Each job asserts the exact list of cases it ran.
|
||||
#
|
||||
# Separate from windows-free-tests.yml because that one runs a curated
|
||||
# unit-test subset; this one exercises the install path itself.
|
||||
#
|
||||
# Runner: GitHub-hosted free windows-latest. ~6-10 min total.
|
||||
# Runner: GitHub-hosted free windows-latest, two parallel jobs. ~10-25 min.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -33,6 +44,9 @@ on:
|
||||
- 'scripts/build-cso-windows.ps1'
|
||||
- 'scripts/write-version-files.sh'
|
||||
- 'setup'
|
||||
- 'setup.ps1'
|
||||
- 'test/setup-ps1.test.ts'
|
||||
- 'docs/troubleshooting.md'
|
||||
- 'browse/src/cli.ts'
|
||||
- 'browse/src/find-browse.ts'
|
||||
- 'browse/src/server.ts'
|
||||
@@ -46,6 +60,9 @@ on:
|
||||
- 'bin/gstack-launch-probe.sh'
|
||||
- 'bin/gstack-hook-check'
|
||||
- 'bin/gstack-session-update'
|
||||
- 'bin/gstack-ff-update'
|
||||
- 'bin/gstack-claude-root.sh'
|
||||
- 'bin/gstack-browser-ensure'
|
||||
- 'bin/gstack-path-spelling.sh'
|
||||
- 'lib/path-spelling.ts'
|
||||
- 'hosts/claude/hooks/**'
|
||||
@@ -97,6 +114,34 @@ jobs:
|
||||
run: bun install --frozen-lockfile
|
||||
shell: bash
|
||||
|
||||
- name: setup.ps1 cases under Windows PowerShell 5.1 with a space in the temp path (#3130)
|
||||
# test/setup-ps1.test.ts runs powershell.exe on Windows: argv forwarding
|
||||
# with adversarial arguments, the empty-argument refusal, and pwsh. The
|
||||
# skips are its Linux-only cases: a missing prerequisite, and the Git
|
||||
# Bash resolution table, whose locations are injected into pwsh.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
: > "$RUNNER_TEMP/setup-cases"
|
||||
# shellcheck disable=SC2016
|
||||
MAJOR=$(powershell.exe -NoProfile -NonInteractive -Command '$PSVersionTable.PSVersion.Major' | tr -d '\r')
|
||||
test "$MAJOR" = 5 || (echo "powershell.exe is PowerShell '$MAJOR', not Windows PowerShell 5.1" && exit 1)
|
||||
echo ps51 >> "$RUNNER_TEMP/setup-cases"
|
||||
SPACED="$RUNNER_TEMP/tmp with space"
|
||||
mkdir -p "$SPACED"
|
||||
TEMP="$(cygpath -w "$SPACED")"
|
||||
export TEMP TMP="$TEMP"
|
||||
set +e
|
||||
OUT=$(bun test test/setup-ps1.test.ts 2>&1)
|
||||
CODE=$?
|
||||
set -e
|
||||
echo "$OUT"
|
||||
test "$CODE" -eq 0 || (echo "test/setup-ps1.test.ts exited $CODE" && exit 1)
|
||||
grep -qE '^ *4 pass$' <<< "$OUT" || (echo "expected exactly 4 executed setup.ps1 cases" && exit 1)
|
||||
grep -qE '^ *0 fail$' <<< "$OUT" || (echo "a setup.ps1 case failed" && exit 1)
|
||||
grep -qE '^ *31 skip$' <<< "$OUT" || (echo "expected exactly 31 skipped setup.ps1 cases (the Linux-only prerequisite case, the 14 pwsh-on-Linux Git Bash resolution rows and the 16 shared-table rows from test/fixtures/windows-bash-resolution.json)" && exit 1)
|
||||
echo setup-ps1-cases >> "$RUNNER_TEMP/setup-cases"
|
||||
shell: bash
|
||||
|
||||
- name: Run bun run build (the previously-broken path)
|
||||
# This is the regression gate. Bun's Windows shell parser rejected
|
||||
# multiple constructs the old inline build chain used; the wave
|
||||
@@ -165,6 +210,33 @@ jobs:
|
||||
echo "runtime root: $ROOT -> source $(cat "$ROOT/.source-path")"
|
||||
shell: bash
|
||||
|
||||
- name: .\setup.ps1 installs from a checkout path with a space under Windows PowerShell 5.1 (#3130)
|
||||
# A copy of this built checkout (build outputs keep their mtimes, so
|
||||
# setup does not rebuild; node_modules is reinstalled) under a path
|
||||
# with a space, installed through powershell.exe into an isolated HOME.
|
||||
# -h stores symlinks as their targets: MSYS tar cannot extract a
|
||||
# symlink that precedes its target (connect-chrome, #3184).
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SPACED="$(cygpath -u "$RUNNER_TEMP")/gstack checkout"
|
||||
mkdir -p "$SPACED"
|
||||
tar --exclude=./node_modules -chf - . | tar -xpf - -C "$SPACED"
|
||||
E2E_HOME="$RUNNER_TEMP/gstack-ps1-home"
|
||||
mkdir -p "$E2E_HOME"
|
||||
set +e
|
||||
OUT=$(HOME="$E2E_HOME" USERPROFILE="$(cygpath -w "$E2E_HOME")" GSTACK_SKIP_PLAYWRIGHT=1 GSTACK_STRICT_BUILD=0 \
|
||||
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$(cygpath -w "$SPACED/setup.ps1")" --host codex 2>&1)
|
||||
CODE=$?
|
||||
set -e
|
||||
echo "$OUT" | tail -n 40
|
||||
test "$CODE" -eq 0 || (echo ".\\setup.ps1 exited $CODE" && exit 1)
|
||||
! grep -q 'unexpected EOF' <<< "$OUT" || (echo "bash read a broken -c script (#3130)" && exit 1)
|
||||
ROOT="$E2E_HOME/.codex/skills/gstack"
|
||||
test -f "$ROOT/.source-path" || (echo "MISSING: $ROOT/.source-path" && exit 1)
|
||||
grep -q 'gstack checkout' "$ROOT/.source-path" || (echo "the runtime root does not come from the spaced checkout: $(cat "$ROOT/.source-path")" && exit 1)
|
||||
echo setup-ps1-install >> "$RUNNER_TEMP/setup-cases"
|
||||
shell: bash
|
||||
|
||||
- name: Installed browse runs a piped chain flow from an unrelated directory
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -297,3 +369,249 @@ jobs:
|
||||
echo "$DOCTOR"
|
||||
echo "$DOCTOR" | grep -qE '^warn +cso +' || (echo "doctor did not report the CSO failure" && exit 1)
|
||||
shell: bash
|
||||
|
||||
- name: Every setup.ps1 case ran
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cat "$RUNNER_TEMP/setup-cases"
|
||||
test "$(cat "$RUNNER_TEMP/setup-cases")" = "$(printf 'ps51\nsetup-ps1-cases\nsetup-ps1-install')" || (echo "a setup.ps1 case did not run" && exit 1)
|
||||
shell: bash
|
||||
|
||||
held-install-journey:
|
||||
# #3184: MSYS tar cannot extract a symlink that precedes its target, so
|
||||
# every v1.91.101.0 install on Windows holds every release. The Git Bash
|
||||
# forms of the recovery run in test/held-install-recovery.test.ts; this
|
||||
# job runs the PowerShell forms under powershell.exe, verbatim from
|
||||
# docs/troubleshooting.md, against the runner's real ~/.claude install
|
||||
# path ($HOME in PowerShell). GSTACK_E2E_POWERSHELL and
|
||||
# GSTACK_E2E_UPDATER_PATH_PREFIX exist only to run these steps off Windows.
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 50
|
||||
env:
|
||||
GSTACK_SKIP_PLAYWRIGHT: '1'
|
||||
GSTACK_STRICT_BUILD: '0'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config --global user.email "windows-setup-e2e@gstack.test"
|
||||
git config --global user.name "Windows Setup E2E"
|
||||
git config --global init.defaultBranch main
|
||||
shell: bash
|
||||
|
||||
- name: Build the held-install fixture (v1.91.101.0 behind this PR's tree)
|
||||
# origin's main carries this PR's tree on top of the v1.91.101.0
|
||||
# release tree (commits built from the two trees, so the shallow
|
||||
# checkout's history is never needed); fix-branch adds one file for
|
||||
# the trial form.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
OLD_RELEASE=47d639abffa882b8cbb641d7d1dedf08ecada9ec # v1.91.101.0
|
||||
T="$RUNNER_TEMP/held"
|
||||
rm -rf "$T" && mkdir -p "$T"
|
||||
git cat-file -e "$OLD_RELEASE^{commit}" 2>/dev/null || git fetch -q --no-tags --depth=1 origin "$OLD_RELEASE"
|
||||
c() { git commit-tree "$@"; }
|
||||
HELD=$(c -m "v1.91.101.0" "$OLD_RELEASE^{tree}")
|
||||
MAIN=$(c -p "$HELD" -m "this PR's tree" 'HEAD^{tree}')
|
||||
export GIT_INDEX_FILE="$T/fix.index"
|
||||
git read-tree "$MAIN"
|
||||
git update-index --add --cacheinfo "100644,$(printf 'trial\n' | git hash-object -w --stdin),e2e-trial-marker"
|
||||
FIX=$(c -p "$MAIN" -m "a fix branch to try" "$(git write-tree)")
|
||||
unset GIT_INDEX_FILE
|
||||
test "$(git show "$HELD:VERSION")" = 1.91.101.0 || (echo "the held tree is not v1.91.101.0" && exit 1)
|
||||
git ls-tree "$MAIN" connect-chrome | grep -q '^120000 ' || (echo "this PR's tree has no connect-chrome symlink to reproduce the hold" && exit 1)
|
||||
git init -q --bare -b main "$T/origin.git"
|
||||
git push -q "$T/origin.git" "$MAIN:refs/heads/main" "$FIX:refs/heads/fix-branch"
|
||||
printf 'HELD=%s\nMAIN=%s\nFIX=%s\n' "$HELD" "$MAIN" "$FIX" > "$T/vars"
|
||||
: > "$T/cases"
|
||||
cat > "$T/lib.sh" <<'LIB'
|
||||
T="$RUNNER_TEMP/held"
|
||||
. "$T/vars"
|
||||
INSTALL="$HOME/.claude/skills/gstack"
|
||||
STATE="$HOME/.gstack"
|
||||
LOG="$STATE/analytics/session-update.log"
|
||||
PS="${GSTACK_E2E_POWERSHELL:-powershell.exe}"
|
||||
w() { if command -v cygpath >/dev/null 2>&1; then cygpath -w "$1"; else printf '%s\n' "$1"; fi; }
|
||||
die() { echo "FAIL: $*" >&2; [ ! -f "$LOG" ] || { echo "--- updater log" && cat "$LOG"; } >&2; exit 1; }
|
||||
case_ok() { echo "$1" >> "$T/cases"; echo "CASE OK: $1"; }
|
||||
# The command docs/troubleshooting.md publishes under <!-- form:NAME -->.
|
||||
form() { awk -v m="<!-- form:$1 -->" '$0 == m { f = 1; next } f && /^```/ { if (o) exit; o = 1; next } f && o { print }' "$GITHUB_WORKSPACE/docs/troubleshooting.md"; }
|
||||
# run_ps_form NAME [REPLACEMENT-FOR-.\setup.ps1] [BRANCH]: the form,
|
||||
# verbatim, as a script under powershell.exe; prints its output.
|
||||
run_ps_form() {
|
||||
f=$(form "$1")
|
||||
case "$f" in *'{ .\setup.ps1 }') ;; *) die "form $1 is missing or does not end in .\setup.ps1: $f" ;; esac
|
||||
[ -z "${2:-}" ] || f="${f%'.\setup.ps1 }'}$2 }"
|
||||
[ -z "${3:-}" ] || f=${f//'<branch>'/$3}
|
||||
printf '%s\r\nexit $LASTEXITCODE\r\n' "$f" > "$T/form.ps1"
|
||||
"$PS" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$(w "$T/form.ps1")" 2>&1
|
||||
}
|
||||
# run_updater PATTERN [SECONDS]: one session-start check with the
|
||||
# throttle cleared, waiting for its background run to log PATTERN.
|
||||
run_updater() {
|
||||
rm -f "$STATE/.last-session-update"
|
||||
n0=$( { cat "$LOG" 2>/dev/null || true; } | wc -l)
|
||||
( cd "$T" && PATH="${GSTACK_E2E_UPDATER_PATH_PREFIX:+$GSTACK_E2E_UPDATER_PATH_PREFIX:}$PATH" bash "$INSTALL/bin/gstack-session-update" ) || die "the updater exited $?"
|
||||
i=0
|
||||
until tail -n +"$((n0 + 1))" "$LOG" 2>/dev/null | grep -E "$1" > "$T/updater-line"; do
|
||||
i=$((i + 1)); [ "$i" -le "${2:-180}" ] || die "no updater log line matching '$1' within ${2:-180}s"
|
||||
sleep 1
|
||||
done
|
||||
cat "$T/updater-line"
|
||||
i=0; while [ -d "$STATE/.setup-lock" ] && [ "$i" -lt 120 ]; do i=$((i + 1)); sleep 1; done
|
||||
}
|
||||
# install_state clean|dirty|unmerged: a prefix-mode v1.91.101.0
|
||||
# install one release behind origin's main.
|
||||
install_state() {
|
||||
rm -rf "$INSTALL" "$STATE"
|
||||
mkdir -p "$(dirname "$INSTALL")"
|
||||
git clone -q "$T/origin.git" "$INSTALL"
|
||||
git -C "$INSTALL" reset -q --hard "$HELD"
|
||||
GSTACK_SETUP_RUNNING=1 bash "$INSTALL/bin/gstack-config" set auto_upgrade true
|
||||
GSTACK_SETUP_RUNNING=1 bash "$INSTALL/bin/gstack-config" set skill_prefix true
|
||||
bash "$INSTALL/bin/gstack-patch-names" "$INSTALL" true >/dev/null
|
||||
! git -C "$INSTALL" diff --quiet -- SKILL.md '*/SKILL.md' || die "prefix mode left no footprint"
|
||||
case "$1" in
|
||||
dirty)
|
||||
git -C "$INSTALL" diff -U0 "$HELD" "$MAIN" -- docs/troubleshooting.md > "$T/upstream.diff"
|
||||
L=$(sed -n 's/^-\([^-]\)/\1/p' "$T/upstream.diff" | sed -n 1p)
|
||||
[ -n "$L" ] || die "docs/troubleshooting.md has no upstream change to conflict with"
|
||||
L="$L" awk '!d && $0 == ENVIRON["L"] { print $0 " LOCAL-EDIT"; d = 1; next } { print }' "$INSTALL/docs/troubleshooting.md" > "$T/edited"
|
||||
cat "$T/edited" > "$INSTALL/docs/troubleshooting.md"
|
||||
grep -q 'LOCAL-EDIT' "$INSTALL/docs/troubleshooting.md" || die "the local edit did not apply"
|
||||
;;
|
||||
unmerged)
|
||||
b=$(printf 'base\n' | git -C "$INSTALL" hash-object -w --stdin)
|
||||
o=$(printf 'ours LOCAL-EDIT\n' | git -C "$INSTALL" hash-object -w --stdin)
|
||||
t=$(printf 'theirs\n' | git -C "$INSTALL" hash-object -w --stdin)
|
||||
git -C "$INSTALL" update-index --force-remove README.md
|
||||
printf '100644 %s 1\tREADME.md\n100644 %s 2\tREADME.md\n100644 %s 3\tREADME.md\n' "$b" "$o" "$t" | git -C "$INSTALL" update-index --index-info
|
||||
printf '<<<<<<< ours\nours LOCAL-EDIT\n=======\ntheirs\n>>>>>>> theirs\n' > "$INSTALL/README.md"
|
||||
[ -n "$(git -C "$INSTALL" ls-files -u)" ] || die "the install has no unmerged files"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
# check_recovered STATE: at origin's main, nothing unmerged, and
|
||||
# every local edit (only those) in one rescue ref.
|
||||
check_recovered() {
|
||||
[ "$(git -C "$INSTALL" rev-parse HEAD)" = "$MAIN" ] || die "$1: the install is at $(git -C "$INSTALL" rev-parse HEAD), not $MAIN"
|
||||
[ -z "$(git -C "$INSTALL" ls-files -u)" ] || die "$1: unmerged files remain"
|
||||
[ -f "$INSTALL/bin/gstack-ff-update" ] || die "$1: bin/gstack-ff-update is missing"
|
||||
refs=$(git -C "$INSTALL" for-each-ref --format='%(refname)' refs/gstack/rescue)
|
||||
if [ "$1" = clean ]; then
|
||||
[ -z "$refs" ] || die "clean: a rescue ref was made: $refs"
|
||||
return 0
|
||||
fi
|
||||
[ "$(printf '%s\n' "$refs" | grep -c .)" = 1 ] || die "$1: expected one rescue ref, got: $refs"
|
||||
file=docs/troubleshooting.md; [ "$1" != unmerged ] || file=README.md
|
||||
git -C "$INSTALL" show "$refs:$file" > "$T/rescued"
|
||||
grep -q 'LOCAL-EDIT' "$T/rescued" || die "$1: the rescue ref lacks the local edit to $file"
|
||||
[ "$(git -C "$INSTALL" diff --name-only "$refs^" "$refs")" = "$file" ] || die "$1: the rescue ref holds more than the user's edit"
|
||||
}
|
||||
LIB
|
||||
bash -n "$T/lib.sh"
|
||||
shell: bash
|
||||
|
||||
- name: 'Held clean and already-unmerged installs: v1.91.101.0 holds, the PowerShell recovery form recovers'
|
||||
# The form's last step (.\setup.ps1) is replaced by a marker here; the
|
||||
# dirty-conflicting state below runs it verbatim.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. "$RUNNER_TEMP/held/lib.sh"
|
||||
for state in clean unmerged; do
|
||||
install_state "$state"
|
||||
run_updater '^[^ ]+ HELD hook-check-unavailable'
|
||||
case_ok "$state/v1.91.101.0-held"
|
||||
CODE=0
|
||||
OUT=$(run_ps_form recovery-powershell 'Write-Output SETUP_WOULD_RUN') || CODE=$?
|
||||
echo "$OUT"
|
||||
[ "$CODE" -eq 0 ] || die "$state: the recovery form exited $CODE"
|
||||
grep -q '^SETUP_WOULD_RUN' <<< "$OUT" || die "$state: the recovery form did not reach its setup step"
|
||||
check_recovered "$state"
|
||||
case_ok "$state/recovered"
|
||||
done
|
||||
shell: bash
|
||||
|
||||
- name: 'Held dirty-conflicting install: the PowerShell recovery form, verbatim with .\setup.ps1'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. "$RUNNER_TEMP/held/lib.sh"
|
||||
install_state dirty
|
||||
run_updater '^[^ ]+ HELD hook-check-unavailable'
|
||||
case_ok dirty/v1.91.101.0-held
|
||||
set +e
|
||||
OUT=$(run_ps_form recovery-powershell)
|
||||
CODE=$?
|
||||
set -e
|
||||
echo "$OUT" | tail -n 60
|
||||
[ "$CODE" -eq 0 ] || die "dirty: the recovery form exited $CODE"
|
||||
check_recovered dirty
|
||||
case_ok dirty/recovered-and-set-up
|
||||
shell: bash
|
||||
|
||||
- name: The PowerShell trial and go-back forms move the install
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. "$RUNNER_TEMP/held/lib.sh"
|
||||
set +e
|
||||
OUT=$(run_ps_form trial-powershell '' fix-branch)
|
||||
CODE=$?
|
||||
set -e
|
||||
echo "$OUT" | tail -n 30
|
||||
[ "$CODE" -eq 0 ] || die "the trial form exited $CODE"
|
||||
[ "$(git -C "$INSTALL" rev-parse HEAD)" = "$FIX" ] || die "the trial form did not check out fix-branch"
|
||||
! git -C "$INSTALL" symbolic-ref -q HEAD >/dev/null || die "the trial form left HEAD on a branch"
|
||||
case_ok trial
|
||||
set +e
|
||||
OUT=$(run_ps_form goback-powershell)
|
||||
CODE=$?
|
||||
set -e
|
||||
echo "$OUT" | tail -n 30
|
||||
[ "$CODE" -eq 0 ] || die "the go-back form exited $CODE"
|
||||
[ "$(git -C "$INSTALL" symbolic-ref --short HEAD)" = main ] || die "the go-back form did not return to main"
|
||||
[ "$(git -C "$INSTALL" rev-parse HEAD)" = "$MAIN" ] || die "main is not at $MAIN"
|
||||
case_ok goback
|
||||
shell: bash
|
||||
|
||||
- name: The new updater takes a later release whose symlink sorts before its target
|
||||
# Pushed only now (after recovery), so the hold above is
|
||||
# connect-chrome's alone. The old updater's archive | tar extraction is
|
||||
# what MSYS tar failed; the new one extracts without tar.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. "$RUNNER_TEMP/held/lib.sh"
|
||||
export GIT_INDEX_FILE="$T/synth.index"
|
||||
git read-tree "$MAIN"
|
||||
git update-index --add \
|
||||
--cacheinfo "120000,$(printf 'b-target' | git hash-object -w --stdin),e2e-synthetic/a-link" \
|
||||
--cacheinfo "100644,$(printf 'target\n' | git hash-object -w --stdin),e2e-synthetic/b-target"
|
||||
SYNTH=$(git commit-tree -p "$MAIN" -m "a later release: a symlink sorted before its target" "$(git write-tree)")
|
||||
unset GIT_INDEX_FILE
|
||||
git push -q "$T/origin.git" "$SYNTH:refs/heads/main"
|
||||
run_updater '^[^ ]+ (UPDATED|HELD|PULL_FAILED|SETUP_FAILED|MIGRATIONS_FAILED) ' 1800
|
||||
grep -q ' UPDATED ' "$T/updater-line" || die "the new updater did not log UPDATED"
|
||||
[ "$(git -C "$INSTALL" rev-parse HEAD)" = "$SYNTH" ] || die "the install is not at the later release"
|
||||
case_ok later-release/updated
|
||||
shell: bash
|
||||
|
||||
- name: Every held-install case ran
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cat "$RUNNER_TEMP/held/cases"
|
||||
EXPECTED='clean/v1.91.101.0-held
|
||||
clean/recovered
|
||||
unmerged/v1.91.101.0-held
|
||||
unmerged/recovered
|
||||
dirty/v1.91.101.0-held
|
||||
dirty/recovered-and-set-up
|
||||
trial
|
||||
goback
|
||||
later-release/updated'
|
||||
test "$(cat "$RUNNER_TEMP/held/cases")" = "$(printf '%s\n' "$EXPECTED" | sed 's/^ *//')" || (echo "a held-install case did not run" && exit 1)
|
||||
shell: bash
|
||||
Reference in new issue
Block a user