Skip to content
Open
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
170 changes: 170 additions & 0 deletions .github/workflows/flutter-build-and-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
---
name: Format, Build & Test Flutter app

#
# Format, build, analyze & test a Flutter application
# Note: will create artifacts for generated code and coverage reports.
#

on:
workflow_call:
inputs:
build-timeout:
description: Time (in minutes) after which the test job will timeout
default: 5
type: number
test-timeout:
description: Time (in minutes) after which the test job will timeout
default: 5
type: number
test-coverage:
description: Minimum test coverage required (defaults to 0)
default: 0
type: number
skip-formatting:
description: Skip formatting check (defaults to false)
default: false
type: boolean
skip-reporting:
description: Skip reporting coverage to Codecov (defaults to false)
default: false
type: boolean

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
verify-formatting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- name: Run flutter pub get
run: flutter pub get
- name: Verify formatting
if: ${{ !inputs.skip-formatting }}
run: dart format . --set-exit-if-changed
- name: Generate intl
run: |
dart pub global activate intl_utils
dart pub global run intl_utils:generate
- name: Upload generated code
uses: actions/upload-artifact@v4
with:
name: intl
path: lib/generated

generate-matrix:
name: Generate job matrices
runs-on: ubuntu-latest
outputs:
deployments: ${{ steps.changed-paths-filter.outputs.matrix }}
steps:
- name: Generate Matrix
id: changed-paths-filter
uses: wisemen-digital/devops-ga-changed-paths-filter@main
with:
filter-file: .github/package-filters.yaml

generate-code:
needs: [generate-matrix, verify-formatting]
runs-on: ubuntu-latest
timeout-minutes: ${{ inputs.build-timeout }}
strategy:
matrix:
deployment: ${{ fromJson(needs.generate-matrix.outputs.deployments) }}
steps:
- uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- name: Run flutter pub get
run: flutter pub get
- name: Generate ${{ matrix.deployment.path }} code
working-directory: ${{ matrix.deployment.path == '.' && './' || format('packages/{0}', matrix.deployment.path) }}
run: |
if grep -q "build_runner" pubspec.yaml; then
dart pub run build_runner build -d
fi
- name: Upload generated code
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.deployment.path == '.' && 'app-lib' || matrix.deployment.path }}
path: ${{ matrix.deployment.path == '.' && 'lib' || format('packages/{0}', matrix.deployment.path) }}

merge:
runs-on: ubuntu-latest
needs: [generate-code]
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
with:
name: merged-artifacts
delete-merged: true
separate-directories: true

test:
needs: [generate-matrix, generate-code, merge]
runs-on: ubuntu-latest
timeout-minutes: ${{ inputs.test-timeout }}
strategy:
matrix:
deployment: ${{ fromJson(needs.generate-matrix.outputs.deployments) }}
if: ${{ needs.generate-matrix.outputs.deployments != '[]' }}
env:
WORKING_DIRECTORY: ${{ matrix.deployment.path == '.' && './' || format('packages/{0}', matrix.deployment.path) }}
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: merged-artifacts
path: tmp-artifacts
- name: Move artifacts
shell: bash
run: |
rsync -a --ignore-existing --remove-source-files tmp-artifacts/app-lib/* lib
rm -rf tmp-artifacts/app-lib/
rsync -a --ignore-existing --remove-source-files tmp-artifacts/intl/* lib/generated
rm -rf tmp-artifacts/intl/
for package in ./tmp-artifacts/*; do
packageName=$(basename "$package")
if [ -d "$package" ]; then
rsync -a --ignore-existing --remove-source-files "$package/" "packages/$packageName/"
fi
done
rm -rf tmp-artifacts/
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- name: Run flutter pub get
run: flutter pub get
- name: Analyze project source
shell: bash
working-directory: ${{ env.WORKING_DIRECTORY }}
run: dart analyze --fatal-infos --fatal-warnings
- name: Run Flutter ${{ matrix.deployment.path }} tests
shell: bash
working-directory: ${{ env.WORKING_DIRECTORY }}
run: flutter test --no-pub --coverage
- name: Setup LCOV
uses: hrishikesh-kadam/setup-lcov@v1

- name: Report code coverage
uses: zgosalvez/github-actions-report-lcov@v7.0.2
if: ${{ !inputs.skip-reporting }}
with:
coverage-files: ${{ env.WORKING_DIRECTORY }}/coverage/lcov.info
minimum-coverage: ${{ env.WORKING_DIRECTORY }}/${{ inputs.test-coverage }}
github-token: ${{ secrets.GITHUB_TOKEN }}
working-directory: ${{ env.WORKING_DIRECTORY }}
artifact-name: ${{ matrix.deployment.path }}-coverage
39 changes: 39 additions & 0 deletions Docs/flutter-build-and-test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Workflow: flutter build & test

## Description

This workflow will format, build, analyze & test a Flutter application.

### Verify-formatting

This job runs a dart format command that uses formatting rules from `analysis_options.yaml`

### Generate-matrix

This requires a `package-filters.yaml` file in the `.github` folder of the repository. Generates a matrix for the listed options so the next steps can run async.

The root app has to be defined as `.`

### Generate-code

Uses dart build runner to generate code used by packages. Creates artifacts that are combined in the next job.

### Merge

Merge generated artifacts because test job needs all generated code to be compilable.

### Test

Fixes artifact paths and runs tests with coverage. This job requires at least one test to be able to report coverage.

## Inputs

| Input | Description |
| ----- | ----------- |
| `build-timeout` | Time in minutes after which the generate-code job will timeout (defaults to `5`) |
| `test-timeout` | Time in minutes after which the test job will timeout (defaults to `5`) |
| `test-coverage` | Minimum required code coverage for test step to pass (defaults to `0`) |

## Outputs

The build job will generate an artifact with the contents of the `dist` and `_build` folders.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Verification (PR check):
| [node-build-and-test.yml](Docs/node-build-and-test.md) | Lint, build & test a Node app |
| [nuxt-build-and-test.yml](Docs/nuxt-build-and-test.md) | Lint, build & test a Nuxt app |
| [web-build-and-test.yml](Docs/web-build-and-test.md) | Lint, build & test a Web app |
| [flutter-build-and-test.yml](Docs/web-build-and-test.md) | Lint, build, analyze & test a Flutter app |

## Infra Workflows

Expand Down
Loading