GitHub’s enshittification has gotten entirely out of hand. Not only are they so obviously and unethically exfiltrating all of my code into their drain-lake-give-wrong-answer box, but they’re simultaneously forcing the business they’ve illegally built on it down my throat in every part of the UI that still functions, which is becoming fewer and fewer these days.
Along with everyone, I saw this coming since the Microsoft acquisition, but I’ve so far procrastinated on jumping ship. I saw little hope of anyone coming remotely close on functionality without being equally unethical (e.g. GitLab). But I’ve finally tested out Codeberg, and I have renewed hope.
Mastodon & ActivityPub ๐
In case you’re not familiar, it’s worth taking a small detour for the context into which Codeberg fits. Mastodon is an application built on, and the first implementation of, the ActivityPub protocol, which it uses to communicate with other such apps, forming a federated social network known as the Fediverse. It’s where a lot of folks (myself included) jumped as Twitter fell apart.
The mechanics of federation sound heady and weird, but it’s really just like email:
| Fediverse | ||
|---|---|---|
| You configure an application | Outlook, Thunderbird, web interface, etc | Mastodon, Pixelfed, etc |
| To use a hosting provider | Fastmail, Gmail, your own server or laptop, etc | mastodon.social, functional.cafe, your own server or laptop, etc |
| And communicate with anyone using a standardized protocol | SMTP, IMAP, etc | ActivityPub |
| To do the thing you want | Send and receive email | Follow, post, favorite, boost, reply |
The decentralization is a big deal. (And no, Bluesky is not decentralized.1 2) It means there is no corporate owner of the Fediverse. There is no one that can enshittify the experience in pursuit of share-holder profit. No one can buy it and fill it with Nazis. My feed is in chronological order and free of ads. It’s not without it’s problems, but it’s one of the few Good Things happening in internet technology these days.
And it gets better. The ActivityPub protocol is extensible enough to support other kinds of social interactions. Beyond statuses, replies, and likes, ActivityPub could also support federating commit events, Issues, and Pull Requests. If there were a GitHub-like service built on ActivityPub, not only would we see pretty interesting ergonomics (I could presumably “follow” a project repository from Mastodon and see its git activity as statuses in my feed that I could favorite or boost), but I would be confident that anything I build on top of it will last. I can use a hosted solution now, knowing the option to self-host is guaranteed by design.
Gitea, Forgejo, & Codeberg ๐
And this is exactly what Gitea (and others) are doing through the ForgeFed project: a self-hosted Git solution, with GitHub-like features, that supports ActivityPub federation.
Unfortunately, the landscape in this space is a little fragmented. There is Gitea, then there is Forgejo, a fork thereof. Both offer cloud-hosted instances that are free to join (with various restrictions), and there are various other communities running hosted instances you can join too. This is a feature (not a bug) of decentralization. It reminds me of navigating the jump to Mastodon.
Due mostly to popularity and visibility (I only really looked into the history after the fact), I landed on codeberg.org, a hosted Forgejo instance operated by the EU-based non-profit that created it. You might wonder, doesn’t everyone moving to a single popular instance defeat the purpose of decentralization? Yes and no. Yes, it’s a form of centralization, but that’s mitigated by the federated nature of the platform (migration and self-hosting are always guaranteed options). In exchange, we get the benefit of network effects and a smoother off-ramp from GitHub as a way to jump-start mass migration. There was and is much of the same debate around the largest Mastodon instance, mastodon.social, too. The sky hasn’t yet fallen.
I think any of these hosted offerings are worth considering. The basic GitHub functionalities were implemented well in Gitea and inherited by Forgejo and others. For me, the most important feature however is Actions.
Actions ๐
I’ll say it: Actions is good. Really, really good. As someone who designs systems and platforms, I am truly in awe of how well GitHub designed Actions.
The unit of composition, the action, is simple and isolated: a process with
environment variables as input and standard streams as output. It’s downright
Unix. This makes it extensible and easy to author, share, and orchestrate. This
design led directly to an explosion of community-provided actions, and enables
alternative orchestration tools like nektos/act.
This design is why Actions won; not because of vendor-lock-in, but in spite of
its absence. Receive some webhooks, sprinkle a little docker, carefully craft
a GitHub-like ENV, and you’ve got yourself a GitHub Actions Runner. In fact,
GitHub has to continue to provide that flexibility so that it can run the same
actions on GitHub hosted vs enterprise. It has a vested interest in ensuring
actions can run unchanged in any environment that quacks like a GitHub. How
convenient.
Building on act, that’s exactly what Forgejo Actions does.
I love how much Forgejo Actions has leaned into quacking like a GitHub. I
understand the urge to “improve” or “differentiate”, but it’s been so much
better to be able to take workflows and actions that work for GitHub and just
use them. Things I’d never expect to work just do. Things like
caching, artifacts, and
semantic-release, all just worked.3 Forgejo sets all
the same environment variables and its API is very similar to GitHub. I know
they are tweaking things here and there (“familiar, not compatible”) but it’s
felt quite compatible so far.
Self-Hosted Runner ๐
My experience with Forgejo Actions has been so great partly because I went the self-hosted route for that. There are hosted runner options, but I wanted to be able to run workflows without worrying about being a bad neighbor. I also wanted to make things faster and minimize cache eviction by having beefier specs. I can start up a big instance when I’m working, then stop it when I’m done to save cost.
I deployed this setup using Terraform, which means it should be pretty easy for you to replicate. All you need is an AWS account (though I’d love to move to Hetzner eventually). If you’re interested in self-hosting Forgejo Actions, you can find my Terraform module and supporting files here.
Conclusion ๐
I have to admit, I’m not sure what the goal of this post is. Am I convincing you to jump ship from GitHub? To try Codeberg? To self-host your own Forgejo instance? I don’t know, maybe. This post feels more diary and less call-to-action. It’s been so long since I’ve seen a Good Thing happening in technology, I just have to share it.
โ๏ธ
-
https://dustycloud.org/blog/how-decentralized-is-bluesky/ ↩︎
-
To be fair, semantic-release needed a little help. But the bug was fixed quickly. ↩︎