Flutter Package CI/CD Pipeline
Reusable pipeline pattern distilled from bloc, riverpod, Very Good Workflows, and flutter/packages, validated on production packages.
When to use
- New Flutter/Dart library (pub package) needs GitHub Actions
- Existing package CI needs audit, DRY refactor, or release automation
- User asks for pub.dev publish automation, Dependabot, or package quality gates
Quick start (new project)
- Profile the project — fill project-profile.md
- Copy scaffold — create
.github/actions/ + .github/workflows/ per profile toggles
- Customize placeholders — package name, repo, paths, optional jobs
- Validate locally —
dart format, flutter analyze, flutter test, flutter pub publish --dry-run, pana .
- Configure pub.dev OIDC — one-time admin setup (see reference.md)
- Enable Dependabot —
.github/dependabot.yml with project's pub workspaces
Architecture
Pull Request ─┬─ semantic-pr.yml (PR title convention)
├─ pr-tests.yml (multi-OS lint + test + dry-run)
├─ release-gate.yml (main-target PR: version/changelog/pana)
├─ check-generation.yml (optional: codegen drift)
└─ project-specific.yml (benchmarks, migration, docs)
Push main ────┬─ ci-main.yml (lint → test → publish dry-run)
└─ check-generation.yml
Push tag v* ──┬─ release-tags.yml
│ ├─ release-gate (validate)
│ ├─ publish (OIDC → pub.dev)
│ └─ github-release (optional CLI artifacts)
Schedule ─────┬─ nightly.yml
└─ dependabot.yml (weekly PRs)
Composite actions (DRY core)
Always prefer composite actions over duplicated workflow steps.
| Action |
Purpose |
setup-flutter |
Flutter SDK + pub get for root and optional workspaces |
package-hygiene |
README, LICENSE/NOTICE, license_checker, changelog-on-bump |
flutter-package-checks |
dart format, flutter analyze, flutter test (+ random seed) |
pana-score |
pub.dev quality gate (default min 130/160) |
coverage-report |
lcov summary, JUnit from machine report, artifacts |
Scaffold copies: reference.md
Workflow inventory
| Workflow |
Trigger |
Required? |
Notes |
ci-main.yml |
push main |
Yes |
paths-ignore for docs-only changes |
pr-tests.yml |
all PRs |
Yes |
OS matrix: ubuntu, macos, windows |
semantic-pr.yml |
PR events |
Recommended |
Conventional PR titles |
release-gate.yml |
PR → main |
Yes for publishable packages |
Strict changelog + smoke checks |
release-tags.yml |
tag v*.*.* |
Yes if publishing |
3 jobs: validate → publish → GH release |
check-generation.yml |
path-filtered |
If codegen committed |
generate && git diff --exit-code |
dependabot.yml |
weekly |
Recommended |
pub + github-actions |
nightly.yml |
cron |
Optional |
Full suite + benchmarks |
github-pages.yml |
push/PR |
Optional |
MkDocs or static docs |
Project adaptation checklist
Before generating files, determine:
Project profile:
- [ ] Package name and README usage grep pattern
- [ ] Default branch (main/master)
- [ ] Workspaces: example/, tool/*, packages/* (list paths)
- [ ] Has committed generated code? → check-generation.yml
- [ ] Has CLI binaries for GitHub Release? → release artifact step
- [ ] Has custom smoke tests? → release-gate generator step
- [ ] License checker config path (or disable)
- [ ] Min pana score (run `pana .` first)
- [ ] Docs site (MkDocs) → github-pages.yml
- [ ] Monorepo? → use melos/paths-filter instead of single-package actions
Full template: project-profile.md
Adaptation rules
Package name in hygiene checks
Replace README usage awk pattern with project identifiers:
# Example for package "my_package":
$0 ~ /(my_package|MyPackage)/
setup-flutter workspaces
Add install_<workspace> inputs for each extra pubspec.yaml (example, tool apps). Remove unused inputs in consuming workflows.
Multi-OS PR matrix
Run expensive checks (lychee, dart doc, pana) on ubuntu-latest only. Format/analyze on all OSes to catch path issues.
Release tag pattern
Must match pub.dev OIDC config:
- Git tag:
v0.1.0
- pubspec:
version: 0.1.0
- pub.dev tag pattern:
v{{version}}
OIDC publish constraints
- Publish job only on tag push (not
workflow_dispatch, not branch push)
- Job needs
permissions: id-token: write
- Use official
dart-lang/setup-dart/.github/workflows/publish.yml@v1
Dependabot pub directories
List every directory with its own pubspec.yaml. Root library packages typically omit pubspec.lock; Dependabot still works on pubspec.yaml.
Optional: approval gate before publish
Add environment: pub.dev to publish job and configure matching environment on pub.dev admin + GitHub repo settings.
Implementation workflow for the agent
When user asks to set up or port this pipeline:
- Read target project:
pubspec.yaml, example/, tool/, existing .github/, CHANGELOG.md, .pubignore
- Fill project profile (ask user for repo owner/name if unclear)
- Create composite actions first (stable foundation)
- Create workflows from smallest to largest:
semantic-pr → ci-main → pr-tests → release-gate → release-tags → dependabot
- Add optional workflows only if profile flags them
- Run local gates:
dart analyze, flutter test, pana ., flutter pub publish --dry-run
- Document pub.dev OIDC setup in
CONTRIBUTING.md (brief section)
Patterns from famous packages
| Source |
Pattern adopted |
| bloc |
Composite actions, semantic PR, pana gate, test randomization |
| riverpod |
paths-ignore for markdown, separate codegen drift workflow |
| Very Good Workflows |
Reusable job structure, coverage artifacts |
| flutter/packages |
OIDC publish, Dependabot for pub + actions |
| dart.dev |
dart-lang/setup-dart publish workflow, no long-lived secrets |
Anti-patterns
- Do not put
dart pub publish in a branch-triggered workflow (OIDC fails)
- Do not duplicate 50-line hygiene blocks across workflows — use composites
- Do not require
pubspec.lock in library root packages
- Do not ship
doc/api/ to pub.dev — exclude via .pubignore, generate in CI before dry-run
- Do not use
workflow_dispatch for production publish
Install
# This skill only
curl -fsSL https://raw.githubusercontent.com/Melsaeed276/cursor-skills/main/skills/flutter-package-ci-pipeline/install.sh | bash
# Or via root installer
curl -fsSL https://raw.githubusercontent.com/Melsaeed276/cursor-skills/main/scripts/install.sh | bash -s -- flutter-package-ci-pipeline
Then invoke: "Use the flutter-package-ci-pipeline skill to set up CI for this project."
Additional resources
1---2name: flutter-package-ci-pipeline3description: Design, scaffold, audit, and adapt GitHub Actions CI/CD for Flutter/Dart pub packages — composite actions, PR/main/release workflows, OIDC pub publish, Dependabot, semantic PRs, codegen drift checks, pana gates. Use when setting up or improving package pipelines, GitHub Actions, release automation, or copying CI patterns to a new Flutter/Dart library project.4---56# Flutter Package CI/CD Pipeline78Reusable pipeline pattern distilled from **bloc**, **riverpod**, **Very Good Workflows**, and **flutter/packages**, validated on production packages.910## When to use1112- New Flutter/Dart **library** (pub package) needs GitHub Actions13- Existing package CI needs audit, DRY refactor, or release automation14- User asks for pub.dev publish automation, Dependabot, or package quality gates1516## Quick start (new project)17181. **Profile the project** — fill [project-profile.md](project-profile.md)192. **Copy scaffold** — create `.github/actions/` + `.github/workflows/` per profile toggles203. **Customize placeholders** — package name, repo, paths, optional jobs214. **Validate locally** — `dart format`, `flutter analyze`, `flutter test`, `flutter pub publish --dry-run`, `pana .`225. **Configure pub.dev OIDC** — one-time admin setup (see [reference.md](reference.md#pubdev-oidc-setup))236. **Enable Dependabot** — `.github/dependabot.yml` with project's pub workspaces2425## Architecture2627```28Pull Request ─┬─ semantic-pr.yml (PR title convention)29 ├─ pr-tests.yml (multi-OS lint + test + dry-run)30 ├─ release-gate.yml (main-target PR: version/changelog/pana)31 ├─ check-generation.yml (optional: codegen drift)32 └─ project-specific.yml (benchmarks, migration, docs)3334Push main ────┬─ ci-main.yml (lint → test → publish dry-run)35 └─ check-generation.yml3637Push tag v* ──┬─ release-tags.yml38 │ ├─ release-gate (validate)39 │ ├─ publish (OIDC → pub.dev)40 │ └─ github-release (optional CLI artifacts)4142Schedule ─────┬─ nightly.yml43 └─ dependabot.yml (weekly PRs)44```4546## Composite actions (DRY core)4748Always prefer composite actions over duplicated workflow steps.4950| Action | Purpose |51|--------|---------|52| `setup-flutter` | Flutter SDK + `pub get` for root and optional workspaces |53| `package-hygiene` | README, LICENSE/NOTICE, license_checker, changelog-on-bump |54| `flutter-package-checks` | `dart format`, `flutter analyze`, `flutter test` (+ random seed) |55| `pana-score` | pub.dev quality gate (default min 130/160) |56| `coverage-report` | lcov summary, JUnit from machine report, artifacts |5758Scaffold copies: [reference.md](reference.md#composite-action-templates)5960## Workflow inventory6162| Workflow | Trigger | Required? | Notes |63|----------|---------|-----------|-------|64| `ci-main.yml` | push `main` | Yes | `paths-ignore` for docs-only changes |65| `pr-tests.yml` | all PRs | Yes | OS matrix: ubuntu, macos, windows |66| `semantic-pr.yml` | PR events | Recommended | Conventional PR titles |67| `release-gate.yml` | PR → `main` | Yes for publishable packages | Strict changelog + smoke checks |68| `release-tags.yml` | tag `v*.*.*` | Yes if publishing | 3 jobs: validate → publish → GH release |69| `check-generation.yml` | path-filtered | If codegen committed | `generate && git diff --exit-code` |70| `dependabot.yml` | weekly | Recommended | pub + github-actions |71| `nightly.yml` | cron | Optional | Full suite + benchmarks |72| `github-pages.yml` | push/PR | Optional | MkDocs or static docs |7374## Project adaptation checklist7576Before generating files, determine:7778```79Project profile:80- [ ] Package name and README usage grep pattern81- [ ] Default branch (main/master)82- [ ] Workspaces: example/, tool/*, packages/* (list paths)83- [ ] Has committed generated code? → check-generation.yml84- [ ] Has CLI binaries for GitHub Release? → release artifact step85- [ ] Has custom smoke tests? → release-gate generator step86- [ ] License checker config path (or disable)87- [ ] Min pana score (run `pana .` first)88- [ ] Docs site (MkDocs) → github-pages.yml89- [ ] Monorepo? → use melos/paths-filter instead of single-package actions90```9192Full template: [project-profile.md](project-profile.md)9394## Adaptation rules9596### Package name in hygiene checks9798Replace README usage awk pattern with project identifiers:99100```bash101# Example for package "my_package":102$0 ~ /(my_package|MyPackage)/103```104105### setup-flutter workspaces106107Add `install_<workspace>` inputs for each extra `pubspec.yaml` (example, tool apps). Remove unused inputs in consuming workflows.108109### Multi-OS PR matrix110111Run expensive checks (lychee, `dart doc`, pana) on `ubuntu-latest` only. Format/analyze on all OSes to catch path issues.112113### Release tag pattern114115Must match pub.dev OIDC config:116117- Git tag: `v0.1.0`118- pubspec: `version: 0.1.0`119- pub.dev tag pattern: `v{{version}}`120121### OIDC publish constraints122123- Publish job **only** on tag push (not `workflow_dispatch`, not branch push)124- Job needs `permissions: id-token: write`125- Use official `dart-lang/setup-dart/.github/workflows/publish.yml@v1`126127### Dependabot pub directories128129List every directory with its own `pubspec.yaml`. Root library packages typically **omit** `pubspec.lock`; Dependabot still works on `pubspec.yaml`.130131### Optional: approval gate before publish132133Add `environment: pub.dev` to publish job and configure matching environment on pub.dev admin + GitHub repo settings.134135## Implementation workflow for the agent136137When user asks to set up or port this pipeline:1381391. Read target project: `pubspec.yaml`, `example/`, `tool/`, existing `.github/`, `CHANGELOG.md`, `.pubignore`1402. Fill project profile (ask user for repo owner/name if unclear)1413. Create composite actions first (stable foundation)1424. Create workflows from smallest to largest: `semantic-pr` → `ci-main` → `pr-tests` → `release-gate` → `release-tags` → `dependabot`1435. Add optional workflows only if profile flags them1446. Run local gates: `dart analyze`, `flutter test`, `pana .`, `flutter pub publish --dry-run`1457. Document pub.dev OIDC setup in `CONTRIBUTING.md` (brief section)146147## Patterns from famous packages148149| Source | Pattern adopted |150|--------|-----------------|151| bloc | Composite actions, semantic PR, pana gate, test randomization |152| riverpod | `paths-ignore` for markdown, separate codegen drift workflow |153| Very Good Workflows | Reusable job structure, coverage artifacts |154| flutter/packages | OIDC publish, Dependabot for pub + actions |155| dart.dev | `dart-lang/setup-dart` publish workflow, no long-lived secrets |156157## Anti-patterns158159- Do **not** put `dart pub publish` in a branch-triggered workflow (OIDC fails)160- Do **not** duplicate 50-line hygiene blocks across workflows — use composites161- Do **not** require `pubspec.lock` in library root packages162- Do **not** ship `doc/api/` to pub.dev — exclude via `.pubignore`, generate in CI before dry-run163- Do **not** use `workflow_dispatch` for production publish164165## Install166167```bash168# This skill only169curl -fsSL https://raw.githubusercontent.com/Melsaeed276/cursor-skills/main/skills/flutter-package-ci-pipeline/install.sh | bash170171# Or via root installer172curl -fsSL https://raw.githubusercontent.com/Melsaeed276/cursor-skills/main/scripts/install.sh | bash -s -- flutter-package-ci-pipeline173```174175Then invoke: *"Use the flutter-package-ci-pipeline skill to set up CI for this project."*176177## Additional resources178179- Composite action + workflow templates: [reference.md](reference.md)180- Per-project customization form: [project-profile.md](project-profile.md)181- Reference implementation: [anas_localization `.github/`](https://github.com/Melsaeed276/anas_localization/tree/main/.github)182- Skills collection: [github.com/Melsaeed276/cursor-skills](https://github.com/Melsaeed276/cursor-skills)