362 lines
13 KiB
YAML
362 lines
13 KiB
YAML
---
|
|
name: Reusable Build
|
|
"on":
|
|
workflow_call:
|
|
inputs:
|
|
image_version:
|
|
description: 'Which image version to build'
|
|
type: string
|
|
required: true
|
|
image_tag:
|
|
description: 'Image tag to build from'
|
|
type: string
|
|
default: lts
|
|
upload_artifacts:
|
|
description: 'Upload ISOs as job artifacts'
|
|
type: boolean
|
|
default: false
|
|
upload_r2:
|
|
description: 'Upload ISOs to Cloudflare R2'
|
|
type: boolean
|
|
default: true
|
|
secrets:
|
|
R2_ACCESS_KEY_ID_2025:
|
|
required: false
|
|
R2_SECRET_ACCESS_KEY_2025:
|
|
required: false
|
|
R2_ENDPOINT_2025:
|
|
required: false
|
|
pull_request:
|
|
paths:
|
|
- ".github/workflows/reusable-build-iso-anaconda.yml"
|
|
- "iso/enable_anaconda.sh"
|
|
|
|
env:
|
|
IMAGE_REGISTRY: "ghcr.io/ublue-os"
|
|
IMAGE_NAME: "bluefin"
|
|
|
|
jobs:
|
|
# Define which variants to build based on input
|
|
# This job ensures strict separation: each image_version builds ONLY its own ISOs
|
|
determine-matrix:
|
|
name: Determine Build Matrix
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
steps:
|
|
- name: Set Matrix
|
|
id: set-matrix
|
|
run: |
|
|
# Define the matrix based on the input selection
|
|
# When called via workflow_call, the image_version input determines which ISOs to build
|
|
# Each variant builds ONLY its own specific ISOs - no cross-contamination
|
|
# NOTE: Check if inputs.image_version is provided (indicates workflow_call)
|
|
# rather than checking github.event_name, which may not be reliable
|
|
if [[ -n "${{ inputs.image_version }}" ]]; then
|
|
case "${{ inputs.image_version }}" in
|
|
"lts")
|
|
# LTS variant: builds ONLY LTS ISOs (4 total)
|
|
matrix='{"include":[
|
|
{"platform":"amd64","flavor":"main","image_version":"lts"},
|
|
{"platform":"arm64","flavor":"main","image_version":"lts"},
|
|
{"platform":"amd64","flavor":"gdx","image_version":"lts"},
|
|
{"platform":"arm64","flavor":"gdx","image_version":"lts"}
|
|
]}'
|
|
;;
|
|
"lts-hwe")
|
|
# LTS-HWE variant: builds ONLY LTS-HWE ISOs (2 total)
|
|
matrix='{"include":[
|
|
{"platform":"amd64","flavor":"main","image_version":"lts-hwe"},
|
|
{"platform":"arm64","flavor":"main","image_version":"lts-hwe"}
|
|
]}'
|
|
;;
|
|
"stable")
|
|
# Stable variant: builds ONLY Stable ISOs (2 total)
|
|
matrix='{"include":[
|
|
{"platform":"amd64","flavor":"main","image_version":"stable"},
|
|
{"platform":"amd64","flavor":"nvidia-open","image_version":"stable"}
|
|
]}'
|
|
;;
|
|
"all")
|
|
# "all" is reserved for testing - builds all variants
|
|
matrix='{"include":[
|
|
{"platform":"amd64","flavor":"main","image_version":"stable"},
|
|
{"platform":"amd64","flavor":"nvidia-open","image_version":"stable"},
|
|
{"platform":"amd64","flavor":"main","image_version":"lts"},
|
|
{"platform":"arm64","flavor":"main","image_version":"lts"},
|
|
{"platform":"amd64","flavor":"gdx","image_version":"lts"},
|
|
{"platform":"arm64","flavor":"gdx","image_version":"lts"},
|
|
{"platform":"amd64","flavor":"main","image_version":"lts-hwe"},
|
|
{"platform":"arm64","flavor":"main","image_version":"lts-hwe"}
|
|
]}'
|
|
;;
|
|
esac
|
|
else
|
|
# Default for when image_version is not provided (e.g., pull_request triggers)
|
|
# Build Stable only for faster PR validation
|
|
matrix='{"include":[
|
|
{"platform":"amd64","flavor":"main","image_version":"stable"},
|
|
{"platform":"amd64","flavor":"nvidia-open","image_version":"stable"}
|
|
]}'
|
|
fi
|
|
|
|
# Compact the JSON and output it
|
|
compact_matrix=$(echo "$matrix" | jq -c .)
|
|
echo "matrix=$compact_matrix" >> $GITHUB_OUTPUT
|
|
echo "Generated matrix:"
|
|
echo "$matrix" | jq .
|
|
|
|
build:
|
|
name: Build ISOs
|
|
runs-on: ${{ matrix.platform == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
|
|
needs: determine-matrix
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJSON(needs.determine-matrix.outputs.matrix) }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
id-token: write
|
|
|
|
steps:
|
|
- name: Install dependencies
|
|
if: matrix.platform == 'arm64'
|
|
run: |
|
|
set -x
|
|
sudo apt update -y
|
|
sudo apt install -y \
|
|
podman
|
|
|
|
- name: Checkout
|
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Setup Just
|
|
uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3
|
|
|
|
- name: Check Just Syntax
|
|
shell: bash
|
|
run: |
|
|
just check
|
|
|
|
- name: Format image ref
|
|
id: image_ref
|
|
env:
|
|
FLAVOR: ${{ matrix.flavor }}
|
|
run: |
|
|
set -eoux pipefail
|
|
# Standard variants use the Just recipe to determine image name
|
|
image_name=$(just image_name "bluefin" "${{ matrix.image_version}}" "${{ matrix.flavor}}")
|
|
image_ref="${IMAGE_REGISTRY}/${image_name}"
|
|
artifact_format="$image_name-${{ matrix.image_version }}-$(uname -m)"
|
|
KARGS="NONE"
|
|
echo "image_ref=$image_ref" >> "${GITHUB_OUTPUT}"
|
|
echo "artifact_format=$artifact_format" >> "${GITHUB_OUTPUT}"
|
|
echo "kargs=$KARGS" >> "${GITHUB_OUTPUT}"
|
|
|
|
- name: Generate titanoboa-compatible file list
|
|
id: flatpak_list
|
|
run: |
|
|
set -eoux pipefail
|
|
FILE_LIST="$(mktemp)"
|
|
git clone https://github.com/projectbluefin/common.git common
|
|
find common -iname "*system-flatpaks.Brewfile" -exec cat '{}' ';' | grep -v '#' | grep -F -e "flatpak" | sed 's/flatpak //' | tr -d '"' | tee "${FILE_LIST}"
|
|
echo "file_list_path=${FILE_LIST}" | tee "${GITHUB_OUTPUT}"
|
|
|
|
- name: Build ISO
|
|
id: build
|
|
uses: ublue-os/titanoboa@main
|
|
with:
|
|
image-ref: ${{ steps.image_ref.outputs.image_ref }}:${{ inputs.image_tag || matrix.image_version }}
|
|
flatpaks-list: ${{ steps.flatpak_list.outputs.file_list_path }}
|
|
hook-post-rootfs: ${{ (matrix.image_version == 'lts' || matrix.image_version == 'lts-hwe') && format('{0}/iso_files/configure_lts_iso_anaconda.sh', github.workspace) || format('{0}/iso_files/configure_iso_anaconda.sh', github.workspace) }}
|
|
kargs: ${{ steps.image_ref.outputs.kargs }}
|
|
builder-distro: ${{ (matrix.image_version == 'lts' || matrix.image_version == 'lts-hwe') && 'centos' || 'fedora' }}
|
|
|
|
- name: Rename ISO
|
|
id: rename
|
|
env:
|
|
OUTPUT_PATH: ${{ steps.build.outputs.iso-dest }}
|
|
FLAVOR: ${{ matrix.flavor }}
|
|
OUTPUT_NAME: ${{ steps.image_ref.outputs.artifact_format }}
|
|
IMAGE_VERSION: ${{ matrix.image_version }}
|
|
run: |
|
|
set -x
|
|
mkdir -p output
|
|
OUTPUT_DIRECTORY="$(realpath output)"
|
|
mv "${OUTPUT_PATH}" "${OUTPUT_DIRECTORY}/${OUTPUT_NAME}.iso"
|
|
(cd "${OUTPUT_DIRECTORY}" && sha256sum "${OUTPUT_NAME}.iso" | tee "${OUTPUT_NAME}.iso-CHECKSUM")
|
|
echo "output_directory=$OUTPUT_DIRECTORY" >> "${GITHUB_OUTPUT}"
|
|
|
|
- name: Generate Torrent File
|
|
env:
|
|
OUTPUT_DIRECTORY: ${{ steps.rename.outputs.output_directory }}
|
|
OUTPUT_NAME: ${{ steps.image_ref.outputs.artifact_format }}
|
|
IMAGE_VERSION: ${{ matrix.image_version }}
|
|
FLAVOR: ${{ matrix.flavor }}
|
|
PLATFORM: ${{ matrix.platform }}
|
|
run: |
|
|
set -eoux pipefail
|
|
|
|
sudo apt-get install -y mktorrent
|
|
|
|
BUILD_DATE=$(date -u +%Y-%m-%d)
|
|
|
|
cd "${OUTPUT_DIRECTORY}"
|
|
mktorrent \
|
|
-a udp://tracker.opentrackr.org:1337/announce \
|
|
-a udp://open.tracker.cl:1337/announce \
|
|
-a udp://open.demonii.com:1337/announce \
|
|
-a udp://tracker.openbittorrent.com:6969/announce \
|
|
-a udp://exodus.desync.com:6969/announce \
|
|
-a udp://tracker.torrent.eu.org:451/announce \
|
|
-a udp://tracker.moeking.me:6969/announce \
|
|
-a https://tracker.gbitt.info:443/announce \
|
|
-a https://tracker.tamersunion.org:443/announce \
|
|
-a wss://tracker.btorrent.xyz \
|
|
-a wss://tracker.openwebtorrent.com \
|
|
-w "https://projectbluefin.dev/${OUTPUT_NAME}.iso" \
|
|
-w "https://download.projectbluefin.io/${OUTPUT_NAME}.iso" \
|
|
-c "Bluefin ${IMAGE_VERSION} ${FLAVOR} (${PLATFORM}) - ${BUILD_DATE}" \
|
|
-o "${OUTPUT_NAME}.iso.torrent" \
|
|
"${OUTPUT_NAME}.iso"
|
|
|
|
sha256sum "${OUTPUT_NAME}.iso.torrent" | tee "${OUTPUT_NAME}.iso.torrent-CHECKSUM"
|
|
|
|
- name: Upload to Job Artifacts
|
|
if: inputs.upload_artifacts
|
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
|
with:
|
|
name: ${{ steps.image_ref.outputs.artifact_format }}
|
|
if-no-files-found: error
|
|
path: ${{ steps.rename.outputs.output_directory }}
|
|
|
|
- name: Set up Homebrew
|
|
if: inputs.upload_r2 && github.event_name != 'pull_request'
|
|
uses: Homebrew/actions/setup-homebrew@master
|
|
|
|
- name: Install rclone
|
|
if: inputs.upload_r2 && github.event_name != 'pull_request'
|
|
run: brew install rclone
|
|
|
|
- name: Upload to CloudFlare
|
|
if: inputs.upload_r2 && github.event_name != 'pull_request'
|
|
shell: bash
|
|
env:
|
|
RCLONE_CONFIG_R2_TYPE: s3
|
|
RCLONE_CONFIG_R2_PROVIDER: Cloudflare
|
|
RCLONE_CONFIG_R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID_2025 }}
|
|
RCLONE_CONFIG_R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY_2025 }}
|
|
RCLONE_CONFIG_R2_REGION: auto
|
|
RCLONE_CONFIG_R2_ENDPOINT: ${{ secrets.R2_ENDPOINT_2025 }}
|
|
SOURCE_DIR: ${{ steps.rename.outputs.output_directory }}
|
|
run: |
|
|
rclone copy --log-level INFO --checksum "${SOURCE_DIR}" R2:testing
|
|
|
|
create-prerelease:
|
|
name: Create GitHub Prerelease
|
|
needs: build
|
|
if: github.event_name != 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
env:
|
|
RCLONE_CONFIG_R2_TYPE: s3
|
|
RCLONE_CONFIG_R2_PROVIDER: Cloudflare
|
|
RCLONE_CONFIG_R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID_2025 }}
|
|
RCLONE_CONFIG_R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY_2025 }}
|
|
RCLONE_CONFIG_R2_REGION: auto
|
|
RCLONE_CONFIG_R2_ENDPOINT: ${{ secrets.R2_ENDPOINT_2025 }}
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
|
|
|
- name: Set up Homebrew
|
|
uses: Homebrew/actions/setup-homebrew@master
|
|
|
|
- name: Install rclone
|
|
run: brew install rclone
|
|
|
|
- name: Download Torrent Files from R2
|
|
run: |
|
|
set -eoux pipefail
|
|
mkdir -p torrents
|
|
rclone copy R2:testing torrents \
|
|
--include "*.iso.torrent" \
|
|
--include "*.iso.torrent-CHECKSUM" \
|
|
--log-level INFO
|
|
|
|
echo "Downloaded torrent files:"
|
|
ls -lh torrents/
|
|
|
|
if [ -z "$(ls torrents/*.torrent 2>/dev/null)" ]; then
|
|
echo "No torrent files found in R2 testing bucket"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Determine Release Version
|
|
id: version
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
set -eoux pipefail
|
|
YEAR_MONTH=$(date -u +%y.%m)
|
|
|
|
if gh release view "${YEAR_MONTH}" >/dev/null 2>&1; then
|
|
PATCH=1
|
|
while gh release view "${YEAR_MONTH}.${PATCH}" >/dev/null 2>&1; do
|
|
PATCH=$((PATCH + 1))
|
|
done
|
|
VERSION="${YEAR_MONTH}.${PATCH}"
|
|
else
|
|
VERSION="${YEAR_MONTH}"
|
|
fi
|
|
|
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Create GitHub Prerelease
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
run: |
|
|
set -eoux pipefail
|
|
|
|
TORRENT_LIST=""
|
|
for f in torrents/*.torrent torrents/*.torrent-CHECKSUM; do
|
|
[ -f "$f" ] && TORRENT_LIST="${TORRENT_LIST} ${f}"
|
|
done
|
|
|
|
gh release create "${VERSION}" \
|
|
--prerelease \
|
|
--title "Bluefin ISOs ${VERSION} (Prerelease)" \
|
|
--notes "$(cat <<'EOF'
|
|
## ⚠️ Prerelease - Testing Builds
|
|
|
|
These ISOs are automatically generated from successful builds and uploaded to the **testing** bucket.
|
|
|
|
**Status**: Not yet promoted to production
|
|
**For**: Testing and validation only
|
|
|
|
Once validated, these builds can be promoted to production using the promotion workflow.
|
|
|
|
### How to Download
|
|
|
|
1. Download a `.torrent` file below
|
|
2. Open with a BitTorrent client (qBittorrent, Transmission, etc.)
|
|
3. Torrents include web seeds -- downloads work immediately
|
|
|
|
### Direct Downloads
|
|
|
|
ISOs are also available at https://docs.projectbluefin.io/downloads-testing
|
|
|
|
### Verify
|
|
|
|
```bash
|
|
sha256sum -c <filename>.torrent-CHECKSUM
|
|
```
|
|
EOF
|
|
)" \
|
|
${TORRENT_LIST}
|