build: extract marketing and simplify releases (#1594)

This commit is contained in:
Hampus
2026-08-14 21:14:13 +02:00
committed by GitHub
parent beb906753f
commit 08566fc244
258 changed files with 940 additions and 26031 deletions
+7
View File
@@ -0,0 +1,7 @@
/.github/CODEOWNERS @fluxerapp/developers
/.github/workflows/ @fluxerapp/developers
/fluxer_marketing @fluxerapp/developers
/.gitmodules @fluxerapp/developers
/.github/workflows/dispatch-private-marketing-build.yaml @fluxerapp/developers
/packages/i18n/marketing/ @fluxerapp/developers
/scripts/setup-private-marketing.sh @fluxerapp/developers
+18
View File
@@ -89,3 +89,21 @@ Submit translations through [Weblate](https://weblate.fluxer.tools), not through
All repository activity is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).
Fluxer is distributed under the [GNU Affero General Public License, version 3.0 or later](../LICENSE). By adding a DCO sign-off, you certify that you have the right to submit the contribution under that licence.
## Private marketing project
The marketing implementation is maintained in a private repository at the `fluxer_marketing` submodule path. The public workspace, bootstrap, checks, and development stack work without initializing it.
Authorized maintainers can initialize only that submodule and install its independent dependencies:
```sh
./scripts/setup-private-marketing.sh
pnpm --dir fluxer_marketing install --frozen-lockfile
cargo metadata --locked --manifest-path fluxer_marketing/Cargo.toml
```
To run the private marketing service in the local development stack and direct application links to it, add this override to the ignored `config/env/local.env` file:
```sh
FLUXER_MARKETING_ENDPOINT=http://localhost:8088/marketing
```
+3 -1
View File
@@ -24,7 +24,9 @@ f:gateway:
- any-glob-to-any-file: fluxer_gateway/**/*
f:marketing:
- changed-files:
- any-glob-to-any-file: fluxer_marketing/**/*
- any-glob-to-any-file:
- fluxer_marketing
- packages/i18n/marketing/**/*
f:media_proxy:
- changed-files:
- any-glob-to-any-file: fluxer_media_proxy/**/*
+46 -65
View File
@@ -32,17 +32,15 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this image fragment is uploaded. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
permissions:
actions: read
contents: write
packages: write
concurrency:
group: publish-${{ inputs.image }}
cancel-in-progress: false
defaults:
run:
shell: bash
@@ -55,6 +53,8 @@ jobs:
name: resolve metadata
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
outputs:
build_version: ${{ steps.vars.outputs.build_version }}
steps:
@@ -79,6 +79,10 @@ jobs:
needs: meta
runs-on: ${{ matrix.runner }}
timeout-minutes: 75
permissions:
actions: read
contents: read
packages: write
strategy:
fail-fast: false
matrix:
@@ -96,7 +100,7 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ github.token }}
- uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf
with:
context: ${{ inputs.context }}
@@ -119,6 +123,9 @@ jobs:
needs: [meta, build]
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
@@ -132,71 +139,45 @@ jobs:
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ github.token }}
- name: create and push multi-arch manifest
env:
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}
VERSION: ${{ needs.meta.outputs.build_version }}
run: |
set -euo pipefail
docker buildx imagetools create -t "${IMAGE}:${VERSION}" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
docker buildx imagetools inspect "${IMAGE}:${VERSION}"
- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
SOURCE_SHA: ${{ github.sha }}
VERSION: ${{ needs.meta.outputs.build_version }}
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
publish
--component "${{ inputs.image }}"
--build-version "${VERSION}"
--source-sha "${SOURCE_SHA}"
--previous-sha "${RELEASE_BASELINE_SHA}"
- name: Advance moving image tags
env:
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}
VERSION: ${{ needs.meta.outputs.build_version }}
MOVING_TAGS: ${{ inputs.moving-tags }}
run: |
set -euo pipefail
tag_args=( "-t" "${IMAGE}:${VERSION}" )
tag_args=()
IFS=',' read -ra moving <<< "${MOVING_TAGS}"
for raw in "${moving[@]}"; do
t="$(echo "$raw" | xargs)"
[ -n "$t" ] && tag_args+=( "-t" "${IMAGE}:${t}" )
tag="$(echo "$raw" | xargs)"
[ -n "$tag" ] && tag_args+=( "-t" "${IMAGE}:${tag}" )
done
docker buildx imagetools create "${tag_args[@]}" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
docker buildx imagetools inspect "${IMAGE}:${VERSION}"
- name: Write GitHub release image fragment
env:
GH_TOKEN: ${{ github.token }}
IMAGE_REF: ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}:${{ needs.meta.outputs.build_version }}
VERSION: ${{ needs.meta.outputs.build_version }}
MOVING_TAGS: ${{ inputs.moving-tags }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
publish-image
--build-version "${VERSION}"
--image "${{ inputs.image }}"
--image-ref "${IMAGE_REF}"
--moving-tags "${MOVING_TAGS}"
- name: Upload GitHub release fragment
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: release-fragment-${{ inputs.image }}
path: release-out/fragments/fluxer-release-fragment-image-${{ inputs.image }}.json
if-no-files-found: error
retention-days: 14
finalise:
name: finalise GitHub release
if: ${{ inputs['finalise-release'] }}
needs: [meta, merge]
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: Set up Rust toolchain (CI helpers)
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Download GitHub release fragments
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
pattern: release-fragment-*
path: release-out/fragments
merge-multiple: true
- name: finalise GitHub release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.meta.outputs.build_version }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
finalise
--build-version "${VERSION}"
if (( ${#tag_args[@]} > 0 )); then
docker buildx imagetools create "${tag_args[@]}" "${IMAGE}:${VERSION}"
fi
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-admin
dockerfile: fluxer_admin/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-api
dockerfile: fluxer_api/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,12 +28,10 @@ jobs:
build:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-app-proxy-self-hosted
dockerfile: fluxer_app_proxy/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
extra-build-args: |
FLUXER_APP_PROXY_TIME_FREEZE_ENABLED=false
+31 -77
View File
@@ -9,41 +9,23 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
contents: write
packages: write
concurrency:
group: publish-fluxer-app-proxy
cancel-in-progress: false
env:
GHCR_OWNER: ${{ github.repository_owner }}
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -54,9 +36,10 @@ jobs:
meta:
name: resolve metadata
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
outputs:
build_version: ${{ steps.vars.outputs.build_version }}
steps:
@@ -79,6 +62,10 @@ jobs:
needs: meta
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 45
permissions:
actions: read
contents: read
packages: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
@@ -117,13 +104,6 @@ jobs:
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
--step generate_asset_manifest
- name: Upload asset manifest handoff
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: app-proxy-assets-manifest
path: app-dist-output/dist/assets-manifest.txt
if-no-files-found: error
- name: upload assets to S3 static bucket
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -139,6 +119,10 @@ jobs:
needs: meta
runs-on: blacksmith-4vcpu-ubuntu-2404-arm
timeout-minutes: 60
permissions:
actions: read
contents: read
packages: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
@@ -172,6 +156,9 @@ jobs:
needs: [meta, build, build-arm64]
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
@@ -180,11 +167,6 @@ jobs:
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Download app-proxy asset manifest
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
name: app-proxy-assets-manifest
path: release-input/app-proxy
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
with:
@@ -201,58 +183,30 @@ jobs:
echo "amd64 digest: ${amd64_digest}"
docker buildx imagetools create \
-t "${IMAGE}:${VERSION}" \
-t "${IMAGE}:v1" \
-t "${IMAGE}:latest" \
"${IMAGE}@${amd64_digest}" \
"${IMAGE}:${VERSION}-arm64"
docker buildx imagetools inspect "${IMAGE}:${VERSION}"
- name: Write GitHub release app-proxy fragment
- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
IMAGE_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:${{ needs.meta.outputs.build_version }}
SOURCE_SHA: ${{ github.sha }}
VERSION: ${{ needs.meta.outputs.build_version }}
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
publish-app-proxy
publish
--component fluxer-app-proxy
--build-version "${VERSION}"
--image fluxer-app-proxy
--image-ref "${IMAGE_REF}"
--moving-tags "v1,latest"
--asset-manifest release-input/app-proxy/assets-manifest.txt
- name: Upload GitHub release fragment
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: release-fragment-fluxer-app-proxy
path: release-out/fragments/fluxer-release-fragment-app-proxy.json
if-no-files-found: error
retention-days: 14
--source-sha "${SOURCE_SHA}"
--previous-sha "${RELEASE_BASELINE_SHA}"
finalise:
name: finalise GitHub release
if: ${{ inputs['finalise-release'] != false }}
needs: [meta, merge]
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Advance moving image tags
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: Set up Rust toolchain (CI helpers)
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Download GitHub release fragments
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
pattern: release-fragment-*
path: release-out/fragments
merge-multiple: true
- name: finalise GitHub release
env:
GH_TOKEN: ${{ github.token }}
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy
VERSION: ${{ needs.meta.outputs.build_version }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
finalise
--build-version "${VERSION}"
docker buildx imagetools create
-t "${IMAGE}:v1"
-t "${IMAGE}:latest"
"${IMAGE}:${VERSION}"
+32 -35
View File
@@ -46,6 +46,8 @@ jobs:
runs-on: ubuntu-24.04-arm
environment: desktop-releases
timeout-minutes: 25
permissions:
contents: read
outputs:
version: ${{ steps.meta.outputs.version }}
pub_date: ${{ steps.meta.outputs.pub_date }}
@@ -81,6 +83,8 @@ jobs:
runs-on: ubuntu-24.04-arm
environment: desktop-releases
timeout-minutes: 25
permissions:
contents: read
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
@@ -107,6 +111,10 @@ jobs:
runs-on: ${{ matrix.os }}
environment: desktop-releases
timeout-minutes: 60
permissions:
actions: read
contents: read
id-token: write
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.matrix.outputs.matrix) }}
@@ -492,6 +500,8 @@ jobs:
runs-on: ubuntu-24.04-arm
environment: desktop-releases
timeout-minutes: 60
permissions:
contents: read
env:
CHANNEL: ${{ needs.meta.outputs.build_channel }}
DISPLAY_CHANNEL: ${{ needs.meta.outputs.channel }}
@@ -544,34 +554,14 @@ jobs:
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
--step build_summary
- name: Write GitHub release desktop fragment
env:
GH_TOKEN: ${{ github.token }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
publish-desktop
--build-version "${{ needs.meta.outputs.version }}"
--channel "${{ needs.meta.outputs.build_channel }}"
--test-build "${{ needs.meta.outputs.test_build }}"
--s3-prefix "${{ needs.meta.outputs.s3_prefix }}"
--payload-root s3_payload
--source-sha "${{ needs.meta.outputs.source_sha }}"
- name: Upload GitHub release fragment
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: release-fragment-desktop
path: release-out/fragments/fluxer-release-fragment-desktop-${{ needs.meta.outputs.build_channel }}.json
if-no-files-found: error
retention-days: 14
- name: Cleanup S3 handoff
if: ${{ success() }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
--step cleanup_handoff
finalise_release:
name: Finalise GitHub desktop release
publish_release:
name: Publish GitHub desktop release
if: ${{ !cancelled() && needs.upload.result == 'success' && needs.meta.outputs.test_build != 'true' }}
needs:
- meta
@@ -579,6 +569,8 @@ jobs:
runs-on: ubuntu-24.04-arm
environment: desktop-releases
timeout-minutes: 10
permissions:
contents: write
steps:
- name: Checkout source
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
@@ -589,18 +581,23 @@ jobs:
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Download GitHub release fragments
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
pattern: release-fragment-*
path: release-out/fragments
merge-multiple: true
- name: Finalise GitHub desktop release
- name: Publish GitHub desktop release
env:
GH_TOKEN: ${{ github.token }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
finalise
--build-version "${{ needs.meta.outputs.version }}"
--source-sha "${{ needs.meta.outputs.source_sha }}"
CHANNEL: ${{ needs.meta.outputs.build_channel }}
VERSION: ${{ needs.meta.outputs.version }}
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
run: |
set -euo pipefail
release_args=(
release publish
--component "fluxer-desktop-${CHANNEL}"
--build-version "${VERSION}"
--source-sha "${SOURCE_SHA}"
--previous-sha "${RELEASE_BASELINE_SHA}"
)
if [[ "${CHANNEL}" == "canary" ]]; then
release_args+=(--prerelease)
fi
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- "${release_args[@]}"
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,12 +28,9 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-docs
dockerfile: fluxer_docs/Dockerfile
context: fluxer_docs
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-gateway
dockerfile: fluxer_gateway/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-gifs
dockerfile: fluxer_gifs/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
-60
View File
@@ -1,60 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
name: build marketing
on:
workflow_dispatch:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
contents: write
packages: write
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
steps:
- name: approved
run: echo "Build release approved."
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-marketing
dockerfile: fluxer_marketing/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-media-proxy
dockerfile: fluxer_media_proxy/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-messages
dockerfile: fluxer_messages/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-snowflakes
dockerfile: fluxer_snowflakes/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-static
dockerfile: fluxer_static/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-unfurl
dockerfile: fluxer_unfurl/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
+1 -26
View File
@@ -9,28 +9,6 @@ on:
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
workflow_call:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
finalise-release:
description: "Publish the GitHub Release after this workflow completes. Set false when an orchestrator will finalise the release."
type: boolean
required: false
default: true
approval-required:
description: "Require the protected builds environment approval before this build runs."
type: boolean
required: false
default: true
permissions:
actions: read
@@ -40,7 +18,7 @@ permissions:
jobs:
approve:
name: approve build release
if: ${{ format('{0}', inputs['approval-required']) != 'false' }}
permissions: {}
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
@@ -50,11 +28,8 @@ jobs:
image:
needs: approve
if: ${{ !cancelled() && (needs.approve.result == 'success' || needs.approve.result == 'skipped') }}
uses: ./.github/workflows/_build-image.yaml
with:
image: fluxer-users
dockerfile: fluxer_users/Dockerfile
build-version: ${{ inputs['build-version'] }}
finalise-release: ${{ inputs['finalise-release'] != false }}
secrets: inherit
-473
View File
@@ -1,473 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
name: deploy service
on:
workflow_dispatch:
inputs:
service:
description: "Helm chart name to deploy"
type: choice
required: true
options:
- api
- app-proxy
- admin
- docs
- marketing
- media-proxy
- gateway
- messages
- search
- snowflakes
- users
- unfurl
- uploads
- worker
channel:
description: "Release channel (stable or canary)"
type: choice
required: true
options:
- stable
- canary
image-tag:
description: "Docker image tag to deploy (Fluxer CalVer: YYYY.MDD.MICRO)"
type: string
required: true
build-version:
description: "Fluxer CalVer build version to inject into runtime env vars"
type: string
required: false
default: ""
allow-rollback:
description: "Allow deploying an older image tag than the newest GHCR tag"
type: boolean
required: false
default: false
workflow_call:
inputs:
service:
description: "Helm chart name to deploy"
type: string
required: true
channel:
description: "Release channel (stable or canary)"
type: string
required: true
image-tag:
description: "Docker image tag to deploy (Fluxer CalVer: YYYY.MDD.MICRO)"
type: string
required: true
build-version:
description: "Fluxer CalVer build version to inject into runtime env vars"
type: string
required: false
default: ""
allow-rollback:
description: "Allow deploying an older image tag than the newest GHCR tag"
type: boolean
required: false
default: false
secrets:
KUBE_CONFIG:
required: true
GHCR_USERNAME:
required: false
GHCR_TOKEN:
required: false
env:
GHCR_OWNER: ${{ github.repository_owner }}
GHCR_REGISTRY: ghcr.io/${{ github.repository_owner }}
jobs:
deploy:
name: deploy ${{ inputs.service }}
runs-on: ubuntu-24.04
timeout-minutes: 60
environment: ${{ inputs.channel }}
permissions:
contents: read
packages: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: install helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310
- name: configure kubectl
shell: bash
env:
KUBE_CONFIG_B64: ${{ secrets.KUBE_CONFIG }}
run: |
mkdir -p "$HOME/.kube"
printf '%s' "$KUBE_CONFIG_B64" | base64 -d > "$HOME/.kube/config"
chmod 600 "$HOME/.kube/config"
- name: resolve helm args
id: helm
shell: bash
env:
INPUT_SERVICE: ${{ inputs.service }}
INPUT_CHANNEL: ${{ inputs.channel }}
INPUT_IMAGE_TAG: ${{ inputs['image-tag'] }}
INPUT_BUILD_VERSION: ${{ inputs['build-version'] }}
run: |
SERVICE="$INPUT_SERVICE"
CHANNEL="$INPUT_CHANNEL"
TAG="$INPUT_IMAGE_TAG"
BUILD_VERSION="$INPUT_BUILD_VERSION"
GHCR_REGISTRY="${GHCR_REGISTRY:?GHCR_REGISTRY is required}"
if [[ -z "$BUILD_VERSION" ]]; then
BUILD_VERSION="$TAG"
fi
CALVER_RE='^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.(0|[1-9][0-9]{0,5})$'
if [[ ! "$TAG" =~ $CALVER_RE ]]; then
echo "::error::image-tag must be a Fluxer CalVer tag (YYYY.MDD.MICRO). Channel tags, latest tags, and suffixed tags are not deployable."
exit 1
fi
if [[ ! "$BUILD_VERSION" =~ $CALVER_RE ]]; then
echo "::error::build-version must be a Fluxer CalVer value (YYYY.MDD.MICRO)."
exit 1
fi
CHART_DIR="./deploy/helm/${SERVICE}"
VALUES_ARGS="-f ${CHART_DIR}/values.yaml"
SETS=""
BUILD_PATHS=""
DEPLOY_IMAGE=""
SYNC_WORKER_RELEASE=""
SYNC_WORKER_CHART_DIR=""
SYNC_WORKER_VALUES_ARGS=""
SYNC_WORKER_SETS=""
case "$SERVICE" in
uploads)
if [[ "$CHANNEL" != "stable" ]]; then
echo "::error::uploads deployments are stable-only (single relay serves both channels)."
exit 1
fi
RELEASE="fluxer-uploads"
DEPLOY_IMAGE="fluxer-media-proxy"
SETS="--set-string app.name=uploads --set-string app.image=fluxer-media-proxy --set-string app.tag=${TAG} --set-string app.config=stable"
SETS="${SETS} --set-string app.build.version=${BUILD_VERSION}"
SETS="${SETS} --set-string app.build.channel=stable"
;;
api|app-proxy|admin|docs|marketing)
BASE_IMAGE="fluxer-${SERVICE}"
if [[ "$SERVICE" == "docs" && "$CHANNEL" != "stable" ]]; then
echo "::error::docs deployments are stable-only."
exit 1
fi
if [[ "$CHANNEL" == "canary" ]]; then
NAME="${SERVICE}-canary"
else
NAME="${SERVICE}"
fi
DEPLOY_IMAGE="${BASE_IMAGE}"
RELEASE="fluxer-${SERVICE}-${CHANNEL}"
VALUES_ARGS="${VALUES_ARGS} -f ${CHART_DIR}/values.${CHANNEL}.prod.yaml"
SETS="--set-string app.name=${NAME} --set-string app.image=${DEPLOY_IMAGE} --set-string app.tag=${TAG}"
SETS="${SETS} --set-string app.build.version=${BUILD_VERSION}"
SETS="${SETS} --set-string app.build.channel=${CHANNEL}"
;;
media-proxy)
if [[ "$CHANNEL" != "canary" ]]; then
echo "::error::Media-proxy deployments are only supported on the canary lane."
exit 1
fi
RELEASE="fluxer-${SERVICE}"
DEPLOY_IMAGE="fluxer-media-proxy"
VALUES_ARGS="${VALUES_ARGS} -f ${CHART_DIR}/values.prod.yaml"
SETS="--set-string mediaProxy.image=fluxer-media-proxy --set-string staticProxy.image=fluxer-media-proxy --set-string mediaProxy.tag=${TAG} --set-string staticProxy.tag=${TAG} --set mediaProxy.replicas=16 --set staticProxy.replicas=4 --set-string mediaProxy.nsfwServiceEndpoint=http://int.flx-nyc-misc1.srv.fluxer.dev:8000"
BUILD_PATHS="mediaProxy staticProxy"
;;
gateway)
if [[ "$CHANNEL" != "stable" ]]; then
echo "::error::gateway deployments are stable-only."
exit 1
fi
RELEASE="fluxer-${SERVICE}"
DEPLOY_IMAGE="fluxer-gateway"
VALUES_ARGS="${VALUES_ARGS} -f ${CHART_DIR}/values.prod.yaml"
SETS="--set-string gateway.image=${DEPLOY_IMAGE} --set-string gateway.tag=${TAG}"
BUILD_PATHS="gateway"
;;
worker)
if [[ "$CHANNEL" != "stable" ]]; then
echo "::error::Worker deployments are only supported on the stable lane."
exit 1
fi
RELEASE="fluxer-${SERVICE}"
DEPLOY_IMAGE="fluxer-api"
VALUES_ARGS="${VALUES_ARGS} -f ${CHART_DIR}/values.prod.yaml"
SETS="--set-string workerRealtime.image=fluxer-api --set-string workerUnfurl.image=fluxer-api --set-string workerLifecycle.image=fluxer-api --set-string workerBatch.image=fluxer-api --set-string workerRealtime.tag=${TAG} --set-string workerUnfurl.tag=${TAG} --set-string workerLifecycle.tag=${TAG} --set-string workerBatch.tag=${TAG}"
BUILD_PATHS="workerRealtime workerUnfurl workerLifecycle workerBatch"
;;
messages|search|snowflakes|users|unfurl)
if [[ "$CHANNEL" != "stable" ]]; then
echo "::error::Shared microservice deployments are stable-only; canary traffic selection is done by the callers."
exit 1
fi
DEPLOY_IMAGE="fluxer-${SERVICE}"
RELEASE="fluxer-${SERVICE}"
VALUES_ARGS="${VALUES_ARGS} -f ${CHART_DIR}/values.prod.yaml"
SETS="--set-string svc.image=${DEPLOY_IMAGE} --set-string svc.tag=${TAG}"
SETS="${SETS} --set-string svc.build.version=${BUILD_VERSION}"
SETS="${SETS} --set-string svc.build.channel=stable"
;;
*)
echo "::error::Unknown service chart: ${SERVICE}"
exit 1
;;
esac
for BUILD_PATH in $BUILD_PATHS; do
SETS="${SETS} --set-string ${BUILD_PATH}.build.version=${BUILD_VERSION}"
SETS="${SETS} --set-string ${BUILD_PATH}.build.channel=${CHANNEL}"
done
SETS="--set-string global.registry=${GHCR_REGISTRY} ${SETS}"
if [[ "$SERVICE" == "api" && "$CHANNEL" == "canary" ]]; then
SYNC_WORKER_RELEASE="fluxer-worker"
SYNC_WORKER_CHART_DIR="./deploy/helm/worker"
SYNC_WORKER_VALUES_ARGS="-f ${SYNC_WORKER_CHART_DIR}/values.yaml -f ${SYNC_WORKER_CHART_DIR}/values.prod.yaml"
SYNC_WORKER_SETS="--set-string workerRealtime.image=fluxer-api --set-string workerUnfurl.image=fluxer-api --set-string workerLifecycle.image=fluxer-api --set-string workerBatch.image=fluxer-api"
SYNC_WORKER_SETS="${SYNC_WORKER_SETS} --set-string workerRealtime.tag=${TAG} --set-string workerUnfurl.tag=${TAG} --set-string workerLifecycle.tag=${TAG} --set-string workerBatch.tag=${TAG}"
for BUILD_PATH in workerRealtime workerUnfurl workerLifecycle workerBatch; do
SYNC_WORKER_SETS="${SYNC_WORKER_SETS} --set-string ${BUILD_PATH}.build.version=${BUILD_VERSION}"
SYNC_WORKER_SETS="${SYNC_WORKER_SETS} --set-string ${BUILD_PATH}.build.channel=${CHANNEL}"
done
SYNC_WORKER_SETS="--set-string global.registry=${GHCR_REGISTRY} ${SYNC_WORKER_SETS}"
fi
{
echo "chart-dir=${CHART_DIR}"
echo "release=${RELEASE}"
echo "values-args=${VALUES_ARGS}"
echo "sets=${SETS}"
echo "deploy-image=${DEPLOY_IMAGE}"
echo "deploy-tag=${TAG}"
echo "sync-worker-release=${SYNC_WORKER_RELEASE}"
echo "sync-worker-chart-dir=${SYNC_WORKER_CHART_DIR}"
echo "sync-worker-values-args=${SYNC_WORKER_VALUES_ARGS}"
echo "sync-worker-sets=${SYNC_WORKER_SETS}"
} >> "$GITHUB_OUTPUT"
- name: helm dependency update
shell: bash
run: |
helm dependency update "${{ steps.helm.outputs.chart-dir }}"
if [[ -n "${{ steps.helm.outputs.sync-worker-chart-dir }}" ]]; then
helm dependency update "${{ steps.helm.outputs.sync-worker-chart-dir }}"
fi
- name: prepare docker config
if: steps.helm.outputs.deploy-image != ''
shell: bash
run: |
echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config" >> "$GITHUB_ENV"
mkdir -p "${RUNNER_TEMP}/docker-config"
- name: configure ghcr auth
if: steps.helm.outputs.deploy-image != ''
shell: bash
env:
GHCR_USERNAME: ${{ github.actor }}
GHCR_TOKEN: ${{ github.token }}
run: |
auth="$(printf '%s:%s' "$GHCR_USERNAME" "$GHCR_TOKEN" | base64 | tr -d '\n')"
printf '{"auths":{"ghcr.io":{"auth":"%s"}}}\n' "$auth" > "$DOCKER_CONFIG/config.json"
- name: verify deploy image exists
if: steps.helm.outputs.deploy-image != ''
shell: bash
run: |
IMAGE_REF="${GHCR_REGISTRY}/${{ steps.helm.outputs.deploy-image }}:${{ steps.helm.outputs.deploy-tag }}"
echo "Verifying ${IMAGE_REF}"
docker manifest inspect "${IMAGE_REF}" > /dev/null
env:
DOCKER_CLI_EXPERIMENTAL: enabled
- name: verify api deploy uses latest image
if: ${{ steps.helm.outputs.deploy-image == 'fluxer-api' && !inputs['allow-rollback'] }}
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GHCR_OWNER: ${{ env.GHCR_OWNER }}
DEPLOY_TAG: ${{ steps.helm.outputs.deploy-tag }}
run: |
set -euo pipefail
CALVER_RE='^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.(0|[1-9][0-9]{0,5})$'
OWNER_TYPE="$(
curl -fsS \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL:-https://api.github.com}/repos/${GITHUB_REPOSITORY}" \
| jq -r '.owner.type'
)"
case "$OWNER_TYPE" in
Organization) PACKAGE_OWNER_PATH="orgs/${GHCR_OWNER}" ;;
User) PACKAGE_OWNER_PATH="users/${GHCR_OWNER}" ;;
*)
echo "::error::Unsupported GitHub owner type for package lookup: ${OWNER_TYPE}"
exit 1
;;
esac
LATEST_TAG="$(
curl -fsS \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL:-https://api.github.com}/${PACKAGE_OWNER_PATH}/packages/container/fluxer-api/versions?per_page=100" \
| jq -r --arg re "$CALVER_RE" '
[.[].metadata.container.tags[]? |
select(test($re)) |
{tag: ., parts: (split(".") | map(tonumber))}
] | max_by(.parts) | .tag // empty
'
)"
if [[ -z "$LATEST_TAG" ]]; then
echo "::error::Could not resolve the latest fluxer-api CalVer tag from GHCR."
exit 1
fi
if [[ "$DEPLOY_TAG" != "$LATEST_TAG" ]]; then
echo "::error::Refusing to deploy fluxer-api:${DEPLOY_TAG}; latest GHCR tag is fluxer-api:${LATEST_TAG}. Re-run with allow-rollback=true only for an intentional rollback."
exit 1
fi
- name: approve api image for admission policy
if: ${{ inputs.service == 'api' }}
shell: bash
env:
INPUT_CHANNEL: ${{ inputs.channel }}
run: |
DEPLOYMENT="api"
if [[ "$INPUT_CHANNEL" == "canary" ]]; then
DEPLOYMENT="api-canary"
fi
IMAGE_REF="${GHCR_REGISTRY}/${{ steps.helm.outputs.deploy-image }}:${{ steps.helm.outputs.deploy-tag }}"
PREVIOUS_IMAGE="$(kubectl -n fluxer get deployment "$DEPLOYMENT" -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null || true)"
PREVIOUS_TAG=""
if [[ -n "$PREVIOUS_IMAGE" && "$PREVIOUS_IMAGE" != "$IMAGE_REF" && "$PREVIOUS_IMAGE" == *:* ]]; then
PREVIOUS_TAG="${PREVIOUS_IMAGE##*:}"
else
PREVIOUS_IMAGE=""
fi
kubectl -n fluxer create configmap fluxer-api-approved-image \
--from-literal=tag="${{ steps.helm.outputs.deploy-tag }}" \
--from-literal=image="${IMAGE_REF}" \
--from-literal=previousTag="${PREVIOUS_TAG}" \
--from-literal=previousImage="${PREVIOUS_IMAGE}" \
--dry-run=client -o yaml \
| kubectl apply -f -
- name: ensure api admission policy
if: ${{ inputs.service == 'api' }}
shell: bash
run: kubectl apply -f deploy/k8s/fluxer-api-approved-image-policy.yaml
- name: helm upgrade
shell: bash
run: |
RELEASE="${{ steps.helm.outputs.release }}"
CHART_DIR="${{ steps.helm.outputs.chart-dir }}"
VALUES_ARGS="${{ steps.helm.outputs.values-args }}"
SETS="${{ steps.helm.outputs.sets }}"
wait_for_release_idle() {
local release="$1"
local max_checks="$2"
local check=0
local status="unknown"
while (( check < max_checks )); do
check=$((check + 1))
status=$(helm status "$release" -n fluxer -o json 2>/dev/null | jq -r '.info.status // "unknown"' || echo "unknown")
if [[ "$status" != pending-* ]]; then
echo "Release ${release} is ${status}; continuing."
return 0
fi
echo "Release ${release} is ${status}; waiting 10s (${check}/${max_checks})."
sleep 10
done
echo "::warning::Release ${release} still ${status} after ${max_checks} checks; forcing rollback."
if helm rollback "$release" -n fluxer --wait --timeout 5m 2>&1; then
echo "Rollback succeeded; continuing."
return 0
fi
echo "::error::Release ${release} is stuck in ${status} and rollback failed."
return 1
}
helm_upgrade_with_retries() {
local release="$1"
local chart_dir="$2"
local values_args="$3"
local sets="$4"
local values_args_array=()
local sets_array=()
read -r -a values_args_array <<< "$values_args"
read -r -a sets_array <<< "$sets"
wait_for_release_idle "$release" 18
local max_attempts=4
for attempt in $(seq 1 "$max_attempts"); do
echo "Running helm upgrade for ${release}, attempt ${attempt}/${max_attempts}."
set +e
upgrade_output=$(helm upgrade --install "$release" \
"$chart_dir" \
"${values_args_array[@]}" \
-n fluxer \
"${sets_array[@]}" \
--wait --timeout 20m --atomic --history-max 10 2>&1)
exit_code=$?
set -e
printf '%s\n' "$upgrade_output"
if [[ $exit_code -eq 0 ]]; then
return 0
fi
if ! grep -q "another operation (install/upgrade/rollback) is in progress" <<< "$upgrade_output"; then
return "$exit_code"
fi
if [[ $attempt -eq $max_attempts ]]; then
echo "::error::Helm upgrade failed for ${release} after ${max_attempts} attempts because another operation remained in progress."
return "$exit_code"
fi
wait_for_release_idle "$release" 18
done
}
helm_upgrade_with_retries "$RELEASE" "$CHART_DIR" "$VALUES_ARGS" "$SETS"
if [[ -n "${{ steps.helm.outputs.sync-worker-release }}" ]]; then
helm_upgrade_with_retries \
"${{ steps.helm.outputs.sync-worker-release }}" \
"${{ steps.helm.outputs.sync-worker-chart-dir }}" \
"${{ steps.helm.outputs.sync-worker-values-args }}" \
"${{ steps.helm.outputs.sync-worker-sets }}"
fi
- name: seal api admission approved image
if: ${{ success() && inputs.service == 'api' }}
shell: bash
run: |
IMAGE_REF="${GHCR_REGISTRY}/${{ steps.helm.outputs.deploy-image }}:${{ steps.helm.outputs.deploy-tag }}"
kubectl -n fluxer create configmap fluxer-api-approved-image \
--from-literal=tag="${{ steps.helm.outputs.deploy-tag }}" \
--from-literal=image="${IMAGE_REF}" \
--from-literal=previousTag="" \
--from-literal=previousImage="" \
--dry-run=client -o yaml \
| kubectl apply -f -
- name: recover stuck release on failure
if: failure() || cancelled()
shell: bash
run: |
RELEASE="${{ steps.helm.outputs.release }}"
for RELEASE in "$RELEASE" "${{ steps.helm.outputs.sync-worker-release }}"; do
if [[ -z "$RELEASE" ]]; then
continue
fi
STATUS=$(helm status "$RELEASE" -n fluxer -o json 2>/dev/null | jq -r '.info.status' 2>/dev/null || echo "unknown")
if [[ "$STATUS" == "pending-upgrade" || "$STATUS" == "pending-install" || "$STATUS" == "pending-rollback" ]]; then
echo "::warning::Release ${RELEASE} stuck in ${STATUS}, rolling back..."
helm rollback "$RELEASE" -n fluxer --wait --timeout 5m || true
fi
done
@@ -0,0 +1,218 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
name: Dispatch private marketing build
on:
push:
branches:
- main
paths:
- fluxer_marketing
- Cargo.toml
- fluxer_common/**
- packages/fonts/manifest.json
- packages/fonts/NOTICE.md
- packages/fonts/LICENSE-IBM-PLEX.txt
- packages/fonts/css/locale-fallbacks.css
- packages/fonts/files/FluxerSans/**
- packages/fonts/files/FluxerMono/**
- packages/i18n/marketing/**
- .github/workflows/dispatch-private-marketing-build.yaml
permissions:
actions: read
contents: read
concurrency:
group: private-marketing-dispatch
cancel-in-progress: false
jobs:
metadata:
name: resolve exact private build metadata
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
parent_sha: ${{ steps.inputs.outputs.parent_sha }}
gitlink_sha: ${{ steps.inputs.outputs.gitlink_sha }}
build_version: ${{ steps.inputs.outputs.build_version }}
correlation_id: ${{ steps.inputs.outputs.correlation_id }}
steps:
- name: Resolve trusted build inputs
id: inputs
env:
EVENT_AFTER: ${{ github.event.after }}
GH_TOKEN: ${{ github.token }}
PARENT_SHA: ${{ github.sha }}
PUBLIC_REPOSITORY: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
RUN_ATTEMPT: ${{ github.run_attempt }}
run: |
set -euo pipefail
[[ "$GITHUB_EVENT_NAME" == "push" ]]
[[ "$GITHUB_REF" == "refs/heads/main" ]]
[[ "$PUBLIC_REPOSITORY" == "fluxerapp/fluxer" ]]
[[ "$PARENT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$EVENT_AFTER" == "$PARENT_SHA" ]]
[[ "$RUN_ID" =~ ^[1-9][0-9]*$ ]]
[[ "$RUN_ATTEMPT" =~ ^[1-9][0-9]*$ ]]
(( 10#$RUN_ATTEMPT <= 10 ))
main_sha="$(gh api "repos/$PUBLIC_REPOSITORY/git/ref/heads/main" --jq .object.sha)"
[[ "$main_sha" =~ ^[0-9a-f]{40}$ ]]
main_comparison="$(gh api "repos/$PUBLIC_REPOSITORY/compare/$PARENT_SHA...$main_sha")"
main_status="$(jq -r .status <<<"$main_comparison")"
[[ "$main_status" == "identical" || "$main_status" == "ahead" ]]
[[ "$(jq -r .merge_base_commit.sha <<<"$main_comparison")" == "$PARENT_SHA" ]]
commit="$(gh api "repos/$PUBLIC_REPOSITORY/git/commits/$PARENT_SHA")"
[[ "$(jq -r .sha <<<"$commit")" == "$PARENT_SHA" ]]
tree_sha="$(jq -r .tree.sha <<<"$commit")"
[[ "$tree_sha" =~ ^[0-9a-f]{40}$ ]]
entry="$(
gh api "repos/$PUBLIC_REPOSITORY/git/trees/$tree_sha" |
jq -cer '[.tree[] | select(.path == "fluxer_marketing")] | if length == 1 then .[0] else error("expected exactly one marketing gitlink") end'
)"
mode="$(jq -r .mode <<<"$entry")"
type="$(jq -r .type <<<"$entry")"
gitlink_sha="$(jq -r .sha <<<"$entry")"
path="$(jq -r .path <<<"$entry")"
if [[ "$mode" != "160000" || "$type" != "commit" || "$path" != "fluxer_marketing" || ! "$gitlink_sha" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::Public parent does not contain a valid fluxer_marketing gitlink."
exit 1
fi
run="$(gh api "repos/$PUBLIC_REPOSITORY/actions/runs/$RUN_ID")"
[[ "$(jq -r .id <<<"$run")" == "$RUN_ID" ]]
[[ "$(jq -r .run_attempt <<<"$run")" == "$RUN_ATTEMPT" ]]
[[ "$(jq -r .event <<<"$run")" == "push" ]]
[[ "$(jq -r .head_sha <<<"$run")" == "$PARENT_SHA" ]]
run_created_at="$(jq -r .created_at <<<"$run")"
[[ "$run_created_at" =~ ^[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]
run_created_epoch="$(date -u -d "$run_created_at" +%s)"
[[ "$run_created_epoch" =~ ^[1-9][0-9]*$ ]]
build_epoch=$((run_created_epoch + 10#$RUN_ATTEMPT - 1))
read -r year month day time_segment <<<"$(date -u -d "@$build_epoch" '+%Y %m %d %H%M%S')"
month="$((10#$month))"
micro="$((10#$time_segment))"
build_version="$year.$month$day.$micro"
[[ "$build_version" =~ ^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.([0-9]|[1-9][0-9]{0,5})$ ]]
correlation_id="public-${RUN_ID}-${RUN_ATTEMPT}"
[[ "$correlation_id" =~ ^[A-Za-z0-9._:-]{1,64}$ ]]
{
echo "parent_sha=$PARENT_SHA"
echo "gitlink_sha=$gitlink_sha"
echo "build_version=$build_version"
echo "correlation_id=$correlation_id"
} >>"$GITHUB_OUTPUT"
dispatch:
name: dispatch exact private build
needs: metadata
runs-on: ubuntu-24.04
timeout-minutes: 65
environment: private-marketing-dispatch
permissions: {}
steps:
- name: Validate trusted build inputs
env:
DISPATCH_ENABLED: ${{ vars.MARKETING_DISPATCH_ENABLED }}
EXPECTED_PARENT_SHA: ${{ github.sha }}
EXPECTED_CORRELATION_ID: public-${{ github.run_id }}-${{ github.run_attempt }}
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
run: |
set -euo pipefail
[[ "$GITHUB_EVENT_NAME" == "push" ]]
[[ "$GITHUB_REF" == "refs/heads/main" ]]
[[ "$GITHUB_REPOSITORY" == "fluxerapp/fluxer" ]]
[[ "$PARENT_SHA" == "$EXPECTED_PARENT_SHA" ]]
[[ "$PARENT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$GITLINK_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$BUILD_VERSION" =~ ^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.([0-9]|[1-9][0-9]{0,5})$ ]]
[[ "$CORRELATION_ID" == "$EXPECTED_CORRELATION_ID" ]]
[[ "$CORRELATION_ID" =~ ^[A-Za-z0-9._:-]{1,64}$ ]]
if [[ "$DISPATCH_ENABLED" != "true" ]]; then
echo "::error::Private marketing dispatch is intentionally disabled until the package cutover guard completes."
exit 1
fi
- name: Create private dispatch token
id: private-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
with:
client-id: ${{ vars.FLUXER_CI_APP_ID }}
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
owner: fluxerapp
repositories: marketing
permission-actions: write
- name: Dispatch exact private build
env:
GH_TOKEN: ${{ steps.private-token.outputs.token }}
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
run: |
set -euo pipefail
gh api --method POST repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/dispatches \
--field ref=main \
--field "inputs[parent_sha]=$PARENT_SHA" \
--field "inputs[gitlink_sha]=$GITLINK_SHA" \
--field "inputs[build_version]=$BUILD_VERSION" \
--field "inputs[correlation_id]=$CORRELATION_ID"
- name: Wait for private build conclusion
env:
GH_TOKEN: ${{ steps.private-token.outputs.token }}
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
run: |
set -euo pipefail
expected_title="marketing-build correlation=$CORRELATION_ID parent=$PARENT_SHA gitlink=$GITLINK_SHA version=$BUILD_VERSION"
deadline=$((SECONDS + 3600))
run_id=""
while (( SECONDS < deadline )); do
runs="$(gh api "repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/runs?event=workflow_dispatch&per_page=100" --jq '[.workflow_runs[] | {id, event, display_title, status, conclusion}]')"
matches="$(jq --arg title "$expected_title" '[.[] | select(.event == "workflow_dispatch" and .display_title == $title)]' <<<"$runs")"
count="$(jq 'length' <<<"$matches")"
if [[ "$count" == "1" ]]; then
run_id="$(jq -r '.[0].id' <<<"$matches")"
break
fi
if [[ "$count" != "0" ]]; then
echo "::error::Private build correlation matched multiple workflow runs."
exit 1
fi
sleep 10
done
if [[ -z "$run_id" ]]; then
echo "::error::Timed out waiting for the private build dispatch to appear."
exit 1
fi
while (( SECONDS < deadline )); do
runs="$(gh api "repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/runs?event=workflow_dispatch&per_page=100" --jq '[.workflow_runs[] | {id, event, display_title, status, conclusion}]')"
matches="$(jq --arg title "$expected_title" '[.[] | select(.event == "workflow_dispatch" and .display_title == $title)]' <<<"$runs")"
if [[ "$(jq 'length' <<<"$matches")" != "1" || "$(jq -r '.[0].id' <<<"$matches")" != "$run_id" ]]; then
echo "::error::Private build correlation is missing or ambiguous."
exit 1
fi
run="$(jq '.[0]' <<<"$matches")"
status="$(jq -r '.status' <<<"$run")"
conclusion="$(jq -r '.conclusion // empty' <<<"$run")"
if [[ "$status" == "completed" ]]; then
if [[ "$conclusion" != "success" ]]; then
echo "::error::Private marketing build concluded with $conclusion."
exit 1
fi
echo "Private marketing build completed successfully."
exit 0
fi
sleep 15
done
echo "::error::Timed out waiting for the private marketing build."
exit 1
-51
View File
@@ -1,51 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
name: finalise release
on:
workflow_dispatch:
inputs:
build-version:
description: "Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes)"
type: string
required: true
fragment-run-id:
description: "Workflow run id that produced the release-fragment-* artifacts"
type: string
required: true
permissions:
actions: read
contents: write
defaults:
run:
shell: bash
jobs:
finalise:
name: finalise GitHub release manifest
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 10
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: Set up Rust toolchain (CI helpers)
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Download GitHub release fragments
env:
GH_TOKEN: ${{ github.token }}
run: >-
gh run download "${{ inputs.fragment-run-id }}"
--pattern "release-fragment-*"
--dir release-out/fragments
- name: Finalise release
env:
GH_TOKEN: ${{ github.token }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
finalise
--build-version "${{ inputs.build-version }}"
+2 -2
View File
@@ -71,7 +71,7 @@ jobs:
GH_TOKEN: ${{ steps.create-token.outputs.token }}
run: |
set -euo pipefail
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales fluxer_marketing/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
echo "No source catalog changes."
exit 0
fi
@@ -79,7 +79,7 @@ jobs:
git config user.name "fluxer-ci[bot]"
git config user.email "${{ vars.FLUXER_CI_APP_USER_ID }}+fluxer-ci[bot]@users.noreply.github.com"
git switch -c "$SOURCE_BRANCH"
git add fluxer_app/src/features/i18n/locales fluxer_marketing/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
git add fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
git commit -m "chore(i18n): refresh source catalogs"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git fetch origin "$SOURCE_BRANCH" || true
+2 -2
View File
@@ -77,14 +77,14 @@ jobs:
GH_TOKEN: ${{ steps.create-token.outputs.token }}
run: |
set -euo pipefail
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/i18n/marketing packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
echo "No generated catalog changes."
exit 0
fi
git config user.name "fluxer-ci[bot]"
git config user.email "${{ vars.FLUXER_CI_APP_USER_ID }}+fluxer-ci[bot]@users.noreply.github.com"
git add fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
git add fluxer_app/src/features/i18n/locales packages/i18n/marketing packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
git commit -m "i18n: compile Weblate catalogs"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git push origin "HEAD:$WEBLATE_BRANCH"
-282
View File
@@ -1,282 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
name: release all builds
on:
workflow_dispatch:
inputs:
build-version:
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
type: string
required: false
default: ""
permissions:
actions: read
contents: write
packages: write
defaults:
run:
shell: bash
concurrency:
group: release-all-${{ inputs['build-version'] || github.run_id }}
cancel-in-progress: false
jobs:
approve:
name: approve release build
runs-on: ubuntu-24.04
environment: builds
timeout-minutes: 5
steps:
- name: approved
run: echo "Release build approved."
meta:
name: resolve metadata
needs: approve
if: ${{ !failure() && !cancelled() }}
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
build_version: ${{ steps.vars.outputs.build_version }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: Set up Rust toolchain (CI helpers)
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: set variables
id: vars
env:
GH_TOKEN: ${{ github.token }}
FLUXER_BUILD_VERSION: ${{ inputs['build-version'] }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- resolve-calver
--github-output
build_admin:
needs: meta
uses: ./.github/workflows/build-admin.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_api:
needs: meta
uses: ./.github/workflows/build-api.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_app_proxy:
needs: meta
uses: ./.github/workflows/build-app-proxy.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_app_proxy_self_hosted:
needs: meta
uses: ./.github/workflows/build-app-proxy-self-hosted.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_docs:
needs: meta
uses: ./.github/workflows/build-docs.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_gateway:
needs: meta
uses: ./.github/workflows/build-gateway.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_gifs:
needs: meta
uses: ./.github/workflows/build-gifs.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_marketing:
needs: meta
uses: ./.github/workflows/build-marketing.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_media_proxy:
needs: meta
uses: ./.github/workflows/build-media-proxy.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_messages:
needs: meta
uses: ./.github/workflows/build-messages.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_snowflakes:
needs: meta
uses: ./.github/workflows/build-snowflakes.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_static:
needs: meta
uses: ./.github/workflows/build-static.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_unfurl:
needs: meta
uses: ./.github/workflows/build-unfurl.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
build_users:
needs: meta
uses: ./.github/workflows/build-users.yaml
with:
build-version: ${{ needs.meta.outputs.build_version }}
finalise-release: false
approval-required: false
secrets: inherit
release_assets:
name: package Helm/self-hosting
if: ${{ !failure() && !cancelled() }}
needs:
- meta
- build_admin
- build_api
- build_app_proxy
- build_app_proxy_self_hosted
- build_docs
- build_gateway
- build_gifs
- build_marketing
- build_media_proxy
- build_messages
- build_snowflakes
- build_static
- build_unfurl
- build_users
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: Set up Rust toolchain (CI helpers)
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Set up Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310
- name: Publish self-hosting bundle
env:
GH_TOKEN: ${{ github.token }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
publish-self-hosting
--build-version "${{ needs.meta.outputs.build_version }}"
- name: Publish Helm chart bundle
env:
GH_TOKEN: ${{ github.token }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
publish-helm
--build-version "${{ needs.meta.outputs.build_version }}"
- name: Upload release asset fragments
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: release-fragment-release-assets
path: release-out/fragments/*.json
if-no-files-found: error
retention-days: 14
finalise:
name: finalise GitHub release manifest
if: ${{ !failure() && !cancelled() }}
needs:
- meta
- build_admin
- build_api
- build_app_proxy
- build_app_proxy_self_hosted
- build_docs
- build_gateway
- build_gifs
- build_marketing
- build_media_proxy
- build_messages
- build_snowflakes
- build_static
- build_unfurl
- build_users
- release_assets
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
env:
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
- name: Set up Rust toolchain (CI helpers)
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: "1.93.0"
- name: Download GitHub release fragments
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
pattern: release-fragment-*
path: release-out/fragments
merge-multiple: true
- name: Finalise GitHub release manifest
env:
GH_TOKEN: ${{ github.token }}
run: >-
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
finalise
--build-version "${{ needs.meta.outputs.build_version }}"
+1 -1
View File
@@ -125,7 +125,7 @@ jobs:
libwebp-dev
- name: Install Node.js dependencies
run: pnpm --filter fluxer_admin --filter fluxer_marketing install
run: pnpm --filter fluxer_admin install
- name: Check formatting
run: cargo fmt --all -- --check