Lessons
Trigger Another Repository's Github Action Workflow and Wait for Result
In this lesson, I will walk you through triggering a workflow in a second Github repository. The most common use case is probably for triggering a single batch of tests while your code base is divided among multiple repositories. Another great use is triggering deployments of your API (in its own repo) before deploying your frontend (web app). This can be done fairly simply with a Github Action called Trigger Workflow and Wait.
Full transparency: I created this Github Action for Convictional and an internal use case. Its been made open-sourced to help others out. I would appreciate it if you enjoy it, please star it. Thanks!
High Level Explanation
Required arguments are (pulled off README):
owner
repo
github_token
workflow_file_name
The owner and repository are pretty clear. The Github token is a personal access token. A user must trigger a workflow. The workflow name is because we want to trigger a specific workflow.
The optional arguments is:
wait_interval
ref
inputs
propagate_failure
trigger_workflow
wait_workflow
In my words:
- The
wait_interval
is the pauses between checking the workflow status. It's measured in seconds. If you know your second workflow will take 10+ minutes to complete, there is no point in checking every second. You should just set it to check every 60 seconds. ref
is theGITHUB_REF
(the hash that represents a branch or commit).inputs
is any inputs for trigger client payload.propagate_failure
allows you to toggle if you want to return errors to the original workflow that triggered.trigger_workflow
allows you to toggle if you want to trigger the second workflow. You may just want to watch for the results of it.wait_workflow
allows you to toggle if you want to wait for the output.
More Detailed Explanation
I'm going to explain how the actual code works. If this doesn't matter to you, feel free to skip.
The entrypoint is:
1 2 3 4 5 6 7
function main { validate_args trigger_workflow wait_for_workflow_to_finish } main
validate_args
verifies you have the required arguments. trigger_workflow
is called. It calls the Github API using your personal access token, and event type:
1 2 3 4 5 6 7 8 9 10 11
function trigger_workflow { echo "https://api.github.com/repos/${INPUT_OWNER}/${INPUT_REPO}/actions/workflows/$INPUT_WORKFLOW_FILE_NAME/dispatches" curl -X POST "https://api.github.com/repos/${INPUT_OWNER}/${INPUT_REPO}/actions/workflows/$INPUT_WORKFLOW_FILE_NAME/dispatches" \ -H "Accept: application/vnd.github.v3+json" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${INPUT_GITHUB_TOKEN}" \ --data "{\"ref\":\"${ref}\",\"inputs\":${inputs}}" echo "Sleeping for $wait_interval seconds" sleep $wait_interval }
The last step is wait_for_workflow_to_finish
. The code grabs the status of last workflow run. If its pending
, then it waits based on the wait interval. Otherwise, its failure
or success
. If its failure
, it exits with a 1
exit code. On success, it continues.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
# Find the id of the last build last_workflow=$(curl -X GET "https://api.github.com/repos/$INPUT_OWNER/$INPUT_REPO/actions/workflows/$INPUT_WORKFLOW_FILE_NAME/runs" \ -H 'Accept: application/vnd.github.antiope-preview+json' \ -H "Authorization: Bearer $INPUT_GITHUB_TOKEN" | jq '[.workflow_runs[]] | first') last_workflow_id=$(echo $last_workflow | jq '.id') echo "The workflow id is [$last_workflow_id]." echo "" conclusion=$(echo $last_workflow | jq '.conclusion') status=$(echo $last_workflow | jq '.status') while [[ $conclusion == "null" && $status != "\"completed\"" ]] do echo "Sleeping for $wait_interval seconds" sleep $wait_interval workflow=$(curl -X GET "https://api.github.com/repos/$INPUT_OWNER/$INPUT_REPO/actions/workflows/$INPUT_WORKFLOW_FILE_NAME/runs" \ -H 'Accept: application/vnd.github.antiope-preview+json' \ -H "Authorization: Bearer $INPUT_GITHUB_TOKEN" | jq '.workflow_runs[] | select(.id == '$last_workflow_id')') conclusion=$(echo $workflow | jq '.conclusion') status=$(echo $workflow | jq '.status') echo "Checking conclusion [$conclusion]" echo "Checking status [$status]" done if [[ $conclusion == "\"success\"" && $status == "\"completed\"" ]] then echo "Yes, success" else # Alternative "failure" echo "Conclusion is not success, its [$conclusion]." if [ "$propagate_failure" = true ] then echo "Propagating failure to upstream job" exit 1 fi fi
The code really isn't complicated. The Github Action is a nice interface. Next a demo!
Demo
I will create two repositories. The first one is the web-app
and the second repository is web-api
. I want to trigger a "deployment" on the API on each code merged into the master of "web-app".
Start with creating the API repository.
Clone the repository and open up the codebase in an editor.
1 2
git clone git@github.com:keithweaver/demo-web-api.git cd demo-web-api
In your editor, create a new file README.md
:
1
# Demo Web API
Create another file .github/workflows/deploy.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
name: Deploy on: workflow_dispatch: push: branches: - master jobs: build: name: Run API runs-on: ubuntu-latest steps: - name: Build API run: | echo "Build API" sleep 10s
Push your changes to master.
If you navigate to your Actions tab, you should see the workflow run. This ran on push to master.
Now it's time to setup the second repository. This will be called demo-web-app
and it will build, trigger the API's deploy workflow, and if passes continue onto its own deployment. Start by creating a new repository.
Again, clone it to your local machine.
1 2
git clone git@github.com:keithweaver/demo-web-app.git cd demo-web-app
Open in your favourite editor. Create a .github/workflows/deploy.yml
file and put the following in it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
name: Deploy on: push: branches: - master jobs: build: name: Run Web App runs-on: ubuntu-latest steps: - name: Build Web App run: | echo "Build Web App" sleep 10s - uses: convictional/trigger-workflow-and-wait@v1.3.0 with: owner: keithweaver repo: demo-web-api github_token: ${{ secrets.G_ACCESS_TOKEN }} workflow_file_name: deploy.yml - name: Deploy Web App run: | echo "Deploy Web App" sleep 10s
Before you push this code up to master, you will need to setup a personal access token on the repository's secrets. Two differences from the README that is provided (It will probably be updated soon). First, there is no version on the uses
so we add it on: convictional/trigger-workflow-and-wait@v1.3.0
. You can also use master
which looks like: convictional/trigger-workflow-and-wait@master
. The second, we changed secret name from GITHUB_PERSONAL_ACCESS_TOKEN
to G_ACCESS_TOKEN
. I received this error when trying to add the secret:
You can create a personal access token by heading over to settings.
On the left side, you should see Developer Settings
.
Next, select Personal Access Tokens
and Generate New Token
.
You will need to give it a name. The token requires repo access and actions access.
You personal token is created! Take note of the new token. Do not lose it or you will have to regenerate it. Next, it is time to add secrets. Go to the repository, open settings, and open Secrets
.
After hitting New Secret
, you can add the name and value. The name would be G_ACCESS_TOKEN
. The value is your new personal access tokens.
You are all setup! Now time to push the code to your remote repository.
1 2 3
git add --all git commit -m "Let there be light" git push
Open the Actions
tab, and see your new run. It will run on push to master.
If you open your first repository Actions, you should see it get triggered by the web app.
When the API is successful, it will return to the web app.
You are all setup!
Conclusion
That is it! Thats the general overview of triggering one repo from another. Github Actions is a really nice way of interfacing with the API. Thanks for reading!