Skip to content
Closed
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
11 changes: 11 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# actionlint 1.7.12 does not know these newer workflow features yet:
# `cache-mode` (rhysd/actionlint#745), the concurrency `queue` (#657), the
# `$/` reference to a reusable workflow in the same repository (#711) and the
# `job.workflow_*` context properties.
paths:
.github/workflows/**/*.{yml,yaml}:
ignore:
- 'unexpected key "cache-mode" for "(workflow|job)" section'
- 'unexpected key "queue" for "concurrency" section'
- 'reusable workflow call "\$/\.github/workflows/[^"]+" at "uses" is not following the format'
- 'property "workflow_(repository|sha)" is not defined in object type'
4 changes: 4 additions & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
$schema: 'https://docs.renovatebot.com/renovate-schema.json',
extends: ['config:recommended'],
}
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI

# Lints the workflows and runs the store scripts against local mocks of the
# store APIs.

on:
pull_request:
push:
branches: [main]
workflow_dispatch:

permissions: {}

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

jobs:
lint:
name: Lint
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read # clone the repository
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # gitleaks scans the full history
persist-credentials: false
- uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1
with:
cache_save: ${{ github.ref_name == github.event.repository.default_branch }}
- run: mise run lint

test:
name: Store scripts
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read # clone the repository
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- run: python3 -m unittest discover -s tests -t . -v
163 changes: 163 additions & 0 deletions .github/workflows/flutter-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
name: Flutter CI

# Reusable: lint, test and build a Flutter app on every push and pull request.
# The calling repository provides the mise tasks of the task contract (see
# README.md): check, build:apk, build:web, and codegen / build:ios if those
# inputs are on.

on:
workflow_call:
inputs:
app-dir:
description: Directory of the Flutter app (the one with pubspec.yaml), relative to the repository root.
type: string
default: .
mise-version:
description: The mise version to install; empty (the default) installs the newest release.
type: string
default: ""
codegen:
description: Run `mise run codegen` and fail if it changes anything in the app's lib/ (generated code that was not committed).
type: boolean
default: false
android:
description: Build the release APKs (`mise run build:apk`) and keep them as a workflow artifact.
type: boolean
default: true
web:
description: Build the web app (`mise run build:web`).
type: boolean
default: true
ios:
description: Build the iOS app without code signing (`mise run build:ios`) on macOS. macOS minutes count ten times on private repositories.
type: boolean
default: false
macos-runner:
description: Runner label of the iOS build.
type: string
default: macos-26
xcode-version:
description: Xcode version of the iOS build, as installed on the runner (/Applications/Xcode_<version>.app).
type: string
default: "26.6"

permissions: {}

env:
# The Android build uses the runner's preinstalled Android SDK (licenses
# accepted), so a mise android-sdk tool is never installed here.
MISE_DISABLE_TOOLS: android-sdk

jobs:
check:
name: Lint and test
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read # clone the repository
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # secret scanners such as gitleaks read the full history
persist-credentials: false
- uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1
with:
version: ${{ inputs.mise-version }}
# The toolchain entry is large (Flutter is about 1.7 GB): save it from
# the default branch only, so pull requests reuse it.
cache_save: ${{ github.ref_name == github.event.repository.default_branch }}
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.pub-cache
key: pub-${{ runner.os }}-${{ hashFiles(format('{0}/pubspec.lock', inputs.app-dir)) }}
- name: Lint and test
run: mise run check
- if: ${{ inputs.codegen }}
name: Check that generated code is up to date
env:
APP_DIR: ${{ inputs.app-dir }}
run: |
mise run codegen
git diff --exit-code -- "$APP_DIR/lib"

build-android:
name: Build Android
needs: check
if: ${{ inputs.android }}
runs-on: ubuntu-24.04
timeout-minutes: 45
permissions:
contents: read # clone the repository
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1
with:
version: ${{ inputs.mise-version }}
cache_save: ${{ github.ref_name == github.event.repository.default_branch }}
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.pub-cache
key: pub-${{ runner.os }}-${{ hashFiles(format('{0}/pubspec.lock', inputs.app-dir)) }}
- uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0
with:
cache-provider: basic
# Without signing secrets the app's release build has to fall back to a
# debug or unsigned key (see README.md, "Task contract").
- name: Build release APKs
run: mise run build:apk
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: apk
path: ${{ inputs.app-dir }}/build/app/outputs/flutter-apk/*.apk
retention-days: 7
if-no-files-found: error

build-web:
name: Build web
needs: check
if: ${{ inputs.web }}
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read # clone the repository
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1
with:
version: ${{ inputs.mise-version }}
cache_save: ${{ github.ref_name == github.event.repository.default_branch }}
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.pub-cache
key: pub-${{ runner.os }}-${{ hashFiles(format('{0}/pubspec.lock', inputs.app-dir)) }}
- name: Build web
run: mise run build:web

build-ios:
name: Build iOS
needs: check
if: ${{ inputs.ios }}
runs-on: ${{ inputs.macos-runner }}
timeout-minutes: 60
permissions:
contents: read # clone the repository
env:
DEVELOPER_DIR: /Applications/Xcode_${{ inputs.xcode-version }}.app/Contents/Developer
# Only Flutter is needed.
MISE_ENABLE_TOOLS: flutter
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@7a4e45a543138629540c9a1616d08632b893e492 # v5.0.1
with:
version: ${{ inputs.mise-version }}
# The macOS toolchain would be another large cache entry; iOS builds
# are optional and rare.
cache: false
- name: Build iOS without code signing
run: mise run build:ios
87 changes: 87 additions & 0 deletions .github/workflows/flutter-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Flutter web on GitHub Pages

# Reusable: serve the newest release's web build at the site root and the
# newest release of any kind, usually a pre-release, under /beta/. It uses the
# <prefix>-<tag>-web.zip assets that flutter-release.yml attaches to the
# releases, and drops the BETA badge (see README.md, "Task contract") from the
# root. flutter-release.yml calls it; call it from a workflow_dispatch workflow
# to redeploy by hand.
#
# Enable Pages with "Source: GitHub Actions", then allow the release tags to
# deploy: release runs use their tag as the ref, and the github-pages
# environment only admits the default branch at first (Settings > Environments
# > github-pages > Deployment branches and tags > add the tag rule "*").

on:
workflow_call:

permissions: {}

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
name: Assemble the site
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read # read the releases and their web builds
pages: read # configure-pages reads the site's base path
steps:
- id: pages
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- name: Download the web builds
env:
GH_TOKEN: ${{ github.token }}
BASE_PATH: ${{ steps.pages.outputs.base_path }}
run: |
# Releases with a web build, newest first, as "<tag> <prerelease>".
gh api --paginate "repos/$GITHUB_REPOSITORY/releases" --jq '.[]
| select((.draft | not) and any(.assets[]; .name | endswith("-web.zip")))
| "\(.tag_name) \(.prerelease)"' > releases.txt
beta=$(awk 'NR == 1 { print $1 }' releases.txt)
prod=$(awk '$2 == "false" { print $1; exit }' releases.txt)
if [ -z "$beta" ]; then
echo "::error::No release has a web build yet."
exit 1
fi
# The web builds are made for "/"; point them at their path on the site.
unpack() {
mkdir -p "$2"
gh release download "$1" --repo "$GITHUB_REPOSITORY" \
--pattern '*-web.zip' --output web.zip --clobber
unzip -q web.zip -d "$2"
rm web.zip
sed -i "s|<base href=\"/\">|<base href=\"$3\">|" "$2/index.html"
}
if [ -n "$prod" ]; then
unpack "$prod" _site "${BASE_PATH}/"
# A promoted beta was built with the BETA badge; production has none.
sed -i '/<!-- beta-badge/,/<!-- \/beta-badge -->/d' _site/index.html
else
mkdir _site
echo '<!DOCTYPE html><meta http-equiv="refresh" content="0; url=beta/">' \
> _site/index.html
fi
unpack "$beta" _site/beta "${BASE_PATH}/beta/"
echo "Production: ${prod:-none}, beta: $beta" >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: _site

deploy:
name: Deploy
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
pages: write # publish the site
id-token: write # authenticate the Pages deployment (OIDC)
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
Loading