From 5d619a615d4d19a6b37dae95be5cbe6700c3bd12 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Thu, 27 Feb 2025 16:23:15 +0100 Subject: [PATCH 01/20] feat(action): automatically cache - with this patch the action will automatically cache the produced output files - it also will cache the temporary files, such as time-stamps and so on to detect code changes - the actions/cache actions do not accept dynamically generated arrays, and therefore relecant files are moved in and out - TODO: firmware-action also needs to keep git commit hashes, for the git submodules, to detect reverts and downgrades (these user actions will not be detected with time-stamps) Signed-off-by: AtomicFS --- action.yml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/action.yml b/action.yml index e8c5836a..289a4a25 100644 --- a/action.yml +++ b/action.yml @@ -88,6 +88,9 @@ runs: with: go-version: stable + #============================================== + # Acquire firmware-action executable for Linux + #============================================== - id: fetch_unix if: ${{ ( runner.os == 'Linux' || runner.os == 'macOS' ) && inputs.compile == 'false' }} shell: bash @@ -103,6 +106,10 @@ runs: run: | go build -ldflags="-s -w" -o ../../firmware-action + #================================================ + # Acquire firmware-action executable for Windows + #================================================ + - id: fetch_windows if: ${{ runner.os == 'Windows' && inputs.compile == 'false' }} shell: pwsh @@ -116,6 +123,49 @@ runs: run: | go build -ldflags="-s -w" -o ../../firmware-action.exe + #================ + # CACHE: Restore + #================ + # + # GitHub does not allow to run a single step in some sort of for-loop, nor does allow to call another + # reusable action to potentially use matrix strategy to achieve this. + # I also looked into GitHub CI commands (link to docs below), but there is no support for uploading + # cache or artifacts + # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions + # The only way that I could come up with is to pack it (move all the files into single directory) and then upload. + # And upon download it is unpacked. + # One way might be to implement GitHub API interface right into the golang code, but that seems like too much + # overkill for what we want. + + - name: restore_cache + uses: actions/cache/restore@v4 + id: cache + with: + path: .firmware-action/ + key: firmware-action-${{ inputs.target }}-${{ hashFiles(inputs.config) }}-${{ github.sha }}-${{ github.run_id }} + restore-keys: | + firmware-action-${{ inputs.target }}-${{ hashFiles(inputs.config) }}-${{ github.sha }}- + firmware-action-${{ inputs.target }}-${{ hashFiles(inputs.config) }}- + firmware-action-${{ inputs.target }}- + + - name: unpack_cached_files + shell: bash + if: steps.cache.outputs.cache-hit == 'true' + run: | + # Get output directories from config + mapfile -t OUTPUT_DIRS < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' inputs.config) + + # For each output directory + for DIR in "${OUTPUT_DIRS[@]}"; do + if [ -d ".firmware-action/artifacts/${DIR}" ]; then + mv ".firmware-action/artifacts/${DIR}" ./ + fi + done + + #================================= + # RUN: firmware-action executable + #================================= + - name: run_unix if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }} shell: bash @@ -137,3 +187,31 @@ runs: INPUT_TARGET: ${{ inputs.target }} INPUT_RECURSIVE: ${{ inputs.recursive }} INPUT_PRUNE: ${{ inputs.prune }} + + #=============== + # CACHE: Create + #=============== + + - name: copy_artifacts + if: always() + shell: bash + run: | + mkdir -p .firmware-action/artifacts/ + + # Get output directories from config + mapfile -t OUTPUT_DIRS < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' "${{ inputs.config }}") + + # For each output directory + for DIR in "${OUTPUT_DIRS[@]}"; do + if [ -d "${DIR}" ]; then + echo "copying ${DIR}" + cp -r "${DIR}" .firmware-action/artifacts/ + fi + done + + - name: save_cache + if: always() + uses: actions/cache/save@v4 + with: + path: .firmware-action/ + key: firmware-action-${{ inputs.target }}-${{ hashFiles(inputs.config) }}-${{ github.sha }}-${{ github.run_id }} From db18447109bc7543883a36b81690f1603fe045bb Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 20:07:59 +0100 Subject: [PATCH 02/20] chore(action): improve CI logging by grouping output log Signed-off-by: AtomicFS --- action.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/action.yml b/action.yml index 289a4a25..240838e8 100644 --- a/action.yml +++ b/action.yml @@ -95,16 +95,20 @@ runs: if: ${{ ( runner.os == 'Linux' || runner.os == 'macOS' ) && inputs.compile == 'false' }} shell: bash run: | + echo "::group::curl" curl -L -o "${{ steps.filename.outputs.filename }}" "${{ steps.url.outputs.url }}" tar -xvzf "${{ steps.filename.outputs.filename }}" chmod +x firmware-action + echo "::endgroup::" # chmod should not be necessary, but just to be safe - name: compile_unix if: ${{ ( runner.os == 'Linux' || runner.os == 'macOS' ) && inputs.compile == 'true' }} shell: bash working-directory: ./cmd/firmware-action run: | + echo "::group::compile firmware-action" go build -ldflags="-s -w" -o ../../firmware-action + echo "::endgroup::" #================================================ # Acquire firmware-action executable for Windows @@ -114,14 +118,18 @@ runs: if: ${{ runner.os == 'Windows' && inputs.compile == 'false' }} shell: pwsh run: | + echo ##[group]fetch Invoke-WebRequest -Uri "${{ steps.url.outputs.url }}" -OutFile "${{ steps.filename.outputs.filename }}" Expand-Archive -Path "${{ steps.filename.outputs.filename }}" -DestinationPath .\ + echo ##[endgroup] - name: compile_windows if: ${{ runner.os == 'Windows' && inputs.compile == 'true' }} shell: pwsh working-directory: ./cmd/firmware-action run: | + echo ##[group]compile firmware-action go build -ldflags="-s -w" -o ../../firmware-action.exe + echo ##[endgroup] #================ # CACHE: Restore @@ -196,6 +204,7 @@ runs: if: always() shell: bash run: | + echo "::group::pack" mkdir -p .firmware-action/artifacts/ # Get output directories from config From 5dd9d2943f2f30de8ec1ef6c846e103502ead65e Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Thu, 27 Feb 2025 16:32:03 +0100 Subject: [PATCH 03/20] feat(action): automatically upload artifacts - just like we automatically cache, we can now automatically upload artifacts - add inputs specific to artifact uploading which are then just passed over to actions/upload-artifact action Signed-off-by: AtomicFS --- action.yml | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/action.yml b/action.yml index 240838e8..7bb3e4f7 100644 --- a/action.yml +++ b/action.yml @@ -29,6 +29,74 @@ inputs: required: false default: 'false' + # Options passed over to artifact uploading + artifact-if-no-files-found: + description: | + The desired behavior if no files are found using the provided path. + + Available Options: + warn: Output a warning but do not fail the action + error: Fail the action with an error message + ignore: Do not output any warnings or errors, the action does not fail + default: 'warn' + artifact-compression-level: + description: | + The level of compression for Zlib to be applied to the artifact archive. + The value can range from 0 to 9: + - 0: No compression + - 1: Best speed + - 6: Default compression (same as GNU Gzip) + - 9: Best compression + Higher levels will result in better compression, but will take longer to complete. + For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads. + default: '6' + artifact-overwrite: + description: | + If true, an artifact with a matching name will be deleted before a new one is uploaded. + If false, the action will fail if an artifact for the given name already exists. + Does not fail if the artifact does not exist. + default: 'false' + ## We do need this enabled because we are uploading the `./firmware-action` directory + ## which would not get uploaded at all with this option set to 'false' + ## We might change the behavior in the future if anyone needs it + ## (maybe just renaming the directory before upload) + #artifact-include-hidden-files: + # description: | + # If true, hidden files will be included in the artifact. + # If false, hidden files will be excluded from the artifact. + # default: 'false' + ## Not sure how the action would behave if a empty input would be provided, + ## and not sure if I want to just give it some arbitrarily picked default. + ## So let's leave it empty and the actions/upload-artifact will just pick the + ## repository default. + #artifact-retention-days: + # description: | + # Duration after which artifact will expire in days. 0 means using default retention. + # + # Minimum 1 day. + # Maximum 90 days unless changed from the repository settings page. + +outputs: + artifact-name: + description: | + Name of the artifact which will be uploaded to GitHub + value: ${{ steps.get_artifact_name.outputs.artifact_name }} + + # These outputs are just passing on outputs of 'upload-artifact' + # Docs: https://github.com/actions/upload-artifact + artifact-id: + description: | + GitHub ID of an Artifact, can be used by the REST API + value: ${{ steps.upload_artifact.outputs.artifact-id }} + artifact-url: + description: | + URL to download an Artifact. Can be used in many scenarios such as linking to artifacts in issues or pull requests. Users must be logged-in in order for this URL to work. This URL is valid as long as the artifact has not expired or the artifact, run or repository have not been deleted + value: ${{ steps.upload_artifact.outputs.artifact-url }} + artifact-digest: + description: | + SHA-256 digest of an Artifact + value: ${{ steps.upload_artifact.outputs.artifact-digest }} + runs: using: 'composite' steps: @@ -170,6 +238,23 @@ runs: fi done + #===================== + # ARTIFACTS: Download + #===================== + # + # Download all artifacts for the current workflow run. + # Docs: https://github.com/actions/download-artifact?tab=readme-ov-file#download-all-artifacts + + - name: download_artifacts + uses: actions/download-artifact@v4 + with: + path: .firmware-action2/ + merge-multiple: true + - name: merge_firmware_action_directory + shell: bash + run: | + # Get output directories from merged config + #================================= # RUN: firmware-action executable #================================= @@ -224,3 +309,29 @@ runs: with: path: .firmware-action/ key: firmware-action-${{ inputs.target }}-${{ hashFiles(inputs.config) }}-${{ github.sha }}-${{ github.run_id }} + + #=================== + # ARTIFACTS: Upload + #=================== + + - name: get_artifact_name + if: always() + shell: bash + id: get_artifact_name + run: | + # Extract output_dir for the specific target from config + OUTPUT_DIR=$(jq -r --arg TARGET "${{ inputs.target }}" 'to_entries[] | select(.value | to_entries[].key == $TARGET) | .value[$TARGET].output_dir' "${{ inputs.config }}" | sed -E 's/\/$//g') + DATETIME=$(date "+%Y-%m-%d_%H-%M-%S.%N") + echo "artifact_name=artifacts--${{ inputs.target }}--${OUTPUT_DIR}--${DATETIME}" >> "${GITHUB_OUTPUT}" + + - name: upload_artifact + if: always() + uses: actions/upload-artifact@v4 + id: upload_artifact + with: + name: ${{ steps.get_artifact_name.outputs.artifact_name }} + path: .firmware-action/ + include-hidden-files: true + if-no-files-found: ${{ inputs.artifact-if-no-files-found }} + compression-level: ${{ inputs.artifact-compression-level }} + overwrite: ${{ inputs.artifact-overwrite }} From 7eb2ef919a201eaab70eff13800b3cfbbb6a2fad Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 20:38:05 +0100 Subject: [PATCH 04/20] feat(action): add input options to control action behavior Signed-off-by: AtomicFS --- action.yml | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index 7bb3e4f7..107eccb4 100644 --- a/action.yml +++ b/action.yml @@ -29,6 +29,35 @@ inputs: required: false default: 'false' + # Options for automatic caches and artifacts + auto-cache: + description: | + Automatically cache the '.firmware-action' directory along with all existing output directories. + Firmware-action can automatically cache the produced files, by iterating over all 'output_dir' + entries in the confirmation file. These files, if exists, can be cached. + Because firmware-action has multiple methods of detecting changes in the sources, it can then + rebuild the files if needed. But it there was no change, it can greatly speed up the CI run. + required: false + default: 'false' + auto-artifact-download: + description: | + Automatically download all artifacts for the current workflow run. + There is no easy convenient way to download all required artifacts, so firmware-action offers the + option to just automatically download all available artifacts. This does not mean that they will + be used during the build, but it means that you do not need to handle the downloading of artifacts + yourself. + required: false + default: 'false' + auto-artifact-upload: + description: | + Automatically upload all artifacts. + Firmware action can automatically upload the artifacts for the current target (upload the 'output_dir' + directory), so that you don't have it. Combined with the option 'auto-artifact-download' + firmware-action should be able to built entire firmware stack in CI even if it is split into multiple + jobs and even if there are multiple matrix builds running in parallel. + required: false + default: 'false' + # Options passed over to artifact uploading artifact-if-no-files-found: description: | @@ -215,6 +244,7 @@ runs: - name: restore_cache uses: actions/cache/restore@v4 + if: inputs.auto-cache == 'true' id: cache with: path: .firmware-action/ @@ -226,7 +256,7 @@ runs: - name: unpack_cached_files shell: bash - if: steps.cache.outputs.cache-hit == 'true' + if: ${{ steps.cache.outputs.cache-hit == 'true' && inputs.auto-cache == 'true' }} run: | # Get output directories from config mapfile -t OUTPUT_DIRS < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' inputs.config) @@ -247,10 +277,12 @@ runs: - name: download_artifacts uses: actions/download-artifact@v4 + if: inputs.auto-artifact-download == 'true' with: path: .firmware-action2/ merge-multiple: true - name: merge_firmware_action_directory + if: inputs.auto-artifact-download == 'true' shell: bash run: | # Get output directories from merged config @@ -286,7 +318,7 @@ runs: #=============== - name: copy_artifacts - if: always() + if: ${{ always() && ( inputs.auto-cache == 'true' || inputs.auto-artifact-upload == 'true' ) }} shell: bash run: | echo "::group::pack" @@ -304,7 +336,7 @@ runs: done - name: save_cache - if: always() + if: ${{ always() && inputs.auto-cache == 'true' }} uses: actions/cache/save@v4 with: path: .firmware-action/ @@ -315,7 +347,7 @@ runs: #=================== - name: get_artifact_name - if: always() + if: ${{ always() && inputs.auto-artifact-upload == 'true' }} shell: bash id: get_artifact_name run: | @@ -325,7 +357,7 @@ runs: echo "artifact_name=artifacts--${{ inputs.target }}--${OUTPUT_DIR}--${DATETIME}" >> "${GITHUB_OUTPUT}" - name: upload_artifact - if: always() + if: ${{ always() && inputs.auto-artifact-upload == 'true' }} uses: actions/upload-artifact@v4 id: upload_artifact with: From 60132d05ced61ce7834a026f52f4f7351b72f88d Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 11:05:35 +0100 Subject: [PATCH 05/20] fix(action): multiple configuration files in cache and artifact uploads AI-Generated: true AI-Model: claude-3.5-sonnet Signed-off-by: AtomicFS --- action.yml | 82 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/action.yml b/action.yml index 107eccb4..28ef0502 100644 --- a/action.yml +++ b/action.yml @@ -254,18 +254,32 @@ runs: firmware-action-${{ inputs.target }}-${{ hashFiles(inputs.config) }}- firmware-action-${{ inputs.target }}- - - name: unpack_cached_files + - name: merge_config_files shell: bash - if: ${{ steps.cache.outputs.cache-hit == 'true' && inputs.auto-cache == 'true' }} + id: merge_config run: | - # Get output directories from config - mapfile -t OUTPUT_DIRS < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' inputs.config) + # Create temporary directory for merged config + TEMP_DIR=$(mktemp -d) + MERGED_CONFIG="${TEMP_DIR}/merged.json" + echo "merged_config=${MERGED_CONFIG}" >> "${GITHUB_OUTPUT}" - # For each output directory - for DIR in "${OUTPUT_DIRS[@]}"; do - if [ -d ".firmware-action/artifacts/${DIR}" ]; then - mv ".firmware-action/artifacts/${DIR}" ./ - fi + # Initialize empty JSON object + echo '{}' > "${MERGED_CONFIG}" + + # Split config input into individual files + readarray -t CONFIG_FILES <<< "${{ inputs.config }}" + + # Process and merge each config file + for CONFIG_FILE in "${CONFIG_FILES[@]}"; do + # Trim whitespace + CONFIG_FILE=$(echo "${CONFIG_FILE}" | xargs) + + # Skip empty lines + [ -z "${CONFIG_FILE}" ] && continue + + # Merge this config with accumulated config + jq -s '.[0] * .[1]' "${MERGED_CONFIG}" "${CONFIG_FILE}" > "${TEMP_DIR}/temp.json" + mv "${TEMP_DIR}/temp.json" "${MERGED_CONFIG}" done #===================== @@ -285,7 +299,33 @@ runs: if: inputs.auto-artifact-download == 'true' shell: bash run: | + echo "::group::merge" + mkdir -p .firmware-action/ + # Check if firmware-action2 directory exists and has content + if [ -d ".firmware-action2/" ] && [ "$(ls -A .firmware-action2/ 2>/dev/null)" ]; then + # Copy all content from firmware-action2 to firmware-action, overwriting existing files + cp -rf .firmware-action2/. .firmware-action/ + echo "Merged downloaded artifacts into .firmware-action directory" + else + echo "No downloaded artifacts found in .firmware-action2/" + fi + echo "::endgroup::" + + - name: unpack_cached_files + shell: bash + if: ${{ steps.cache.outputs.cache-hit == 'true' || inputs.auto-cache == 'true' }} + run: | + echo "::group::unpack" # Get output directories from merged config + while IFS= read -r DIR; do + # Expand any environment variables in DIR + EXPANDED_DIR=$(eval echo "${DIR}") + if [ -d ".firmware-action/artifacts/${EXPANDED_DIR}" ]; then + echo "moving ${EXPANDED_DIR}" + mv ".firmware-action/artifacts/${EXPANDED_DIR}" ./ + fi + done < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' "${{ steps.merge_config.outputs.merged_config }}") + echo "::endgroup::" #================================= # RUN: firmware-action executable @@ -324,16 +364,16 @@ runs: echo "::group::pack" mkdir -p .firmware-action/artifacts/ - # Get output directories from config - mapfile -t OUTPUT_DIRS < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' "${{ inputs.config }}") - - # For each output directory - for DIR in "${OUTPUT_DIRS[@]}"; do - if [ -d "${DIR}" ]; then - echo "copying ${DIR}" - cp -r "${DIR}" .firmware-action/artifacts/ + # Get output directories from merged config and copy them + while IFS= read -r DIR; do + # Expand any environment variables in DIR + EXPANDED_DIR=$(eval echo "${DIR}") + if [ -d "${EXPANDED_DIR}" ]; then + echo "copying ${EXPANDED_DIR}" + cp -r "${EXPANDED_DIR}" .firmware-action/artifacts/ fi - done + done < <(jq -r '[.. | objects | ."output_dir"? | select(. != null)][]' "${{ steps.merge_config.outputs.merged_config }}") + echo "::endgroup::" - name: save_cache if: ${{ always() && inputs.auto-cache == 'true' }} @@ -351,8 +391,10 @@ runs: shell: bash id: get_artifact_name run: | - # Extract output_dir for the specific target from config - OUTPUT_DIR=$(jq -r --arg TARGET "${{ inputs.target }}" 'to_entries[] | select(.value | to_entries[].key == $TARGET) | .value[$TARGET].output_dir' "${{ inputs.config }}" | sed -E 's/\/$//g') + # Extract output_dir for the specific target from merged config + OUTPUT_DIR=$(jq -r --arg TARGET "${{ inputs.target }}" 'to_entries[] | select(.value | to_entries[].key == $TARGET) | .value[$TARGET].output_dir' "${{ steps.merge_config.outputs.merged_config }}" | sed -E 's/\/$//g') + # Expand any environment variables in OUTPUT_DIR + OUTPUT_DIR=$(eval echo "${OUTPUT_DIR}") DATETIME=$(date "+%Y-%m-%d_%H-%M-%S.%N") echo "artifact_name=artifacts--${{ inputs.target }}--${OUTPUT_DIR}--${DATETIME}" >> "${GITHUB_OUTPUT}" From ce5b951e243e68818506b96dc7477292a3a8dddb Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 15:12:38 +0100 Subject: [PATCH 06/20] chore(example): cleanup Signed-off-by: AtomicFS --- .github/workflows/example.yml | 42 ----------------------------------- 1 file changed, 42 deletions(-) diff --git a/.github/workflows/example.yml b/.github/workflows/example.yml index fa202ffc..a21bfd9c 100644 --- a/.github/workflows/example.yml +++ b/.github/workflows/example.yml @@ -166,13 +166,6 @@ jobs: env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} UROOT_VERSION: "dummy" - - - name: Get artifacts - uses: actions/upload-artifact@v4 - with: - name: coreboot-${{ matrix.coreboot-version }}-${{ matrix.arch }} - path: output-coreboot - retention-days: 14 # ANCHOR_END: example_build_coreboot # Example of building Linux kernel @@ -241,13 +234,6 @@ jobs: LINUX_VERSION: ${{ matrix.linux-version }} SYSTEM_ARCH: ${{ matrix.arch }} UROOT_VERSION: "dummy" - - - name: Get artifacts - uses: actions/upload-artifact@v4 - with: - name: linux-${{ matrix.linux-version }}-${{ matrix.arch }} - path: output-linux - retention-days: 14 # ANCHOR_END: example_build_linux_kernel # Example of building EDK2 @@ -320,13 +306,6 @@ jobs: env: EDK2_VERSION: ${{ matrix.edk2-version }} GCC_TOOLCHAIN_VERSION: ${{ steps.gcc_toolchain.outputs.gcc_toolchain_version }} - - - name: Get artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.edk2-version }} - path: output-edk2 - retention-days: 14 # ANCHOR_END: example_build_edk2 # Example of building Firmware Stitching @@ -378,13 +357,6 @@ jobs: compile: ${{ needs.changes.outputs.compile }} env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} - - - name: Get artifacts - uses: actions/upload-artifact@v4 - with: - name: stitch-${{ matrix.coreboot-version }}-${{ matrix.arch }} - path: output-stitch - retention-days: 14 # ANCHOR_END: example_build_stitch # Example of building u-root @@ -436,13 +408,6 @@ jobs: compile: ${{ needs.changes.outputs.compile }} env: UROOT_VERSION: ${{ matrix.uroot-version }} - - - name: Get artifacts - uses: actions/upload-artifact@v4 - with: - name: uroot-${{ matrix.uroot-version }}-${{ matrix.arch }} - path: output-uroot - retention-days: 14 # ANCHOR_END: example_build_uroot # Example of building u-boot @@ -501,13 +466,6 @@ jobs: compile: ${{ needs.changes.outputs.compile }} env: UBOOT_VERSION: ${{ matrix.uboot-version }} - - - name: Get artifacts - uses: actions/upload-artifact@v4 - with: - name: uboot-${{ matrix.uboot-version }}-${{ matrix.arch }} - path: output-uboot - retention-days: 14 # ANCHOR_END: example_build_uboot # Example of using universal module From 4f471675bd1bf717c54ad2f3e44f5598adfefca9 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 10:20:10 +0100 Subject: [PATCH 07/20] refactor(action): update action.yml multi-line string styles Signed-off-by: AtomicFS --- action.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 28ef0502..d75acdb6 100644 --- a/action.yml +++ b/action.yml @@ -23,6 +23,11 @@ inputs: Enable this when building complex firmware stack in single job recursively and you are running out of disk space. required: false default: 'false' + debug: + description: | + Run the action with increased verbosity. + required: false + default: 'false' compile: description: | Compile the action from source instead of downloading pre-compiled binary from releases. @@ -119,7 +124,10 @@ outputs: value: ${{ steps.upload_artifact.outputs.artifact-id }} artifact-url: description: | - URL to download an Artifact. Can be used in many scenarios such as linking to artifacts in issues or pull requests. Users must be logged-in in order for this URL to work. This URL is valid as long as the artifact has not expired or the artifact, run or repository have not been deleted + URL to download an Artifact. + Can be used in many scenarios such as linking to artifacts in issues or pull requests. + Users must be logged-in in order for this URL to work. + This URL is valid as long as the artifact has not expired or the artifact, run or repository have not been deleted. value: ${{ steps.upload_artifact.outputs.artifact-url }} artifact-digest: description: | From 889dc86fda55f6d728ea78d8acde5788a9780919 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 12:06:45 +0100 Subject: [PATCH 08/20] feat(example): enable debug in CI Signed-off-by: AtomicFS --- .github/workflows/example.yml | 7 +++++++ cmd/firmware-action/main.go | 1 + 2 files changed, 8 insertions(+) diff --git a/.github/workflows/example.yml b/.github/workflows/example.yml index a21bfd9c..e99bee7b 100644 --- a/.github/workflows/example.yml +++ b/.github/workflows/example.yml @@ -163,6 +163,7 @@ jobs: target: 'coreboot-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} UROOT_VERSION: "dummy" @@ -230,6 +231,7 @@ jobs: target: 'linux-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: LINUX_VERSION: ${{ matrix.linux-version }} SYSTEM_ARCH: ${{ matrix.arch }} @@ -303,6 +305,7 @@ jobs: target: 'edk2-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: EDK2_VERSION: ${{ matrix.edk2-version }} GCC_TOOLCHAIN_VERSION: ${{ steps.gcc_toolchain.outputs.gcc_toolchain_version }} @@ -355,6 +358,7 @@ jobs: target: 'stitching-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} # ANCHOR_END: example_build_stitch @@ -406,6 +410,7 @@ jobs: target: 'u-root-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: UROOT_VERSION: ${{ matrix.uroot-version }} # ANCHOR_END: example_build_uroot @@ -464,6 +469,7 @@ jobs: target: 'u-boot-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: UBOOT_VERSION: ${{ matrix.uboot-version }} # ANCHOR_END: example_build_uboot @@ -592,6 +598,7 @@ jobs: target: 'u-root-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} + debug: 'true' env: COREBOOT_VERSION: '4.19' LINUX_VERSION: '6.9.9' diff --git a/cmd/firmware-action/main.go b/cmd/firmware-action/main.go index 433553f4..016c870f 100644 --- a/cmd/firmware-action/main.go +++ b/cmd/firmware-action/main.go @@ -296,6 +296,7 @@ func parseGithub() (string, error) { CLI.Build.Recursive = regexTrue.MatchString(action.GetInput("recursive")) CLI.Build.PruneDockerContainers = regexTrue.MatchString(action.GetInput("prune")) CLI.JSON = regexTrue.MatchString(action.GetInput("json")) + CLI.Debug = regexTrue.MatchString(action.GetInput("debug")) return "GitHub", nil } From 9bb1191fece3912fc7b653944c4d710fbabb4710 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Tue, 4 Mar 2025 18:09:28 +0100 Subject: [PATCH 09/20] fix: update Taskfile - just some minor adjustments Signed-off-by: AtomicFS --- Taskfile.yml | 2 ++ tests/Taskfile.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index 39fdc0e1..a19be23f 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -27,6 +27,7 @@ tasks: dir: '{{.GOLANG_CODE_PATH}}' cmds: - go build -ldflags="-s -w -X main.version={{.VERSION}} -X main.commit={{.COMMIT}} -X main.date={{.DATE}}" -o ../../bin/firmware-action-{{OS}}-{{ARCH}}-v{{.VERSION}} + - ln -sf ./firmware-action-{{OS}}-{{ARCH}}-v{{.VERSION}} ../../bin/firmware-action env: CGO_ENABLED: 0 sources: @@ -67,6 +68,7 @@ tasks: dir: docs cmds: - mdbook build + - echo "Visit file://{{.USER_WORKING_DIR}}/docs/public/index.html" build-mdbook-watch: desc: Build mdBook with watch diff --git a/tests/Taskfile.yml b/tests/Taskfile.yml index cbf02061..eae016d0 100644 --- a/tests/Taskfile.yml +++ b/tests/Taskfile.yml @@ -88,7 +88,7 @@ tasks: cmds: - cp -f "../tests/uboot_{{.UBOOT_VERSION}}/uboot.defconfig" "uboot_defconfig" - ln -sf "uboot-{{.UBOOT_VERSION}}" u-boot - - ../bin/firmware-action-linux-amd64-v{{.VERSION}} build --config="../tests/example_config__uboot.json" --target=u-boot-example + - ../bin/firmware-action build --config="../tests/example_config__uboot.json" --target=u-boot-example env: UBOOT_VERSION: '{{.UBOOT_VERSION}}' SYSTEM_ARCH: 'arm64' From b083d8e330c720b6efc7dd47f096c93a4f7bcf9f Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Tue, 4 Mar 2025 18:40:40 +0100 Subject: [PATCH 10/20] test: update Taskfile to simulate GitHub - I am adding another task to the Taskfile in the test directory to simulate GitHub CI environment and persuade firmware-action to act like it is in CI Signed-off-by: AtomicFS --- tests/Taskfile.yml | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/tests/Taskfile.yml b/tests/Taskfile.yml index eae016d0..bda04fe3 100644 --- a/tests/Taskfile.yml +++ b/tests/Taskfile.yml @@ -43,15 +43,37 @@ tasks: internal: true cmds: - cp -f "../tests/linux_{{.LINUX_VERSION}}/linux.defconfig" "ci_defconfig" - - ../bin/firmware-action-linux-amd64-v{{.VERSION}} build --config="../tests/example_config__linux.json" --target=linux-example + - ../bin/firmware-action build --config="../tests/example_config__linux.json" --target=linux-example env: LINUX_VERSION: '{{.LINUX_VERSION}}' SYSTEM_ARCH: 'amd64' + UROOT_VERSION: "" requires: vars: [LINUX_VERSION] - linux-*: - desc: Run example + linux-run-github: + desc: Run firmware-action just like in GitHub runner + dir: '{{.WORKDIR}}' + internal: true + cmds: + - cp -f "../tests/linux_{{.LINUX_VERSION}}/linux.defconfig" "ci_defconfig" + - ../bin/firmware-action + env: + LINUX_VERSION: '{{.LINUX_VERSION}}' + SYSTEM_ARCH: 'amd64' + UROOT_VERSION: "" + # Fake GitHub runner + GITHUB_ACTIONS: "yes" + INPUT_TARGET: "linux-example" + INPUT_RECURSIVE: "false" + # For testing multiple config inputs + #INPUT_CONFIG: " ../tests/example_config__linux.json\n ../tests/example_config__uroot.json \n " + INPUT_CONFIG: "../tests/example_config__linux.json" + requires: + vars: [LINUX_VERSION] + + linux-local-*: + desc: Run example as it would run locally deps: - task: mkdir - task: :build-go-binary @@ -66,6 +88,22 @@ tasks: vars: LINUX_VERSION: '{{.VARIANT}}' + linux-github-*: + desc: Run example as it would run in GitHub CI + deps: + - task: mkdir + - task: :build-go-binary + vars: + VARIANT: '{{index .MATCH 0}}' + cmds: + - task: linux-fetch + vars: + LINUX_VERSION: '{{.VARIANT}}' + - task: linux-run-github + vars: + LINUX_VERSION: '{{.VARIANT}}' + + #======== # U-BOOT #======== From 40e40991790851ec7a4c45eac8b54cb888ae9640 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 12:32:08 +0100 Subject: [PATCH 11/20] chore(cmd): better warning Signed-off-by: AtomicFS --- cmd/firmware-action/filesystem/git.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/firmware-action/filesystem/git.go b/cmd/firmware-action/filesystem/git.go index c57abc91..c98221cb 100644 --- a/cmd/firmware-action/filesystem/git.go +++ b/cmd/firmware-action/filesystem/git.go @@ -117,5 +117,14 @@ func gitDescribe(repoPath string, cfg *describe) (string, error) { // Remove trailing newline result := strings.TrimSpace(describe) + // Check validity of the returned string + pattern := regexp.MustCompile(`[\d\w]{13}(\-dirty)?`) + valid := pattern.MatchString(result) + if !valid { + slog.Warn( + fmt.Sprintf("Output of 'git describe' for '%s' seems to be invalid commit hash, output is '%s'. Will carry on.", repoPath, result), + ) + } + return result, err } From 99171700ed11ee094039d358d361a554ae03ff61 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Fri, 28 Feb 2025 16:45:52 +0100 Subject: [PATCH 12/20] docs: add artifact and caching documentation to GitHub CI usage AI-Generated: true AI-Model: claude-3.5-sonnet Signed-off-by: AtomicFS --- .../get_started/06_run_in_ci.md | 2 + docs/src/firmware-action/usage_github.md | 47 ++++++++++++++----- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/docs/src/firmware-action/get_started/06_run_in_ci.md b/docs/src/firmware-action/get_started/06_run_in_ci.md index 89ff6ae4..bfb7191f 100644 --- a/docs/src/firmware-action/get_started/06_run_in_ci.md +++ b/docs/src/firmware-action/get_started/06_run_in_ci.md @@ -10,5 +10,7 @@ Now that we have `firmware-action` working on local system. Let's set up CI. Commit, push and watch. And that is it. +The action automatically handles artifact uploading and caching. See [GitHub CI Usage](../usage_github.md) for details about artifacts, outputs and caching. + Now you should be able to build coreboot in CI and on your local machine. diff --git a/docs/src/firmware-action/usage_github.md b/docs/src/firmware-action/usage_github.md index 715c5274..a0802fb1 100644 --- a/docs/src/firmware-action/usage_github.md +++ b/docs/src/firmware-action/usage_github.md @@ -1,24 +1,47 @@ # Github CI -You can use `firmware-action` as any other action. +You can use `firmware-action` as any other action. The action automatically handles artifact uploading and caching to improve build times. + + +## Artifacts and Outputs + +The action automatically uploads build artifacts and provides the following outputs: +- `artifact-name`: Name of the uploaded artifact + +Internally, `firmware-action` is using [upload-artifact](https://github.com/actions/upload-artifact) action and passes on it's outputs too: +- `artifact-id`: GitHub ID of the artifact (useful for REST API) +- `artifact-url`: Direct download URL for the artifact (requires GitHub login) +- `artifact-digest`: SHA-256 digest of the artifact ```admonish example +You can use these outputs in subsequent steps: ~~~yaml -name: Firmware example build -jobs: - firmware_build: - runs-on: ubuntu-latest - steps: - - name: Build coreboot with firmware-action - uses: 9elements/firmware-action@main - with: - config: '' - target: '' - recursive: 'false' +steps: + - name: Build firmware + id: firmware + uses: 9elements/firmware-action@main + with: + config: 'config.json' + target: 'my-target' + + - name: Use artifact info + run: | + echo "Artifact name: ${{ steps.firmware.outputs.artifact-name }}" + echo "Download from: ${{ steps.firmware.outputs.artifact-url }}" ~~~ ``` +## Build Caching + +The action automatically caches build artifacts between runs to speed up builds. The cache is: +- Keyed by the config file contents and commit SHA +- Restored at the start of each run +- Saved after each run, even if the build fails + +No configuration is needed - caching works out of the box. + + ## Parametric builds with environment variables To take advantage of matrix builds in GitHub, it is possible to use environment variables inside the JSON configuration file. From b8f65369b05c7e7ee7371bc01917079225c2e22b Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 10:27:56 +0100 Subject: [PATCH 13/20] docs: add notes on YAML multi-line strings AI-Generated: true AI-Model: claude-3.5-sonnet Signed-off-by: AtomicFS --- docs/src/firmware-action/config.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/src/firmware-action/config.md b/docs/src/firmware-action/config.md index a2f1d9c4..5bd89a60 100644 --- a/docs/src/firmware-action/config.md +++ b/docs/src/firmware-action/config.md @@ -9,10 +9,34 @@ ```admonish tip Multiple configuration files can be supplied to `firmware-action`. Dependencies also work across files. +Multiple configs in local build: ~~~ firmware-action build --config=config-01.json --config=config-02.json ... ~~~ +Multiple configs in GitHub CI: +~~~ +- name: firmware-action + uses: ./ + with: + config: |- + config-01.json + config-02.json +~~~ +``` + +```admonish tip +For YAML multi-line string please refer to documentation [Block Style Productions in YAML](https://yaml.org/spec/1.2.2/#block-style-productions) + +| Indicator | Name | Behavior | +|-----------|---------------------|---------------------------------------------------| +| `\|` | Literal Block | Preserves newlines, strips final newline | +| `\|+` | Literal Block Keep | Preserves all newlines including final | +| `\|-` | Literal Block Strip | Strips all trailing newlines | +| `>` | Folded Block | Folds newlines to spaces, keeps paragraph breaks | +| `>+` | Folded Block Keep | Like > but keeps final newline | +| `>-` | Folded Block Strip | Like > but strips final newline | + Beware that modules with identical names are permitted, as long as they are not in the same configuration file. `firmware-action` processes the files in order in which they were supplied and in case of name-collision, the configuration in last file takes precedence. From d22b928492511baff6ae6c930a50691f999f101c Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Tue, 4 Mar 2025 17:53:57 +0100 Subject: [PATCH 14/20] chore(linter): cspell Signed-off-by: AtomicFS --- .cspell.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.cspell.json b/.cspell.json index 8f52faa0..dbe89e2c 100644 --- a/.cspell.json +++ b/.cspell.json @@ -89,6 +89,7 @@ "edkii", "elif", "emeraldlake", + "endgroup", "exitcode", "filenamify", "githubaction", @@ -119,6 +120,7 @@ "markdownlint", "megalinter", "menuconfig", + "mktemp", "modifyitems", "mountpoint", "multilib", @@ -138,6 +140,7 @@ "pylint", "pytest", "rdparty", + "readarray", "rootdir", "runslow", "rustup", From dddb5778636b8d4f40ce62f9f17048b298ab255f Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 16:57:20 +0100 Subject: [PATCH 15/20] chore: cosmetic Signed-off-by: AtomicFS --- .github/workflows/example.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/example.yml b/.github/workflows/example.yml index e99bee7b..8573c16a 100644 --- a/.github/workflows/example.yml +++ b/.github/workflows/example.yml @@ -166,7 +166,7 @@ jobs: debug: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} - UROOT_VERSION: "dummy" + UROOT_VERSION: 'dummy' # ANCHOR_END: example_build_coreboot # Example of building Linux kernel @@ -235,7 +235,7 @@ jobs: env: LINUX_VERSION: ${{ matrix.linux-version }} SYSTEM_ARCH: ${{ matrix.arch }} - UROOT_VERSION: "dummy" + UROOT_VERSION: 'dummy' # ANCHOR_END: example_build_linux_kernel # Example of building EDK2 From e12f3958afbdf68946d36a00681540cdbd098ac5 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 20:39:36 +0100 Subject: [PATCH 16/20] chore(example): update example Signed-off-by: AtomicFS --- .github/workflows/example.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/example.yml b/.github/workflows/example.yml index 8573c16a..e1a89d6a 100644 --- a/.github/workflows/example.yml +++ b/.github/workflows/example.yml @@ -164,6 +164,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} UROOT_VERSION: 'dummy' @@ -232,6 +235,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: LINUX_VERSION: ${{ matrix.linux-version }} SYSTEM_ARCH: ${{ matrix.arch }} @@ -306,6 +312,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: EDK2_VERSION: ${{ matrix.edk2-version }} GCC_TOOLCHAIN_VERSION: ${{ steps.gcc_toolchain.outputs.gcc_toolchain_version }} @@ -359,6 +368,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} # ANCHOR_END: example_build_stitch @@ -411,6 +423,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: UROOT_VERSION: ${{ matrix.uroot-version }} # ANCHOR_END: example_build_uroot @@ -470,6 +485,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: UBOOT_VERSION: ${{ matrix.uboot-version }} # ANCHOR_END: example_build_uboot @@ -599,6 +617,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' env: COREBOOT_VERSION: '4.19' LINUX_VERSION: '6.9.9' From bda9be60c23f4d6db02705aa7a4d2123f3c592c0 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 5 Mar 2025 22:07:30 +0100 Subject: [PATCH 17/20] docs: update GitHub CI usage documentation AI-Generated: true AI-Model: claude-3.5-sonnet Signed-off-by: AtomicFS --- docs/src/firmware-action/usage_github.md | 91 +++++++++++++----------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/docs/src/firmware-action/usage_github.md b/docs/src/firmware-action/usage_github.md index a0802fb1..0d5b1a7f 100644 --- a/docs/src/firmware-action/usage_github.md +++ b/docs/src/firmware-action/usage_github.md @@ -1,80 +1,89 @@ # Github CI -You can use `firmware-action` as any other action. The action automatically handles artifact uploading and caching to improve build times. - +You can use `firmware-action` as any other GitHub action. The action requires a configuration file (`config`) and target (`target`) to build, with additional options for artifact handling and caching to improve build times. ## Artifacts and Outputs -The action automatically uploads build artifacts and provides the following outputs: -- `artifact-name`: Name of the uploaded artifact +The action can automatically upload build artifacts when the `auto-artifact-upload` option is enabled (disabled by default). When enabled, the action provides the following outputs: -Internally, `firmware-action` is using [upload-artifact](https://github.com/actions/upload-artifact) action and passes on it's outputs too: +- `artifact-name`: Name of the uploaded artifact - `artifact-id`: GitHub ID of the artifact (useful for REST API) - `artifact-url`: Direct download URL for the artifact (requires GitHub login) - `artifact-digest`: SHA-256 digest of the artifact +Internally, `firmware-action` uses the [upload-artifact](https://github.com/actions/upload-artifact) action to handle artifact uploads. + ```admonish example You can use these outputs in subsequent steps: ~~~yaml -steps: - - name: Build firmware - id: firmware - uses: 9elements/firmware-action@main - with: - config: 'config.json' - target: 'my-target' - - - name: Use artifact info - run: | - echo "Artifact name: ${{ steps.firmware.outputs.artifact-name }}" - echo "Download from: ${{ steps.firmware.outputs.artifact-url }}" +{{#include ../firmware-action-example/.github/workflows/coreboot-example.yml:CorebootExample}} ~~~ ``` +You can configure artifact handling with these options: +- `artifact-if-no-files-found`: Behavior if no files are found ('warn', 'error', or 'ignore', default: 'warn') +- `artifact-compression-level`: Compression level for artifacts (0-9, default: '6') +- `artifact-overwrite`: Whether to overwrite existing artifacts with the same name (default: 'false') ## Build Caching -The action automatically caches build artifacts between runs to speed up builds. The cache is: +The action can cache build artifacts between runs to speed up builds, but this feature must be explicitly enabled with the `auto-cache` input (disabled by default). + +When enabled, the cache is: - Keyed by the config file contents and commit SHA - Restored at the start of each run - Saved after each run, even if the build fails -No configuration is needed - caching works out of the box. +You can also use the `recursive` option to build a target with all its dependencies, and the `debug` option for increased verbosity when troubleshooting. +## Artifact Downloading + +When `auto-artifact-download` is enabled (disabled by default), the action automatically downloads all artifacts from the current workflow run. This feature is particularly useful in workflows with multiple jobs that depend on each other, as it can save a lot of copy-pasting between workflow steps. + +```admonish note +Due to limitations in GitHub Actions, it's not possible for the action to download only relevant artifacts. When enabled, it downloads all artifacts from the current workflow run regardless of whether they're needed for the current build. +``` + +```admonish warning +When using `auto-artifact-download`, be careful to avoid naming conflicts in the `output_dir` values across different targets. Since all artifacts are downloaded and merged into the same workspace, files with the same paths will overwrite each other. +``` + +```admonish warning +At the time of writing, GitHub-hosted runners have only 14GB of disk space. If your artifacts are large and/or you have many matrix combinations, the workflow could run out of disk space. Monitor your disk usage when using this feature with large builds. +``` + +## Complete Configuration Example + +For a complete example with all options: + +```admonish example +~~~yaml +{{#include ../firmware-action-example/.github/workflows/linuxboot-example.yml:AllFeatures}} +~~~ +``` ## Parametric builds with environment variables To take advantage of matrix builds in GitHub, it is possible to use environment variables inside the JSON configuration file. ```admonish example -For example let's make `COREBOOT_VERSION` environment variable which will hold version of coreboot. +For example let's make `RELEASE_TYPE` environment variable which will hold either `DEBUG` or `RELEASE`. JSON would look like this: ~~~json -... -"sdk_url": "ghcr.io/9elements/firmware-action/coreboot_${COREBOOT_VERSION}:main", -... -"defconfig_path": "tests/coreboot_${COREBOOT_VERSION}/seabios.defconfig", -... +{ + "u-root": { + "uroot-example-${RELEASE_TYPE}": { + ... + "output_dir": "output-linuxboot-uroot-${RELEASE_TYPE}/", + ... + } + } +} ~~~ YAML would look like this: ~~~yaml -name: Firmware example build -jobs: - firmware_build: - runs-on: ubuntu-latest - strategy: - matrix: - coreboot_version: ["4.19", "4.20"] - steps: - - name: Build coreboot with firmware-action - uses: 9elements/firmware-action@main - with: - config: '' - target: '' - recursive: 'false' - env: - COREBOOT_VERSION: ${{ matrix.coreboot_version }} +{{#include ../firmware-action-example/.github/workflows/linuxboot-example-separate-jobs.yml:Parametric}} ~~~ ``` From 1b114827c80a44b53058b049940f37856e52796a Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Thu, 6 Mar 2025 10:34:21 +0100 Subject: [PATCH 18/20] docs: add notes on migrating to new version Signed-off-by: AtomicFS --- docs/src/SUMMARY.md | 1 + .../migration/v0.14.x--v0.15.0/migrate.md | 9 ++ .../migration/v0.14.x--v0.15.0/new.yml | 30 ++++ .../migration/v0.14.x--v0.15.0/old.yml | 128 +++++++++++++++++ .../v0.14.x--v0.15.0/workflow.yml.patch | 132 ++++++++++++++++++ 5 files changed, 300 insertions(+) create mode 100644 docs/src/firmware-action/migration/v0.14.x--v0.15.0/migrate.md create mode 100644 docs/src/firmware-action/migration/v0.14.x--v0.15.0/new.yml create mode 100644 docs/src/firmware-action/migration/v0.14.x--v0.15.0/old.yml create mode 100644 docs/src/firmware-action/migration/v0.14.x--v0.15.0/workflow.yml.patch diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 0c0d5da5..734e1f12 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -28,6 +28,7 @@ - [Change detection](firmware-action/change_detection.md) - [Migration instructions]() - [Migration from v0.13.x to v0.14.0](firmware-action/migration/v0.13.x--v0.14.0/migrate.md) + - [Migration from v0.14.x to v0.15.0](firmware-action/migration/v0.14.x--v0.15.0/migrate.md) --- diff --git a/docs/src/firmware-action/migration/v0.14.x--v0.15.0/migrate.md b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/migrate.md new file mode 100644 index 00000000..f18edec1 --- /dev/null +++ b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/migrate.md @@ -0,0 +1,9 @@ +# Migration guide from v0.14.x to v0.15.0 + +Drop-in replacement, should work out of the box. But there are many simplifications and quality of life improvements you might want to check out. + +Most important being the optional automatic handling of caches and artifacts. This can greatly simplify your workflows. + +```patch +{{#include ./workflow.yml.patch}} +``` diff --git a/docs/src/firmware-action/migration/v0.14.x--v0.15.0/new.yml b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/new.yml new file mode 100644 index 00000000..1ee777f1 --- /dev/null +++ b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/new.yml @@ -0,0 +1,30 @@ +--- +name: linuxboot build +on: + push: + +permissions: + contents: read + +jobs: + build-coreboot-linuxboot-example: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: Fetch few missing submodules + run: | + git submodule update --depth 1 --init --recursive --checkout + + - name: firmware-action + uses: 9elements/firmware-action@v0.15.0 + with: + config: 'coreboot-linuxboot-example.json' + target: 'coreboot-example-with-linuxboot' + recursive: 'true' + debug: 'true' + auto-cache: 'true' + auto-artifact-download: 'true' + auto-artifact-upload: 'true' diff --git a/docs/src/firmware-action/migration/v0.14.x--v0.15.0/old.yml b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/old.yml new file mode 100644 index 00000000..24dc50cf --- /dev/null +++ b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/old.yml @@ -0,0 +1,128 @@ +--- +name: linuxboot build +on: + push: + +permissions: + contents: read + +jobs: + build-coreboot-linuxboot-example: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: Fetch few missing submodules + run: | + git submodule update --depth 1 --init --recursive --checkout + + #================================== + # Get commit hashes for submodules + #================================== + + - name: Extract uroot commit sha + id: uroot_commit + run: | + echo "uroot_commit=$( git rev-parse HEAD:coreboot-linuxboot-example/u-root )" >> "${GITHUB_OUTPUT}" + + - name: Extract Linux commit sha + id: linux_commit + run: | + echo "linux_commit=$( git rev-parse HEAD:coreboot-linuxboot-example/linux )" >> "${GITHUB_OUTPUT}" + + - name: Extract Coreboot commit sha + id: coreboot_commit + run: | + echo "coreboot_commit=$( git rev-parse HEAD:coreboot-linuxboot-example/coreboot )" >> "${GITHUB_OUTPUT}" + + #=============== + # Restore cache + #=============== + + - name: Restore cached u-root artefact + uses: actions/cache/restore@v4 + id: cache-uroot + with: + path: output-linuxboot-uroot + key: uroot-${{ steps.uroot_commit.outputs.uroot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json') }} + + - name: Restore cached Linux artefact + uses: actions/cache/restore@v4 + id: cache-linux + with: + path: output-linuxboot-linux + key: linux-${{ steps.linux_commit.outputs.linux_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/linux_defconfig', 'output-linuxboot-uroot/*') }} + + - name: Restore cached coreboot artefact + uses: actions/cache/restore@v4 + id: cache-coreboot + with: + path: output-linuxboot-coreboot + key: coreboot-${{ steps.coreboot_commit.outputs.coreboot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/coreboot_linuxboot_defconfig', 'output-linuxboot-linux/*') }} + + #============================ + # Build with firmware-action + #============================ + + - name: firmware-action + uses: 9elements/firmware-action@v0.14.1 + with: + config: 'coreboot-linuxboot-example.json' + target: 'coreboot-example-with-linuxboot' + recursive: 'true' + + #========================== + # Upload artifacts - uroot + #========================== + + - name: Cache u-root + uses: actions/cache/save@v4 + if: always() + with: + key: uroot-${{ steps.uroot_commit.outputs.uroot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json') }} + path: output-linuxboot-uroot + + - name: Upload artifacts for uroot + uses: actions/upload-artifact@v4 + if: always() + with: + name: linuxboot-uroot + path: output-linuxboot-uroot + + #========================== + # Upload artifacts - Linux + #========================== + + - name: Cache Linux + uses: actions/cache/save@v4 + if: always() + with: + key: linux-${{ steps.linux_commit.outputs.linux_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/linux_defconfig', 'output-linuxboot-uroot/*') }} + path: output-linuxboot-linux + + - name: Upload artifacts for Linux + uses: actions/upload-artifact@v4 + if: always() + with: + name: linuxboot-linux + path: output-linuxboot-linux + + #============================= + # Upload artifacts - coreboot + #============================= + + - name: Cache coreboot + uses: actions/cache/save@v4 + if: always() + with: + key: coreboot-${{ steps.coreboot_commit.outputs.coreboot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/coreboot_linuxboot_defconfig', 'output-linuxboot-linux/*') }} + path: output-linuxboot-coreboot + + - name: Upload artifacts for coreboot + uses: actions/upload-artifact@v4 + if: always() + with: + name: linuxboot-coreboot + path: output-linuxboot-coreboot diff --git a/docs/src/firmware-action/migration/v0.14.x--v0.15.0/workflow.yml.patch b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/workflow.yml.patch new file mode 100644 index 00000000..35f07e5d --- /dev/null +++ b/docs/src/firmware-action/migration/v0.14.x--v0.15.0/workflow.yml.patch @@ -0,0 +1,132 @@ + --- + name: linuxboot build + on: + push: + + permissions: + contents: read + + jobs: + build-coreboot-linuxboot-example: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: Fetch few missing submodules + run: | + git submodule update --depth 1 --init --recursive --checkout + +- #================================== +- # Get commit hashes for submodules +- #================================== +- +- - name: Extract uroot commit sha +- id: uroot_commit +- run: | +- echo "uroot_commit=$( git rev-parse HEAD:coreboot-linuxboot-example/u-root )" >> "${GITHUB_OUTPUT}" +- +- - name: Extract Linux commit sha +- id: linux_commit +- run: | +- echo "linux_commit=$( git rev-parse HEAD:coreboot-linuxboot-example/linux )" >> "${GITHUB_OUTPUT}" +- +- - name: Extract Coreboot commit sha +- id: coreboot_commit +- run: | +- echo "coreboot_commit=$( git rev-parse HEAD:coreboot-linuxboot-example/coreboot )" >> "${GITHUB_OUTPUT}" +- +- #=============== +- # Restore cache +- #=============== +- +- - name: Restore cached u-root artefact +- uses: actions/cache/restore@v4 +- id: cache-uroot +- with: +- path: output-linuxboot-uroot +- key: uroot-${{ steps.uroot_commit.outputs.uroot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json') }} +- +- - name: Restore cached Linux artefact +- uses: actions/cache/restore@v4 +- id: cache-linux +- with: +- path: output-linuxboot-linux +- key: linux-${{ steps.linux_commit.outputs.linux_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/linux_defconfig', 'output-linuxboot-uroot/*') }} +- +- - name: Restore cached coreboot artefact +- uses: actions/cache/restore@v4 +- id: cache-coreboot +- with: +- path: output-linuxboot-coreboot +- key: coreboot-${{ steps.coreboot_commit.outputs.coreboot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/coreboot_linuxboot_defconfig', 'output-linuxboot-linux/*') }} +- +- #============================ +- # Build with firmware-action +- #============================ +- + - name: firmware-action +- uses: 9elements/firmware-action@v0.14.1 ++ uses: 9elements/firmware-action@v0.15.0 + with: + config: 'coreboot-linuxboot-example.json' + target: 'coreboot-example-with-linuxboot' + recursive: 'true' ++ auto-cache: 'true' ++ auto-artifact-download: 'true' ++ auto-artifact-upload: 'true' +- +- #========================== +- # Upload artifacts - uroot +- #========================== +- +- - name: Cache u-root +- uses: actions/cache/save@v4 +- if: always() +- with: +- key: uroot-${{ steps.uroot_commit.outputs.uroot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json') }} +- path: output-linuxboot-uroot +- +- - name: Upload artifacts for uroot +- uses: actions/upload-artifact@v4 +- if: always() +- with: +- name: linuxboot-uroot +- path: output-linuxboot-uroot +- +- #========================== +- # Upload artifacts - Linux +- #========================== +- +- - name: Cache Linux +- uses: actions/cache/save@v4 +- if: always() +- with: +- key: linux-${{ steps.linux_commit.outputs.linux_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/linux_defconfig', 'output-linuxboot-uroot/*') }} +- path: output-linuxboot-linux +- +- - name: Upload artifacts for Linux +- uses: actions/upload-artifact@v4 +- if: always() +- with: +- name: linuxboot-linux +- path: output-linuxboot-linux +- +- #============================= +- # Upload artifacts - coreboot +- #============================= +- +- - name: Cache coreboot +- uses: actions/cache/save@v4 +- if: always() +- with: +- key: coreboot-${{ steps.coreboot_commit.outputs.coreboot_commit }}-${{ hashFiles('coreboot-linuxboot-example.json', 'coreboot-linuxboot-example/coreboot_linuxboot_defconfig', 'output-linuxboot-linux/*') }} +- path: output-linuxboot-coreboot +- +- - name: Upload artifacts for coreboot +- uses: actions/upload-artifact@v4 +- if: always() +- with: +- name: linuxboot-coreboot +- path: output-linuxboot-coreboot From 9b33b87adf4efce02610f250148808cc74aad6c2 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Mon, 17 Mar 2025 15:55:06 +0100 Subject: [PATCH 19/20] docs: update comment in action.yml Signed-off-by: AtomicFS --- action.yml | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/action.yml b/action.yml index d75acdb6..70697b1e 100644 --- a/action.yml +++ b/action.yml @@ -90,25 +90,18 @@ inputs: If false, the action will fail if an artifact for the given name already exists. Does not fail if the artifact does not exist. default: 'false' - ## We do need this enabled because we are uploading the `./firmware-action` directory - ## which would not get uploaded at all with this option set to 'false' - ## We might change the behavior in the future if anyone needs it - ## (maybe just renaming the directory before upload) - #artifact-include-hidden-files: - # description: | - # If true, hidden files will be included in the artifact. - # If false, hidden files will be excluded from the artifact. - # default: 'false' - ## Not sure how the action would behave if a empty input would be provided, - ## and not sure if I want to just give it some arbitrarily picked default. - ## So let's leave it empty and the actions/upload-artifact will just pick the - ## repository default. - #artifact-retention-days: - # description: | - # Duration after which artifact will expire in days. 0 means using default retention. + # We do need this enabled because we are uploading the `./firmware-action` directory + # which would not get uploaded at all with this option set to 'false' + # We might change the behavior in the future if anyone needs it + # (maybe just renaming the directory before upload) # - # Minimum 1 day. - # Maximum 90 days unless changed from the repository settings page. + # Action `actions/upload-artifact` also has these inputs: + # - artifact-include-hidden-files: + # - artifact-retention-days: + # Not sure how the action would behave if a empty input would be provided, + # and not sure if I want to just give it some arbitrarily picked default. + # So let's leave it empty and the actions/upload-artifact will just pick the + # repository default. outputs: artifact-name: From 4427e2829ff49b8fde5e863d18d41c4fe7992596 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Tue, 18 Mar 2025 11:12:40 +0100 Subject: [PATCH 20/20] chore: changes according to review Signed-off-by: AtomicFS --- .github/workflows/example.yml | 42 ++++++------- action.yml | 78 ++++++++++-------------- docs/src/firmware-action/usage_github.md | 2 +- 3 files changed, 54 insertions(+), 68 deletions(-) diff --git a/.github/workflows/example.yml b/.github/workflows/example.yml index e1a89d6a..055546da 100644 --- a/.github/workflows/example.yml +++ b/.github/workflows/example.yml @@ -164,9 +164,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} UROOT_VERSION: 'dummy' @@ -235,9 +235,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: LINUX_VERSION: ${{ matrix.linux-version }} SYSTEM_ARCH: ${{ matrix.arch }} @@ -312,9 +312,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: EDK2_VERSION: ${{ matrix.edk2-version }} GCC_TOOLCHAIN_VERSION: ${{ steps.gcc_toolchain.outputs.gcc_toolchain_version }} @@ -368,9 +368,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} # ANCHOR_END: example_build_stitch @@ -423,9 +423,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: UROOT_VERSION: ${{ matrix.uroot-version }} # ANCHOR_END: example_build_uroot @@ -485,9 +485,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: UBOOT_VERSION: ${{ matrix.uboot-version }} # ANCHOR_END: example_build_uboot @@ -617,9 +617,9 @@ jobs: recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' - auto-cache: 'true' - auto-artifact-download: 'true' - auto-artifact-upload: 'true' + enable-cache: 'true' + auto-download-artifacts: 'true' + auto-upload-artifacts: 'true' env: COREBOOT_VERSION: '4.19' LINUX_VERSION: '6.9.9' diff --git a/action.yml b/action.yml index 70697b1e..bef8b9e7 100644 --- a/action.yml +++ b/action.yml @@ -35,7 +35,7 @@ inputs: default: 'false' # Options for automatic caches and artifacts - auto-cache: + enable-cache: description: | Automatically cache the '.firmware-action' directory along with all existing output directories. Firmware-action can automatically cache the produced files, by iterating over all 'output_dir' @@ -44,64 +44,49 @@ inputs: rebuild the files if needed. But it there was no change, it can greatly speed up the CI run. required: false default: 'false' - auto-artifact-download: + auto-download-artifacts: description: | Automatically download all artifacts for the current workflow run. There is no easy convenient way to download all required artifacts, so firmware-action offers the option to just automatically download all available artifacts. This does not mean that they will be used during the build, but it means that you do not need to handle the downloading of artifacts yourself. + Internally a actions/download-artifact@v4 is used required: false default: 'false' - auto-artifact-upload: + auto-upload-artifacts: description: | - Automatically upload all artifacts. + Automatically upload all artifacts.inputs.auto-upload-artifacts-if-no-files-found Firmware action can automatically upload the artifacts for the current target (upload the 'output_dir' - directory), so that you don't have it. Combined with the option 'auto-artifact-download' + directory), so that you don't have it. Combined with the option 'auto-download-artifacts' firmware-action should be able to built entire firmware stack in CI even if it is split into multiple jobs and even if there are multiple matrix builds running in parallel. + Internally a actions/upload-artifact@v4 is used required: false default: 'false' # Options passed over to artifact uploading - artifact-if-no-files-found: + auto-upload-artifacts-if-no-files-found: description: | - The desired behavior if no files are found using the provided path. - - Available Options: - warn: Output a warning but do not fail the action - error: Fail the action with an error message - ignore: Do not output any warnings or errors, the action does not fail + See 'if-no-files-found' at https://github.com/actions/upload-artifact default: 'warn' - artifact-compression-level: + auto-upload-artifacts-retention-days: + description: | + See 'retention-days' at https://github.com/actions/upload-artifact + default: '0' + auto-upload-artifacts-compression-level: description: | - The level of compression for Zlib to be applied to the artifact archive. - The value can range from 0 to 9: - - 0: No compression - - 1: Best speed - - 6: Default compression (same as GNU Gzip) - - 9: Best compression - Higher levels will result in better compression, but will take longer to complete. - For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads. + See 'compression-level' at https://github.com/actions/upload-artifact default: '6' - artifact-overwrite: + auto-upload-artifacts-overwrite: description: | - If true, an artifact with a matching name will be deleted before a new one is uploaded. - If false, the action will fail if an artifact for the given name already exists. - Does not fail if the artifact does not exist. + See 'overwrite' at https://github.com/actions/upload-artifact default: 'false' - # We do need this enabled because we are uploading the `./firmware-action` directory + # As for the only omitted input 'include-hidden-files', we do need this enabled + # because we are uploading the `./firmware-action` directory # which would not get uploaded at all with this option set to 'false' # We might change the behavior in the future if anyone needs it # (maybe just renaming the directory before upload) - # - # Action `actions/upload-artifact` also has these inputs: - # - artifact-include-hidden-files: - # - artifact-retention-days: - # Not sure how the action would behave if a empty input would be provided, - # and not sure if I want to just give it some arbitrarily picked default. - # So let's leave it empty and the actions/upload-artifact will just pick the - # repository default. outputs: artifact-name: @@ -193,7 +178,7 @@ runs: if: ${{ ( runner.os == 'Linux' || runner.os == 'macOS' ) && inputs.compile == 'false' }} shell: bash run: | - echo "::group::curl" + echo "::group::curl"inputs.auto-upload-artifacts-if-no-files-found curl -L -o "${{ steps.filename.outputs.filename }}" "${{ steps.url.outputs.url }}" tar -xvzf "${{ steps.filename.outputs.filename }}" chmod +x firmware-action @@ -245,7 +230,7 @@ runs: - name: restore_cache uses: actions/cache/restore@v4 - if: inputs.auto-cache == 'true' + if: inputs.enable-cache == 'true' id: cache with: path: .firmware-action/ @@ -292,12 +277,12 @@ runs: - name: download_artifacts uses: actions/download-artifact@v4 - if: inputs.auto-artifact-download == 'true' + if: inputs.auto-download-artifacts == 'true' with: path: .firmware-action2/ merge-multiple: true - name: merge_firmware_action_directory - if: inputs.auto-artifact-download == 'true' + if: inputs.auto-download-artifacts == 'true' shell: bash run: | echo "::group::merge" @@ -314,7 +299,7 @@ runs: - name: unpack_cached_files shell: bash - if: ${{ steps.cache.outputs.cache-hit == 'true' || inputs.auto-cache == 'true' }} + if: ${{ steps.cache.outputs.cache-hit == 'true' || inputs.enable-cache == 'true' }} run: | echo "::group::unpack" # Get output directories from merged config @@ -359,7 +344,7 @@ runs: #=============== - name: copy_artifacts - if: ${{ always() && ( inputs.auto-cache == 'true' || inputs.auto-artifact-upload == 'true' ) }} + if: ${{ always() && ( inputs.enable-cache == 'true' || inputs.auto-upload-artifacts == 'true' ) }} shell: bash run: | echo "::group::pack" @@ -377,7 +362,7 @@ runs: echo "::endgroup::" - name: save_cache - if: ${{ always() && inputs.auto-cache == 'true' }} + if: ${{ always() && inputs.enable-cache == 'true' }} uses: actions/cache/save@v4 with: path: .firmware-action/ @@ -388,7 +373,7 @@ runs: #=================== - name: get_artifact_name - if: ${{ always() && inputs.auto-artifact-upload == 'true' }} + if: ${{ always() && inputs.auto-upload-artifacts == 'true' }} shell: bash id: get_artifact_name run: | @@ -400,13 +385,14 @@ runs: echo "artifact_name=artifacts--${{ inputs.target }}--${OUTPUT_DIR}--${DATETIME}" >> "${GITHUB_OUTPUT}" - name: upload_artifact - if: ${{ always() && inputs.auto-artifact-upload == 'true' }} + if: ${{ always() && inputs.auto-upload-artifacts == 'true' }} uses: actions/upload-artifact@v4 id: upload_artifact with: name: ${{ steps.get_artifact_name.outputs.artifact_name }} path: .firmware-action/ include-hidden-files: true - if-no-files-found: ${{ inputs.artifact-if-no-files-found }} - compression-level: ${{ inputs.artifact-compression-level }} - overwrite: ${{ inputs.artifact-overwrite }} + if-no-files-found: ${{ inputs.auto-upload-artifacts-if-no-files-found }} + retention-days: ${{ inputs.auto-upload-artifacts-retention-days }} + compression-level: ${{ inputs.auto-upload-artifacts-compression-level }} + overwrite: ${{ inputs.auto-upload-artifacts-overwrite }} diff --git a/docs/src/firmware-action/usage_github.md b/docs/src/firmware-action/usage_github.md index 0d5b1a7f..1326cab8 100644 --- a/docs/src/firmware-action/usage_github.md +++ b/docs/src/firmware-action/usage_github.md @@ -11,7 +11,7 @@ The action can automatically upload build artifacts when the `auto-artifact-uplo - `artifact-url`: Direct download URL for the artifact (requires GitHub login) - `artifact-digest`: SHA-256 digest of the artifact -Internally, `firmware-action` uses the [upload-artifact](https://github.com/actions/upload-artifact) action to handle artifact uploads. +Internally, `firmware-action` uses the [actions/upload-artifact@v4](https://github.com/actions/upload-artifact)@v4 action to handle artifact uploads and [actions/download-artifact@v4](https://github.com/actions/download-artifact) to handle artifact downloads. ```admonish example You can use these outputs in subsequent steps: