Skip to content
Merged
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
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
go:
name: Go check (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
Expand All @@ -37,7 +38,7 @@ jobs:
fi

- name: Test
run: go test ./...
run: go test ./... -count=1 -timeout=3m

- name: Check Windows test tree cleanliness
if: runner.os == 'Windows'
Expand All @@ -49,9 +50,19 @@ jobs:
exit 1
fi

- name: ACP prompt and steering race regression
if: runner.os == 'Linux'
timeout-minutes: 2
shell: bash
run: |
go test -race ./internal/acp \
-run 'Test(StartPromptWaitsForPromptDispatchBeforeSteering|ClaudeSteeringFallbackCancelsOldRunAndStartsObservableTurn|CodexSteeringFallbackCancelsOldRunAndStartsObservableTurn)$' \
-count=20 \
-timeout=90s

- name: Race
if: runner.os == 'Linux'
run: go test -race ./...
run: go test -race ./... -count=1 -timeout=3m

- name: Vet
run: go vet ./...
Expand Down Expand Up @@ -103,6 +114,7 @@ jobs:
browser-integration:
name: Native browser integration
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -123,12 +135,13 @@ jobs:
run: |
browser_path="$(command -v google-chrome-stable || command -v google-chrome || command -v chromium-browser || command -v chromium || true)"
test -n "$browser_path"
xvfb-run -a env AGENTDOCK_BROWSER_EXECUTABLE_PATH="$browser_path" go test -race -tags browser_integration ./internal/tool/browser ./internal/app -count=1
xvfb-run -a env AGENTDOCK_BROWSER_EXECUTABLE_PATH="$browser_path" go test -race -tags browser_integration ./internal/tool/browser ./internal/app -count=1 -timeout=3m


container:
name: Container check
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
82 changes: 81 additions & 1 deletion .github/workflows/windows-installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ on:
- 'go.mod'
- 'go.sum'
- '.github/workflows/windows-installer.yml'
pull_request:
branches:
- main
workflow_dispatch:
inputs:
test_tag:
Expand All @@ -24,9 +27,54 @@ permissions:
contents: write

jobs:
changes:
name: Detect Windows installer changes
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
relevant: ${{ steps.filter.outputs.relevant }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Decide whether installer validation is required
id: filter
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
if [[ "$EVENT_NAME" != "pull_request" ]]; then
echo 'relevant=true' >> "$GITHUB_OUTPUT"
exit 0
fi

changed_paths="$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- \
scripts \
packaging \
desktop/windows \
cmd \
internal \
go.mod \
go.sum \
.github/workflows/windows-installer.yml)"
if [[ -n "$changed_paths" ]]; then
printf 'Windows installer validation required by:\n%s\n' "$changed_paths"
echo 'relevant=true' >> "$GITHUB_OUTPUT"
else
echo 'No Windows installer-relevant changes detected.'
echo 'relevant=false' >> "$GITHUB_OUTPUT"
fi

validate:
name: Validate installer on Windows PowerShell 5.1
needs: changes
if: needs.changes.outputs.relevant == 'true'
runs-on: windows-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -305,7 +353,7 @@ jobs:


- name: Build and publish signed Windows test package
if: ${{ inputs.test_tag != '' }}
if: ${{ github.event_name == 'workflow_dispatch' && inputs.test_tag != '' }}
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
Expand Down Expand Up @@ -393,3 +441,35 @@ jobs:
--prerelease `
--title "AgentDock Windows test $env:TEST_TAG" `
--notes "Temporary Windows test build from commit $env:GITHUB_SHA. Uses the existing AgentDock self-signed Authenticode certificate."

gate:
name: Windows Installer gate
needs: [changes, validate]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Verify installer validation result
shell: bash
env:
CHANGES_RESULT: ${{ needs.changes.result }}
RELEVANT: ${{ needs.changes.outputs.relevant }}
VALIDATE_RESULT: ${{ needs.validate.result }}
run: |
if [[ "$CHANGES_RESULT" != "success" ]]; then
echo "Windows installer change detection failed: $CHANGES_RESULT" >&2
exit 1
fi
if [[ "$RELEVANT" == "true" ]]; then
if [[ "$VALIDATE_RESULT" != "success" ]]; then
echo "Windows installer validation did not pass: $VALIDATE_RESULT" >&2
exit 1
fi
echo 'Windows installer-relevant changes passed full validation.'
exit 0
fi
if [[ "$VALIDATE_RESULT" != "skipped" ]]; then
echo "Unexpected Windows installer validation result for an unrelated change: $VALIDATE_RESULT" >&2
exit 1
fi
echo 'Windows installer validation not required for this change.'
59 changes: 59 additions & 0 deletions scripts/test/ci_workflow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package scripts

import (
"os"
"path/filepath"
"strings"
"testing"
)

func readWorkflow(t *testing.T, name string) string {
t.Helper()
data, err := os.ReadFile(filepath.Join("..", "..", ".github", "workflows", name))
if err != nil {
t.Fatalf("read workflow %s: %v", name, err)
}
return strings.ReplaceAll(string(data), "\r\n", "\n")
}

func TestCIWorkflowUsesFreshBoundedGoTests(t *testing.T) {
workflow := readWorkflow(t, "ci.yml")
for _, want := range []string{
"timeout-minutes: 20",
"go test ./... -count=1 -timeout=3m",
"name: ACP prompt and steering race regression",
"-count=20",
"-timeout=90s",
"go test -race ./... -count=1 -timeout=3m",
"go test -race -tags browser_integration ./internal/tool/browser ./internal/app -count=1 -timeout=3m",
"timeout-minutes: 15",
} {
if !strings.Contains(workflow, want) {
t.Fatalf("CI workflow must keep bounded non-cached validation; missing %q", want)
}
}
}

func TestWindowsInstallerWorkflowHasAlwaysPresentPullRequestGate(t *testing.T) {
workflow := readWorkflow(t, "windows-installer.yml")
for _, want := range []string{
"pull_request:\n branches:\n - main",
"name: Detect Windows installer changes",
"fetch-depth: 0",
"git diff --name-only \"$BASE_SHA\" \"$HEAD_SHA\"",
"name: Validate installer on Windows PowerShell 5.1",
"needs: changes",
"if: needs.changes.outputs.relevant == 'true'",
"timeout-minutes: 30",
"name: Windows Installer gate",
"needs: [changes, validate]",
"if: always()",
"CHANGES_RESULT: ${{ needs.changes.result }}",
"VALIDATE_RESULT: ${{ needs.validate.result }}",
"github.event_name == 'workflow_dispatch' && inputs.test_tag != ''",
} {
if !strings.Contains(workflow, want) {
t.Fatalf("Windows Installer workflow must keep a safe pull-request gate; missing %q", want)
}
}
}
Loading