Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
bfc2c72
feat: add archive-based installation support
leoafarias Nov 5, 2025
c3d2531
fix: code review fixes for archive-based installation
leoafarias Nov 24, 2025
d60ce39
refactor: extract error cleanup helper and add ArchiveService tests
leoafarias Dec 3, 2025
24addd6
Add archive archive tests and preserve useArchive on retry
leoafarias Dec 5, 2025
4aa8b72
fix: handle bare git cache in updateLocalMirror
leoafarias Dec 15, 2025
2242af4
Fix CI: use Dart 3.8 for release tool and clean analyzer
leoafarias Dec 15, 2025
41d7cb7
Remove non-behavioral archive service tests
leoafarias Dec 22, 2025
17ecc01
fix: remove orphaned FileLocker references from git_service.dart
leoafarias Feb 2, 2026
55210ac
fix: enforce archive release channel qualifier behavior
leoafarias Feb 10, 2026
a97578f
chore: resolve dcm findings in cache and git workflows
leoafarias Feb 10, 2026
5591e73
fix: harden archive install with staging directory and network resili…
leoafarias Feb 10, 2026
c7c1bc0
chore: retrigger vercel deployment
leoafarias Feb 12, 2026
5e14a71
Harden archive install finalization and align archive validation tests
leoafarias Feb 12, 2026
69f3e08
ci: add archive regression agent workflow
leoafarias Feb 13, 2026
d5184c3
docs: pin next-mdx-remote to v6
leoafarias Feb 13, 2026
891c044
Merge origin/main into issue-688-relink
leoafarias Feb 20, 2026
801ad03
chore: standardize CI sdk fallback and add git mirror tests
leoafarias Feb 20, 2026
034386d
chore: remove code review note document
leoafarias Mar 3, 2026
45e1094
refactor: simplify archive service and reduce test duplication
leoafarias Mar 3, 2026
1c47770
fix: harden archive install recovery and expand test coverage
leoafarias Mar 4, 2026
1b1b228
chore: remove local regression agent and workspace .fvmrc
leoafarias Mar 4, 2026
5a376ee
Merge branch 'main' into issue-688-relink
leoafarias Mar 4, 2026
067683b
refactor: improve archive service clarity and test maintainability
leoafarias Mar 4, 2026
44fc6a2
Merge origin/main into issue-688-relink
leoafarias Mar 5, 2026
5684462
refactor: harden service operations, improve cleanup and validation
leoafarias Mar 5, 2026
cf9669f
refactor: consolidate lock lifecycle in GitService and remove noise c…
leoafarias Mar 5, 2026
9b70297
refactor: harden cache listing, git URL validation, and CI mirror def…
leoafarias Mar 6, 2026
bbbb69d
revert validation rules to match main
leoafarias Mar 6, 2026
44e382e
format fvm package
leoafarias Mar 6, 2026
9e64a4c
Merge remote-tracking branch 'origin/main' into issue-688-relink
leoafarias Mar 6, 2026
2858536
chore: strip drift and keep archive install changes only
leoafarias Mar 6, 2026
eb00163
fix: pre-seed shared test git cache in CI to prevent clone timeouts
leoafarias Mar 6, 2026
9f97094
fix: revert CI pre-seed workaround, bump test-os timeout, remove redu…
leoafarias Mar 6, 2026
0f7479e
fix: handle Windows PowerShell args in archive test helpers
leoafarias Mar 6, 2026
fdc8b42
chore: set 20-minute timeout on all CI test jobs
leoafarias Mar 11, 2026
51e6e4b
fix: bump CI timeouts to account for setup overhead
leoafarias Mar 14, 2026
ae2818a
fix archive install workflow and test cleanup
leoafarias Mar 14, 2026
96f29e9
Fix DCM CI failures
leoafarias Mar 14, 2026
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
6 changes: 6 additions & 0 deletions .fvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"flutter": "stable",
"flavors": {
"bar": "stable"
}
}
6 changes: 5 additions & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
7. Everything deploys automatically!

### `release-fvm-mcp.yml`
**Trigger**: Git tag push with `fvm-mcp-v*` pattern + manual dispatch
**Trigger**: Git tag push with `fvm-mcp-v*` pattern + manual dispatch
**Purpose**: Build and publish `fvm_mcp` standalone binaries to GitHub Releases
**Process**:
1. **Validate** - Enforce release tag format and version consistency:
Expand Down Expand Up @@ -61,6 +61,10 @@
**Purpose**: Run all tests and quality checks
**Used by**: Other workflows for validation before deployment

Includes an `archive-regression` job that runs `scripts/local_regression_agent.sh`
in CI for archive-focused regression coverage and publishes `.context/testing-runs`
artifacts for inspection.

### `test-install.yml`
**Trigger**: Manual dispatch
**Purpose**: Test FVM installation across different platforms
Expand Down
44 changes: 43 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ jobs:
working-directory: fvm_mcp
run: dart test

# Release tooling requires Dart >=3.8 (see tool/release_tool/pubspec.yaml)
- name: Switch to Dart 3.8 for release tool
uses: dart-lang/setup-dart@v1
with:
sdk: "3.8.0"

- name: Release tool | Install dependencies
working-directory: tool/release_tool
run: dart pub get
Expand All @@ -111,9 +117,45 @@ jobs:

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
if: ${{ secrets.CODECOV_TOKEN != '' }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

archive-regression:
name: Archive Regression Agent
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Prepare environment
uses: ./.github/actions/prepare
with:
sdk-version: ${{ (github.event_name == 'workflow_call' && inputs.sdk-version) || env.SDK_VERSION }}

- name: Install DCM
uses: CQLabs/setup-dcm@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Run local regression agent script
shell: bash
run: |
bash scripts/local_regression_agent.sh \
--scope archive-only \
--integration false \
--heavy false \
--skip-full-for-archive

- name: Upload regression run artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: archive-regression-${{ github.run_id }}-${{ github.run_attempt }}
path: .context/testing-runs/**
if-no-files-found: warn


test-os:
name: Test on ${{ matrix.os }}
Expand Down Expand Up @@ -155,7 +197,7 @@ jobs:
integration-test:
name: Integration Tests on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
needs: [test, test-os] # Wait for all unit tests before integration
needs: [test, archive-regression, test-os] # Wait for all unit tests before integration
timeout-minutes: 45
# Skip heavy integration tests for the fvm-mcp PR branch (MCP-only changes).
if: github.event_name != 'pull_request' || github.event.pull_request.head.ref != 'fvm-mcp'
Expand Down
147 changes: 147 additions & 0 deletions agents/local-regression-testing-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# FVM Local Regression Testing Agent

## Purpose
This file defines a deterministic local-testing agent workflow for FVM. The agent validates local environment readiness, runs regression checks, and reports pass/fail with evidence.

Primary target: detect regressions in CLI behavior, with archive install behavior treated as mandatory coverage.

## Runtime Model
- This "agent" is command automation only.
- It does not invoke Claude, Codex, or any LLM during execution.
- It runs the scripted shell/Dart commands and reports results from those commands.

## Agent Inputs
- `scope`: `archive-only` or `full-regression`.
- `run_integration`: `true` or `false`.
- `run_heavy`: `true` or `false`.

Default values:
- `scope=archive-only`
- `run_integration=false`
- `run_heavy=false`

## Agent Outputs
- Terminal summary by stage.
- Artifacts written to `.context/testing-runs/<timestamp>/`:
- `env.txt`
- `commands.log`
- `summary.md`
- `failures.md` (if failures occur)

## Hard Rules
- Do not skip required checks.
- Do not use `--no-verify`.
- Stop immediately on blocker failures.
- Log every executed command.
- For expected-failure tests, treat success as failure.

## Execution Stages

### Stage 0: Workspace Guard
Commands:
1. `pwd`
2. `git rev-parse --abbrev-ref HEAD`
3. `git status --short`

Rules:
- Must run from repository root.
- Dirty tree is allowed, but report it in summary.

### Stage A: Environment Preflight (Blocker)
Commands:
1. `dart --version`
2. `git --version`
3. `dart pub get`
4. `which tar` (macOS/Linux)
5. `which unzip` (macOS/Linux)
6. `flutter --version` (optional warning if missing)

Fail if:
- `dart` missing,
- `git` missing,
- `dart pub get` fails,
- archive extraction tools missing for current OS.

### Stage B: Static Quality Gates
Commands:
1. `dart analyze --fatal-infos`
2. `dcm analyze lib`

Fail policy:
- Any failure stops the run.

### Stage C: Archive Regression Target Set
Commands:
1. `dart test test/services/archive_service_test.dart`
2. `dart test test/commands/install_command_test.dart`
3. `dart test test/commands/use_command_test.dart`
4. `dart test test/src/workflows/ensure_cache_ci_test.dart`

Required behavior coverage:
- unsupported archive version types rejected,
- qualifier rules enforced (`@stable` rejected, invalid qualifiers rejected),
- corrupted-cache reinstall preserves archive mode,
- finalize/swap flow is safe.

### Stage D: Full Unit Regression
Command:
1. `dart test`

Rules:
- Always run for `scope=full-regression`.
- For `scope=archive-only`, run unless explicitly skipped by caller.

### Stage E: Integration Suite (Optional)
Condition: `run_integration=true`

Commands:
1. `dart run grinder test-setup`
2. `dart run grinder integration-test`

Rules:
- If skipped, record explicit reason in `summary.md`.

### Stage F: Local Archive CLI Smoke (Optional)
Condition: `run_heavy=true`

Use local source command (not global dependency):
- `dart run bin/main.dart ...`

Positive check:
1. `dart run bin/main.dart install stable --archive --no-setup`

Expected-failure checks:
1. `dart run bin/main.dart install f4c74a6ec3 --archive`
2. `dart run bin/main.dart install 2.2.2@stable --archive`
3. `dart run bin/main.dart use 2.2.2@master --archive --skip-setup --skip-pub-get`

Rules:
- These expected-failure commands must exit non-zero.
- If any exits zero, mark run as failed.

## Reporting Contract
`summary.md` must include:
- input parameters,
- stage-by-stage status,
- first failure (if any),
- shipping recommendation (`safe-to-ship: yes/no`).

`failures.md` must include (for each failure):
- stage,
- command,
- exit code,
- concise stderr excerpt,
- recommended next action.

## Quick Start for Agents
Recommended command:

```bash
scripts/local_regression_agent.sh --scope archive-only --integration false --heavy false
```

Full run:

```bash
scripts/local_regression_agent.sh --scope full-regression --integration true --heavy true
```
19 changes: 17 additions & 2 deletions lib/src/commands/install_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,20 @@ class InstallCommand extends BaseFvmCommand {
help: 'Skip resolving dependencies after switching Flutter SDK',
defaultsTo: false,
negatable: false,
)
..addFlag(
'archive',
help: 'Install from a precompiled archive instead of cloning from git',
defaultsTo: false,
negatable: false,
);
}

@override
Future<int> run() async {
final setup = boolArg('setup');
final skipPubGet = boolArg('skip-pub-get');
final useArchive = boolArg('archive');

final ensureCache = EnsureCacheWorkflow(context);
final useVersion = UseVersionWorkflow(context);
Expand All @@ -60,7 +67,11 @@ class InstallCommand extends BaseFvmCommand {
);
}

final cacheVersion = await ensureCache(version, shouldInstall: true);
final cacheVersion = await ensureCache(
version,
shouldInstall: true,
useArchive: useArchive,
);

await useVersion(
version: cacheVersion,
Expand All @@ -76,7 +87,11 @@ class InstallCommand extends BaseFvmCommand {

final flutterVersion = validateFlutterVersion(version);

final cacheVersion = await ensureCache(flutterVersion, shouldInstall: true);
final cacheVersion = await ensureCache(
flutterVersion,
shouldInstall: true,
useArchive: useArchive,
);

if (setup) {
await setupFlutter(cacheVersion);
Expand Down
13 changes: 12 additions & 1 deletion lib/src/commands/use_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ class UseCommand extends BaseFvmCommand {
abbr: 's',
help: 'Skips downloading SDK dependencies after switching versions',
negatable: false,
)
..addFlag(
'archive',
help: 'Install from a precompiled archive instead of cloning from git',
defaultsTo: false,
negatable: false,
);
}
@override
Expand All @@ -60,6 +66,7 @@ class UseCommand extends BaseFvmCommand {
final skipPubGet = boolArg('skip-pub-get');
final flavorOption = stringArg('flavor');
final skipSetup = boolArg('skip-setup');
final useArchive = boolArg('archive');

String? version;

Expand Down Expand Up @@ -136,7 +143,11 @@ class UseCommand extends BaseFvmCommand {

final flutterVersion = validateFlutterVersion(version);

final cacheVersion = await ensureCache(flutterVersion, force: forceOption);
final cacheVersion = await ensureCache(
flutterVersion,
force: forceOption,
useArchive: useArchive,
);

/// Run use workflow
await useVersion(
Expand Down
Loading