← Back to context

Comment by woodruffw

8 hours ago

I think this post accurately isolates the single main issue with GitHub Actions, i.e. the lack of a tight feedback loop. Pushing and waiting for completion on what's often a very simple failure mode is frustrating.

Others have pointed out that there are architectural steps you can take to minimize this pain, like keeping all CI operations isolated within scripts that can be run locally (and treating GitHub Actions features purely as progressive enhancements, e.g. only using `GITHUB_STEP_SUMMARY` if actually present).

Another thing that works pretty well to address the feedback loop pain is `workflow_dispatch` + `gh workflow run`: you still need to go through a push cycle, but `gh workflow run` lets you stay in development flow until you actually need to go look at the logs.

(One frustrating limitation with that is that `gh workflow run` doesn't actually spit out the URL of the workflow run it triggers. GitHub claims this is because it's an async dispatch, but I don't see how there can possibly be no context for GitHub to provide here, given that they clearly obtain it later in the web UI.)

I've standardized on getting github actions to create/pull a docker image and run build/test inside that. So if something goes wrong I have a decent live debug environment that's very similar to what github actions is running. For what it's worth.

  • I just use the fact that any action run can trigger a webhook.

    The action does nothing other than trigger the hook.

    Then my server catches the hook and can do whatever I want.

    • I wish I had the courage to run my own CI server. But yes, I think your approach is the best for serious teams that can manage more infrastructure.

  • I do the same with Nix as it works for macOS builds as well

    It has the massive benefit of solving the lock-in problem. Your workflow is generally very short so it is easy to move to an alternative CI if (for example) Github were to jack up their prices for self hosted runners...

    That said, when using it in this way I personally love Github actions

    • Nix is so nice that you can put almost your entire workflow into a check or package. Like your code-coverage report step(s) become a package that you build (I'm not brave enough to do this)

      I run my own jenkins for personal stuff on top of nixos, all jobs run inside devenv shell, devenv handles whatever background services required (i.e. database), /nix/store is shared between workers + attic cache in local network.

      Oh, and there is also nixosModule that is tested in the VM that also smoke tests the service.

      First build might take some time, but all future jobs run fast. The same can be done on GHA, but on github-hosted runners you can't get shared /nix/store.

    • same here. though, i think bazel is better for DAGs. i wish i could use it for my personal project (in conjunction with, and bootstrapped with nix), but that's a pretty serious tooling investment that I just feel is just going to be a rabbit hole.

  • I was doing something similar when moving from Earthly. But I have since moved to Nix to manage the environment. It is a lot better of a developer experience and faster! I would checkout an environment manager like Nix/Mise etc so you can have the same tools etc locally and on CI.

  • I tend to have most of my workflows setup as scripts that can run locally in a _scripts diorectory, I've also started to lean on Deno if I need anything more complex than I'm comfortable with in bash (even bash in windows) or powershell, since it executes .ts directly and can refer directly to modules/repos without a separate install step.

    This may also leverage docker (compose) to build/run different services depending on the stage of action. Sometimes also creating "builder" containers that will have a mount point for src and output to build and output the project in different OSes, etc. Docker + QEMU allows for some nice cross-compile options.

    The less I rely on Github Actions environment the happier I am... the main points of use are checkout, deno runtime, release please and uploading assets in a release.

    It sucks that the process is less connected and slow, but ensuring as much as reasonable can run locally goes a very long way.

  • Yeah, images seem to work very well as an abstraction layer for most CI/CD users. It's kind of unfortunate that they don't (can't) fully generalize across Windows and macOS runners as well, though, since in practice that's where a lot of people start to get snagged by needing to do things in GitHub Actions versus using GitHub Actions as an execution layer.

  • Me, too, though getting the trusted publisher NPM settings working didn't help with this. But it does help with most other CI issues.

    • Most of the npm modules I've built are fortunately pretty much just feature complete... I haven't had to deal with that in a while...

      I do have plans to create a couple libraries in the near future so will have to work through the pain(s)... also wanting to publish to jsr for it.

It's insane to me that being able to run CI steps locally is not the first priority of every CI system. It ought to be a basic requirement.

  • I've often thought about this. There are times I would rather have CI run locally, and use my PGP signature to add a git note to the commit. Something like:

    ``` echo "CI passed" | gpg2 --clearsign --output=- | git notes add -F- ```

    Then CI could check git notes and check the dev signature, and skip the workflow/pipeline if correctly signed. With more local CI, the incentive may shift to buying devs fancier machines instead of spending that money on cloud CI. I bet most devs have extra cores to spare and would not mind having a beefier dev machine.

I’ve contemplated building my own CI tool (with a local runner) and the thing is if you assume “write a pipeline that runs locally but also on push”, then the feature depth is mostly about queuing, analyzing output, and often left off, but IMO important, charting telemetry about the build history.

Most of these are off the shelf, at least in some programming languages. It’s the integrations and the overmanagement where a lot of the weight is.

I've never used gh workflow run, but I have used the GitHub API to run workflows and wanted to show the URL. I had to have it make another call to get the workflow runs and assume the last run is the one with the correct URL. This would obviously not work correctly if there were multiple run requests at the same time. Maybe some more checking could detect that, but it works for my purposes so far.

  • Does the metadata in the further call not identify the branch/start time/some other useful info that could help disambiguate this? (honest question)

This is one of the big problems we solved with the RWX CI platform (RWX.com). You can use ‘rwx run’ and it automatically syncs your local changes, so no need to push — and with our automated caching, steps like setting up the environment cache hit so you don’t have to execute the same stuff over and over again while writing your workflow. Plus with our API or MCP server you can get the results directly in your terminal so no need to open the UI at all unless you want to do some in-depth spelunking.

But very often the CI operations _are_ the problem. It's just YAML files with unlimited configuration options that have very limited documentation, without any type of LSP.

> i.e. the lack of a tight feedback loop.

Lefthook helps a lot https://anttiharju.dev/a/1#pre-commit-hooks-are-useful

Thing is that people are not willing to invest in it due to bad experiences with various git hooks, but there are ways to have it be excellent

  • Yeah, I'm one of those people who seems to consistently have middling-to-bad experiences with Git hooks (and Git hook managers). I think the bigger issue is that even with consistent developer tooling between both developer machines and CI, you still have the issue where CI needs to do a lot more stuff that local machines just can't/won't do (like matrix builds).

    Those things are fundamentally remote and kind of annoying to debug, but GitHub could invest a lot more in reducing the frustration involved in getting a fast remote cycle set up.

    • GitHub could invest a lot more in actions for sure. Even just in basic stuff like actions/checkout@v6 being broken for self-hosted runners.

We need SSH access to the failed instances so we can poke around and iterate from any step in the workflow.

Production runs should be immutable, but we should be able to get in to diagnose, edit, and retry. It'd lead to faster diagnosis, resolution, and fixing.

The logs and everything should be there for us.

And speaking of the logs situation, the GHA logs are really buggy sometimes. They don't load about half of the time I need them to.

I’ve never used Nix and frankly am a sceptic, but can it solve this problem by efficiently caching steps?