Set a global timeout for your jobs. Seriously. Think you don't need one? You're wrong. Set a global timeout for your jobs. Whoever pays that bill will thank you later. Private actions don't give a damn if `setup-node` is taking a whole hour to install Node. They don't care if your hosting service is having trouble and runs a deployment for 5 hours. You will be billed for that, and it adds up. Set a global timeout for your jobs.
If you want to run github actions locally before any pitfalls, you can try out<p><a href="https://github.com/nektos/act" rel="nofollow">https://github.com/nektos/act</a>
I believe pull request from forks are not triggered by default because some people where using this to mine cryptocrap on cpu using the quotas of other projects.
The UI for seeing logs is driving me insaaaane.
It's extremely slow and sluggish. Sometimes you have to refresh the page to see the actual latest line of the log.
A few other pitfalls:<p>* Scheduled actions basically never run anywhere close to on schedule. If you schedule something to run every 13 minutes, it may just run 1-3 times an hour with random 30 minute to 1 hour waits in between executions.<p>* Triggering a workflow as a result of an action from another workflow doesn't work if you're using the GITHUB_TOKEN as part of the action. Github does this to prevent accidental recursion, but it forces you to either use insecure PATs or rearchitect how to handle chained events: <a href="https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow" rel="nofollow">https://docs.github.com/en/actions/using-workflows/triggerin...</a>
The biggest pitfall I see is people inadvertently making them "smart" which causes massive headaches when debugging them.<p>As much intelligence as possible ought to be pushed down to and tested and debugged on the script level so that you're left with little more than a linear sequence of 4-5 commands in your YAML.<p>The debugging tooling on github actions is, frankly, abysmal. You need a third party ngrok action to even run ssh.
Dear GitHub actions. I want &pointers so I don’t have to repeat myself.<p>Also, I like that you build the hypothetical merge of branch + main. But that commit SHA is gone after that successful build. Give me a way to track this. I need to store artifacts related to this build, as I don’t want to build those again!
Also a fun one is the "on" key that specifies when the workflow should run. "on" is magic in yaml, and some implementations will convert it to the string (!) "True" when it occurs as a key (I'm not talking about values here). This was a bit confusing when I tried to replace a hand-written yaml with a generated json ... They were identical, except for the on/True key. It's still not clear to me whether this is according to yaml spec or not, but in any case a json "on" key does work ... So I wonder, does GitHub Actions internally look for both "on" and "True"?
The twice run workflow from "Push for all?" definitely happened to me, too. The others not so much.<p>In New projects I tend to use scripts to perform any required task for the ci and have github actions only run the script. Way easier to reason about.<p>Gitlab CI definitely handles this better with it "script" concept.
I've used Github Actions at work for the past year and I'm a fan overall. The clearest sign of this is my feedback for improvement is almost entirely about missing features instead of broken ones. For examples, it'd be nice:<p>1. for Github to natively allow CI management for several repos in a centralized way, so repo setup can just be "select this CI config" instead of "copy this YAML file and change the project name in some places"<p>2. to mandate certain CI steps at the organization level (such as running `black`) so it isn't opt-in
The most annoying thing for me is that a workflow_dispatch only workflow can't be launch manually until it's push into default branch as they are not listed. I can understand the Web-UI won't list them but even GitHub cli can't launch them. Once they appear in the default branch, only then you are free to launch them on any branch.
Another pitfall I have encountered is the lack of a true ephemeral agent runner solution for running the actions runner agent in your own infrastructure. The way it works (the last time I checked) is when you register a worker as "ephemeral: true" it automatically deregisters itself from your runner pool and kills the agent process when a job is completed, but it is up to you to clean things up. This leads to somewhat hacky scripts to delete the compute instance after the agent process exits. There is also no officially supported kubernetes controller for creating ephemeral agents but the community created one [1] is often mistaken as an official github project.<p>- [1] <a href="https://github.com/actions-runner-controller/actions-runner-controller" rel="nofollow">https://github.com/actions-runner-controller/actions-runner-...</a>
Their self-hosted runners are pretty jank. If your workflow writes something to the docker container's user's home directory, you will see it in the next workflow you run. Due to this and other things, I need a "preamble" action that needs to run right after checkout. Oh, if don't checkout at the beginning of your workflow, you will be using the previous workflow's copy of the repository.<p>I'm 100% sure they don't use this internally as these are glaring issues that impacts anyone using the self hosted runner. They also recommend running the container as root[1] instead of designing something more secure and sane.<p>1: <a href="https://github.com/actions/runner/issues/434#issuecomment-615378062" rel="nofollow">https://github.com/actions/runner/issues/434#issuecomment-61...</a>
There’s an awkward gotcha/incompatibility between “Required status checks” and workflows that get skipped [1], eg due to setting a “paths” property of a push/pull_request workflow trigger [2].<p>The checks associated with the workflow don’t run and stay in a pending state, preventing the PR from being merged.<p>The only workaround I’m aware of is to use an action such as paths-filter [3] instead at the job level.<p>A further, related frustration/limitation - you can _only_ set the “paths” property [2] at the workflow level (i.e. not per-job), so those rules apply to all jobs in the workflow. Given that you can only build a DAG of jobs (ie “needs”) within a single workflow, it makes it quite difficult to do anything non trivial in a monorepo.<p>[1]: <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks" rel="nofollow">https://docs.github.com/en/repositories/configuring-branches...</a><p>[2]: <a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore" rel="nofollow">https://docs.github.com/en/actions/using-workflows/workflow-...</a><p>[3]: <a href="https://github.com/dorny/paths-filter" rel="nofollow">https://github.com/dorny/paths-filter</a>
We recently converted all our projects to Github Actions, and while it really brings a lot of convenience it also feels to me like a very brittle solution with lots of gotchas and messy API surfaces.<p>Of course, the nature of running various commands on virtual machines and shells is inherently messy, but GHA could have done a lot to hide that. Instead I feel like I'm forced mix YAML, bash, Powershell and various higher-level scripting languages (that came with the projects) in an unholy concoction that is hard to get right (return codes, passing values and escaping directly comes to mind) and that is even harder to debug, due to the nature of running somewhere else (act helps, a little, but it doesn't properly replicate the GHA environment).<p>I kind of wished I could write all my workflows cross-platform from start with some well known but fullfledged scripting language. (Which of course I could, and just use GHA to call that script). What options are out there to make this whole thing less brittle?
Another surprise: "ubuntu-latest" is not the latest ubuntu! It is stuck at 20.04. If you want 22.04 you need to specify "ubuntu-22.04". Similar issue with macos-latest.
> The problem is that exec does not return a non-zero return code if the command fails. Instead, it returns a rejected promise.<p>> While this behavior can be changed by passing ignoreReturnCode as the third argument ExecOptions, the default behavior is very surprising.<p>This is the same behavior as node's child process exec when wrapped by util.promisify[1] If something returns a promise (async func) it should be expected that it has the possibility of being rejected.<p>[1] <a href="https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback" rel="nofollow">https://nodejs.org/api/child_process.html#child_processexecc...</a>
The first pitfall can be statically detected with actionlint<p><a href="https://github.com/rhysd/actionlint" rel="nofollow">https://github.com/rhysd/actionlint</a><p>> oops.yaml:20:24: property "jobone" is not defined in object type {jobtwo: {outputs: {}; result: string}} [expression]
Another pitfall I ran into recently with a workflow I've been working on [1]: Checks and CI that are made with GitHub Actions are reported to the new Checks API, while some (all?) external services report to their old Statuses API. This makes it needlessly difficult to ascertain whether a PR/branch is "green" or not. They finally decided to create a "statusRollUp" that combines the state of the two APIs, but it's not available in their REST api, only their GraphQL API.<p>[1] <a href="https://github.com/hrvey/combine-prs-workflow/" rel="nofollow">https://github.com/hrvey/combine-prs-workflow/</a>
Docker request limits are kind of a pain to deal with in Github Actions. This recently bit us, and no amount of logging into a _paid_ docker account would rectify the problem.<p>As it turns out, images are pulled at the start of the run, which means your docker login will have no effect if you're currently bumping into these pull limits. This is made worse by the fact that the images themselves are controlled in the remote actions you're using, not something in your own codebase.<p>So you're left with either: forking the action and controlling it yourself, or hoping the maintainer will push to the Github registry.
I generally like Actions but occasionally run into limitations (possibly my own).<p>For example, I'd like to build an action that triggers a documentation update based on the path and filename that is changed.<p><pre><code> on:
push:
branches:
- main
paths:
- */README.md
</code></pre>
But there does not appear to be a way to pass a list of changed paths to the job.
We have a new integration at Cronitor to fully monitor your GitHub actions - works with both hosted and self-hosted runners. This is in beta right now. If anybody would like to check it out, let me know, Shane at cronitor