Flatter is a GitHub Action for building and hosting a Flatpak repository in a static hosting environment, such as GitHub Pages.
The action uses flatpak
and flatpak-builder
to build, sign and export
Flatpak applications as a repository and bundles. It includes built-in caching
to speed up builds and support an incrementally updated repository.
This action is ideal for low-traffic use cases, such as a nightly or development build repository for a small project. For high-traffic use cases, see Flathub instead, which also has a beta channel.
name: Flatter
on:
# Rebuild once a day
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
flatter:
name: Flatter
runs-on: ubuntu-latest
container:
image: ghcr.io/andyholmes/flatter/gnome:46
options: --privileged
strategy:
matrix:
arch: [x86_64, aarch64]
fail-fast: false
# Only one job at a time can use the shared repository cache
max-parallel: 1
steps:
# Checkout a repository with Flatpak manifests
- name: Checkout
uses: actions/checkout@v3
# See "Multiple Architectures" below
- name: Setup QEMU
if: ${{ matrix.arch == 'aarch64' }}
id: qemu
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
# See "GPG Signing" below
- name: Setup GPG
id: gpg
uses: crazy-max/ghaction-import-gpg@v5
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
# Generate a CNAME file on-the-fly for a configured host
- name: Generate CNAME
run: |
echo "flatter.andyholmes.ca" > CNAME
- name: Build
uses: andyholmes/flatter@main
with:
files: |
build-aux/flatpak/com.example.App.json
arch: ${{ matrix.arch }}
gpg-sign: ${{ steps.gpg.outputs.fingerprint }}
upload-bundles: true
upload-pages-artifact: ${{ matrix.arch == 'aarch64' }}
upload-pages-includes: |
CNAME
default.css
index.html
# See "Github Pages" below
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: flatter
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
The only required input is files
, which should be a list of paths to Flatpak
manifests (JSON or YAML) to build.
Name | Default | Description |
---|---|---|
files |
None | A list of paths to Flatpak manifests |
arch |
x86_64 |
The architecture to build for |
gpg-sign |
None | A GPG Key fingerprint |
cache-key |
flatter |
A cache key, or '' to disable |
The files
input may be either a single-line or multi-line string value:
# One manifest
files: one.manifestFile.json
# One or more manifests
files: |
one.manifest.File.json
two.manifest.File.yml
The arch
input must be set if building for a non-x86-64
architecture, like
aarch64
. See Multiple Architectures for more
information.
The gpg-sign
input corresponds to the --gpg-sign
command-line option and
should be a GPG key fingerprint. See GPG Signing for more
information.
The cache-key
input is used as a base to generate cache keys for the
repository and build directories. The key can be rotated if the repository
becomes too large or needs to be reset for some other reason.
For more information about deploying Flatter, see Deployment.
Name | Default | Description |
---|---|---|
upload-bundles |
false |
Upload a bundle for each application |
upload-pages-artifact |
false |
Upload the repo for GitHub Pages |
upload-pages-includes |
None | Files to include in GitHub Pages |
The upload-bundles
input controls whether a Flatpak bundle will be uploaded
when an application is built. See Flatpak Bundles for more
information.
The upload-pages-artifact
input controls whether the repository will be
uploaded as a GitHub Pages artifact. See GitHub Pages for more
information.
The upload-pages-includes
input allows including additional files in the GitHub Pages
artifact, such as a index.html
. See GitHub Pages for more
information.
Flatter supports an opinionated test runner, dynamically rewriting Flatpak manifests to accommodate a testing environment, including a D-Bus session and X11 server. The intention is that a Flatpak manifest can be passed for testing in a CI, then passed for distribution as a nightly build if successful.
Name | Default | Description |
---|---|---|
run-tests |
false |
Override for the manifest's value |
test-config-opts |
None | Options for meson setup |
test-modules |
None | Manifest of test dependencies |
The run-tests
input overrides the manifest field of the same name, instructing
flatpak-builder
to run ninja test
once the project is built. If this input
is true
, the repository cache will not be used.
The test-config-opts
input is a list of extra options to pass to meson setup
for the target application, used for options like -Dtests=true
.
The test-modules
input is a path to a manifest of extra dependencies, relative
to the application manifest. This is a convenient way to keep test dependencies
separate from release dependencies.
For advanced use cases, extra command-line options can be passed to flatpak
and flatpak-builder
.
Name | Default | Description |
---|---|---|
flatpak-builder-args |
None | Options for flatpak-builder |
flatpak-build-bundle-args |
None | Options for flatpak build-bundle |
The flatpak-builder-args
input is a multi-line string of options to pass to
flatpak-builder
:
flatpak-builder-args: |
--default-branch=nightly
--skip-if-unchanged
The following options are set internally for flatpak-builder
:
--arch
--ccache
--disable-rofiles-fuse
--force-clean
--gpg-sign
--repo
--state-dir
The flatpak-build-bundle-args
input is a multi-line string of options to pass
to flatpak build-bundle
:
flatpak-build-bundle-args: |
--runtime-repo=https://platform.io/platform.flatpakrepo
The following options are set internally for flatpak build-bundle
:
--arch
--gpg-sign
The only output is repository
, currently.
Name | Description |
---|---|
repository |
Absolute path to the Flatpak repository |
The repository
output is an absolute path to the repository directory,
corresponding to the --repo
command-line option.
Feel free to open pull request for additional runtimes
Flatter provides containers with pre-installed runtimes for several platforms,
built from the base Dockerfile
:
Image Name | Version Tags | Architectures |
---|---|---|
freedesktop |
22.08 , 23.08 |
x86_64 , aarch64 |
rust |
23.08 , nightly |
x86_64 , aarch64 |
elementary |
juno-22.08 |
x86_64 |
gnome |
45 , 46 , master |
x86_64 , aarch64 |
gnome-rust |
45 , 46 |
x86_64 , aarch64 |
gnome-typescript |
46 |
x86_64 , aarch64 |
gnome-vala |
46 |
x86_64 , aarch64 |
workbench 1 |
master |
x86_64 , aarch64 |
kde |
5.15-23.08 |
x86_64 , aarch64 |
1 This is custom container for Workbench, based on GNOME Nightly with many language extensions installed by default.
Containers are referenced in the form ghcr.io/andyholmes/flatter/<image>:<tag>
,
such as ghcr.io/andyholmes/flatter/gnome:46
:
name: Flatter
on:
# Rebuild once a day
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
flatter:
name: Flatter
runs-on: ubuntu-latest
container:
image: ghcr.io/andyholmes/flatter/gnome:46
options: --privileged
Flatter supports signing the repository and bundles with GPG. First generate a GPG key for your repository:
mkdir flatter
gpg2 --homedir flatter --quick-gen-key username@github.io
Export the private key, then add the key and passphrase as GitHub Action secrets
(e.g. GPG_PRIVATE_KEY
and GPG_PASSPHRASE
):
gpg2 --homedir flatter --armor --export-secret-key username@github.io
crazy-max/ghaction-import-gpg
can be used to easily import and
preset the passphrase for signing:
name: Flatter (Signed)
on:
# Rebuild once a day
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
flatter:
name: Flatter
runs-on: ubuntu-latest
container:
image: ghcr.io/andyholmes/flatter/gnome:46
options: --privileged
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup GPG
id: gpg
uses: crazy-max/ghaction-import-gpg@v5
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Build
uses: andyholmes/actions/flatter@main
with:
files: |
build-aux/flatpak/com.example.App.json
gpg-sign: ${{ steps.gpg.outputs.fingerprint }}
Flatpak repositories generated by flatpak-builder
are deployable as static
assets, so deployment is quite flexible.
For each manifest built, Flatter can bundle and upload the application as a job
artifact. The artifacts are consistently named in the form
<application-id>-<architecture>
(e.g. com.example.App-x86_64
).
Set the upload-bundles
input to true
and together with
nightly.link, you can get static links to the most
recent Flatpak bundle built by Flatter.
Flatter can upload the repository as an artifact compatible with GitHub Pages,
making the pages for the GitHub repository a Flatpak Repository. Flutter will
generate an index.flatpakrepo
file in the repository directory and other files
can be added with the upload-pages-includes
input (e.g.index.html
).
- Set the
upload-pages-artifact
input totrue
- In the Settings for the GitHub repository, select Pages in the sidebar and set Source to "GitHub Pages"
- Add a job with
actions/deploy-pages
to the workflow
name: Flatter (GitHub Pages)
on:
# Rebuild once a day
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
flatter:
name: Flatter
runs-on: ubuntu-latest
container:
image: ghcr.io/andyholmes/flatter/gnome:46
options: --privileged
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Build
uses: andyholmes/actions/flatter@main
with:
files: |
build-aux/flatpak/com.example.App.json
upload-pages-artifact: true
upload-pages-includes: |
default.css
index.html
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: flatter
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
The Flatpak repository directory can also be deployed with another action, such
as JamesIves/github-pages-deploy-action
. The example below
triggers a GitHub Pages deployment by committing the Flatpak repository to the
gh-pages
branch as the subfolder /repo
:
name: Flatter (Deploy)
on:
push:
branches: [main]
workflow_dispatch:
jobs:
flatter:
name: Flatter
runs-on: ubuntu-latest
container:
image: ghcr.io/andyholmes/flatter/gnome:46
options: --privileged
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Build
id: flatpak
uses: andyholmes/actions/flatter@main
with:
files: |
build-aux/flatpak/com.example.App.json
- name: Deploy Repository
uses: JamesIves/github-pages-deploy-action@releases/v4
with:
folder: ${{ steps.flatpak.outputs.repository }}
target-folder: repo
Flatter support building repositories with multiple architectures, such as
x86_64
for desktop and aarch64
for mobile devices.
Multiple architectures can be built in a job matrix or by adding
more jobs, but must not run concurrently if they share a repository directory.
Either use max-parallel
with matrix
or use a
concurrency
group.
name: Flatter
on:
# Rebuild once a day
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
flatter:
name: Flatter
runs-on: ubuntu-latest
container:
image: ghcr.io/andyholmes/flatter/gnome:46
options: --privileged
# A matrix can be used, but must set `max-parallel: 1`
strategy:
matrix:
arch: [x86_64, aarch64]
fail-fast: false
max-parallel: 1
steps:
# Checkout a repository with Flatpak manifests
- name: Checkout
uses: actions/checkout@v3
# See "Multiple Architectures"
- name: Setup QEMU
if: ${{ matrix.arch == 'aarch64' }}
id: qemu
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Build
uses: andyholmes/flatter@main
with:
files: |
build-aux/flatpak/com.example.App.json
arch: ${{ matrix.arch }}