Running custom code before and after the merge for continuous deployment (or other uses)

#1

Hi all,

I’ve been looking for a way to automate a continuous-deployment workflow:

  1. PR is approved.
  2. Automation bumps version number, does appropriate fiddling with release notes. And while we’re at it, let’s do other boring house-keeping like running a code auto-formatter.
  3. We test the new version (b/c of course you have to test after making these changes)
  4. If the test passes, merge to master
  5. If the test passes, upload the release artifacts to your favorite repository

This isn’t exactly what bors is intended to do, but (a) what bors is intended to do is also awesome, and it would be nice to have continuous deployment and not-rocket-science at the same time, (b) it occurs to me that there’s significant overlap between this workflow and what bors already does – in particular, the continuous deployment bot has to force all PR merges to be processed in sequential order so it can assign version numbers, and if you have a heavy merge load then you probably want to roll up multiple changes together into a single release. (Also, some people hack together something like this by using CI tools like Travis, but I need a separate bot b/c not everyone with write permissions on my repo should have access to the release secrets.)

AFAICT, bors can’t handle this currently. My question: do you think that could change – maybe be specifying some code to run before and after merging? Or any other ideas for how to do this?

1 Like

#2

Hi there,

I agree with you that being able to tie an auto-formatter into your merge bot sounds like a good idea, since there isn’t really a good way to handle that other than baking it in like that (the alternatives all involve rejecting pull requests based on formating, which is annoying). I’d like a more detailed RFC, though, since this is going to have some more complex requirements.

For example, we’ll probably want to at least support running the formatter and the bot on separate machines:

  • For cost reasons, the public instance can’t just download the source code and run the formatter locally.

  • On a similar note, if your code locks up, then we need a timeout and a way to reliably kill it and all of its sub processes. Or if it starts eating infinite disk space, or infinite RAM, we want to cut it off with a quota instead of letting it wreck bors.

It gets hairy. Which isn’t a reason not to do it, but it is a good reason to discuss and experiment in a fork before we make it available to all of bors’s users and trying to keep it from breaking.

0 Likes

#3

Did you think of doing that step as a PR? Then it could go through the usual bors process.

0 Likes

#4

The point is that I want to do this on every PR.

Yeah, possibly I should have led with that, because there are probably more projects that want auto-formatting than are ready to dive into continuous deployment :-).

Sure, if it looks like this makes sense then I have no problem writing RFCs. First I want to figure out if it makes sense :slight_smile:

While supporting this on the public instance would definitely be ideal, my best alternative is to write and host my own thing from scratch. So if it initially required me to host a private bors-ng instance, I could live with that :slight_smile:

I wonder if we could somehow leverage a “run arbitrary dev code as a service” service like Github Actions or Azure Pipelines, or even something like a function-as-a-service platform. [insert pause for googling] Huh, Lambda’s free tier includes a million invocations/month. I probably don’t need that many version bumps.

So this is almost too trivial, but, here’s a straw man proposal: suppose we add options to bors.toml to set a pre-check hook and a post-merge hook. These are URLs. The semantics are:

After creating a temporary branch to test, but before CI runs on it, bors sends a POST to the pre-check hook; payload is JSON that includes information on the branch location (at least). [Uh, I’m assuming that bors-ng works by creating a temp branch in the main repo with the contents of the PR, waiting for CI to run, and then checking the statuses on this branch. If that’s wrong this may not make sense.]

After a temporary branch has passed muster and been merged into master, bors sends a POST to the post-merge hook, with details on which branch and commit were just merged (at least).

Whenever bors POSTs to a hook, it always blocks until it gets a response. This means the pre-check hook can freely mutate the branch, and bors will only continue after it’s done. The post-merge hook can safely upload release artifacts to a central repository, without having to worry about racing with another merge branch that’s trying to upload a different version.

If a hook returns an error status (4xx/5xx), or times out, bors treats it like a CI failure (fails out, reports in the PR thread, etc.). (Hmm, maybe the “post-merge” hook should actually run just before merging into master, so failures have a chance to block merging?)

1 Like

#5

@notriddle Should I interpret your :heart: as “that sounds great, you should [write an RFC, open an issue, something like that]”?

0 Likes

#6

Yeah, that’s exactly what it means.

0 Likes