Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 83 additions & 7 deletions .github/workflows/cli-installer-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ name: CLI Installer Smoke
on:
workflow_dispatch:
inputs:
windows_network:
description: Only accept public stable-to-beta downloads on Windows PowerShell 5.1
type: boolean
default: false
windows_published_installer:
description: Use the checksum-bound published installer instead of checkout (network mode)
type: boolean
default: false
windows_preview:
description: Build only the independent Windows x64/ARM64 preview
type: boolean
Expand All @@ -19,11 +27,18 @@ on:
# below builds every native candidate and accepts the live preview channel.
# Hosted checkout/Bun/SSH candidate work begins at the master boundary.
pull_request:
branches: [master]
branches: [dev, master]
paths:
- ".bun-version"
- ".github/workflows/cli-installer-smoke.yml"
- ".github/workflows/release.yml"
- "install.ps1"
- "scripts/windows-cli-preview-smoke.ts"
- "scripts/windows-cli-preview.spec.ts"
- "scripts/cli-installer-workflow.spec.ts"
- "tests/integration/installer-powershell/**"
- ".github/workflows/windows-cli-preview.yml"
- "packages/update-lifecycle/**"
- "install"
- "package.json"
- "packages/cli/**"
Expand Down Expand Up @@ -78,15 +93,75 @@ concurrency:
cancel-in-progress: true

jobs:
windows-network-scope:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
relevant: ${{ steps.scope.outputs.relevant }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- id: scope
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Keep unrelated UI/business PRs off the Windows network lane.
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > "$RUNNER_TEMP/windows-network-paths"
if grep -Eq '^(install\.ps1|packages/cli/|packages/update-lifecycle/|scripts/windows-cli-preview|scripts/cli-installer-workflow|tests/integration/installer-powershell/|\.github/workflows/(cli-installer-smoke|windows-cli-preview)\.yml)' "$RUNNER_TEMP/windows-network-paths"; then
echo 'relevant=true' >> "$GITHUB_OUTPUT"
else
echo 'relevant=false' >> "$GITHUB_OUTPUT"
fi

windows-network:
needs: windows-network-scope
if: >-
!cancelled() &&
((github.event_name == 'workflow_dispatch' && inputs.windows_network) ||
(github.event_name == 'pull_request' && needs.windows-network-scope.outputs.relevant == 'true'))
name: PowerShell 5.1 public install and update
runs-on: windows-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- uses: oven-sh/setup-bun@v2
with:
bun-version-file: .bun-version
- name: Accept real public release lifecycle
env:
PUBLISHED_INSTALLER: ${{ inputs.windows_published_installer && '1' || '0' }}
shell: powershell
run: |
$extra = @()
if ($env:PUBLISHED_INSTALLER -eq '1') { $extra += '--published-installer' }
bun scripts/windows-cli-preview-smoke.ts --published @extra
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Preserve PowerShell and public release evidence
if: always()
uses: actions/upload-artifact@v6
with:
name: windows-network-${{ github.event.pull_request.head.sha || github.sha }}
path: dist/windows-cli-preview/**/native-smoke.json
if-no-files-found: warn
retention-days: 30

windows-preview:
if: github.event_name == 'workflow_dispatch' && inputs.windows_preview
if: github.event_name == 'workflow_dispatch' && inputs.windows_preview && !inputs.windows_network
uses: ./.github/workflows/windows-cli-preview.yml
with:
candidate_run: ${{ inputs.windows_candidate_run || '' }}
channel_build: ${{ inputs.windows_channel_build || false }}

release-prep-scope:
if: github.event_name != 'push' && !inputs.windows_preview
if: github.event_name != 'push' && !inputs.windows_preview && !inputs.windows_network && (github.event_name != 'pull_request' || github.base_ref == 'master')
name: release-prep scope
runs-on: ubuntu-latest
timeout-minutes: 5
Expand Down Expand Up @@ -118,7 +193,7 @@ jobs:
needs: release-prep-scope
if: >-
!cancelled() &&
!inputs.windows_preview &&
!inputs.windows_preview && !inputs.windows_network &&
github.event_name != 'push' &&
(github.event_name != 'pull_request' || github.base_ref == 'master') &&
(
Expand Down Expand Up @@ -185,8 +260,9 @@ jobs:
needs: release-prep-scope
if: >-
!cancelled() &&
!inputs.windows_preview &&
!inputs.windows_preview && !inputs.windows_network &&
github.event_name != 'push' &&
(github.event_name != 'pull_request' || github.base_ref == 'master') &&
(
needs.release-prep-scope.result != 'success' ||
needs.release-prep-scope.outputs.beta_release_prep != 'true'
Expand All @@ -209,7 +285,7 @@ jobs:
needs: release-prep-scope
if: >-
!cancelled() &&
!inputs.windows_preview &&
!inputs.windows_preview && !inputs.windows_network &&
github.event_name != 'push' &&
(github.event_name != 'pull_request' || github.base_ref == 'master') &&
(
Expand Down Expand Up @@ -639,7 +715,7 @@ jobs:
echo "activated=true" >> "$GITHUB_OUTPUT"

dev-channel-install:
if: always() && !inputs.windows_preview && ((github.event_name == 'push' && needs.activate-dev-cli.result == 'success' && needs.activate-dev-cli.outputs.activated == 'true') || github.event_name == 'workflow_dispatch')
if: always() && !inputs.windows_preview && !inputs.windows_network && ((github.event_name == 'push' && needs.activate-dev-cli.result == 'success' && needs.activate-dev-cli.outputs.activated == 'true') || github.event_name == 'workflow_dispatch')
name: Live raw dev channel install
needs: activate-dev-cli
runs-on: ubuntu-latest
Expand Down
45 changes: 45 additions & 0 deletions docs/cli-installer.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,51 @@ rebuilding. An installer or test-only fix may replay those bytes; executable
changes require a new candidate. The earlier custom ZIPs remain historical
diagnostic fixtures, not a second channel or an upgrade target.

### Windows PowerShell 5.1 public-network acceptance

The existing Windows smoke has two deliberately separate modes. Candidate
acceptance uses local archives and a synthetic previous version; it cannot prove
public checksum transport or a released updater. The public mode uses the system
`WindowsPowerShell/v1.0/powershell.exe`, asserts Desktop edition and version 5.1,
and records the full host version in `native-smoke.json`:

```bash
bun scripts/windows-cli-preview-smoke.ts --published
# Also accept the public manifest's checksum-bound installer snapshot:
bun scripts/windows-cli-preview-smoke.ts --published --published-installer

gh workflow run cli-installer-smoke.yml --ref <branch> -f windows_network=true
# Published installer instead of checked-out installer:
gh workflow run cli-installer-smoke.yml --ref <branch> \
-f windows_network=true -f windows_published_installer=true
```

This explicit system lane needs native Windows, system Git/Bash and tar, Bun
from `.bun-version`, and public GitHub/CDN access; it needs no release credentials
or workspace dependency install. It resolves the live stable and beta manifests,
requires different releases, and fails if the target changes during acceptance.
It probes the live binary SHA256 sidecar with the checked-out `Download-Text`
function (or selected published snapshot), requiring `System.Byte[]` input and
`System.String` output. Ordinary installer invocations then download and verify
the real archives without `-Archive` or `-Sha256` overrides.

The shared lifecycle checks fresh beta install/version/start/stop, then a fresh
stable install followed by the **released binary's** real `update --channel beta`
while its Runtime is running, pending activation, rollback in both directions,
updated Runtime readiness, and deferred data-preserving uninstall. This does not
execute unshipped updater code: source updater coverage remains in its existing
integration tests and candidate acceptance. Receipts distinguish checkout versus
published installer, actual release identities, and synthetic versus real updates.

The installer workflow selects this Windows job for installer/CLI/update-lifecycle
PR changes to dev or master; unrelated UI/business changes do not run it. Manual
network mode runs only this lane and does not publish or activate any channel.
Tests allocate temporary install/home/profile paths, bind loopback, use lite
mode without provider credentials, avoid persistent PATH changes, and clean only
their own files and Runtime. An unavailable release/network is a failure, never a
skipped pass. The `runtime-cli-acceptance` suite owns both modes of the existing
`windows-cli-preview` runner.

## Artifact contract

Every accepted archive is named:
Expand Down
6 changes: 3 additions & 3 deletions scripts/beta-release-prep-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ describe('exact beta release-preparation workflow lane', () => {
const cli = workflow('cli-installer-smoke.yml')
const jobs = cli.jobs
const scope = jobs['release-prep-scope']
expect(cli.on?.pull_request?.branches).toEqual(['master'])
expect(cli.on?.pull_request?.branches).toEqual(['dev', 'master'])
expectTrustedClassifier(scope)
expectOutcomeGatedOutput(scope)
expect(scope.if).toBe("github.event_name != 'push' && !inputs.windows_preview")
expect(scope.if).toBe("github.event_name != 'push' && !inputs.windows_preview && !inputs.windows_network && (github.event_name != 'pull_request' || github.base_ref == 'master')")
for (const name of ['bun-cli-feasibility', 'checkout-install', 'checkout-remote']) {
expect(jobs[name].needs).toBe('release-prep-scope')
expect(jobs[name].if).toContain('!cancelled()')
Expand All @@ -112,7 +112,7 @@ describe('exact beta release-preparation workflow lane', () => {
}
expect(jobs['bun-cli-feasibility'].if).toContain("github.base_ref == 'master'")
expect(jobs['checkout-remote'].if).toContain("github.base_ref == 'master'")
expect(jobs['checkout-install'].if).not.toContain("github.base_ref == 'master'")
expect(jobs['checkout-install'].if).toContain("github.base_ref == 'master'")
expect(jobs['build-dev-cli-neutral'].if).toBe("github.event_name == 'push'")
expect(jobs['build-dev-cli'].if).toBe("github.event_name == 'push'")
expect(jobs['build-dev-cli'].needs).toEqual(['build-dev-cli-neutral', 'build-dev-broker-packs'])
Expand Down
4 changes: 2 additions & 2 deletions scripts/cli-installer-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function step(job: WorkflowJob, name: string): WorkflowStep {
describe('CLI installer dev publication workflow', () => {
it('owns every dev push while reserving hosted PR acceptance for master', () => {
expect(workflow.on?.push?.branches).toEqual(['dev'])
expect(workflow.on?.pull_request?.branches).toEqual(['master'])
expect(workflow.on?.pull_request?.branches).toEqual(['dev', 'master'])
})

it('keeps master and manual acceptance behind the trusted preflight', () => {
Expand All @@ -58,7 +58,7 @@ describe('CLI installer dev publication workflow', () => {
expect(job.if).toContain("needs.release-prep-scope.result != 'success'")
expect(job.if).toContain("beta_release_prep != 'true'")
}
expect(checkoutInstall.if).not.toContain("github.base_ref == 'master'")
expect(checkoutInstall.if).toContain("github.base_ref == 'master'")
expect(checkoutInstall.if).toContain("needs.release-prep-scope.result != 'success'")
expect(checkoutInstall.if).toContain("beta_release_prep != 'true'")
})
Expand Down
Loading
Loading