diff --git a/.github/workflows/nix-changes-comment.yml b/.github/workflows/nix-changes-comment.yml index 371ed669d1f..fc642dee29b 100644 --- a/.github/workflows/nix-changes-comment.yml +++ b/.github/workflows/nix-changes-comment.yml @@ -16,6 +16,7 @@ jobs: runs-on: ubuntu-slim permissions: pull-requests: write + statuses: write steps: - name: Download artefacts uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 @@ -41,7 +42,7 @@ jobs: set -x > requisites-before.list > requisites-after.list - TABLE=$( + { echo '| Platform | Number of requisites | Proportion of new derivations |' echo '| :-: | -: | -: |' TOTAL_BEFORE=0 @@ -49,13 +50,17 @@ jobs: TOTAL_CHANGED=0 QUOTE='`' for PLATFORM in x86_64-linux aarch64-linux x86_64-darwin aarch64-darwin; do + if [ ! -f "requisites-${PLATFORM}-before.list" ] || [ ! -f "requisites-${PLATFORM}-after.list" ]; then + echo "| ${QUOTE}${PLATFORM}${QUOTE} | _missing data_ | _missing data_ |" + continue + fi BEFORE=$(wc -l < "requisites-${PLATFORM}-before.list") TOTAL_BEFORE=$(($TOTAL_BEFORE + $BEFORE)) AFTER=$(wc -l < "requisites-${PLATFORM}-after.list") TOTAL_AFTER=$(($TOTAL_AFTER + $AFTER)) DIFF="_no changes_" [ "$BEFORE" = "$AFTER" ] || DIFF="**$([ "$AFTER" -lt "$BEFORE" ] || echo '+')$(($AFTER - $BEFORE))**" - CHANGED=$(git diff --no-index "requisites-${PLATFORM}-before.list" "requisites-${PLATFORM}-after.list" | grep -c '^+[^+]') + CHANGED=$(git diff --no-index "requisites-${PLATFORM}-before.list" "requisites-${PLATFORM}-after.list" | grep -c '^+[^+]' || true) TOTAL_CHANGED=$(($TOTAL_CHANGED + $CHANGED)) PERCENT=100 [ "$CHANGED" = "$AFTER" ] || { @@ -63,8 +68,24 @@ jobs: PERCENT="$((PERMILLE / 10)).$((PERMILLE % 10))" } echo "| ${QUOTE}${PLATFORM}${QUOTE} | $BEFORE -> $AFTER => $DIFF | $CHANGED / $AFTER = $PERCENT% |" - awk '{ print $0 " ('"$PLATFORM"')" }' "requisites-${PLATFORM}-before.list" >> requisites-before.list - awk '{ print $0 " ('"$PLATFORM"')" }' "requisites-${PLATFORM}-after.list" >> requisites-after.list + for STATE in before after; do + # Split store paths into package name, output (or source archive extension), and version. + awk -v OFS='\t' -v PLATFORM="$PLATFORM" '{ + name = substr($0, 45) + pname = name + output = "out" + version = "_unversioned_" + if (match(name, /-[^A-Za-z]/)) { + pname = substr(name, 1, RSTART - 1) + version = substr(name, RSTART + 1) + if (match(version, /-[a-z]+$/) || match(version, /\.(tar(\.[a-z0-9]+)?|tgz|tbz2?|txz|zip|patch|diff)$/)) { + output = substr(version, RSTART + 1) + version = substr(version, 1, RSTART - 1) + } + } + print pname, output, version, PLATFORM, $0 + }' "requisites-${PLATFORM}-${STATE}.list" >> "requisites-${STATE}.list" + done done DIFF="_no changes_" @@ -75,24 +96,87 @@ jobs: PERCENT="$((PERMILLE / 10)).$((PERMILLE % 10))" } echo "| **Total** | $TOTAL_BEFORE -> $TOTAL_AFTER => $DIFF | $TOTAL_CHANGED / $TOTAL_AFTER = $PERCENT% |" - ) - sort -k1.45 requisites-before.list > requisites-before.sort - sort -k1.45 requisites-after.list > requisites-after.sort + } > comment.md + sort requisites-before.list > requisites-before.sort + sort requisites-after.list > requisites-after.sort if git diff -U0 --no-color --no-index requisites-before.sort requisites-after.sort > requisites.diff; then echo 'No changes detected.' else - { - echo "$TABLE" - echo - echo '
Changelog' - echo - echo '```diff' - tail -n +5 requisites.diff - echo '```' - echo - echo '
' - } | gh pr comment -R "$GITHUB_REPOSITORY" "$PR_NUMBER" -F - + awk -F '\t' ' + function insert(list, v, n, a, i, out, done) { + n = split(list, a, " ") + for (i = 1; i <= n; i++) if (a[i] == v) return list + out = ""; done = 0 + for (i = 1; i <= n; i++) { + if (!done && v < a[i]) { out = out " " v; done = 1 } + out = out " " a[i] + } + if (!done) out = out " " v + return substr(out, 2) + } + function join(list, pre, post, s) { + s = pre list post + gsub(/ /, post ", " pre, s) + return s + } + /^[-+]/ && NF == 5 { + key = substr($1, 2) SUBSEP $2 SUBSEP $4 + if (substr($1, 1, 1) == "-") removed[key] = insert(removed[key], $3) + else added[key] = insert(added[key], $3) + } + END { + for (key in removed) if (!(key in added)) added[key] = "" + for (key in added) { + split(key, k, SUBSEP) + r = (key in removed) ? removed[key] : "" + a = added[key] + if (r == a) change = "_no version change_: " join(a) + else if (r == "") change = "_added_: " join(a, "**", "**") + else if (a == "") change = "_removed_: " join(r) + else change = join(r) " -> " join(a, "**", "**") + platforms[k[1] SUBSEP k[2] SUBSEP change] = insert(platforms[k[1] SUBSEP k[2] SUBSEP change], k[3]) + } + for (key in platforms) { + split(key, k, SUBSEP) + row = k[1] SUBSEP k[3] SUBSEP join(platforms[key]) + outputs[row] = insert(outputs[row], k[2]) + } + for (row in outputs) { + split(row, k, SUBSEP) + n = split(outputs[row], o, " ") + name = "" + for (i = 1; i <= n; i++) name = name ", `" k[1] (o[i] == "out" ? "" : "." o[i]) "`" + rank = k[2] ~ /^_added_/ ? 0 : k[2] ~ /^_removed_/ ? 2 : k[2] ~ /^_no version change_/ ? 3 : 1 + print rank "\t| " substr(name, 3) " | " k[2] " | " k[3] " |" + } + } + ' requisites.diff > versions.tsv + { + echo + echo '
Version changes' + echo + echo '| Package | Version | Platforms |' + echo '| :- | :- | :- |' + LC_ALL=C sort -t '`' -k1,1 -k2,2 -k3 versions.tsv | cut -f2- + echo + echo '
' + } >> comment.md + gh pr comment -R "$GITHUB_REPOSITORY" "$PR_NUMBER" -F comment.md fi env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ steps.pr-data.outputs.NUMBER }} + + - name: Report status on the PR + if: ${{ always() }} + run: | + gh api --method POST "repos/${GITHUB_REPOSITORY}/statuses/${HEAD_SHA}" \ + -f state="$STATE" \ + -f context="$GITHUB_WORKFLOW" \ + -f description="$DESCRIPTION" \ + -f target_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + env: + GH_TOKEN: ${{ github.token }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + STATE: ${{ job.status == 'success' && 'success' || 'failure' }} + DESCRIPTION: ${{ job.status == 'success' && 'Nix requisites changes aggregated' || 'Failed to aggregate Nix requisites changes' }}