-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ci(gh-actions): Generate CI matrix based on the cache status
- Loading branch information
1 parent
5ada090
commit e5e4754
Showing
7 changed files
with
326 additions
and
15 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: Evaluate CI Matrix | ||
description: Evaluate all packages, check cache status generate CI matrix and publish comment with the summary | ||
|
||
inputs: | ||
is-initial: | ||
description: Is this the start of the CI workflow, or the end | ||
default: 'true' | ||
required: true | ||
cachix-cache: | ||
description: The name of the cachix cache to use | ||
required: true | ||
outputs: | ||
matrix: | ||
description: 'Generated Matrix' | ||
value: ${{ steps.generate-matrix.outputs.matrix }} | ||
comment: | ||
description: 'Comment' | ||
value: ${{ steps.generate-matrix.outputs.comment }} | ||
|
||
runs: | ||
using: "composite" | ||
steps: | ||
- name: Install Nix | ||
uses: DeterminateSystems/nix-installer-action@v9 | ||
with: | ||
extra-conf: accept-flake-config = true | ||
|
||
- name: Generate CI Matrix | ||
id: generate-matrix | ||
shell: bash | ||
env: | ||
IS_INITIAL: ${{ inputs.is-initial }} | ||
CACHIX_CACHE: ${{ inputs.cachix-cache }} | ||
run: nix develop .#ci -c ./scripts/ci-matrix.sh | ||
|
||
- name: Upload CI Matrix | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: matrix-${{ inputs.is-initial == 'true' && 'pre' || 'post' }}.json | ||
path: matrix-${{ inputs.is-initial == 'true' && 'pre' || 'post' }}.json | ||
|
||
- name: Update GitHub Comment | ||
uses: marocchino/sticky-pull-request-comment@v2.9.0 | ||
with: | ||
path: comment.md |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
# Nix build output | ||
.result | ||
result | ||
comment.md | ||
matrix-pre.json | ||
matrix-post.json | ||
|
||
# direnv temporary files | ||
.direnv/ | ||
|
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -euo pipefail | ||
|
||
root_dir="$(git rev-parse --show-toplevel)" | ||
|
||
# shellcheck source=./nix-eval-jobs.sh | ||
source "$root_dir/scripts/nix-eval-jobs.sh" | ||
|
||
eval_packages_to_json() { | ||
flake_attr_pre="${1:-packages}" | ||
flake_attr_post="${2:-}" | ||
|
||
cachix_url="https://${CACHIX_CACHE}.cachix.org" | ||
|
||
nix eval --json .#lib.allowedToFailMap > "${result_dir}/allowed-to-fail.json" | ||
|
||
nix_eval_for_all_systems "$flake_attr_pre" "$flake_attr_post" \ | ||
| cat "${result_dir}/allowed-to-fail.json" - \ | ||
| jq -sr ' | ||
.[0] as $allowed_to_fail | ||
| .[1:] as $nix_eval_results | ||
| { | ||
"x86_64-linux": "ubuntu-latest", | ||
"x86_64-darwin": "macos-14", | ||
"aarch64-darwin": "macos-14" | ||
} as $system_to_gh_platform | ||
| $nix_eval_results | ||
| map({ | ||
package: .attr, | ||
attrPath: "\(.system).\(.attr)", | ||
allowedToFail: $allowed_to_fail[.attr][.system], | ||
isCached, | ||
system, | ||
cache_url: .outputs.out | ||
| "'"$cachix_url"'/\(match("^\/nix\/store\/([^-]+)-").captures[0].string).narinfo", | ||
os: $system_to_gh_platform[.system] | ||
}) | ||
| sort_by(.package | ascii_downcase) | ||
' | ||
} | ||
|
||
save_gh_ci_matrix() { | ||
packages_to_build=$(echo "$packages" | jq -c '. | map(select((.isCached | not) and (.allowedToFail | not)))') | ||
matrix='{"include":'"$packages_to_build"'}' | ||
res_path='' | ||
if [ "${IS_INITIAL:-true}" = "true" ]; then | ||
res_path='matrix-pre.json' | ||
else | ||
res_path='matrix-post.json' | ||
fi | ||
echo "$matrix" > "$res_path" | ||
echo "matrix=$matrix" >> "${GITHUB_OUTPUT:-${result_dir}/gh-output.env}" | ||
} | ||
|
||
convert_nix_eval_to_table_summary_json() { | ||
is_initial="${IS_INITIAL:-true}" | ||
echo "$packages" \ | ||
| jq ' | ||
def getStatus(pkg; key): | ||
if (pkg | has(key)) | ||
then ( | ||
if pkg[key].isCached | ||
then "[✅ cached](\(pkg[key].cache_url))" | ||
else ( | ||
if pkg[key].allowedToFail | ||
then "🚧 known to fail (disabled)" | ||
else ( | ||
if "'"$is_initial"'" == "true" | ||
then "⏳ building..." | ||
else "❌ build failed" | ||
end | ||
) end | ||
) end | ||
) else "🚫 not supported" | ||
end; | ||
group_by(.package) | ||
| map( | ||
. | INDEX(.system) as $pkg | ||
| .[0].package as $name | ||
| { | ||
package: $name, | ||
"x86_64-linux": getStatus($pkg; "x86_64-linux"), | ||
"x86_64-darwin": getStatus($pkg; "x86_64-darwin"), | ||
"aarch64-darwin": getStatus($pkg; "aarch64-darwin"), | ||
} | ||
) | ||
| sort_by(.package)' | ||
} | ||
|
||
printTableForCacheStatus() { | ||
create_result_dirs | ||
packages="$(eval_packages_to_json "$@")" | ||
|
||
save_gh_ci_matrix | ||
|
||
{ | ||
echo "Thanks for your Pull Request!" | ||
echo | ||
echo "Below you will find a summary of the cachix status of each package, for each supported platform." | ||
echo | ||
# shellcheck disable=SC2016 | ||
echo '| package | `x86_64-linux` | `x86_64-darwin` | `aarch64-darwin` |' | ||
echo '| ------- | -------------- | --------------- | ---------------- |' | ||
convert_nix_eval_to_table_summary_json | jq -r ' | ||
.[] | "| `\(.package)` | \(.["x86_64-linux"]) | \(.["x86_64-darwin"]) | \(.["aarch64-darwin"]) |" | ||
' | ||
echo | ||
} > comment.md | ||
} | ||
|
||
printTableForCacheStatus "$@" | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -euo pipefail | ||
|
||
root_dir="$(git rev-parse --show-toplevel)" | ||
result_dir="$root_dir/.result" | ||
gc_roots_dir="$result_dir/gc-roots" | ||
|
||
# shellcheck source=./system-info.sh | ||
source "$root_dir/scripts/system-info.sh" | ||
|
||
create_result_dirs() { | ||
mkdir -p "$result_dir" "$gc_roots_dir" | ||
} | ||
|
||
nix_eval_jobs() { | ||
flake_attr="$1" | ||
|
||
get_platform | ||
get_available_memory_mb | ||
get_nix_eval_worker_count | ||
|
||
{ | ||
( | ||
set -x | ||
nix-eval-jobs \ | ||
--quiet \ | ||
--option warn-dirty false \ | ||
--check-cache-status \ | ||
--gc-roots-dir "$gc_roots_dir" \ | ||
--workers "$max_workers" \ | ||
--max-memory-size "$max_memory_mb" \ | ||
--flake "$root_dir#$flake_attr" | ||
) \ | ||
| tee /dev/fd/3 \ | ||
| stdbuf -i0 -o0 -e0 jq --color-output -c '{ attr, isCached, out: .outputs.out }' > /dev/stderr | ||
} 3>&1 2> >( | ||
grep -vP "(SQLite database|warning: unknown setting 'allowed-users'|warning: unknown setting 'trusted-users')" \ | ||
>&2 | ||
) | ||
} | ||
|
||
nix_eval_for_all_systems() { | ||
flake_pre="$1" | ||
flake_post="${2:+.$2}" | ||
|
||
systems=( {x86_64-linux,{x86_64,aarch64}-darwin} ) | ||
|
||
for system in "${systems[@]}"; do | ||
nix_eval_jobs "${flake_pre}.${system}${flake_post}" | ||
done | ||
} | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -euo pipefail | ||
|
||
get_platform() { | ||
case "$(uname -s).$(uname -m)" in | ||
Linux.x86_64) | ||
export system=x86_64-linux | ||
export is_linux=true | ||
export is_darwin=false | ||
;; | ||
Linux.i?86) | ||
export system=i686-linux | ||
export is_linux=true | ||
export is_darwin=false | ||
;; | ||
Linux.aarch64) | ||
export system=aarch64-linux | ||
export is_linux=true | ||
export is_darwin=false | ||
;; | ||
Linux.armv6l_linux) | ||
export system=armv6l-linux | ||
export is_linux=true | ||
export is_darwin=false | ||
;; | ||
Linux.armv7l_linux) | ||
export system=armv7l-linux | ||
export is_linux=true | ||
export is_darwin=false | ||
;; | ||
Darwin.x86_64) | ||
export system=x86_64-darwin | ||
export is_linux=false | ||
export is_darwin=true | ||
;; | ||
Darwin.arm64|Darwin.aarch64) | ||
system=aarch64-darwin | ||
export is_linux=false | ||
export is_darwin=true | ||
;; | ||
*) error "sorry, there is no binary distribution of Nix for your platform";; | ||
esac | ||
} | ||
|
||
get_nix_eval_worker_count() { | ||
if [[ -z "${MAX_WORKERS:-}" ]]; then | ||
available_parallelism="$(nproc)" | ||
export max_workers="$((available_parallelism < 8 ? available_parallelism : 8))" | ||
else | ||
export max_workers="$MAX_WORKERS" | ||
fi | ||
} | ||
|
||
get_available_memory_mb() { | ||
if [ "$is_darwin" = 'true' ]; then | ||
free_pages="$(vm_stat | grep 'Pages free:' | tr -s ' ' | cut -d ' ' -f 3 | tr -d '.')" | ||
inactive_pages="$(vm_stat | grep 'Pages inactive:' | tr -s ' ' | cut -d ' ' -f 3 | tr -d '.')" | ||
pages="$((free_pages + inactive_pages))" | ||
page_size="$(pagesize)" | ||
export max_memory_mb="${MAX_MEMORY:-$(((pages * page_size) / 1024 / 1024 ))}" | ||
else | ||
free="$(< /proc/meminfo grep MemFree | tr -s ' ' | cut -d ' ' -f 2)" | ||
cached="$(< /proc/meminfo grep Cached | grep -v SwapCached | tr -s ' ' | cut -d ' ' -f 2)" | ||
buffers="$(< /proc/meminfo grep Buffers | tr -s ' ' | cut -d ' ' -f 2)" | ||
shmem="$(< /proc/meminfo grep Shmem: | tr -s ' ' | cut -d ' ' -f 2)" | ||
export max_memory_mb="${MAX_MEMORY:-$(((free + cached + buffers + shmem) / 1024 ))}" | ||
fi | ||
} |