Managing flows between different repositoriesGithub Actions are designed to have various levels of reusability, such as composite actions or reusable workflows. A common approach to storing these items is having them contained in a separate repository, including tangential items related to them, such as scripts.This article explores how a caller workflow reaches out to a reusable workflow and checks out its repository to execute a script to perform some basic logic. It’s a guide but not in a step-by-step format. However, you can follow along with the code this article is based on via the various repository links provided in the section below (in particular, the README in the ttn-workflows repository is very thorough for some reason — I must have been in the mood for documentation).Be sure …
Managing flows between different repositoriesGithub Actions are designed to have various levels of reusability, such as composite actions or reusable workflows. A common approach to storing these items is having them contained in a separate repository, including tangential items related to them, such as scripts.This article explores how a caller workflow reaches out to a reusable workflow and checks out its repository to execute a script to perform some basic logic. It’s a guide but not in a step-by-step format. However, you can follow along with the code this article is based on via the various repository links provided in the section below (in particular, the README in the ttn-workflows repository is very thorough for some reason — I must have been in the mood for documentation).Be sure to check out the other links as well —for your convenience, they are all listed in the section at the end of this article.The organization org-mushroom-kingdom has recently begun work on a news application “Toad Town News.” The work for this application has broken up into three repositories:ttn-frontend, which handles the frontend of the application.ttn-backend, which handles the backend of the application.ttn-workflows, a repository dedicated to reusable workflows and items related to them such as scripts.The senior devs of this application have decided that any major frontend or backend release must have a pull request that includes a changelog file (hereafter referred to as a CHANGELOG file to match how it’s referred to in the above repositories’ code/documentation). This file gives the summary of the major changes associated with that release.This CHANGELOG file has strict conventions surrounding it: there must exactly one CHANGELOG file present per release branch. Furthermore, this file must meet certain naming conventions.When a pull request in ttn-frontend or ttn-backend is opened whose source branch is a release branch (a branch that begins with the string “release”) and whose target branch is main, a caller workflow is activated. This caller workflow calls a reusable workflow (changelog-quality-checks.yml, full path .github/workflows/changelog-quality-checks.yml) in the ttn-workflows repository that when triggered will check if the release branch meets the expected CHANGELOG file criteria.Some of changelog-quality-checks.yml’s work is performed by a script (changelog-quality-checks.py, full path scripts/changelog-quality-check.py). This script is also present in the ttn-workflows repository. This article won’t break down the CHANGELOG file assessment-related code present in the reusable workflow nor its script as that is not the main focus here— however, this logic elaborated extensively in the ttn-workflows README.Checking out ttn-workflows: Why and HowIf you’ve read my previousarticles about reusable workflows, you will see that things get a little more complex here compared to previous scenarios where all the work could be performed within the reusable workflow file itself. This time, we’re referencing a script within the reusable workflow’s repository and we have explicitly point to it to perform the brunt of our logic.Why the Need to Checkout?When a caller workflow is triggered, it is run within the context of its own repository. This poses an issue for us— trying to run or even grant permissions to the reusable workflow’s script will give us errors that the script doesn’t exist.This may seem obvious because there is no scripts/changelog-quality-check.py path in ttn-frontend or ttn-backend, but it surprised me at first. I had assumed that the reusable workflow could access a script in its own repository with no problem — you might think that since it’s running, it would implicitly switch to the context of its own repo. As I found out, that’s not the case. Our caller workflow fired off first, so we’re running things from the context of its repository. Because of that, we have to checkout the ttn-workflows repo so we can access the script.How to Checkout Another Repository in a WorkflowSo do we access this script? We checkout the reusable workflow’s repository, then point to it. It’s easier than you think — if you’ve used Github Actions at all, you’re familiar with the practically ubiquitous action actions/checkout.It’s commonly the first thing you see in several workflows. In this scenario we use it twice: first in the caller repo, and now again in the reusable workflow, this time with arguments!Take a look at the changelog-quality-checks.yml gist below:The “Checkout ttn-workflows repo (if non-manually triggered)” step assesses if we’re running the workflow manually (if we were, the checkout would be skipped since we’d already be in the context of the ttn-workflows repo). Since the workflow was triggered via workflow_call, the step will use actions/checkout in conjunction with the following arguments:repository: The specific repository to checkout. (: In the actions/checkout used in the caller workflow, we don’t need to specify this because the default activity checks out the caller workflow’s repository. Since we need to check out ttn-workflows, we specify it here.)path: The directory in the runner to put the repository contents (: this is relative to GITHUB_WORKSPACE. It should be present at top-level. In this example we checkout the ttn-workflows repository into the ttn-workflows-repo directory).token: The token that has the relevant permissions (specifically, the repo permission) necessary to checkout the reusable workflow’s repository. (: This is a generated token — we can’t use the pre-established GITHUB_TOKEN in the caller repo and pass it to the reusable workflow because GITHUB_TOKEN’s permissions are scoped to a single repository.)Accessing the Contents of a Checked Out RepoAfter we’ve checked out the ttn-workflows repository into the ttn-workflows-repo path, we can then call the changelog-quality-check.py script simply by referencing its path like so:The logic above also accounts changelog-quality-checks.yml being triggered manually or not. It isn’t in our case, so we set the REPO_PATH environmental variable to “ttn-workflows-repo”, the value of path used in the previous step. In other words, the full path used in the lower two steps would be ttn-workflows-repo/scripts/changelog-quality-check.py.Based upon the results of the script, the changelog-quality-checks.yml workflow returns a status (not pictured) that can then be leveraged by the caller workflow, such as in a branch protection rule. Standard post-checkout activity occurs, and that’s it. Not bad at all!Testing to see if the caller-reusable workflow relationship works as expected is very easy. All we need to do is create a release branch, make a commit on it, and then open a pull request to main.The synchronize trigger is key here — I can just make another commit while the pull request is open and run a different test case. For example, let’s say in ttn-frontend I have a release/v1.2 branch, and my first commit is creating a CHANGELOG file named CHANGELOG-frontend-v1.2.txt (the happy path scenario). I open the pull request which will be the very first time the caller workflow is triggered.I then go and look at the results. Things look great, but I still want to test scenarios like a bad CHANGELOG name. To do that, I can just rename my CHANGELOG file incorrectly in a new commit, and then push it. The pull request more or less detects that change (this is the synchronize activity). That triggers the caller workflow again; I can rinse and repeat from there.As an aside, in previously displayed code snippets there is logic that allows one to test this reusable workflow via manually triggering it in its own repository in addition to calling it from a caller workflow. Basically, the reusable workflow assesses what repository called it and/or if it was manually executed. The evaluation of that determines whether the workflow will execute certain steps. It’s handy to have it set up like this in case you want to specifically test something related to the reusable workflow/script versus the caller-reusable workflow relationship, or if you want to iterate further on the reusable workflow.This article has shown how to call upon a reusable workflow in a different repository and explained the how and why of checking out that workflow’s repository to execute desired behavior. Using the methodology explained here, you can see why it’s important to properly contain reusable workflows and their associated items (like scripts) in their own repository. Perhaps more importantly, you have been shown to link it all together.Are you as sick as I am of the word ‘reusable’ after getting to this point? Once you get over that malaise, try setting up something similar for yourself! The best way to learn, after all, is through (Github) action!Links present in the article are listed here in order of appearance.Please note the following:Some links may be present more than once in the article. To keep things brief, only the first instance is listed.A # present in the title of the source indicates a bookmark on that page.