Update CI #277
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: ποΈ Build | |
# Trigger this workflow when changes happen to our core directories | |
on: | |
push: | |
paths: | |
- "engine/**" # Our Rust backend | |
- "web/**" # Our web frontend | |
- ".github/workflows/build.yaml" | |
# Set up some global variables we'll use throughout | |
env: | |
REGISTRY: ghcr.io | |
IMAGE_NAME: v3xlabs/v3x-property/engine | |
BINARY_NAME: v3x-property-engine | |
DOCKER_BUILDKIT: 1 # Enable BuildKit | |
COMPOSE_DOCKER_CLI_BUILD: 1 | |
jobs: | |
# π¦ First job: Build our Rust backend for multiple architectures | |
build-engine: | |
strategy: | |
matrix: | |
platform: | |
- arch: x86_64-unknown-linux-musl | |
docker: linux/amd64 | |
- arch: aarch64-unknown-linux-musl | |
docker: linux/arm64 | |
timeout-minutes: 20 # Prevent hanging builds | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
# Set up Rust with the specific target we need | |
- name: Install Rust | |
run: rustup toolchain install stable --profile minimal --no-self-update | |
# Speed up builds by caching dependencies | |
- name: Cache Rust | |
uses: Swatinem/rust-cache@v2 | |
with: | |
workspaces: engine | |
key: ${{ matrix.platform.arch }} | |
# Install cross | |
- name: Install cross | |
run: cargo install cross | |
# Update version number in engine/Cargo.toml | |
# If tag is a release use that | |
# Otherwise use the version number in the engine/Cargo.toml and append it with -alpha | |
- name: Update version number | |
run: | | |
if [[ ${{ github.ref }} =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then | |
echo "Release tag detected, using tag version: ${{ github.ref }}" | |
# update the version in Cargo.toml | |
sed -i "s/^version = .*/version = \"${{ github.ref }}\"/" engine/Cargo.toml | |
else | |
echo "No release tag detected, using version from Cargo.toml: ${{ github.ref }}" | |
version=$(grep -oP '(?<=version = ")[^"]+' engine/Cargo.toml) | |
# update the version in Cargo.toml | |
sed -i "s/^version = .*/version = \"${version}-alpha\"/" engine/Cargo.toml | |
fi | |
# π¨ Build our static binary | |
- name: Build Rust binary | |
working-directory: ./engine | |
env: | |
BINARY_NAME: ${{ env.BINARY_NAME }} | |
SQLX_OFFLINE: true # Use prepared SQL queries | |
run: cross build --target ${{ matrix.platform.arch }} --release | |
# π¦ Save our binary for later | |
- name: Upload built binary as artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: engine-${{ matrix.platform.arch }} | |
path: engine/target/${{ matrix.platform.arch }}/release/${{ env.BINARY_NAME }} | |
retention-days: 1 # Save storage by cleaning up quickly | |
compression-level: 9 # Maximum compression | |
# π Second job: Build our web frontend | |
build-web: | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
# Get our Node.js tools ready | |
- name: Install Tools & Dependencies | |
uses: ./.github/actions/install | |
# Build the web assets | |
- name: Build | |
working-directory: ./web | |
run: NODE_ENV=production pnpm run build | |
# π¦ Save our web assets for later | |
- name: Upload built web as artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: web | |
path: web/dist | |
# π³ Third job: Package everything into a multi-arch Docker digests | |
docker-build: | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
packages: write | |
needs: # Wait for other jobs to finish | |
- build-engine | |
- build-web | |
strategy: | |
matrix: | |
platform: | |
- arch: x86_64-unknown-linux-musl | |
docker: linux/amd64 | |
- arch: aarch64-unknown-linux-musl | |
docker: linux/arm64 | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
# π₯ Grab our built binary | |
- name: Download built binary | |
uses: actions/download-artifact@v4 | |
id: engine-binary | |
with: | |
name: engine-${{ matrix.platform.arch }} | |
path: artifacts | |
# π₯ Grab our web assets | |
- name: Download built web | |
uses: actions/download-artifact@v4 | |
id: web | |
with: | |
name: web | |
path: artifacts/web | |
- name: Prepare artifacts | |
run: | | |
chmod 755 ./artifacts/v3x-property-engine | |
ls -la ./artifacts | |
# Set up QEMU for multi-arch builds | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
# Set up Docker Buildx | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
# Log into GitHub's container registry | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
# Extract metadata | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
# π Build and push multi-arch Docker image | |
- name: Build Docker digests | |
uses: docker/build-push-action@v6 | |
id: build | |
with: | |
context: ./artifacts | |
file: ./engine/.build/Dockerfile.scratch | |
platforms: ${{ matrix.platform.docker }} | |
labels: ${{ steps.meta.outputs.labels }} | |
annotations: ${{ steps.meta.outputs.annotations }} | |
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true | |
build-args: | | |
BINARY_PATH=./v3x-property-engine | |
WEBUI_PATH=./web | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
- name: Export digest | |
run: | | |
mkdir -p /tmp/digests | |
digest="${{ steps.build.outputs.digest }}" | |
touch "/tmp/digests/${digest#sha256:}" | |
- name: Upload digest | |
uses: actions/upload-artifact@v4 | |
with: | |
name: digests-${{ matrix.platform.arch }} | |
path: /tmp/digests/* | |
if-no-files-found: error | |
retention-days: 1 | |
# π³ Final job: Merge multi-arch digests into a single artifact | |
docker-merge: | |
runs-on: ubuntu-latest | |
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') | |
permissions: | |
contents: read | |
packages: write | |
attestations: write # For security attestations | |
id-token: write | |
needs: # Wait for other jobs to finish | |
- docker-build | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
# π₯ Grab our digests | |
- name: Download digests | |
uses: actions/download-artifact@v4 | |
with: | |
path: /tmp/digests | |
pattern: digests-* | |
merge-multiple: true | |
# Log into GitHub's container registry | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
# Set up Docker Buildx | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
# Extract metadata | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
tags: | | |
type=semver,pattern={{version}} | |
type=semver,pattern={{major}}.{{minor}} | |
type=semver,pattern={{major}} | |
type=edge | |
type=sha | |
- name: Create manifest list and push | |
working-directory: /tmp/digests | |
run: | | |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) | |
- name: Inspect image | |
run: | | |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} |