Build PR #372 #690
Workflow file for this run
This file contains hidden or 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 | |
| run-name: >- | |
| Build${{ github.event_name == 'workflow_dispatch' | |
| && format( | |
| ' target {0} from {1}@{2} (os {3}@{4}, smartcard {5})', | |
| github.event.inputs.target || 'pi0', | |
| github.event.inputs['app-repo'] || github.repository, | |
| github.event.inputs['source-ref'], | |
| github.event.inputs['os-repo'] || '3rdIteration/seedsigner-os', | |
| github.event.inputs['os-ref'], | |
| (fromJSON(github.event.inputs.smartcard || 'true') && 'enabled') || 'disabled' | |
| ) | |
| || github.event_name == 'push' && format(' push {0}', github.ref_name) | |
| || github.event_name == 'pull_request' && format(' PR #{0}', github.event.pull_request.number) | |
| || '' | |
| }} | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| workflow_dispatch: | |
| inputs: | |
| os-repo: | |
| description: The repository containing the SeedSigner OS sources | |
| required: false | |
| default: 3rdIteration/seedsigner-os | |
| os-ref: | |
| description: The seedsigner-os ref (tag/branch/sha1) to use | |
| default: main | |
| required: true | |
| app-repo: | |
| description: The repository containing the SeedSigner application sources | |
| required: false | |
| default: 3rdIteration/seedsigner | |
| source-ref: | |
| description: The seedsigner ref (tag/branch/sha1) to use | |
| default: dev | |
| required: true | |
| target: | |
| description: Build target profile (pi0, pi2, pi02w, pi4, or "all" for every target) | |
| required: false | |
| default: pi0 | |
| smartcard: | |
| description: Enable smartcard support for the build | |
| required: false | |
| default: 'true' | |
| type: boolean | |
| dev: | |
| description: Build dev image | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| debug-rootfs: | |
| description: Build and export the rootfs debug archive | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| upload-release: | |
| description: Upload built .img files to the matching GitHub release (if it exists) | |
| required: false | |
| default: 'false' | |
| type: boolean | |
| # Increment this number as part of a PR to trigger an image build for the PR | |
| # trigger = 0 | |
| permissions: | |
| contents: read | |
| # Cancel in-progress builds when a PR is updated; unique per-PR or per-SHA | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} | |
| cancel-in-progress: true | |
| jobs: | |
| build: | |
| name: >- | |
| build${{ github.event_name == 'workflow_dispatch' | |
| && format( | |
| ' ({0} from {1}@{2}, os {3}@{4}, smartcard {5})', | |
| github.event.inputs.target || 'pi0', | |
| github.event.inputs['app-repo'] || github.repository, | |
| github.event.inputs['source-ref'], | |
| github.event.inputs['os-repo'] || '3rdIteration/seedsigner-os', | |
| github.event.inputs['os-ref'], | |
| (fromJSON(github.event.inputs.smartcard || 'true') && 'enabled') || 'disabled' | |
| ) | |
| || '' | |
| }} | |
| runs-on: ubuntu-latest | |
| env: | |
| DOCKER_DEFAULT_PLATFORM: linux/amd64 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # PRs build both pi0 and pi02w; push defaults to pi0; | |
| # workflow_dispatch uses user input ("all" expands to every target) | |
| target: >- | |
| ${{ | |
| github.event_name == 'pull_request' | |
| && fromJSON('["pi0", "pi02w"]') | |
| || github.event_name == 'workflow_dispatch' | |
| && (github.event.inputs.target == 'all' | |
| && fromJSON('["pi0", "pi02w", "pi2", "pi4"]') | |
| || fromJSON(format('["{0}"]', github.event.inputs.target || 'pi0'))) | |
| || fromJSON('["pi0"]') | |
| }} | |
| steps: | |
| - name: checkout seedsigner-os | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs['os-repo'] || '3rdIteration/seedsigner-os' }} | |
| # use the os-ref input parameter in case of workflow_dispatch or default to main in case of cron triggers | |
| ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.os-ref || 'main' }} | |
| submodules: true | |
| path: "seedsigner-os" | |
| # get full history + tags for "git describe" | |
| fetch-depth: 0 | |
| - name: Prepare build metadata | |
| run: | | |
| echo "builder_hash=$(git -C seedsigner-os rev-parse --short HEAD)" | tee -a "$GITHUB_ENV" | |
| APP_REPO_INPUT="${{ github.event_name == 'workflow_dispatch' && github.event.inputs['app-repo'] || github.repository }}" | |
| if [[ "${APP_REPO_INPUT}" =~ ^https?:// ]]; then | |
| APP_REPO_URL="${APP_REPO_INPUT}" | |
| else | |
| APP_REPO_URL="https://github.com/${APP_REPO_INPUT}" | |
| fi | |
| APP_REF="${{ | |
| github.event_name == 'workflow_dispatch' && github.event.inputs['source-ref'] | |
| || github.event_name == 'pull_request' && github.event.pull_request.head.sha | |
| || github.sha | |
| }}" | |
| if [[ "${{ github.event_name }}" = "workflow_dispatch" ]] && ! [[ "${APP_REF}" =~ ^[0-9a-fA-F]{7,40}$ ]]; then | |
| APP_REF_ARG="--app-branch=${APP_REF}" | |
| else | |
| APP_REF_ARG="--app-commit-id=${APP_REF}" | |
| fi | |
| SS_ARGS="--${{ matrix.target }} --app-repo=${APP_REPO_URL} ${APP_REF_ARG}" | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.dev }}" = "true" ]; then | |
| SS_ARGS+=" --dev" | |
| fi | |
| if [ "${{ github.event_name }}" != "workflow_dispatch" ] || [ "${{ github.event.inputs.smartcard }}" = "true" ]; then | |
| SS_ARGS+=" --smartcard" | |
| fi | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ github.event.inputs.debug-rootfs }}" = "true" ]; then | |
| SS_ARGS+=" --debug-rootfs" | |
| fi | |
| echo "SS_ARGS=${SS_ARGS}" | tee -a "$GITHUB_ENV" | |
| - name: free disk space | |
| run: | | |
| echo "Disk usage before cleanup:" | |
| df -h | |
| sudo rm -rf \ | |
| /opt/hostedtoolcache/CodeQL \ | |
| /usr/local/lib/android/sdk \ | |
| /usr/share/dotnet | |
| sudo apt-get clean | |
| docker system prune --all --force || true | |
| echo "Disk usage after cleanup:" | |
| df -h | |
| - name: restore build cache | |
| uses: actions/cache@v5 | |
| # Caching reduces the build time to ~50% (currently: ~30 mins instead of ~1 hour, | |
| # while consuming ~850 MB storage space). | |
| with: | |
| path: | | |
| seedsigner-os/.buildroot-ccache | |
| seedsigner-os/.ccache | |
| key: build-cache-${{ matrix.target }}-${{ env.builder_hash }} | |
| restore-keys: | | |
| build-cache-${{ matrix.target }}- | |
| - name: Build image with docker compose | |
| run: | | |
| cd seedsigner-os | |
| mkdir -p .buildroot-ccache .ccache images | |
| docker compose up --force-recreate --build | |
| docker compose down | |
| - name: Fix permissions | |
| run: | | |
| sudo chown -R $USER:$USER seedsigner-os/images seedsigner-os/.buildroot-ccache seedsigner-os/.ccache | |
| - name: list images | |
| run: | | |
| ls -la seedsigner-os/images | |
| - name: print sha256sum | |
| run: | | |
| cd seedsigner-os/images | |
| shopt -s nullglob | |
| zip_files=(*.img.zip) | |
| for zip in "${zip_files[@]}"; do | |
| unzip -o "$zip" | |
| done | |
| if ((${#zip_files[@]})); then | |
| sha256sum "${zip_files[@]}" | |
| fi | |
| img_files=(*.img) | |
| if ((${#img_files[@]})); then | |
| sha256sum "${img_files[@]}" | |
| fi | |
| - name: zip images for upload | |
| run: | | |
| cd seedsigner-os/images | |
| shopt -s nullglob | |
| for img in *.img; do | |
| zip "${img}.zip" "$img" | |
| done | |
| - name: upload images | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: seedsigner_os_images-${{ matrix.target }} | |
| path: "seedsigner-os/images/*.img.zip" | |
| if-no-files-found: error | |
| # maximum 90 days retention | |
| retention-days: 90 | |
| - name: upload rootfs debug archives | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: seedsigner_os_rootfs-${{ matrix.target }} | |
| path: "seedsigner-os/images/*.tar.gz" | |
| if-no-files-found: warn | |
| # maximum 90 days retention | |
| retention-days: 90 | |
| sha256sum: | |
| name: calculate sha256sum | |
| runs-on: ubuntu-latest | |
| needs: build | |
| steps: | |
| - name: download images | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: images | |
| - name: list images | |
| run: | | |
| ls -lRa images | |
| - name: get seedsigner latest commit hash | |
| id: get-seedsigner-hash | |
| run: | | |
| git init | |
| echo "source_hash=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV | |
| - name: write sha256sum | |
| run: | | |
| cd images | |
| # each downloaded image is in its own subfolder | |
| find . -name "*.img.zip" -exec mv {} . \; | |
| shopt -s nullglob | |
| zip_files=(*.img.zip) | |
| for zip in "${zip_files[@]}"; do | |
| unzip -o "$zip" | |
| done | |
| img_files=(*.img) | |
| checksum_files=() | |
| ((${#zip_files[@]})) && checksum_files+=("${zip_files[@]}") | |
| ((${#img_files[@]})) && checksum_files+=("${img_files[@]}") | |
| if ((${#checksum_files[@]})); then | |
| sha256sum "${checksum_files[@]}" > seedsigner_os.${{ env.source_hash }}.sha256 | |
| else | |
| echo "No image files found for checksums" >&2 | |
| exit 1 | |
| fi | |
| - name: upload checksums | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: seedsigner_os_images_sha256 | |
| path: "images/*.sha256" | |
| if-no-files-found: error | |
| # maximum 90 days retention | |
| retention-days: 90 | |
| upload_release: | |
| name: upload images to release | |
| runs-on: ubuntu-latest | |
| needs: [build, sha256sum] | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.upload-release == 'true' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: download build artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: artifacts | |
| - name: prepare release assets | |
| id: prepare | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_TAG: ${{ github.event.inputs['source-ref'] }} | |
| run: | | |
| set -euo pipefail | |
| if ! gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| echo "release_exists=false" >> "$GITHUB_OUTPUT" | |
| echo "has_files=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "release_exists=true" >> "$GITHUB_OUTPUT" | |
| mkdir -p release-assets | |
| find artifacts -name "*.img.zip" -exec cp {} release-assets/ \; | |
| cd release-assets | |
| shopt -s nullglob | |
| zip_files=(*.img.zip) | |
| if ((${#zip_files[@]})); then | |
| for zip in "${zip_files[@]}"; do | |
| unzip -o "$zip" | |
| done | |
| fi | |
| existing_assets=$(gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name') | |
| for img in *.img; do | |
| if echo "$existing_assets" | grep -Fxq "$img"; then | |
| rm -f "$img" | |
| fi | |
| done | |
| if ls *.img >/dev/null 2>&1; then | |
| printf '%s\n' *.img > upload_list.txt | |
| echo "has_files=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "has_files=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: upload images to release | |
| if: steps.prepare.outputs.release_exists == 'true' && steps.prepare.outputs.has_files == 'true' | |
| uses: svenstaro/upload-release-action@v2 | |
| with: | |
| repo_token: ${{ secrets.GITHUB_TOKEN }} | |
| tag: ${{ github.event.inputs['source-ref'] }} | |
| file: release-assets/*.img* | |
| file_glob: true | |
| overwrite: false | |
| - name: append sha256 to release notes | |
| if: steps.prepare.outputs.release_exists == 'true' && steps.prepare.outputs.has_files == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RELEASE_TAG: ${{ github.event.inputs['source-ref'] }} | |
| run: | | |
| set -euo pipefail | |
| sha_file=$(ls artifacts/seedsigner_os_images_sha256/*.sha256 | head -n 1) | |
| if [[ -z "${sha_file}" ]]; then | |
| exit 0 | |
| fi | |
| note_lines="" | |
| while read -r hash filename; do | |
| base_name=$(basename "$filename") | |
| if grep -Fxq "$base_name" release-assets/upload_list.txt; then | |
| note_lines+="- ${base_name}: ${hash}"$'\n' | |
| fi | |
| done < "$sha_file" | |
| if [[ -n "${note_lines}" ]]; then | |
| current_body=$(gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --json body --jq '.body') | |
| printf "%s\n\nUploaded images:\n%s" "$current_body" "$note_lines" > release-body.txt | |
| gh release edit "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --notes-file release-body.txt | |
| fi |