Add container-based build workflow and improve build tooling #196
Workflow file for this run
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 firmwares | |
on: | |
pull_request: | |
paths-ignore: | |
- '.gitignore' | |
- 'README.md' | |
push: | |
paths-ignore: | |
- '.gitignore' | |
- 'README.md' | |
release: | |
types: | |
- published | |
env: | |
REGISTRY: ghcr.io | |
jobs: | |
run-pre-commit: | |
name: Run pre-commit | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
- name: Install pre-commit | |
run: | | |
pip install pre-commit | |
pre-commit install | |
- name: Run pre-commit | |
run: | | |
pre-commit run --show-diff-on-failure --color=always --all-files | |
build-container: | |
name: Create build container image | |
runs-on: ubuntu-latest | |
permissions: | |
packages: write | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Log in to the GitHub container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Read repository information | |
id: read-repo-info | |
run: | | |
if [[ $GITHUB_EVENT_NAME == "pull_request" ]]; then | |
base_image=$(echo ${{ github.event.pull_request.base.repo.full_name }} | awk '{print tolower($0)}') | |
head_image=$(echo ${{ github.event.pull_request.head.repo.full_name }} | awk '{print tolower($0)}') | |
else | |
base_image=$(echo ${{ github.repository }} | awk '{print tolower($0)}') | |
head_image=$(echo ${{ github.repository }} | awk '{print tolower($0)}') | |
fi | |
tag_name=$(echo "${{ hashFiles('Dockerfile') }}" | cut -c-16) | |
# Default to building a new container under the original repo | |
image_name=$head_image | |
build_image=true | |
# Check if we can use the base image (Nabu Casa) | |
if docker manifest inspect ${{ env.REGISTRY }}/$base_image:$tag_name; then | |
image_name=$base_image | |
build_image=false | |
fi | |
# Check if we can use the head image (if this is a PR) | |
if [[ $base_image != $head_image ]]; then | |
if docker manifest inspect ${{ env.REGISTRY }}/$head_image:$tag_name; then | |
image_name=$head_image | |
build_image=false | |
fi | |
fi | |
if [[ $build_image == "true" && $GITHUB_EVENT_NAME == "pull_request" ]]; then | |
echo "Cannot build a new container within a PR. Please re-run this action after $head_image:$tag_name is built." | |
exit 1 | |
fi | |
echo "build_image=$build_image" >> $GITHUB_OUTPUT | |
echo "tag_name=$tag_name" >> $GITHUB_OUTPUT | |
echo "image_name=$image_name" >> $GITHUB_OUTPUT | |
echo "container_name=${{ env.REGISTRY }}/$image_name:$tag_name" >> $GITHUB_OUTPUT | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
if: steps.read-repo-info.outputs.build_image == 'true' | |
- name: Build and Push | |
uses: docker/build-push-action@v6 | |
if: steps.read-repo-info.outputs.build_image == 'true' | |
with: | |
context: . | |
file: Dockerfile | |
tags: ${{ env.REGISTRY }}/${{ steps.read-repo-info.outputs.image_name }}:${{ steps.read-repo-info.outputs.tag_name }} | |
cache-from: ${{ env.REGISTRY }}/${{ steps.read-repo-info.outputs.image_name }}:cache-${{ steps.read-repo-info.outputs.tag_name }} | |
cache-to: ${{ env.REGISTRY }}/${{ steps.read-repo-info.outputs.image_name }}:cache-${{ steps.read-repo-info.outputs.tag_name }} | |
push: true | |
outputs: | |
tag_name: ${{ steps.read-repo-info.outputs.tag_name }} | |
image_name: ${{ steps.read-repo-info.outputs.image_name }} | |
container_name: ${{ steps.read-repo-info.outputs.container_name }} | |
list-manifests: | |
name: List firmware manifests | |
runs-on: ubuntu-latest | |
outputs: | |
matrix: ${{ steps.set-matrix.outputs.matrix }} | |
steps: | |
- uses: actions/checkout@v4 | |
- id: set-matrix | |
run: | | |
echo "matrix=$(find manifests -type f \( -name "*.yaml" -o -name "*.yml" \) -print | sort | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT | |
build-firmwares: | |
name: Firmware builder | |
needs: [list-manifests, build-container] | |
runs-on: ubuntu-latest | |
container: | |
image: ${{ needs.build-container.outputs.container_name }} | |
options: --user root | |
strategy: | |
matrix: | |
manifest: ${{ fromJson(needs.list-manifests.outputs.matrix) }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Build firmware | |
id: build-firmware | |
run: | | |
build_firmware.sh \ | |
--work-dir "$GITHUB_WORKSPACE" \ | |
--manifest "${{ matrix.manifest }}" | |
# Get the basename of the GBL in `outputs` | |
output_basename=$(basename -- $(basename -- $(ls -1 outputs/*.gbl | head -n 1)) .gbl) | |
echo "output_basename=$output_basename" >> $GITHUB_OUTPUT | |
- name: Install node within container (act) | |
if: ${{ env.ACT }} | |
run: | | |
curl -fsSL https://deb.nodesource.com/nsolid_setup_deb.sh | bash -s 20 | |
apt-get install -y nodejs | |
- name: Upload artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: firmware-build-${{ steps.build-firmware.outputs.output_basename }} | |
path: outputs/* | |
compression-level: 9 | |
if-no-files-found: error | |
generate-manifest: | |
name: Generate manifest | |
needs: [build-container, build-firmwares] | |
runs-on: ubuntu-latest | |
container: | |
image: ${{ needs.build-container.outputs.container_name }} | |
options: --user root | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Download all workflow artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
path: artifacts | |
merge-multiple: true | |
pattern: firmware-build-* | |
- name: Generate manifest | |
run: | | |
/opt/venv/bin/python3 tools/create_manifest.py artifacts > artifacts/manifest.json | |
- name: Upload artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: manifest | |
path: artifacts/manifest.json | |
compression-level: 9 | |
if-no-files-found: error | |
release-assets: | |
name: Upload release assets | |
needs: [generate-manifest] | |
if: github.event_name == 'release' | |
runs-on: ubuntu-latest | |
permissions: | |
contents: write | |
steps: | |
- name: Download manifest | |
uses: actions/download-artifact@v4 | |
with: | |
path: artifacts | |
merge-multiple: true | |
pattern: manifest | |
- name: Download all workflow artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
path: artifacts | |
merge-multiple: true | |
pattern: firmware-build-* | |
- name: Upload artifacts | |
uses: softprops/action-gh-release@v2 | |
with: | |
files: | | |
artifacts/*.gbl | |
artifacts/manifest.json |