Maintaining several projects' shell.nix files in one repo

I’ve added shell.nix and some support files to a few projects at work. It’s been very beneficial having these files under version control, and nice to see other team members getting use out of them.

I’d like centralize these files in a separate repository, so instead of keeping a project’s shell.nix version-controlled within the project itself, the project would have a small setup script that locates the appropriate shell.nix file and fetches it. Though shell.nix would be gitignored in the project that uses it, the central repo of shell.nix files would track the version of each shell using git tags.

To flesh the idea out a bit, I’m picturing a workflow like:

  • foo 1.0.0 is released
  • I write shells/foo/shell.nix and shells/foo/init
  • I commit the above files to the central repo and tag the commit foo-1.0.0
  • foo 1.0.1 is released
  • a PR in the central repo is automatically created updating the version field in shells/foo/shell.nix
  • CI tests/builds the shell
  • When the PR is merged, the merge commit is tagged foo-1.0.1

As a developer with a fresh checkout of project foo, I run foo/bin/nix-init, which does the following:

  • search the central repo’s tags for foo-x.y.z, where x.y.z is the version of foo I’ve checked out
  • clone central repo, at found tag, to a temporary location
  • run something like central-repo/init foo, which runs central-repo/shells/foo/init, which in turn knows what kind of foo-specific setup steps are necessary

It would be nice if I could add some automated tests. I’m looking at bats at the moment. I actually like the idea of writing tests in the Nix expression language, but I don’t know if that’s feasible.

A fair amount of this in still only vaguely defined (e.g. what to do when no up-to-date tag is found), but I thought I’d put it out there. I know there’s been discussion of similar ideas here, though what I’m considering is more focused on sharing development environments within a small organization than building out a broader network.

1 Like

I do this with my templates for shells. For example i have templates for haskell, c, and c++. In my project my shell.nix is just an import where i can pass in extra dependencies or otherwise useful parameters to plug into my template thats stored next to all my other nix config files.
Our purposes are slightly different but the implementation sounds very similar.
You can use fetchFromGitHub Rather than import to accomplish your goal.

Good point! I somehow overlooked using import or fetchFromGitHub or fetchTarball for this. I think that would be simpler than using custom init scripts. I’ll try your approach first.

I wrote unit tests for one of the more complex shell.nix environments I have. It covers simple things like whether the expected utilities are present and more complex things like whether a standalone postgres server gets spun up in the background upon entering the shell and shutdown upon leaving the shell.

I’ve never written unit tests for shell scripts before, it’s been more interesting (and less difficult) than I anticipated, and so far I’m really impressed with the bats project, which just happens to be available in nixpkgs as well.