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 the GITHUB_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:

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:

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.

# 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.

Screenshot of Github Workflow Running

Clone the repository and open up the codebase in an editor.

git clone git@github.com:keithweaver/demo-web-api.git
cd demo-web-api

In your editor, create a new file README.md:

# Demo Web API

Create another file .github/workflows/deploy.yml:

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.

Screenshot of Github Workflow Running

If you navigate to your Actions tab, you should see the workflow run. This ran on push to master.

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

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.

Screenshot of Github Workflow Running

Again, clone it to your local machine.

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:

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:

Screenshot of Github Workflow Running

You can create a personal access token by heading over to settings.

Screenshot of Github Workflow Running

On the left side, you should see Developer Settings.

Screenshot of Github Workflow Running

Next, select Personal Access Tokens and Generate New Token.

Screenshot of Github Workflow Running

You will need to give it a name. The token requires repo access and actions access.

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

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.

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

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.

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

You are all setup! Now time to push the code to your remote repository.

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.

Screenshot of Github Workflow Running

If you open your first repository Actions, you should see it get triggered by the web app.

Screenshot of Github Workflow Running

When the API is successful, it will return to the web app.

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

Screenshot of Github Workflow Running

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!