GitHub Shareable Action
Background
I need to set up 3 GitHub workflows for 10 repo. For each workflow, it will run a similar bash script.
First trial - Create Separate Bash Script and Workflow
On my first trial, I did the following:
Here are the three bash scripts:
run-dependabot-alert.sh
#!/bin/sh
TOKEN=$1
REPO=$2
get_response(){
curl -sL \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN"\
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/januschung/"$REPO"/dependabot/alerts
}
do_something(){
echo "Running Dependabot!"
}
get_response
do_something
run-secret-scanning.sh
#!/bin/sh
TOKEN=$1
REPO=$2
get_response(){
? curl -sL \
? ? -H "Accept: application/vnd.github+json" \
? ? -H "Authorization: Bearer $TOKEN"\
? ? -H "X-GitHub-Api-Version: 2022-11-28" \
? ? https://api.github.com/repos/januschung/"$REPO"/secret-scanning/alerts
}
do_something(){
? ? echo "Running Secret Scanning!"
}
get_response
do_something
run-codeql-alert.sh
#!/bin/sh
TOKEN=$1
REPO=$2
get_response(){
? curl -sL \
? ? -H "Accept: application/vnd.github+json" \
? ? -H "Authorization: Bearer $TOKEN"\
? ? -H "X-GitHub-Api-Version: 2022-11-28" \
? ? https://api.github.com/repos/januschung/"$REPO"/code-scanning/alerts
}
do_something(){
? ? echo "Running CodeQL Scanning!"
}
get_response
do_something
Here is one of the three workflows, as they are more like the same:
dependabot-workflow.yml
name: 'Dependabot Alert Check'
on:
? push:
? ? branches:
? ? ? - 'main'
jobs:
? dependabot-scanning-alert-check:
? ? runs-on: ubuntu-latest
? ? steps:
? ? ? - uses: actions/checkout@v3
? ? ? ? with:
? ? ? ? ? token: ${{ secrets.GH_TOKEN }}
? ? ? - name: Run Dependabot Alert Check
? ? ? ? shell: bash
? ? ? ? run: |
? ? ? ? ? ./scripts/run-dependabot-alert.sh ${{ secret.GH_TOKEN }} ${{ github.event.repository.name }}
As you can see, there are a lot of similar logic from both of the bash scripts and the workflows. It will be tedious to repeat the work across the other repos.
Can I do better? Sure!
Second Trial - Create Shareable Composite Action
Since all of the 10 repo will share the same logic, I converted the workflow into a shareable composite action in a dedicated repo. In so doing, the other repo can reference the same action. Here are the benefits:
领英推荐
Here is the shareable composite action:
name: 'Alert Check'
description: 'Run alert check'
inputs:
alert-type:
description: 'Alert type to run - code-scanning, dependabot or secret-scanning'
required: true
default: 'dependabot'
? gh-token:
? ? required: true
runs:
? using: "composite"
? steps:
? ? - uses: actions/checkout@v3
? ? ? with:
? ? ? ? token: ${{ inputs.gh-token }}
? ? - shell: bash
? ? ? run: echo "${{ github.action_path }}" >> $GITHUB_PATH
? ? - shell: bash
? ? ? run: |
? ? ? ? ${{ alert-type }}.sh ${{ inputs.gh-token }} ${{ github.event.repository.name }}
Note that the bash scripts are now migrated from scripts folder into .github/actions/alerts.
The corresponding workflow that reference the shareable composite action:
on: [push]
jobs:
? run_alert:
? ? runs-on: ubuntu-latest
? ? name: Run Dependabot Alert
? ? steps:
? ? ? - uses: actions/checkout@v3
? ? ? - uses: januschung/shared-action-repo/.github/actions/alerts@main
? ? ? ? with:
? ? ? ? ? gh-token: ${{ secrets.GH_TOKEN }}
alert-type: ${{ matrix.type }}
Looking way much better now. But, can I do even better?
Third Trial - Consolidate Into a Single Bash Script and a Single Action
Since all three bash scripts share 80% of the same logic, I consolidated them into a single one:
alert.sh
#!/bin/sh
TOKEN=$1
REPO=$2
TYPE=$3
get_response(){
? curl -sL \
? ? -H "Accept: application/vnd.github+json" \
? ? -H "Authorization: Bearer $TOKEN"\
? ? -H "X-GitHub-Api-Version: 2022-11-28" \
? ? https://api.github.com/repos/januschung/"$REPO"/"$TYPE"/alerts
}
do_something(){
? ? if [ "TYPE" == 'code-scanning' ]; then
? ? ? ? do_something_code_scanning
? ? elif [ "TYPE" == 'dependabot' ]; then
? ? ? ? do_something_dependabot
? ? elif [ "TYPE" == 'secret-scanning' ]; then
? ? ? ? do_something_secret_scanning
? ? else
? ? ? ? exit 1
? ? fi
}
do_something_code_scanning(){
? ? echo "Running Secret Scanning!"
}
do_something_dependabot(){
? ? echo "Running Dependabot!"
}
do_something_secret_scanning(){
? ? echo "Running Secret Scanning!"
}
get_response
do_something
The consolidated action.yml
name: 'Alert Check'
description: 'Run alert check'
inputs:
? alert-type:
? ? description: 'Alert type to run - code-scanning, dependabot or secret-scanning'
? ? required: true
? ? default: 'dependabot'
? gh-token:
? ? required: true
runs:
? using: "composite"
? steps:
? ? - uses: actions/checkout@v3
? ? ? with:
? ? ? ? token: ${{ inputs.gh-token }}
? ? - shell: bash
? ? ? run: echo "${{ github.action_path }}" >> $GITHUB_PATH
? ? - shell: bash
? ? ? run: |
? ? ? ? alert.sh ${{ inputs.gh-token }} ${{ github.event.repository.name }} {{ inputs.alert-type }}
I do not want to create three seperate workflows from the external repo either, so I use GitHub Matrix in a single workflow:
on: [push]
jobs:
? run_alert:
? ? runs-on: ubuntu-latest
? ? name: Run Alert
? ? strategy:
? ? ? matrix:
? ? ? ? type: ['code-scanning', 'dependabot', 'secret-scanning']
? ? steps:
? ? ? - uses: actions/checkout@v3
? ? ? - uses: januschung/shared-action-repo/.github/actions/alerts@main
? ? ? ? with:
? ? ? ? ? gh-token: ${{ secrets.GH_TOKEN }}
alert-type: ${{ matrix.type }}
That is it! I hope this helps if you are into similar situation in the coming future.