Build and Review PR #9 #23
Workflow file for this run
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
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: | |
DID_CUSTOM_ACTION_CODE_CHANGE_DIR: '.github/actions/did-custom-action-code-change' | |
UPDATE_ACTION_VERSION_IN_FILE_DIR: '.github/actions/update-action-version-in-file' | |
IS_FORK: ${{ github.event.pull_request.head.repo.fork }} | |
PR_SOURCE: ${{ github.event.pull_request.head.repo.fork == true && 'fork' || 'branch' }} | |
jobs: | |
review-did-custom-action-code-change: | |
runs-on: ubuntu-latest | |
outputs: | |
HAS_CHANGES: ${{ env.HAS_CHANGES }} | |
env: | |
ACTION_NAME: 'did-custom-action-code-change' | |
HAS_CHANGES: '' # Set in the Action Changed step below | |
NEEDS_BUILD_COMMIT: false # Set to true in a subsequent step if applicable | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: PR Source - ${{ env.PR_SOURCE }} | |
run: echo "PRs can come from a branch or a fork. This PR is from a ${{ env.PR_SOURCE }}." | |
- name: Check if the 'did-custom-action-code-change' action changed | |
id: did-custom-action-code-change | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
folders-with-code: '${{ env.DID_CUSTOM_ACTION_CODE_CHANGE_DIR }}' | |
files-with-code: '' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Action Changed (open for details) | |
run: | | |
hasChanges="${{steps.did-custom-action-code-change.outputs.HAS_CHANGES }}"; | |
echo "HAS_CHANGES=$hasChanges" >> $GITHUB_ENV | |
if [ "$hasChanges" == "true" ]; then | |
echo "This PR changes the '${{ env.ACTION_NAME }}' action. Proceed with subsequent steps." | |
else | |
echo "This PR does not change the '${{ env.ACTION_NAME }}' action. Skipping subsequent steps." | |
fi | |
# ---------------------------------------------------------------------------------------------------- | |
# | |
# The remaining steps in this build will use the env.HAS_CHANGES condition. Setting it on each | |
# step rather than the job will ensure this job always runs and that we can use it for status checks. | |
# | |
# ---------------------------------------------------------------------------------------------------- | |
# ----------------------------------- | |
# Check if action has been recompiled | |
# ----------------------------------- | |
- name: Setup Node 20.x | |
uses: actions/setup-node@v4 | |
if: env.HAS_CHANGES == 'true' | |
with: | |
node-version: 20.x | |
- name: Build the action | |
if: env.HAS_CHANGES == 'true' | |
working-directory: ${{ env.DID_CUSTOM_ACTION_CODE_CHANGE_DIR }} | |
run: npm run build | |
- name: Check for unstaged build changes (open for details) | |
if: env.HAS_CHANGES == 'true' | |
run: | | |
if [[ "$(git status --porcelain)" != "" ]]; then | |
echo "The '${{ env.ACTION_NAME }}' action needs to be re-built." | |
echo "NEEDS_BUILD_COMMIT=true" >> "$GITHUB_ENV" | |
else | |
echo "The '${{ env.ACTION_NAME }}' action has already been re-built" | |
fi | |
# ------------------------------------------- | |
# Fail the workflow if the action needs to be recompiled | |
# ------------------------------------------- | |
- name: Fail the workflow if the action needs to be recompiled | |
if: env.HAS_CHANGES == 'true' && env.NEEDS_BUILD_COMMIT == 'true' | |
id: summary | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
// Construct the instructions for fixing the PR | |
const instructions = 'Before this PR can be merged, please recompile the action by running the following command from the\n"${{ env.DID_CUSTOM_ACTION_CODE_CHANGE_DIR }}" directory:\n`npm run build`'; | |
// Comment on PR for branches. A fork's GH_TOKEN only has 'read' permission on all scopes so a comment cannot be made. | |
if (!${{ env.IS_FORK }}) { | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: instructions | |
}) | |
} | |
// Add workflow summary & fail the build | |
core.summary | |
.addRaw(instructions) | |
.write(); | |
core.setFailed(instructions); | |
test-did-custom-action-code-change: | |
runs-on: ubuntu-latest | |
needs: [review-did-custom-action-code-change] | |
if: always() | |
env: | |
ACTION_NAME: 'did-custom-action-code-change' | |
HAS_CHANGES: ${{ needs.review-did-custom-action-code-change.outputs.HAS_CHANGES }} | |
CODE_HAS_CHANGED: '' | |
PR: 5 | |
PR5_FILE_FULL: '.github/actions/did-custom-action-code-change/action.yml' | |
PR5_FILE_SNIPPET: 'action.yml' | |
PR5_FILE_UNCHANGED: 'this-is-a-file-that-does-not-exist.md' | |
PR5_FOLDER_FULL: '.github/actions/did-custom-action-code-change' | |
PR5_FOLDER_SNIPPET: 'did-custom-action-code-change' | |
PR5_FOLDER_UNCHANGED: 'folder-that-does-not-exist' | |
steps: | |
- name: Action Changed (open for details) | |
run: | | |
if [ "${{env.HAS_CHANGES}}" == "true" ]; then | |
echo "This PR changes the '${{ env.ACTION_NAME }}' action. Proceed with subsequent tests." | |
else | |
echo "This PR does not change the '${{ env.ACTION_NAME }}' action. Skipping subsequent tests." | |
fi | |
# ---------------------------------------------------------------------------------------------------- | |
# The remaining steps in this build will use the env.HAS_CHANGES condition. Setting it on each | |
# step rather than the job will ensure this job always runs and that we can use it for status checks. | |
# ---------------------------------------------------------------------------------------------------- | |
# ------------------------------------------- | |
# SETUP | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: Setup - Checkout | |
if: always() && env.HAS_CHANGES == 'true' | |
uses: actions/checkout@v4 | |
# ------------------------------------------- | |
# FULL FILE PATH THAT MATCHES | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When checking the pr with a full file name that has changes | |
if: always() && env.HAS_CHANGES == 'true' | |
id: full-file | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
files-with-code: '${{ env.PR5_FILE_FULL}}' | |
folders-with-code: '' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
pr-number: ${{ env.PR}} | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.full-file.outcome }}" | |
- name: Then the HAS_CHANGES output and environment vars should be true | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
./test/assert-values-match.sh --name "HAS_CHANGES" --expected "true" --actual "${{ steps.full-file.outputs.HAS_CHANGES }}" | |
./test/assert-values-match.sh --name "CODE_HAS_CHANGED" --expected "true" --actual "${{ env.CODE_HAS_CHANGED }}" | |
echo "CODE_HAS_CHANGED=" >> $GITHUB_ENV | |
# ------------------------------------------- | |
# SNIPPET OF FILE PATH THAT MATCHES | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When checking the pr with a snippet of a file name that has changes | |
if: always() && env.HAS_CHANGES == 'true' | |
id: file-snippet | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
files-with-code: '${{ env.PR5_FILE_SNIPPET }}' | |
folders-with-code: '' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
pr-number: ${{ env.PR}} | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.file-snippet.outcome }}" | |
- name: Then the HAS_CHANGES output and environment vars should be true | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
./test/assert-values-match.sh --name "HAS_CHANGES" --expected "true" --actual "${{ steps.file-snippet.outputs.HAS_CHANGES }}" | |
./test/assert-values-match.sh --name "CODE_HAS_CHANGED" --expected "true" --actual "${{ env.CODE_HAS_CHANGED }}" | |
echo "CODE_HAS_CHANGED=" >> $GITHUB_ENV | |
# ------------------------------------------- | |
# FILE PATH THAT DOES NOT MATCH | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When checking the pr with a file name that does not have changes | |
if: always() && env.HAS_CHANGES == 'true' | |
id: file-no-match | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
files-with-code: '${{ env.PR5_FILE_UNCHANGED}}' | |
folders-with-code: '' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
pr-number: ${{ env.PR}} | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.file-no-match.outcome }}" | |
- name: Then the HAS_CHANGES output and environment vars should be false | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
./test/assert-values-match.sh --name "HAS_CHANGES" --expected "false" --actual "${{ steps.file-no-match.outputs.HAS_CHANGES }}" | |
./test/assert-values-match.sh --name "CODE_HAS_CHANGED" --expected "false" --actual "${{ env.CODE_HAS_CHANGED }}" | |
echo "CODE_HAS_CHANGED=" >> $GITHUB_ENV | |
# ------------------------------------------- | |
# FULL FOLDER PATH THAT MATCHES | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When checking the pr with a full folder path that has changes | |
if: always() && env.HAS_CHANGES == 'true' | |
id: folder-full | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
files-with-code: '' | |
folders-with-code: '${{ env.PR5_FOLDER_FULL }}' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
pr-number: ${{ env.PR}} | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.folder-full.outcome }}" | |
- name: Then the HAS_CHANGES output and environment vars should be true | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
./test/assert-values-match.sh --name "HAS_CHANGES" --expected "true" --actual "${{ steps.folder-full.outputs.HAS_CHANGES }}" | |
./test/assert-values-match.sh --name "CODE_HAS_CHANGED" --expected "true" --actual "${{ env.CODE_HAS_CHANGED }}" | |
echo "CODE_HAS_CHANGED=" >> $GITHUB_ENV | |
# ------------------------------------------- | |
# SNIPPET OF FOLDER PATH THAT MATCHES | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When checking the pr with a snippet of a folder path that has changes | |
if: always() && env.HAS_CHANGES == 'true' | |
id: folder-snippet | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
files-with-code: '' | |
folders-with-code: '${{ env.PR5_FOLDER_SNIPPET }}' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
pr-number: ${{ env.PR}} | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.folder-snippet.outcome }}" | |
- name: Then the HAS_CHANGES output and environment vars should be true | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
./test/assert-values-match.sh --name "HAS_CHANGES" --expected "true" --actual "${{ steps.folder-snippet.outputs.HAS_CHANGES }}" | |
./test/assert-values-match.sh --name "CODE_HAS_CHANGED" --expected "true" --actual "${{ env.CODE_HAS_CHANGED }}" | |
echo "CODE_HAS_CHANGED=" >> $GITHUB_ENV | |
# ------------------------------------------- | |
# FOLDER PATH THAT DOES NOT MATCH | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When checking the pr with a folder that does not have changes | |
if: always() && env.HAS_CHANGES == 'true' | |
id: folder-no-match | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
files-with-code: '' | |
folders-with-code: '${{ env.PR5_FOLDER_UNCHANGED }}' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
pr-number: ${{ env.PR}} | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.folder-no-match.outcome }}" | |
- name: Then the HAS_CHANGES output and environment vars should be false | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
./test/assert-values-match.sh --name "HAS_CHANGES" --expected "false" --actual "${{ steps.folder-no-match.outputs.HAS_CHANGES }}" | |
./test/assert-values-match.sh --name "CODE_HAS_CHANGED" --expected "false" --actual "${{ env.CODE_HAS_CHANGED }}" | |
echo "CODE_HAS_CHANGED=" >> $GITHUB_ENV | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
review-update-action-version-in-file: | |
runs-on: ubuntu-latest | |
outputs: | |
HAS_CHANGES: ${{ env.HAS_CHANGES }} | |
env: | |
ACTION_NAME: 'update-action-version-in-file' | |
HAS_CHANGES: '' # Set in the Action Changed step below | |
NEEDS_BUILD_COMMIT: false # Set to true in a subsequent step if applicable | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: PR Source - ${{ env.PR_SOURCE }} | |
run: echo "PRs can come from a branch or a fork. This PR is from a ${{ env.PR_SOURCE }}." | |
- name: Check if the 'update-action-version-in-file' action changed | |
id: update-action-version-in-file | |
uses: ./.github/actions/did-custom-action-code-change | |
with: | |
folders-with-code: '${{ env.UPDATE_ACTION_VERSION_IN_FILE_DIR }}' | |
files-with-code: '' | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Action Changed (open for details) | |
run: | | |
hasChanges="${{ steps.update-action-version-in-file.outputs.HAS_CHANGES }}"; | |
echo "HAS_CHANGES=$hasChanges" >> $GITHUB_ENV | |
if [ "$hasChanges" == "true" ]; then | |
echo "This PR changes the '${{ env.ACTION_NAME }}' action. Proceed with subsequent steps." | |
else | |
echo "This PR does not change the '${{ env.ACTION_NAME }}' action. Skipping subsequent steps." | |
fi | |
# ---------------------------------------------------------------------------------------------------- | |
# | |
# The remaining steps in this build will use the env.HAS_CHANGES condition. Setting it on each | |
# step rather than the job will ensure this job always runs and that we can use it for status checks. | |
# | |
# ---------------------------------------------------------------------------------------------------- | |
# ----------------------------------- | |
# Check if action has been recompiled | |
# ----------------------------------- | |
- name: Setup Node 20.x | |
uses: actions/setup-node@v4 | |
if: env.HAS_CHANGES == 'true' | |
with: | |
node-version: 20.x | |
- name: Build the action | |
if: env.HAS_CHANGES == 'true' | |
working-directory: ${{ env.UPDATE_ACTION_VERSION_IN_FILE_DIR }} | |
run: npm run build | |
- name: Check for unstaged build changes (open for details) | |
if: env.HAS_CHANGES == 'true' | |
run: | | |
if [[ "$(git status --porcelain)" != "" ]]; then | |
echo "The '${{ env.ACTION_NAME }}' action needs to be re-built." | |
echo "NEEDS_BUILD_COMMIT=true" >> "$GITHUB_ENV" | |
else | |
echo "The '${{ env.ACTION_NAME }}' action has already been re-built" | |
fi | |
# ------------------------------------------- | |
# Fail the workflow if the action needs to be recompiled | |
# ------------------------------------------- | |
- name: Fail the workflow if the action needs to be recompiled | |
if: env.HAS_CHANGES == 'true' && env.NEEDS_BUILD_COMMIT == 'true' | |
id: summary | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
// Construct the instructions for fixing the PR | |
const instructions = 'Before this PR can be merged, please recompile the action by running the following command from the\n"${{ env.UPDATE_ACTION_VERSION_IN_FILE_DIR }}" directory:\n`npm run build`'; | |
// Comment on PR for branches. A fork's GH_TOKEN only has 'read' permission on all scopes so a comment cannot be made. | |
if (!${{ env.IS_FORK }}) { | |
github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: instructions | |
}) | |
} | |
// Add workflow summary & fail the build | |
core.summary | |
.addRaw(instructions) | |
.write(); | |
core.setFailed(instructions); | |
test-update-action-version-in-file: | |
runs-on: ubuntu-latest | |
needs: [review-update-action-version-in-file] | |
if: always() | |
env: | |
ACTION_NAME: 'update-action-version-in-file' | |
HAS_CHANGES: ${{ needs.review-update-action-version-in-file.outputs.HAS_CHANGES }} | |
steps: | |
- name: Action Changed (open for details) | |
run: | | |
if [ "${{env.HAS_CHANGES}}" == "true" ]; then | |
echo "This PR changes the '${{ env.ACTION_NAME }}' action. Proceed with subsequent tests." | |
else | |
echo "This PR does not change the '${{ env.ACTION_NAME }}' action. Skipping subsequent tests." | |
fi | |
# ---------------------------------------------------------------------------------------------------- | |
# The remaining steps in this build will use the env.HAS_CHANGES condition. Setting it on each | |
# step rather than the job will ensure this job always runs and that we can use it for status checks. | |
# ---------------------------------------------------------------------------------------------------- | |
# ------------------------------------------- | |
# SETUP | |
# ------------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: Setup - Checkout | |
if: always() && env.HAS_CHANGES == 'true' | |
uses: actions/checkout@v4 | |
#-------------------------------------- | |
# FILE HAS CHANGES | |
#-------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When updating a file with a new action version | |
uses: ./.github/actions/update-action-version-in-file | |
if: always() && env.HAS_CHANGES == 'true' | |
id: changes | |
with: | |
file-to-update: ./test/files/file-to-update.md | |
action-name: im-open/update-action-version-in-file | |
version-prefix: p | |
updated-version: v1.0.0 | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.changes.outcome }}" | |
- name: And the has-changes output should be true | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "has-changes" --expected "true" --actual "${{ steps.changes.outputs.has-changes }}" | |
- name: And the updated-content output should have updated action versions | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
expectedContent=$(cat ./test/files/expected-output.md) | |
./test/assert-values-match.sh --name "updated-content" --expected "$expectedContent" --actual "${{ steps.changes.outputs.updated-content }}" | |
#-------------------------------------- | |
# FILE HAS NO CHANGES | |
#-------------------------------------- | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" | |
- name: When updating a file with a new action version | |
uses: ./.github/actions/update-action-version-in-file | |
if: always() && env.HAS_CHANGES == 'true' | |
id: no-changes | |
with: | |
file-to-update: ./test/files/file-to-update.md | |
action-name: im-open/different-action-version | |
version-prefix: v | |
updated-version: v1.0.0 | |
- name: Then the outcome should be success | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.no-changes.outcome }}" | |
- name: And the has-changes output should be false | |
if: always() && env.HAS_CHANGES == 'true' | |
run: ./test/assert-values-match.sh --name "has-changes" --expected "false" --actual "${{ steps.no-changes.outputs.has-changes }}" | |
- name: And the updated-content output should be the original content | |
if: always() && env.HAS_CHANGES == 'true' | |
run: | | |
expectedContent=$(cat ./test/files/file-to-update.md) | |
./test/assert-values-match.sh --name "updated-content" --expected "$expectedContent" --actual "${{ steps.no-changes.outputs.updated-content }}" | |
- name: '-------------------------------------------------------------------------------------------------------' | |
run: echo "" |