Skip to content

Build and Review PR #20 #11

Build and Review PR #20

Build and Review PR #20 #11

name: Build and Review PR
run-name: 'Build and Review PR #${{ github.event.pull_request.number }}'
on:
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
#
# This workflow uses the pull_request trigger which prevents write permissions on the
# GH_TOKEN and secrets access from public forks. This should remain as a pull_request
# trigger to minimize the access public forks have in the repository. The reduced
# permissions are adequate but do mean that re-compiles and readme changes will have to be
# made manually by the PR author. These auto-updates could be done by this workflow
# for branches but in order to re-trigger a PR build (which is needed for status checks),
# we would make the commits with a different user and their PAT. To minimize exposure
# and complication we will request those changes be manually made by the PR author.
pull_request:
types: [opened, synchronize, reopened]
# paths:
# Do not include specific paths here. We always want this build to run and produce a
# status check which are branch protection rules can use. If this is skipped because of
# path filtering, a status check will not be created and we won't be able to merge the PR
# without disabling that requirement. If we have a status check that is always produced,
# we can also use that to require all branches be up to date before they are merged.
env:
EMPTY_SUMMARY_INPUT_FILE: './test/input-files/empty.md'
COVERAGE_SUMMARY_INPUT_FILE: './test/input-files/coverage-summary.md'
TRUNCATE_SUMMARY_INPUT_FILE: './test/input-files/truncate.md'
jobs:
build-and-review-pr:
# This reusable workflow will check to see if an action's source code has changed based on
# whether the PR includes files that match the files-with-code arg or are in one of the
# dirs-with-code directories. If there are source code changes, this reusable workflow
# will then run the action's build (if one was provided) and update the README.md with the
# the latest version of the action. If those two steps result in any changes that need to
# be committed, the workflow will fail because the PR needs some updates. Instructions for
# updating the PR will be available in the build log, the workflow summary and as a PR
# comment if the PR came from a branch (not a fork).
# This workflow assumes:
# - The main README.md is at the root of the repo
# - The README contains a contribution guidelines and usage examples section
uses: im-open/.github/.github/workflows/reusable-build-and-review-pr.yml@v1
with:
action-name: ${{ github.repository }}
default-branch: main
readme-name: 'README.md'
# The id of the contribution guidelines section of the README.md
readme-contribution-id: '#contributing'
# The id of the usage examples section of the README.md
readme-examples-id: '#usage-examples'
# The files that contain source code for the action. Only files that affect the action's execution
# should be included like action.yml or package.json. Do not include files like README.md or .gitignore.
# Files do not need to be explicitly provided here if they fall under one of the dirs in dirs-with-code.
# ** This value must match the same files-with-code argument specified in increment-version-on-merge.yml.
files-with-code: 'action.yml,package.json,package-lock.json'
# The directories that contain source code for the action. Only dirs with files that affect the action's
# execution should be included like src or dist. Do not include dirs like .github or node_modules.
# ** This value must match the same dirs-with-code argument specified in increment-version-on-merge.yml.
dirs-with-code: 'src,dist'
# The npm script to run to build the action. This is typically 'npm run build' if the
# action needs to be compiled. For composite-run-steps actions this is typically empty.
build-command: 'npm run build'
unit-tests:
runs-on: ubuntu-latest
env:
PASSING_THRESHOLDS_MD_FILE: './test/expected-markdown/unit-tests/passing-thresholds.md'
FAILING_LINE_MD_FILE: './test/expected-markdown/unit-tests/failing-line.md'
FAILING_BRANCH_MD_FILE: './test/expected-markdown/unit-tests/failing-branch.md'
IGNORE_THRESHOLDS_MD_FILE: './test/expected-markdown/unit-tests/ignore-thresholds.md'
THRESHOLD_0_MD_FILE: './test/expected-markdown/unit-tests/threshold-0.md'
steps:
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' SETUP '
run: echo ""
- name: Setup - Checkout the action
uses: actions/checkout@v4
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 1 - MISSING TOKEN INPUT '
run: echo ""
- name: 1a - When process-code-coverage-summary is called with a missing github-token input
id: missing-github-token
if: always()
continue-on-error: true # This is needed because we expect the step to fail but we need it to "pass" in order for the test job to succeed.
uses: ./
with:
github-token: ''
summary-file: '${{ env.EMPTY_SUMMARY_INPUT_FILE }}'
- name: 1b - Then the action outcome should be failure
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.missing-github-token.outcome }}"
- name: 1c - And each of the outputs should be empty
if: always()
run: |
./test/assert-value-is-empty.sh --name "coverage-outcome output" --value "${{ steps.missing-github-token.outputs.coverage-outcome }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.missing-github-token.outputs.coverage-results-truncated }}"
./test/assert-value-is-empty.sh --name "coverage-results-file-path output" --value "${{ steps.missing-github-token.outputs.coverage-results-file-path }}"
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.missing-github-token.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.missing-github-token.outputs.pr-comment-id }}"
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 2 - MISSING SUMMARY_FILE INPUT '
run: echo ""
- name: 2a - When process-code-coverage-summary is called with a missing summary-file input
id: missing-summary-file
if: always()
continue-on-error: true # This is needed because we expect the step to fail but we need it to "pass" in order for the test job to succeed.
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ''
- name: 2b - Then the action outcome should be failure
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.missing-summary-file.outcome }}"
- name: 2c - And each of the outputs should be empty
if: always()
run: |
./test/assert-value-is-empty.sh --name "coverage-outcome output" --value "${{ steps.missing-summary-file.outputs.coverage-outcome }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.missing-summary-file.outputs.coverage-results-truncated }}"
./test/assert-value-is-empty.sh --name "coverage-results-file-path output" --value "${{ steps.missing-summary-file.outputs.coverage-results-file-path }}"
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.missing-summary-file.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.missing-summary-file.outputs.pr-comment-id }}"
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 3 - SUMMARY_FILE DOES NOT EXIST '
run: echo ""
- name: 3a - When process-code-coverage-summary is called with a summary file that does not exist
id: file-does-not-exist
if: always()
continue-on-error: true # This is needed because we expect the step to fail but we need it to "pass" in order for the test job to succeed.
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: './test/input-files/file-that-does-not-exist.md'
create-status-check: false
create-pr-comment: false
- name: 3b - Then the action outcome should be failure
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.file-does-not-exist.outcome }}"
- name: 3c - And the 'coverage-outcome' output should be Failed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Failed' --actual "${{ steps.file-does-not-exist.outputs.coverage-outcome }}"
- name: 3d - And the remaining outputs should be empty
if: always()
run: |
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.file-does-not-exist.outputs.coverage-results-truncated }}"
./test/assert-value-is-empty.sh --name "coverage-results-file-path output" --value "${{ steps.file-does-not-exist.outputs.coverage-results-file-path }}"
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.file-does-not-exist.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.file-does-not-exist.outputs.pr-comment-id }}"
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 4 - SUMMARY_FILE IS EMPTY '
run: echo ""
- name: 4a - When process-code-coverage-summary is called with a summary file that is empty
id: empty-file
if: always()
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: '${{ env.EMPTY_SUMMARY_INPUT_FILE }}'
create-status-check: false
create-pr-comment: false
ignore-threshold-failures: false
line-threshold: 50
branch-threshold: 50
- name: 4b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.empty-file.outcome }}"
- name: 4c - And the 'coverage-outcome' output should be Failed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Failed' --actual "${{ steps.empty-file.outputs.coverage-outcome }}"
- name: 4d - And the remaining outputs should be empty
if: always()
run: |
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.empty-file.outputs.coverage-results-truncated }}"
./test/assert-value-is-empty.sh --name "coverage-results-file-path output" --value "${{ steps.empty-file.outputs.coverage-results-file-path }}"
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.empty-file.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.empty-file.outputs.pr-comment-id }}"
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 5 - PASSING THRESHOLDS '
run: echo ""
- name: 5a - When process-code-coverage-summary is called with a summary file that exceeds the threshold
id: passing-thresholds
if: always()
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: '${{ env.COVERAGE_SUMMARY_INPUT_FILE }}'
create-status-check: false
create-pr-comment: false
report-name: 'Passing Coverage'
line-threshold: 90 # The actual coverage is 94.4
branch-threshold: 90 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 5b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.passing-thresholds.outcome }}"
- name: 5c - And the 'coverage-outcome' output should be Passed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Passed' --actual "${{ steps.passing-thresholds.outputs.coverage-outcome }}"
- name: 5d - And the 'coverage-results-file-path output' should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "coverage-results-file-path output" --value "${{ steps.passing-thresholds.outputs.coverage-results-file-path }}"
- name: 5e - And the remaining outputs should be empty since status checks and pr comments were not created
if: always()
run: |
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.passing-thresholds.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.passing-thresholds.outputs.pr-comment-id }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.passing-thresholds.outputs.coverage-results-truncated }}"
- name: 5f - And the contents of coverage-results.md file should match the contents of ${{ env.PASSING_THRESHOLDS_MD_FILE }} file
if: always()
run: |
# Comparing the coverage-results.md file will ensure that:
# - The provided report name is used
# - The badges have the right count/status/color
# - The details of the summary.md file are included
expectedFileName="${{ env.PASSING_THRESHOLDS_MD_FILE }}"
actualFileName="${{ steps.passing-thresholds.outputs.coverage-results-file-path }}"
./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 6 - FAILING LINE THRESHOLD & IGNORE-THRESHOLD-FAILURES=FALSE '
run: echo ""
- name: 6a - When process-code-coverage-summary is called with a line coverage below the threshold
id: failing-line
if: always()
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: '${{ env.COVERAGE_SUMMARY_INPUT_FILE }}'
create-status-check: false
create-pr-comment: false
report-name: 'Line Threshold Failure'
line-threshold: 99 # The actual coverage is 94.4
branch-threshold: 50 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 6b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.failing-line.outcome }}"
- name: 6c - And the 'coverage-outcome' output should be Failed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Failed' --actual "${{ steps.failing-line.outputs.coverage-outcome }}"
- name: 6d - And the 'coverage-results-file-path output' should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "coverage-results-file-path output" --value "${{ steps.failing-line.outputs.coverage-results-file-path }}"
- name: 6e - And the remaining outputs should be empty since status checks and pr comments were not created
if: always()
run: |
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.failing-line.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.failing-line.outputs.pr-comment-id }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.failing-line.outputs.coverage-results-truncated }}"
- name: 6f - And the contents of coverage-results.md file should match the contents of ${{ env.FAILING_LINE_MD_FILE }} file
if: always()
run: |
# Comparing the coverage-results.md file will ensure that:
# - The provided report name is used
# - The badges have the right count/status/color
# - The details of the summary.md file are included
expectedFileName="${{ env.FAILING_LINE_MD_FILE }}"
actualFileName="${{ steps.failing-line.outputs.coverage-results-file-path }}"
./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 7 - FAILING BRANCH THRESHOLD & IGNORE-THRESHOLD-FAILURES=FALSE '
run: echo ""
- name: 7a - When process-code-coverage-summary is called with a branch coverage below the threshold
id: failing-branch
if: always()
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: '${{ env.COVERAGE_SUMMARY_INPUT_FILE }}'
create-status-check: false
create-pr-comment: false
report-name: 'Branch Threshold Failure'
line-threshold: 50 # The actual coverage is 94.4
branch-threshold: 99 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 7b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.failing-branch.outcome }}"
- name: 7c - And the 'coverage-outcome' output should be Failed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Failed' --actual "${{ steps.failing-branch.outputs.coverage-outcome }}"
- name: 7d - And the 'coverage-results-file-path output' should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "coverage-results-file-path output" --value "${{ steps.failing-branch.outputs.coverage-results-file-path }}"
- name: 7e - And the remaining outputs should be empty since status checks and pr comments were not created
if: always()
run: |
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.failing-branch.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.failing-branch.outputs.pr-comment-id }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.failing-branch.outputs.coverage-results-truncated }}"
- name: 7f - And the contents of coverage-results.md file should match the contents of ${{ env.FAILING_BRANCH_MD_FILE }} file
if: always()
run: |
# Comparing the coverage-results.md file will ensure that:
# - The provided report name is used
# - The badges have the right count/status/color
# - The details of the summary.md file are included
expectedFileName="${{ env.FAILING_BRANCH_MD_FILE }}"
actualFileName="${{ steps.failing-branch.outputs.coverage-results-file-path }}"
./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 8 - FAILING THRESHOLDS & IGNORE-THRESHOLD-FAILURES=TRUE '
run: echo ""
- name: 8a - When process-code-coverage-summary is called with failing thresholds & ignore-threshold-failures=true
id: ignore-thresholds
if: always()
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: '${{ env.COVERAGE_SUMMARY_INPUT_FILE }}'
create-status-check: false
create-pr-comment: false
# report-name - Test the default (Code Coverage Results)
line-threshold: 99 # The actual coverage is 94.4
branch-threshold: 99 # The actual coverage is 93.8
ignore-threshold-failures: true
- name: 8b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.ignore-thresholds.outcome }}"
- name: 8c - And the 'coverage-outcome' output should be Passed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Passed' --actual "${{ steps.ignore-thresholds.outputs.coverage-outcome }}"
- name: 8d - And the 'coverage-results-file-path output' should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "coverage-results-file-path output" --value "${{ steps.ignore-thresholds.outputs.coverage-results-file-path }}"
- name: 8e - And the remaining outputs should be empty since status checks and pr comments were not created
if: always()
run: |
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.ignore-thresholds.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.ignore-thresholds.outputs.pr-comment-id }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.ignore-thresholds.outputs.coverage-results-truncated }}"
- name: 8f - And the contents of coverage-results.md file should match the contents of ${{ env.IGNORE_THRESHOLDS_MD_FILE }} file
if: always()
run: |
# Comparing the coverage-results.md file will ensure that:
# - The default report name is used (Code Coverage Results)
# - The badges have the right count/status/color
# - The details of the summary.md file are included
expectedFileName="${{ env.IGNORE_THRESHOLDS_MD_FILE }}"
actualFileName="${{ steps.ignore-thresholds.outputs.coverage-results-file-path }}"
./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 9 - THRESHOLD=0 '
run: echo ""
- name: 9a - When process-code-coverage-summary is called with thresholds set to 0
id: threshold-0
if: always()
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: '${{ env.COVERAGE_SUMMARY_INPUT_FILE }}'
create-status-check: false
create-pr-comment: false
# report-name - Test the default (Code Coverage Results)
line-threshold: 0 # The actual coverage is 94.4
branch-threshold: 0 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 9b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.threshold-0.outcome }}"
- name: 9c - And the 'coverage-outcome' output should be Passed
if: always()
run: |
./test/assert-values-match.sh --name "coverage-outcome output" --expected 'Passed' --actual "${{ steps.threshold-0.outputs.coverage-outcome }}"
- name: 9d - And the 'coverage-results-file-path output' should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "coverage-results-file-path output" --value "${{ steps.threshold-0.outputs.coverage-results-file-path }}"
- name: 9e - And the remaining outputs should be empty since status checks and pr comments were not created
if: always()
run: |
./test/assert-value-is-empty.sh --name "status-check-id output" --value "${{ steps.threshold-0.outputs.status-check-id }}"
./test/assert-value-is-empty.sh --name "pr-comment-id output" --value "${{ steps.threshold-0.outputs.pr-comment-id }}"
./test/assert-value-is-empty.sh --name "coverage-results-truncated output" --value "${{ steps.threshold-0.outputs.coverage-results-truncated }}"
- name: 9f - And the contents of coverage-results.md file should match the contents of ${{ env.THRESHOLD_0_MD_FILE }} file
if: always()
run: |
# Comparing the coverage-results.md file will ensure that:
# - The default report name is used (Code Coverage Results)
# - The badges have the right count/status/color
# - The details of the summary.md file are included
expectedFileName="${{ env.THRESHOLD_0_MD_FILE }}"
actualFileName="${{ steps.threshold-0.outputs.coverage-results-file-path }}"
./test/assert-file-contents-match.sh --expectedFileName $expectedFileName --actualFileName $actualFileName
test-status-checks:
runs-on: ubuntu-latest
env:
NO_FAILURES_MD_FILE: './test/expected-markdown/status-checks/no-failures.md'
IGNORE_FAILURES_MD_FILE: './test/expected-markdown/status-checks/ignore-failures.md'
ALLOW_FAILURES_MD_FILE: './test/expected-markdown/status-checks/allow-failures.md'
THRESHOLD_0_MD_FILE: './test/expected-markdown/status-checks/threshold-0.md'
NO_FAILURES_REPORT_NAME: 'No Threshold Failures Scenario'
IGNORE_FAILURES_REPORT_NAME: 'Ignore Threshold Failures Scenario'
ALLOW_FAILURES_REPORT_NAME: 'Allow Failures Failures Scenario'
THRESHOLD_0_REPORT_NAME: 'Threshold 0 Scenario'
NO_FAILURES_CHECK_NAME: 'no-failures-check'
IGNORE_FAILURES_CHECK_NAME: 'ignore-failures-check'
ALLOW_FAILURES_CHECK_NAME: 'allow-failures-check'
THRESHOLD_0_CHECK_NAME: 'threshold-0-check'
steps:
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' SETUP '
run: echo ""
- name: Setup - Fail test job if fork
run: |
if [ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]; then
echo "This test job requires the `checks: write` scope on the GITHUB_TOKEN which PRs from forks do not have. Before this PR can be merged, the tests should be run on an intermediate branch created by repository owners."
exit 1
fi
- name: Setup - Checkout the action
uses: actions/checkout@v4
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 10 - STATUS CHECK - NO FAILURES '
run: echo ""
- name: 10a - When process-code-coverage-summary is called with no threshold failures
if: always()
id: no-failures
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.NO_FAILURES_REPORT_NAME }}
check-name: ${{ env.NO_FAILURES_CHECK_NAME }}
create-status-check: true
line-threshold: 50 # The actual coverage is 94.4
branch-threshold: 50 # The actual coverage is 93.8
ignore-threshold-failures: false
create-pr-comment: false
- name: 10b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.no-failures.outcome }}"
- name: 10c - And the status-check-id output should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.no-failures.outputs.status-check-id }}"
- name: 10d - And the coverage-outcome output should be Passed
if: always()
run: ./test/assert-values-match.sh --name "coverage-outcome output" --expected "Passed" --actual "${{ steps.no-failures.outputs.coverage-outcome }}"
- name: 10e - And the status check should match the inputs
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertStatusCheckExists = require('./test/assert-status-check-exists.js');
const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js');
const checkId = '${{ steps.no-failures.outputs.status-check-id }}';
const actualCheck = await assertStatusCheckExists(github, context, core, checkId);
const expectedBody = fs.readFileSync('${{ env.NO_FAILURES_MD_FILE }}', 'utf8');
const expectedValues = {
name: 'status check - ${{ env.NO_FAILURES_CHECK_NAME }}'.toLowerCase(),
status: 'completed',
conclusion: 'success',
title: '${{ env.NO_FAILURES_REPORT_NAME }}',
text: expectedBody
};
assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 11 - STATUS CHECK - IGNORE FAILURES '
run: echo ""
- name: 11a - When process-code-coverage-summary is called with threshold failures & ignore-threshold-failures=true
if: always()
id: ignore-failures
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.IGNORE_FAILURES_REPORT_NAME }}
check-name: ${{ env.IGNORE_FAILURES_CHECK_NAME }}
create-status-check: true
line-threshold: 99 # The actual coverage is 94.4
branch-threshold: 99 # The actual coverage is 93.8
ignore-threshold-failures: true
create-pr-comment: false
- name: 11b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.ignore-failures.outcome }}"
- name: 11c - And the status-check-id output should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.ignore-failures.outputs.status-check-id }}"
- name: 11d - And the coverage-outcome output should be Passed
if: always()
run: ./test/assert-values-match.sh --name "coverage-outcome output" --expected "Passed" --actual "${{ steps.ignore-failures.outputs.coverage-outcome }}"
- name: 11e - And the status check should match the inputs
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertStatusCheckExists = require('./test/assert-status-check-exists.js');
const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js');
const checkId = '${{ steps.ignore-failures.outputs.status-check-id }}';
const actualCheck = await assertStatusCheckExists(github, context, core, checkId);
const expectedBody = fs.readFileSync('${{ env.IGNORE_FAILURES_MD_FILE }}', 'utf8');
const expectedValues = {
name: 'status check - ${{ env.IGNORE_FAILURES_CHECK_NAME }}'.toLowerCase(),
status: 'completed',
conclusion: 'neutral',
title: '${{ env.IGNORE_FAILURES_REPORT_NAME }}',
text: expectedBody
};
assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 12 - STATUS CHECK - ALLOW FAILURES '
run: echo ""
- name: 12a - When process-code-coverage-summary is called with threshold failures & ignore-threshold-failures=false
if: always()
id: allow-failures
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.ALLOW_FAILURES_REPORT_NAME }}
check-name: ${{ env.ALLOW_FAILURES_CHECK_NAME }}
create-status-check: true
line-threshold: 99 # The actual coverage is 94.4
branch-threshold: 99 # The actual coverage is 93.8
ignore-threshold-failures: false
create-pr-comment: false
- name: 12b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.allow-failures.outcome }}"
- name: 12c - And the status-check-id output should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.allow-failures.outputs.status-check-id }}"
- name: 12d - And the coverage-outcome output should be Failed
if: always()
run: ./test/assert-values-match.sh --name "coverage-outcome output" --expected "Failed" --actual "${{ steps.allow-failures.outputs.coverage-outcome }}"
- name: 12e - And the status check should match the inputs
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertStatusCheckExists = require('./test/assert-status-check-exists.js');
const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js');
const checkId = '${{ steps.allow-failures.outputs.status-check-id }}';
const actualCheck = await assertStatusCheckExists(github, context, core, checkId);
const expectedBody = fs.readFileSync('${{ env.ALLOW_FAILURES_MD_FILE }}', 'utf8');
const expectedValues = {
name: 'status check - ${{ env.ALLOW_FAILURES_CHECK_NAME }}'.toLowerCase(),
status: 'completed',
conclusion: 'failure',
title: '${{ env.ALLOW_FAILURES_REPORT_NAME }}',
text: expectedBody
};
assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 13 - STATUS CHECK - THRESHOLDS SET TO 0 '
run: echo ""
- name: 13a - When process-code-coverage-summary is called with the thresholds set to 0
if: always()
id: threshold-0
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.THRESHOLD_0_REPORT_NAME }}
check-name: ${{ env.THRESHOLD_0_CHECK_NAME }}
create-status-check: true
line-threshold: 0 # The actual coverage is 94.4
branch-threshold: 0 # The actual coverage is 93.8
ignore-threshold-failures: false
create-pr-comment: false
- name: 13b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.threshold-0.outcome }}"
- name: 13c - And the status-check-id output should be populated
if: always()
run: ./test/assert-value-is-not-empty.sh --name "status-check-id output" --value "${{ steps.threshold-0.outputs.status-check-id }}"
- name: 13d - And the coverage-outcome output should be Passed
if: always()
run: ./test/assert-values-match.sh --name "coverage-outcome output" --expected "Passed" --actual "${{ steps.threshold-0.outputs.coverage-outcome }}"
- name: 13e - And the status check should match the inputs
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertStatusCheckExists = require('./test/assert-status-check-exists.js');
const assertStatusCheckMatchesExpectations = require('./test/assert-status-check-matches-expectations.js');
const checkId = '${{ steps.threshold-0.outputs.status-check-id }}';
const actualCheck = await assertStatusCheckExists(github, context, core, checkId);
const expectedBody = fs.readFileSync('${{ env.THRESHOLD_0_MD_FILE }}', 'utf8');
const expectedValues = {
name: 'status check - ${{ env.THRESHOLD_0_CHECK_NAME }}'.toLowerCase(),
status: 'completed',
conclusion: 'neutral',
title: '${{ env.THRESHOLD_0_REPORT_NAME }}',
text: expectedBody
};
assertStatusCheckMatchesExpectations(core, actualCheck, expectedValues);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEARDOWN '
run: echo ""
- name: Teardown - Modify failing Status Check conclusion
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const updateFailingStatusCheck = require('./test/update-failing-status-check.js');
await updateFailingStatusCheck(github, context, core, '${{ steps.allow-failures.outputs.status-check-id }}');
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
test-pr-comments:
runs-on: ubuntu-latest
env:
EXISTING_COMMENT_ID: ''
UPDATE_COMMENT_KEY: 'existing-comment-${{ github.run_id }}'
UPDATE_WITH_MATCHING_PREFIX_MD_FILE: './test/expected-markdown/pr-comments/update-matching-prefix.md'
UPDATE_WITHOUT_MATCHING_PREFIX_MD_FILE: './test/expected-markdown/pr-comments/update-without-matching-prefix.md'
NO_UPDATE_MD_FILE: './test/expected-markdown/pr-comments/no-update.md'
TRUNCATE_FULL_MD_FILE: './test/expected-markdown/pr-comments/truncate-full-markdown.md'
TRUNCATE_TRUNCATED_MD_FILE: './test/expected-markdown/pr-comments/truncate-truncated-markdown.md'
UPDATE_WITH_MATCHING_PREFIX_REPORT_NAME: 'Update Comment with Matching Prefix Scenario'
UPDATE_WITHOUT_MATCHING_PREFIX_REPORT_NAME: 'Update Comment but no Matching Prefix Scenario'
NO_UPDATE_REPORT_NAME: 'Do Not Update Comment Scenario'
TRUNCATE_FAILURES_REPORT_NAME: 'Truncated PR Comment Scenario'
steps:
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' SETUP '
run: echo ""
- name: Setup - Fail test job if fork
run: |
if [ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]; then
echo "This test job requires the `pull_request: write` scope on the GITHUB_TOKEN which PRs from forks do not have. Before this PR can be merged, the tests should be run on an intermediate branch created by repository owners."
exit 1
fi
- name: Setup - Checkout the action
uses: actions/checkout@v4
- name: Setup - Delete pre-existing process-code-coverage-summary PR Comments
if: always()
uses: actions/github-script@v7
with:
script: |
const deletePrComments = require('./test/delete-pre-existing-comments.js');
await deletePrComments(github, context, core);
- name: Setup - Create a process-code-coverage-summary comment that can be updated
if: always()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `<!-- im-open/process-code-coverage-summary ${{ env.UPDATE_COMMENT_KEY }} -->\nThis comment will be replaced soon.`
})
.then(response => {
core.info(`The 'existing' process-code-coverage-summary comment has id: ${response.data.id}`);
core.exportVariable('EXISTING_COMMENT_ID', response.data.id);
})
.catch(error => {
core.setFailed(`An error occurred in the setup step while creating a comment: ${error.message}`);
});
await new Promise(r => setTimeout(r, 5 * 1000));
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 14 - PR COMMENT - UPDATE W/ MATCHING PREFIX '
run: echo ""
- name: 14a - When process-code-coverage-summary is called with updateComment=true and there is a comment with matching prefix
if: always()
id: update-with-matching-prefix
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.UPDATE_WITH_MATCHING_PREFIX_REPORT_NAME }}
create-status-check: false
create-pr-comment: true
update-comment-if-one-exists: true
update-comment-key: ${{ env.UPDATE_COMMENT_KEY }}
line-threshold: 50 # The actual coverage is 94.4
branch-threshold: 50 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 14b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.update-with-matching-prefix.outcome }}"
- name: 14c - And the pr-comment-id output should match the existing comment id
if: always()
run: ./test/assert-values-match.sh --name "pr-comment-id output" --expected "${{ env.EXISTING_COMMENT_ID }}" --actual "${{ steps.update-with-matching-prefix.outputs.pr-comment-id }}"
- name: 14d - And the coverage-results-truncated output should be false
if: always()
run: ./test/assert-values-match.sh --name "coverage-results-truncated output" --expected "false" --actual "${{ steps.update-with-matching-prefix.outputs.coverage-results-truncated }}"
- name: 14e - And the pr-comment should match the match the expected values
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertCommentExists = require('./test/assert-pr-comment-exists.js');
const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js');
const commentId = '${{ steps.update-with-matching-prefix.outputs.pr-comment-id }}';
const actualComment = await assertCommentExists(github, context, core, commentId);
const expectedMarkdown = fs.readFileSync('${{ env.UPDATE_WITH_MATCHING_PREFIX_MD_FILE }}', 'utf8');
const actualTestResults = fs.readFileSync('${{ steps.update-with-matching-prefix.outputs.coverage-results-file-path }}', 'utf8');
const expectedComment = {
prefix: '<!-- im-open/process-code-coverage-summary ${{ env.UPDATE_COMMENT_KEY }} -->',
fullMarkdown: expectedMarkdown,
action: 'updated',
truncated: false
};
assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 15 - PR COMMENT - UPDATE W/O MATCHING PREFIX '
run: echo ""
- name: 15a - When process-code-coverage-summary is called with updateComment=true but there is no comment with matching prefix
if: always()
id: update-without-matching-prefix
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.UPDATE_WITHOUT_MATCHING_PREFIX_REPORT_NAME }}
create-status-check: false
create-pr-comment: true
update-comment-if-one-exists: true
update-comment-key: 'different-identifier-${{ github.run_id }}'
line-threshold: 50 # The actual coverage is 94.4
branch-threshold: 50 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 15b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.update-without-matching-prefix.outcome }}"
- name: 15c - And the pr-comment-id output should be different than the existing comment id
if: always()
run: ./test/assert-values-do-not-match.sh --name "pr-comment-id output" --value1 "${{ env.EXISTING_COMMENT_ID }}" --value2 "${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}"
- name: 15d - And the coverage-results-truncated output should be false
if: always()
run: ./test/assert-values-match.sh --name "coverage-results-truncated output" --expected "false" --actual "${{ steps.update-without-matching-prefix.outputs.coverage-results-truncated }}"
- name: 15e - And the pr-comment should match the expected values
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertCommentExists = require('./test/assert-pr-comment-exists.js');
const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js');
const commentId = '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}';
const actualComment = await assertCommentExists(github, context, core, commentId);
const expectedMarkdown = fs.readFileSync('${{ env.UPDATE_WITHOUT_MATCHING_PREFIX_MD_FILE }}', 'utf8');
const actualTestResults = fs.readFileSync('${{ steps.update-without-matching-prefix.outputs.coverage-results-file-path }}', 'utf8');
const expectedComment = {
prefix: '<!-- im-open/process-code-coverage-summary different-identifier-${{ github.run_id }} -->',
fullMarkdown: expectedMarkdown,
action: 'created',
truncated: false
};
assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 16 - PR COMMENT - NO UPDATE '
run: echo ""
- name: 16a - When process-code-coverage-summary is called with updateComment=false
if: always()
id: matching-prefix-no-update
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.COVERAGE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.NO_UPDATE_REPORT_NAME }}
create-status-check: false
create-pr-comment: true
update-comment-if-one-exists: false
# update-comment-key - Test the default Job-Step
line-threshold: 50 # The actual coverage is 94.4
branch-threshold: 50 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 16b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.matching-prefix-no-update.outcome }}"
- name: 16c - And the pr-comment-id output should be different than the existing comment id
if: always()
run: ./test/assert-values-do-not-match.sh --name "pr-comment-id output" --value1 "${{ env.EXISTING_COMMENT_ID }}" --value2 "${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}"
- name: 16d - And the coverage-results-truncated output should be false
if: always()
run: ./test/assert-values-match.sh --name "coverage-results-truncated output" --expected "false" --actual "${{ steps.matching-prefix-no-update.outputs.coverage-results-truncated }}"
- name: 16e - And the pr-comment should match the expected values
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertCommentExists = require('./test/assert-pr-comment-exists.js');
const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js');
const commentId = '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}';
const actualComment = await assertCommentExists(github, context, core, commentId);
const expectedMarkdown = fs.readFileSync('${{ env.NO_UPDATE_MD_FILE }}', 'utf8');
const actualTestResults = fs.readFileSync('${{ steps.matching-prefix-no-update.outputs.coverage-results-file-path }}', 'utf8');
const expectedComment = {
prefix: `<!-- im-open/process-code-coverage-summary test-pr-comments_matching-prefix-no-update -->`,
fullMarkdown: expectedMarkdown,
action: 'created',
truncated: false
};
assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEST 17 - PR COMMENT - TRUNCATE '
run: echo ""
- name: 17a - When process-code-coverage-summary is called with a large comment that needs to be truncated
if: always()
id: truncate
uses: ./
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
summary-file: ${{ env.TRUNCATE_SUMMARY_INPUT_FILE }}
report-name: ${{ env.TRUNCATE_FAILURES_REPORT_NAME }}
create-status-check: false
create-pr-comment: true
update-comment-if-one-exists: true
update-comment-key: ${{ env.UPDATE_COMMENT_KEY }}
line-threshold: 50 # The actual coverage is 94.4
branch-threshold: 50 # The actual coverage is 93.8
ignore-threshold-failures: false
- name: 17b - Then the action outcome should be success
if: always()
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.truncate.outcome }}"
- name: 17c - And the pr-comment-id output should match the existing comment id
if: always()
run: ./test/assert-values-match.sh --name "pr-comment-id output" --expected "${{ env.EXISTING_COMMENT_ID }}" --actual "${{ steps.truncate.outputs.pr-comment-id }}"
- name: 17d - And the coverage-results-truncated output should be true
if: always()
run: ./test/assert-values-match.sh --name "coverage-results-truncated output" --expected "true" --actual "${{ steps.truncate.outputs.coverage-results-truncated }}"
- name: 17e - And the pr-comment should match the expected values
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const assertCommentExists = require('./test/assert-pr-comment-exists.js');
const assertCommentMatchesExpectations = require('./test/assert-pr-comment-matches-expectations.js');
const commentId = '${{ steps.truncate.outputs.pr-comment-id }}';
const actualComment = await assertCommentExists(github, context, core, commentId);
const expectedMarkdown = fs.readFileSync('${{ env.TRUNCATE_FULL_MD_FILE }}', 'utf8');
const expectedTruncatedMarkdown = fs.readFileSync('${{ env.TRUNCATE_TRUNCATED_MD_FILE }}', 'utf8');
const actualTestResults = fs.readFileSync('${{ steps.truncate.outputs.coverage-results-file-path }}', 'utf8');
const truncateMessage = 'Test results truncated due to character limit. See full report in output.';
const expectedComment = {
prefix: `<!-- im-open/process-code-coverage-summary ${{ env.UPDATE_COMMENT_KEY }} -->`,
fullMarkdown: expectedMarkdown,
action: 'updated',
truncated: true,
truncatedMarkdown: expectedTruncatedMarkdown,
};
assertCommentMatchesExpectations(core, actualComment, actualTestResults, expectedComment);
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""
- name: ' TEARDOWN '
run: echo ""
- name: Teardown - Delete PR Comments
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const deletePrComment = require('./test/delete-pr-comment.js');
await deletePrComment(github, context, core, '${{ env.EXISTING_COMMENT_ID }}');
await deletePrComment(github, context, core, '${{ steps.matching-prefix-no-update.outputs.pr-comment-id }}');
await deletePrComment(github, context, core, '${{ steps.update-without-matching-prefix.outputs.pr-comment-id }}');
- name: '-------------------------------------------------------------------------------------------------------------'
run: echo ""