Recently Chris Bui put together an interesting look at GitHub Actions Limitations and Gotchas, and I thought it was an interesting take and taught me several things that I didn't already know about how the GitHub Actions ecosystem works.
Now - I'm incredibly biased. I work for GitLab, and I've been a massive fan of GitLab CI/CD long before I even worked there. So my thoughts are 100% colored with that background. Now - I also love a lot of things about GitHub Actions. I especially think the approach they took is interesting - making "Actions" and NOT "GitHub CI/CD." This approach has some benefits - it means that the actions you can take with Actions aren't limited to code commits. They can interact with pull requests, issues, and a lot of other parts of the system.
However, one key thing that concerns me about the way Actions works...and comes up in Chris's article in many different ways. Using community-supported and third-party "actions" reminds me too much of my scary days managing a Jenkins environment for various diverse teams. While a plugin or existing action might get you started quickly - in the long run, not knowing exactly what that code is doing or relying on third parties to keep it safe isn't sustainable. You end up with vulnerable code, broken builds, and a lot of pain. That's why I'm more of a fan of convention over configuration and a DevOps Platform that integrates everything directly - and the parts that are truly unique to me are parts I control.
So with that bit of bias for GitLab out of the way... let's dive into even more prejudice: What features that Chris mentions are available in GitLab? Let's look at each of Chris's concerns one by one and talk about how they are (or are not) solved with GitLab.
The two categories Chris buckets the concerns into are: Gotchas with Actions on GitHub Enterprise Server and General Limitations. Let's examine both.
This is surprising to learn. Caching is one of the most critical parts of making your CI jobs as efficient as possible - anyone who has programmed in Node.js or Java can attest to the desire to cache the node_modules or .m2 folders. More on how we avoid this kind of feature disparity in my answer to the next concern...
This is one place where GitLab has a clear advantage - we ship the same code to our hosted GitLab.com version that we ship to self-managed customers. This was a tough decision and continues to be tough to stick to as we scale both parts of the business. But our customers rely heavily on hosting their own DevOps Platform, and it has been critical in making sure features are available on GitLab.com and self-managed. We've seen other large developer tools companies struggle with this, and I hope that GitHub figures out a better way to do feature parity.
As I said earlier, I think the use of "plugins" should be avoided as much as possible. In this light, you might say that this concern is a symptom of the more significant problem. But it is also odd to me that you have to do this kind of "syncing" between environments.
Okay, so this is a problem for anyone using public Docker images to run their builds inside. And both Actions and GitLab CI/CD make building inside Docker containers that go away at the end of the job an essential feature...and that's a good thing. We've seen many supply chain attacks against "pet" CI/CD servers, and I can't tell you how painful it is to inherit one of these servers.
Now, if you're on board with building inside containers, you need a solution for the Dockerhub rate-limited, as Chris mentions. That's why the GitLab DevOps Platform ships with a container registry that can cache docker images to reduce calls out of your CI/CD infrastructure. In fact, you could probably use the GitLab container registry as the source registry for your GitHub Actions images if you wanted 😄.
Well - GitLab doesn't have this either. We do have the ability to pre-fill variables for manual jobs which can help but not dropdowns.
The most significant difference I can draw here is - GitLab is open-core. So if this were the one thing holding a team back from all the other benefits of switching off Jenkins to GitHub Actions or GitLab CI/CD, they would be able to contribute it to GitLab. In contrast, for GitHub, they'd have to wait for the product/engineering team there to prioritize it.
I'm not sure if I follow why default labels are a problem for self-hosted runners. Still, I do know that managing runner labels is critical, and that is something we've put a lot of thought into at GitLab - and there is a lot of advanced configuration to help system administrators ensure that the proper runner gets the right job every time.
This seems like an odd choice to me. In GitLab CI/CD, you can retry any single job or the pipeline as a whole. I guess there could be an argument to be made that sometimes you'd want the whole pipeline to run...but for advanced users who understand and have tuned their pipelines, this seems like a key missing feature.
I haven't experienced this myself with GitHub Actions - but I also haven't run it in a large environment. Having no personal experience, I can only guess that the API may be overwhelmed by inbound from many runners? GitLab's logs scale horizontally reasonably well, including independently scale the API nodes from the frontend application nodes. This kind of self-managed flexibility is critical for many of our large customers.
Oh, and you can also connect directly to a terminal on the runner from the UI 😉
Okay, this seems to be pretty basic. GitLab CI/CD has a lot of options for this, including the includes keyword to create composite pipelines from various pieces, extends to reuse code and leave your YAML DRY, the ability to trigger downstream jobs and also child/parent pipeline relationships.
I'd expect GitHub Actions to mature and grown into some of these use cases eventually - but it's been a long journey to balance usability with flexibility.
This would be a deal-breaker for many customers I know who run DevOps Platforms at large organizations. The ability to understand what's going on with a fleet of runners, the job queue, etc., is critical to making sure users are getting what they need. The GitLab Runner has Prometheus embedded, and it's what we use to create the dashboards our team uses to manage GitLab.com.
This one is tough because I've learned to stop worrying and love the YAML...but I get why many people don't. I will say that YAML syntax can be incredibly hard to get right - balancing flexibility and readability. And it's something our Product and Engineering teams are thinking about all of the time. And our documentation team takes very seriously making the docs on our YAML syntax usable.
I started this blog saying I was biased, and I mean it! I'd love to hear about what I got wrong...you can join the comment section below or yell talk to me on Twitter. And I hope someone writes the OPPOSITE of this article - what are the things available in GitHub Actions that you can't do with GitLab CI/CD?? Be sure to tag me in it when you write it!