10 things that would make GitHub Actions even better
Daniel Sieradski
Posted on February 9, 2022
As a DevOps engineer, I spend a great deal of time working on CI/CD pipelines, knee-deep in YAML, API documentation, and web search results, writing and re-writing workflows, running and re-running them over and over again, trying to smooth out the kinks. As such, I've come to develop strong opinions on how these things ought to work for developer's ease. And having spent the last several months working intimately with GitHub Actions specifically, I've come to develop some strong opinions about it in particular.
Overall, I find GitHub Actions to be an excellent service that's incredibly flexible, generally reliable, and has a wonderful, sizable community contributing to its vast catalog of pre-built workflows and workflow steps. However, there are some improvements that I believe should be made to GitHub Actions that will significantly enhance developers' experience.
1. A less disjointed user interface
Currently, if you want to check out the status of a job run, you have to:
- Navigate to the corresponding repository in your browser (1-3 page loads if you start from the homepage)
- Click the actions tab (+1 page load)
- Select the workflow (+1 page load)
- Click the run (+1 page load)
- Click on the job (+1 page load)
- Unfurl the step you want to view
That's 5-7 page loads just to check a job's status.
Sure, GitHub shows the final status of your job runs on the notifications page. But if you have a high velocity repo with a lot of contributors, that page is essentially useless noise.
There has to be a better way.
GitHub could, for example, add a run status view to the GitHub homepage that shows all your currently running jobs. Or, when you click the Actions tab on a repo, there could be a dropdown menu that shows the latest jobs. Anything is better than what it is now.
2. Subscribe to watch specific workflows
GitHub will notify you about the result of any job you initiate, but it won't notify you about the result of scheduled jobs triggered by GitHub's crontab or jobs initiated by other users. GitHub should therefore add the ability for users to subscribe to workflows so that they get notified of their outcome whenever they're run and by whoever.
3. Modular workflows
It's a little frustrating to have to manage multiple copies of the same block of YAML — especially a big block of YAML — when only one or two variables in that block differ between workflows. GitHub should add a way to include YAML files into other YAML files, and to pass variables between the two, so that you can reuse modules across workflows. Yes, you could create other GitHub Actions to include in your workflows, but that's kind of overkill, especially if the workflow is very specific to your development operations. Why not just...
A module:
name: My module
id: my_module
type: module
inputs:
- myVariable1
- myVariable2
jobs:
etc.
An include:
name: My workflow
jobs:
my_job:
runs-on: ubuntu-latest
steps:
- module: my_module
inputs:
- myVariable1: 'my input'
- myVariable2: 'my other input'
This would save so much hassle.
As of November 2021, this exists. It's called a Workflow Call.
4. Workflows that trigger other workflows and stay grouped to your P.R.
Let's say you have a monorepo and you run separate workflows specific to each package within your monorepo on every pull request.
Each workflow needs to run the same yarn install
from the root when it first starts up. But you've just updated your packages so there's a new yarn.lock
and no cache available for your build. So now, each one of your workflows is going to start from scratch downloading and installing everything, adding at least five minutes to each run, unnecessarily eating up billable runtime.
But what if you could have a workflow that runs before your other workflows that detects changes in yarn.lock
and pre-caches your node_modules
first? You can configure a workflow to trigger other workflows using workflow_run
or even Peter Evans' Repository Dispatch action (in which case use a personal access token, which is not ideal for organizations where it's preferable to not tie access keys to individual users' accounts).
However, the problem is that subsequent workflows will get buried under the Actions tab and won't be connected back to their trigger, specifically the P.R. that initiated the first workflow. Therefore, any checks in those workflows won't be applied to the P.R., rendering them essentially useless if you use them for quality control.
Again, there's gotta be a better way, and it could be as simple as modifying the workflow_run
trigger to keep triggered workflows connected back to their initiator.
5. Custom check results that go where they belong
GitHub Actions allows you to add custom checks to your workflows — validators that can block the merging of pull requests or the deployment of new builds. But for some bizarre reason, it doesn't attach those custom checks to the workflows that triggered them. It will add them to any workflow triggered by the same P.R.
Per Michael Dorner, author of the Test Reporter Action:
Check Runs are created for specific commit SHA. It's not possible to specify under which workflow test report should belong if more workflows are running for the same SHA. Thanks to this GitHub "feature" it's possible your test report will appear in an unexpected place in GitHub UI.
It's true! And extremely confusing! And annoying! And GitHub should fix it!
6. Automatically capture stdout/stderr
from any step as an output and add more metadata as outputs
In GitHub Actions, if you want to return the output of a command as a block of text to use in another job or step, you have to do some crazy BASH wizardry like:
- name: Prettier
id: prettier
run: |
./node_modules/.bin/prettier --check 2>&1 | tee prettier-report.txt
echo "RESULTS<<EOF" >> $GITHUB_ENV
echo -e "$(cat prettier-report.txt)" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
Each job step emits an object that contains user-designated outputs
(which have their own issues, see #7), the outcome
of the commands that were run — whether they were successful or not, and the conclusion
of the step — whether it was successful or not. And...that's it.
Why not include the actual output of what was run on the step
object, too, instead of making me go through all that boilerplate each time I need to capture it?
GitHub could also add other useful metadata to the step
object, such as the duration and time started and finished. These data are available from the GitHub API and gh
CLI, so why not in the workflows themselves?
7. Create an easier way of exporting multiline strings
This jumble right here is how you export a multiline string in GitHub Actions:
echo "RESULTS<<EOF" >> $GITHUB_ENV
echo -e "$(cat my_file.txt)" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
You can't use outputs
because for some inexplicable reason they're single-line only. (You don't want to know how many failed runs I went through before I figured that out.)
You have to use a global environment variable that gets passed to every job in the workflow. Oh, and be careful that what you've echoed to $GITHUB_ENV
isn't too many lines, because it may crash your other jobs with an environment variable is too long
error. Super-helpful, right?
Say it with me one more time: There has to be a better way. Maybe it's...
8. Add another variable layer that is neither secrets nor environment variables
Not everything is a secret that needs to be concealed in the logs. And not everything is an environment variable that needs to be exposed to the whole job container. Sometimes you just need a place to jam some text and a way to get it back later. And that text isn't always gonna be one short, convenient string. There needs to be somewhere other than outputs
and environment variables that developers can temporarily stick stuff for our workflows. So how about adding some other kind of object that can actually handle things like multiline strings and, gasp, JSON objects gracefully? (And don't you dare say "Use Upload Artifacts.")
9. Change the status indicator to a warning symbol when continue_on_error
is enabled and a step fails
As mentioned previously, each job step emits an object that contains the outcome
of the commands that were run — whether they were successful or not, and the conclusion
of the step – whether it was successful or not. The distinction is important.
You can continue a job where the outcome
of a step is failure
by adding a continue_on_error
flag to the step. The step will then succeed even if the command it ran failed.
Sometimes this is useful if you want to, for example, upload test reports before terminating a job. To make the job fail after you complete your final steps, you have to create a validation step at the very end that checks whether the outcome
on the actual test was success
or failure
and then emits an exit code of 0
or 1
.
This is fine if you're only validating one test. But if you're validating multiple tests, you need to evaluate multiple steps' outcome
to determine the status of the job. Suddenly it becomes more difficult to quickly identify which test failed because there's a big green check next to all the tests, but only one red X at the very end.
What GitHub can do here is change it so that if the conclusion
is success
but the outcome
of a step is failure
, the symbol is a yellow warning sign (⚠️) rather than a green checkmark. That way, you'll quickly know which test in the group failed.
10. Better log management
One of the most painful aspects of working with GitHub Actions is reviewing the logs of jobs with a ton of output. Sometimes it's not even worth trying on the website and I go right to the gh
CLI. It's just arduously slow and buggy. Sometimes you'll just see thousands of blank lines and have to refresh the page several times before you see anything.
GitHub can address this in a number of ways. One is by sticking the logs in a scrollable window, truncating them, and tailing only the most recent output, making the previous lines available if you scroll up in the log window. They could also offer the option of showing stdout
, stderr
, or both for each step, so that you can control what gets output to the screen.
Bonus: Notify users on Slack
There are several GitHub Actions you can add to your workflows to send notifications to a Slack channel. But not everybody on your team needs to know about every workflow run and there's presently no way to notify individual users directly of the outcomes of the checks on their own P.R.s. Part of this is simply the limitations of Slack's webhooks integration which is channel restricted. But GitHub itself could partner with Slack to develop an integration that allows organizations to connect their Slack workspaces to GitHub and that ties users' identities on GitHub to their identities on Slack. This way, you could create notifications that target individual users on Slack, instead of whole channels.
As you can see, GitHub Actions offers a great deal of functionality and flexibility to developers. But there's always room for improvement, and in the areas I note, those improvements are sorely needed.
If you have any ideas for ways GitHub Actions could be better, please suggest them below. And if you know anyone on the product team at GitHub whose eyes you can get this article in front of, please do!
Posted on February 9, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.