From 988c4c129a79e6d2aa7e28cc1ec14997c3b4e831 Mon Sep 17 00:00:00 2001 From: "Y.D.X." <73375426+YDX-2147483647@users.noreply.github.com> Date: Thu, 7 Nov 2024 08:34:17 +0800 Subject: [PATCH] Fix bugs about the exit code (#262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - **fix: Make `fail: false` effective even when `failIfEmpty: true`** This commit also makes sure `outputs.exit_code` is “The exit code returned from Lychee”. `failIfEmpty` no longer changes it to `1`. Relevant docs: - [Setting exit codes for actions - GitHub Docs](https://docs.github.com/en/actions/sharing-automations/creating-actions/setting-exit-codes-for-actions) - [exit - POSIX Programmer's Manual](https://manned.org/exit.1posix) Relates to #86, #128, #145, #245, and #251. - **fix: Update `env.exit_code` to `outputs.exit_code`** The previous expression always gives `false`. Both `env.exit_code` and `env.lychee_exit_code` are `null`, probably since the docker→composite refactor #128. When GitHub evaluates the expression, it finds the types do not match, and coerces them to number, namely, `null` → `0`. See [Evaluate expressions in workflows and actions - GitHub Docs](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#operators). Relates to #253. Co-authored-by: Sebastiaan Speck <12570668+sebastiaanspeck@users.noreply.github.com> --- .github/workflows/links.yml | 3 +- .github/workflows/test.yml | 56 +++++++++++++++++++++++++++++++++++++ README.md | 2 +- action.yml | 15 +--------- entrypoint.sh | 37 ++++++++++++++---------- 5 files changed, 83 insertions(+), 30 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 1f078fe..374af07 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -15,6 +15,7 @@ jobs: - uses: actions/checkout@v4 - name: Link Checker + id: lychee uses: ./ # Uses an action in the root directory with: args: --user-agent "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0" --verbose --exclude spinroot.com --no-progress './**/*.md' './**/*.html' './**/*.rst' @@ -23,7 +24,7 @@ jobs: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Create Issue From File - if: env.exit_code != 0 + if: ${{ steps.lychee.outputs.exit_code }} != 0 uses: peter-evans/create-issue-from-file@v5 with: title: Link Checker Report diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 10bb9e1..c4fe117 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -125,6 +125,28 @@ jobs: echo "Output set in args and action input should have failed." exit 1 + - name: test fail - a lychee error should fail the pipeline + id: fail_test + uses: ./ + with: + args: --verbose --no-progress foo.bar + debug: true + continue-on-error: true + + # Explicitly check the exit code of the previous step + # as it's expected to fail + - name: Check fail + if: steps.fail_test.outcome != 'failure' + run: | + echo "Fail should have failed because the URL is invalid." + exit 1 + + - name: test disable fail - it's okay if lychee throws an error + uses: ./ + with: + args: --no-progress foo.bar + fail: false + - name: test failIfEmpty - no links in input should fail the pipeline id: fail_if_empty_test uses: ./ @@ -147,6 +169,40 @@ jobs: args: --no-progress fixtures/empty.md failIfEmpty: false + - name: test disable failIfEmpty - a lychee error should still fail the pipeline + id: fail_but_not_failIfEmpty_test + uses: ./ + with: + args: --verbose --no-progress foo.bar + failIfEmpty: false + debug: true + continue-on-error: true + + # Explicitly check the exit code of the previous step + # as it's expected to fail + - name: Check fail when failIfEmpty is disabled + if: steps.fail_but_not_failIfEmpty_test.outcome != 'failure' + run: | + echo "Fail should have failed because the URL is invalid, even though failIfEmpty is disabled." + exit 1 + + - name: test disable fail - no links in input should still fail the pipeline + id: failIfEmpty_but_not_fail_test + uses: ./ + with: + args: --verbose --no-progress fixtures/empty.md + fail: false + debug: true + continue-on-error: true + + # Explicitly check the exit code of the previous step + # as it's expected to fail + - name: Check failIfEmpty when fail is disabled + if: steps.failIfEmpty_but_not_fail_test.outcome != 'failure' + run: | + echo "FailIfEmpty should have failed because no links were found, even though fail is disabled." + exit 1 + - name: Install jq run: sudo apt-get install jq diff --git a/README.md b/README.md index e36e604..211ef26 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ jobs: uses: lycheeverse/lychee-action@v2 - name: Create Issue From File - if: env.exit_code != 0 + if: ${{ steps.lychee.outputs.exit_code }} != 0 uses: peter-evans/create-issue-from-file@v5 with: title: Link Checker Report diff --git a/action.yml b/action.yml index 9402faa..8e1e6e4 100644 --- a/action.yml +++ b/action.yml @@ -106,20 +106,7 @@ runs: - name: Run Lychee id: run-lychee - run: | - # This step runs lychee and captures its exit code. - # We use 'set +e' to prevent the script from exiting immediately if lychee fails. - # This allows us to capture the exit code and pass it both to GitHub Actions (via GITHUB_OUTPUT) - # and to the shell (via the final 'exit $EXIT_CODE'). - # This ensures that: - # 1. The step fails if lychee fails - # 2. The exit code is available as an output for subsequent steps - # 3. The exit code is properly propagated to the workflow - set +e - ${{ github.action_path }}/entrypoint.sh - EXIT_CODE=$? - echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT - exit $EXIT_CODE + run: ${{ github.action_path }}/entrypoint.sh env: # https://github.com/actions/runner/issues/665 INPUT_TOKEN: ${{ inputs.TOKEN }} diff --git a/entrypoint.sh b/entrypoint.sh index e5cbb55..5711db3 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,13 @@ #!/bin/bash -l set -uo pipefail +# We use ‘set +e’ to prevent the script from exiting immediately if lychee fails. +# This ensures that: +# 1. Lychee exit code can be captured and passed to subsequent steps via `$GITHUB_OUTPUT`. +# 2. This step’s outcome (success/failure) can be controlled according to inputs +# by manually calling the ‘exit’ command. +set +e + # Enable optional debug output if [ "${INPUT_DEBUG}" = true ]; then echo "Debug output enabled" @@ -29,19 +36,17 @@ fi # Execute lychee eval lychee ${FORMAT} --output ${LYCHEE_TMP} ${ARGS} -exit_code=$? +LYCHEE_EXIT_CODE=$? -# Overwrite the exit code in case no links were found -# and `failIfEmpty` is set to `true` (and it is by default) +# If no links were found and `failIfEmpty` is set to `true` (and it is by default), +# fail with an error later, but leave lychee exit code untouched. +should_fail_because_empty=false if [ "${INPUT_FAILIFEMPTY}" = "true" ]; then - # Explicitly set INPUT_FAIL to true to ensure the script fails - # if no links are found - INPUT_FAIL=true # This is a somewhat crude way to check the Markdown output of lychee if grep -E 'Total\s+\|\s+0' "${LYCHEE_TMP}"; then echo "No links were found. This usually indicates a configuration error." >> "${LYCHEE_TMP}" echo "If this was expected, set 'failIfEmpty: false' in the args." >> "${LYCHEE_TMP}" - exit_code=1 + should_fail_because_empty=true fi fi @@ -67,12 +72,16 @@ if [ "${INPUT_FORMAT}" == "markdown" ]; then fi fi -# Pass lychee exit code to next step -echo "exit_code=$exit_code" >> $GITHUB_OUTPUT +# Pass lychee exit code to subsequent steps +echo "exit_code=$LYCHEE_EXIT_CODE" >> "$GITHUB_OUTPUT" -# If `fail` is set to `true` (and it is by default), propagate the real exit -# value to the workflow runner. This will cause the pipeline to fail on -# `exit != # 0`. -if [ "$INPUT_FAIL" = true ] ; then - exit ${exit_code} +# Determine the outcome of this step +# Exiting with a nonzero value will fail the pipeline, but the specific value +# does not matter. (GitHub does not share it with subsequent steps for composite actions.) +if [ "$should_fail_because_empty" = true ] ; then + # If we decided previously to fail because no links were found, fail + exit 1 +elif [ "$INPUT_FAIL" = true ] ; then + # If `fail` is set to `true` (and it is by default), propagate lychee exit code + exit ${LYCHEE_EXIT_CODE} fi