diff --git a/.github/workflows/flatpak-pages.yml b/.github/workflows/flatpak-pages.yml
index dfd48416..06e5e6a2 100644
--- a/.github/workflows/flatpak-pages.yml
+++ b/.github/workflows/flatpak-pages.yml
@@ -12,150 +12,26 @@ on:
permissions:
contents: read
+ actions: write
concurrency:
group: flatpak-pages-${{ github.repository }}
cancel-in-progress: false
jobs:
- build:
- name: Build Flatpak repository
+ publish:
+ name: Request the combined docs, web, and Flatpak deployment
runs-on: ubuntu-24.04
- permissions:
- contents: read
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.event.release.tag_name || inputs.release_tag }}
- APP_ID: ai.storyteller.solvecraft
steps:
- - name: Configure Pages
- id: pages
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
-
- - name: Install Flatpak repository tools
- run: |
- sudo apt-get update
- sudo apt-get install -y --no-install-recommends flatpak ostree
-
- - name: Download and validate release bundles
- shell: bash
+ - name: Deploy through the shared Pages workflow
run: |
set -euo pipefail
- tag="$RELEASE_TAG"
- if ! printf '%s' "$tag" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$'; then
- echo "::error::Release tag '$tag' is not strict SemVer prefixed with v"
- exit 1
- fi
- published_tag="$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$tag" --jq \
- 'select(.draft == false and .published_at != null) | .tag_name')"
- if [[ "$published_tag" != "$tag" ]]; then
- echo "::error::$tag is not a published release in $GITHUB_REPOSITORY"
- exit 1
- fi
-
- version="${tag#v}"
- mkdir -p bundles
- gh release download "$tag" --repo "$GITHUB_REPOSITORY" \
- --pattern SHA256SUMS.txt --dir bundles
- for arch in x86_64 aarch64; do
- asset="solvecraft-$version-linux-$arch.flatpak"
- gh release download "$tag" --repo "$GITHUB_REPOSITORY" \
- --pattern "$asset" --dir bundles
- test -s "bundles/$asset"
- (
- cd bundles
- awk -v file="$asset" '$2 == file || $2 == "*" file { print; found=1 } END { exit !found }' \
- SHA256SUMS.txt | sha256sum --check -
- )
- done
- test "$(find bundles -maxdepth 1 -type f -name '*.flatpak' | wc -l)" -eq 2
-
- for arch in x86_64 aarch64; do
- asset="bundles/solvecraft-$version-linux-$arch.flatpak"
- validation_repo="$(mktemp -d)"
- ostree --repo="$validation_repo" init --mode=archive-z2
- flatpak build-import-bundle "$validation_repo" "$asset"
- expected_ref="app/$APP_ID/$arch/stable"
- ostree --repo="$validation_repo" refs | grep -Fxq "$expected_ref" || {
- echo "::error::$(basename "$asset") does not contain $expected_ref"
- exit 1
- }
- rm -rf "$validation_repo"
- done
-
- - name: Build repository and site
- shell: bash
- env:
- PAGES_BASE_URL: ${{ steps.pages.outputs.base_url }}
- run: |
- set -euo pipefail
- site="$RUNNER_TEMP/site"
- repo_dir="$site/flatpak/repo"
- mkdir -p "$repo_dir"
- ostree --repo="$repo_dir" init --mode=archive-z2
-
- previous_url="${PAGES_BASE_URL%/}/flatpak/repo"
- if curl --fail --silent --show-error --location \
- --output /dev/null "$previous_url/summary"; then
- ostree --repo="$repo_dir" remote add --no-gpg-verify previous "$previous_url"
- ostree --repo="$repo_dir" pull --mirror previous
- ostree --repo="$repo_dir" remote delete previous
- fi
-
- version="${RELEASE_TAG#v}"
- for arch in x86_64 aarch64; do
- flatpak build-import-bundle "$repo_dir" \
- "bundles/solvecraft-$version-linux-$arch.flatpak"
- done
- flatpak build-update-repo \
- --title="SolveCraft" \
- --comment='Official SolveCraft releases' \
- --description='Official Flatpak repository for SolveCraft' \
- --homepage="https://github.com/$GITHUB_REPOSITORY" \
- --default-branch=stable \
- "$repo_dir"
-
- for arch in x86_64 aarch64; do
- ostree --repo="$repo_dir" rev-parse "app/$APP_ID/$arch/stable" >/dev/null
- done
- test -s "$repo_dir/summary"
-
- base_url="${PAGES_BASE_URL%/}"
- repo_url="$base_url/flatpak/repo/"
- cat >"$site/flatpak/solvecraft.flatpakrepo" <"$site/flatpak/index.html" <
SolveCraft Flatpak repositorySolveCraft Flatpak repository
Latest published release: $RELEASE_TAG
Add the SolveCraft repository
flatpak remote-add --if-not-exists solvecraft $base_url/flatpak/solvecraft.flatpakrepo
- flatpak install solvecraft $APP_ID
- HTML
- cat >"$site/index.html" <SolveCraft downloadsSolveCraft downloads
Flatpak repository
Release assets
- HTML
- touch "$site/.nojekyll"
-
- - name: Upload Pages artifact
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
- with:
- path: ${{ runner.temp }}/site
- include-hidden-files: true
-
- deploy:
- name: Deploy Pages
- needs: build
- runs-on: ubuntu-24.04
- permissions:
- pages: write
- id-token: write
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
- steps:
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
+ published="$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_TAG" \
+ --jq 'select(.draft == false and .published_at != null) | .tag_name')"
+ test "$published" = "$RELEASE_TAG"
+ gh workflow run pages.yml --repo "$GITHUB_REPOSITORY" --ref main \
+ -f release_tag="$RELEASE_TAG"
+ echo "Requested the combined Pages deployment for $RELEASE_TAG" >>"$GITHUB_STEP_SUMMARY"
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 80a256b6..d36accb6 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -7,6 +7,12 @@ on:
push:
branches: [main]
workflow_dispatch:
+ inputs:
+ release_tag:
+ description: "Published release for Flatpak (empty: latest stable release)"
+ type: string
+ required: false
+ default: ""
permissions:
contents: read
@@ -50,6 +56,17 @@ jobs:
cp -r target/book/. site/
cp -r dist/web site/app
- uses: actions/configure-pages@v5
+ id: pages
+ - name: Install Flatpak repository tools
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends flatpak ostree
+ - name: Include the published Flatpak repository
+ env:
+ GH_TOKEN: ${{ github.token }}
+ RELEASE_TAG: ${{ inputs.release_tag || '' }}
+ PAGES_BASE_URL: ${{ steps.pages.outputs.base_url }}
+ run: bash packaging/flatpak-site.sh site
- uses: actions/upload-pages-artifact@v3
with:
path: site
diff --git a/docs/releasing.md b/docs/releasing.md
index 588162d3..9fabd24c 100644
--- a/docs/releasing.md
+++ b/docs/releasing.md
@@ -117,7 +117,11 @@ Keep that deployment separate from building the application. A publication made
Actions `GITHUB_TOKEN` does not trigger downstream `release: published` workflows; in that
case explicitly dispatch the Flatpak workflow with the published tag, or use an appropriately
authorized maintainer/App token for publication. Do not assume the repository updated: check
-the deployment run. Coordinate its GitHub Pages output with the existing docs website.
+the deployment run. The Flatpak workflow requests the shared Pages workflow with that tag;
+Pages assembles the documentation, browser app, and Flatpak repository together. Ordinary
+docs updates include the latest stable Flatpak release too. Verify the resulting Pages run,
+not only the dispatch job, so a release cannot erase the docs or app and docs updates cannot
+erase the package repository.
## Repository setup
diff --git a/packaging/flatpak-site.sh b/packaging/flatpak-site.sh
new file mode 100644
index 00000000..44d55572
--- /dev/null
+++ b/packaging/flatpak-site.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# All Pages deployments include the book, web app, and published Flatpak repository.
+# Shared by docs updates and release publication; no other workflow replaces the site.
+set -euo pipefail
+
+site="${1:?site directory required}"
+tag="${RELEASE_TAG:-}"
+app_id=ai.storyteller.solvecraft
+if [ -z "$tag" ]; then
+ tag="$(gh api "repos/$GITHUB_REPOSITORY/releases?per_page=100" \
+ --jq '[.[] | select(.draft == false and .prerelease == false)][0].tag_name // empty')"
+fi
+# Before the first publication the docs and browser app can still deploy.
+if [ -z "$tag" ]; then exit 0; fi
+if ! printf '%s' "$tag" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$'; then
+ echo "invalid release tag: $tag" >&2
+ exit 1
+fi
+published="$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$tag" \
+ --jq 'select(.draft == false and .published_at != null) | .tag_name')"
+test "$published" = "$tag"
+test -s "$site/index.html"
+test -s "$site/app/index.html"
+
+version="${tag#v}"
+bundles="$(mktemp -d)"
+gh release download "$tag" --repo "$GITHUB_REPOSITORY" --pattern SHA256SUMS.txt --dir "$bundles"
+repo_dir="$site/flatpak/repo"
+mkdir -p "$repo_dir"
+ostree --repo="$repo_dir" init --mode=archive-z2
+base_url="${PAGES_BASE_URL%/}"
+previous_url="$base_url/flatpak/repo"
+if curl --fail --silent --location --output /dev/null "$previous_url/summary"; then
+ ostree --repo="$repo_dir" remote add --no-gpg-verify previous "$previous_url"
+ ostree --repo="$repo_dir" pull --mirror previous
+ ostree --repo="$repo_dir" remote delete previous
+fi
+for arch in x86_64 aarch64; do
+ asset="solvecraft-$version-linux-$arch.flatpak"
+ gh release download "$tag" --repo "$GITHUB_REPOSITORY" --pattern "$asset" --dir "$bundles"
+ (
+ cd "$bundles"
+ awk -v file="$asset" '$2 == file || $2 == "*" file { print; found=1 } END { exit !found }' \
+ SHA256SUMS.txt | sha256sum --check -
+ )
+ validation_repo="$(mktemp -d)"
+ ostree --repo="$validation_repo" init --mode=archive-z2
+ flatpak build-import-bundle "$validation_repo" "$bundles/$asset"
+ ostree --repo="$validation_repo" refs | grep -Fxq "app/$app_id/$arch/stable"
+ flatpak build-import-bundle "$repo_dir" "$bundles/$asset"
+done
+flatpak build-update-repo --title="SolveCraft" --comment='Official SolveCraft releases' \
+ --description='Official Flatpak repository for SolveCraft' \
+ --homepage="https://github.com/$GITHUB_REPOSITORY" --default-branch=stable "$repo_dir"
+test -s "$repo_dir/summary"
+cat >"$site/flatpak/solvecraft.flatpakrepo" <"$site/flatpak/index.html" <SolveCraft Flatpak repositorySolveCraft Flatpak repository
Latest published release: $tag
Add the SolveCraft repository
flatpak remote-add --if-not-exists solvecraft $base_url/flatpak/solvecraft.flatpakrepo
+flatpak install solvecraft $app_id
+HTML
+touch "$site/.nojekyll"