From 39f58ee538358e3375ed65b0aa6ed99b49a96fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jalil=20David=20Salam=C3=A9=20Messina?= Date: Thu, 19 Dec 2024 21:56:16 +0100 Subject: [PATCH] refactor!(action): detect when in private branches This removes the need to use the private-repo-workaround input. --- README.md | 13 ++++-- action.yml | 104 ++++++++++++++++++++++++----------------- comment_on_pr.sh | 2 +- retrieve-old-report.sh | 67 +++++++++++++++++--------- utils.sh | 8 ++++ 5 files changed, 125 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index b2ba720..ce98dae 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Nix Flake outputs size -Use `nix path-info` to query the size of flake outputs and produce a markdown report. +Use `nix path-info` to query the size of flake outputs and produce a report. -You can post this report as a comment to the PR associated with the current branch and/or export the report as a markdown artifact. +This repost can be posted to a PR (as formatted markdown) and/or uploaded as a workflow artifact. -Requires `nix`, `jq`, `curl`, `sed` and `coreutils` to be in path. +Requires `nix`, `jq`, `curl`, `sed`, `gunzip`, `tar` and `coreutils` to be in the runner's path. -## Usage +## Example ```yaml - name: Generate size report @@ -15,6 +15,11 @@ Requires `nix`, `jq`, `curl`, `sed` and `coreutils` to be in path. comment-on-pr: 'true' generate-artifact: 'false' artifact-name: 'size-report.md' + # If you want to enable comparisons set this to true + do-comparison: 'false' + job-name: '' # required if do-comparison is true + # This is the branch that will be compared against + base-branch: ${{ github.base_ref }} # or default branch if missing ``` For more details see the [action.yaml](./action.yml) file. diff --git a/action.yml b/action.yml index c70bc8e..ad04455 100644 --- a/action.yml +++ b/action.yml @@ -5,7 +5,7 @@ description: | report. You can post this report as a comment to the PR associated with the current - branch and/or export the report as a markdown artifact. + branch and/or export the report as a JSON artifact. Requires `nix`, `jq`, `curl`, `sed`, `gunzip`, `tar` and `coreutils` to be in the runner's path. @@ -19,75 +19,95 @@ description: | comment-on-pr: 'true' generate-artifact: 'false' artifact-name: 'size-report.md' - base-branch: ${{ github.base_ref }} # set to e.g. main if not triggered by a pull_request - job-name: '' # set to the name of this job if you want to enable comparisons + # If you want to enable comparisons set this to true + do-comparison: 'false' + job-name: '' # required if do-comparison is true + # This is the branch that will be compared against + base-branch: ${{ github.base_ref }} # or default branch if missing ``` inputs: comment-on-pr: - description: Comment the report on the PR associated with the current branch. + description: | + Comment the report on the PR associated with the current branch. + + This is a no-op in case no PR is associated with the current branch. default: 'true' + # Generate workflow artifact generate-artifact: - description: Export the generated markdown document as an artifact. + description: Export the generated markdown document as a workflow artifact. default: 'false' artifact-name: description: The name of the generated artifact. default: report.json - base-branch: + # Comparison Report (comment only) + do-comparison: description: | - The name of the base branch, defaults to github.base_ref which is only - available in pull_request triggered workflows, for other workflows - specify it manually. + When commenting on the PR compare the results with those in the base branch. - It will try to download the generated artifact from this branch so make - sure `generate-artifacte: true` when the workflow is running on that - branch. - default: ${{ github.base_ref }} + This is a no-op when `comment-on-pr: false`. + + It requires `job-name` to be set. + default: 'false' job-name: description: | The name of the job running this action. If not set, no comparisons can be made. default: '' - private-repo-workaround: + base-branch: description: | - Forgejo doesn't support downloading artifacts through the API [see - codeberg.org/forgejo/forgejo#6315](https://codeberg.org/forgejo/forgejo/issues/6315). + The name of the base branch, defaults to `github.base_ref` if present + (when triggered by a `pull_request`). Otherwise defaults to the repo's + default branch. Set in case you want to override this behaviour. - As a workaround, checkout the base branch and regenerate the report. - - This is very innefficient T-T and slow. - default: 'false' + It will try to download the generated artifact from this branch so make + sure `generate-artifacte: true` when the workflow is running on that + branch. + default: ${{ github.base_ref }} outputs: runs: using: 'composite' steps: - name: Create report + if: inputs.comment-on-pr == 'true' || inputs.generate-artifact == 'true' + env: + COMMENT: ${{ inputs.comment-on-pr == }} + ARTIFACT_NAME: ${{ inputs.artifact-name }} + DO_COMPARISON: ${{ inputs.do-comparison }} + BASE_BRANCH: ${{ inputs.base-branch }} + JOB_NAME: ${{ inputs.job-name }} run: | + . "$GITHUB_ACTION_PATH/utils.sh" + + # Input validation + if [ "$DO_COMPARISON" = 'true' ] && [ -z "$JOB_NAME" ]; then + error 'job-name should be set if you want to generate a comparison report' + exit 1 + fi + + # Create Size Report "$GITHUB_ACTION_PATH/create-report.sh" > report.json + + # Nothing else to do + if [ "$COMMENT" != 'true' ]; then exit 0; fi + + # Try to do a comparison report + if [ "$DO_COMPARISON" = 'true' ]; then + if "$GITHUB_ACTION_PATH/retrieve-old-report.sh" && [ -f old-report.json ]; then + log "Reporting on sizes and comparing to sizes in $HEAD_BRANCH" + + "$GITHUB_ACTION_PATH/comment_on_pr.sh" report.json old-report.json + exit 0 + else + error 'Failed to do comparison, fallback to posting the report without them' + fi + fi + + # Just report values + log 'Reporting on sizes' + "$GITHUB_ACTION_PATH/comment_on_pr.sh" report.json - name: Upload Artifact uses: https://code.forgejo.org/forgejo/upload-artifact@v4 if: inputs.generate-artifact == 'true' with: path: report.json name: ${{ inputs.artifact-name }} - - name: Comment Report - if: inputs.comment-on-pr == 'true' - env: - ARTIFACT_NAME: ${{ inputs.artifact-name }} - HEAD_BRANCH: ${{ inputs.base-branch }} - JOB_NAME: ${{ inputs.job-name }} - PRIVATE_REPO: ${{ inputs.private-repo-workaround }} - run: | - . "${GITHUB_ACTION_PATH}/utils.sh" - - if "$GITHUB_ACTION_PATH/retrieve-old-report.sh" && [ -f old-report.json ]; then - log "Reporting on sizes and comparing to sizes in $HEAD_BRANCH" - - group 'Old report data' - cat old-report.json - endgroup - - "$GITHUB_ACTION_PATH/comment_on_pr.sh" report.json old-report.json - else - log 'Reporting on sizes' - "$GITHUB_ACTION_PATH/comment_on_pr.sh" report.json - fi diff --git a/comment_on_pr.sh b/comment_on_pr.sh index 8c1bf74..58b04de 100755 --- a/comment_on_pr.sh +++ b/comment_on_pr.sh @@ -116,7 +116,7 @@ pr_number=$(echo "$prs" | # Protect against running before a PR is made or if it is triggered on the main branch if [ -z "$pr_number" ]; then - log "No PR created for this commit" + warn "No PR created for this commit" exit 0 fi diff --git a/retrieve-old-report.sh b/retrieve-old-report.sh index 362be97..694e5ec 100755 --- a/retrieve-old-report.sh +++ b/retrieve-old-report.sh @@ -1,6 +1,23 @@ +#!/bin/sh + . "${GITHUB_ACTION_PATH}/utils.sh" -# USAGE: base_report_url +repo_info() { + curl -X GET \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H 'accept: application/json' \ + "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY" +} + +in_private_repo() { + test "$(repo_info | jq --raw-output '.private')" = 'true' +} + +default_branch() { + repo_info | jq --raw-output '.default_branch' +} + +# USAGE: base_report_url base_report_url() { curl -X 'GET' \ "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/actions/tasks" \ @@ -8,9 +25,10 @@ base_report_url() { -H 'accept: application/json' | jq --raw-output \ --arg name "$JOB_NAME" \ - --arg head_branch "$HEAD_BRANCH" \ + --arg head_branch "$1" \ '[.workflow_runs[] | select(.name == $name and .head_branch == $head_branch)] | first | .url' } + # USAGE: has_report has_report() { http_code=$(curl -X 'GET' -o /dev/null --silent -Iw '%{http_code}' \ @@ -19,23 +37,11 @@ has_report() { test "$http_code" = '200' } -# If we have a previous report compare against it -if [ "$PRIVATE_REPO" = 'true' ]; then - log "In a private repo, downloading $HEAD_BRANCH to build the old report" +# If a base branch is not provided, use the default branch +base_branch=${BASE_BRANCH-$(default_branch)} - old=$(mktemp -d) - group 'Downloaded files' - curl -X 'GET' \ - "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/archive/$HEAD_BRANCH.tar.gz" \ - -H "Authorization: token $GITHUB_TOKEN" | - tar -zvx --strip-components=1 -C "$old" - endgroup - - (cd "$old" && "$GITHUB_ACTION_PATH/create-report.sh") >old-report.json - - exit 0 -elif [ "$JOB_NAME" ] && [ "$HEAD_BRANCH" ]; then - url=$(base_report_url) +if [ "$(in_private_repo)" != 'true' ] && [ "$JOB_NAME" ]; then + url=$(base_report_url "$base_branch") log "Found previous run at: $url" report_url="$url/artifacts/$ARTIFACT_NAME" @@ -46,11 +52,28 @@ elif [ "$JOB_NAME" ] && [ "$HEAD_BRANCH" ]; then "$report_url" \ -H "Authorization: token $GITHUB_TOKEN" | gunzip >old-report.json - log "Reporting on sizes and comparing to sizes in $HEAD_BRANCH" + log "Reporting on sizes and comparing to sizes in $base_branch" exit 0 - else - log "Failed to find previous report, expected at: $report_url" fi + error "Failed to find previous report, expected at: $report_url" fi -exit 1 +warn "Couldn't retrieve old report:" +warn ' This usuially happens when running on private repos' +warn ' or when job-name is not set.' +warn +warn ' See the README for more details' + +error "Falling back to slow method (checkout $base_branch and generate the report)" + +old=$(mktemp -d) +group "Download files from $base_branch" +curl -X 'GET' \ + "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/archive/$base_branch.tar.gz" \ + -H "Authorization: token $GITHUB_TOKEN" | + tar -zvx --strip-components=1 -C "$old" +endgroup + +(cd "$old" && "$GITHUB_ACTION_PATH/create-report.sh") >old-report.json + +exit 0 diff --git a/utils.sh b/utils.sh index 25fe287..9cba1aa 100755 --- a/utils.sh +++ b/utils.sh @@ -2,6 +2,14 @@ log() { echo "$@" >&2 } +warn() { + log "\e[0;33m[ERROR]:" "$@" "\e[0m" +} + +error() { + log "\e[0;31m[WARN]:" "$@" "\e[0m" +} + group() { log "::group::$1" }