Some jobs purposefully only run on certain base or head branches. By
centralizing the logic, parts of it can easily be re-used later. Also,
this gives them an explicit name and thus makes them easier to
understand.
Instead of deleting each label separately and then making another call
to add new labels, this replaces all labels at once, thus saving API
calls in some cases. Also, the labels are now managed in object-style
compared to the array-style before. This allows putting all the
knowledge about each label into a single place instead of in multiple
places. For example, the rebuild labels had to be special cased in the
workflow before - and the nix code to compare had to match that. Also,
the approval labels had to be considered in the `before` and `after`
phases.
The next commit shows how easy it is to add a new label now.
When we made the switch from eval.yml to pr.yml we adjusted the labels
job as well - but didn't take into account that we also need to deal
with old PRs at the same time.
Here, we fallback to another API request to get a run for eval.yml when
we can't find one for pr.yml.
When labels.yml is changed the new code is not tested in the PR
directly, yet, because we forgot to add labels.yml to the list of
pull_request files in pr.yml. This lead to one syntax error merged
already.
First data shows, that we're unlikely to need more than 250 within an
hour of regular activity. Once this is empty, we'll need to wait until
the next hourly refill - thus, we'll rather set this a bit higher to be
on the safe side.
The hourly limit is at 5000 and we peaked around 3500, so far. We'll
certainly have to look into reducing API calls, but this should still
work out for now.
When we switched to a scheduled workflow, we also changed these lines to
take the labels directly from the pull request list we iterate over. At
the time it saved us an API request. Meanwhile, we have introduced
throttling to the workflow and this causes a potential race condition:
When the scheduled or manually triggered workflow is kicked off and
empties its reservoir of API requests it might be blocked to wait up
to.. an hour! If this happens, the labels taken from the pull request
list might already be outdated at the time the workflow continues. This
would cause some labels to be reset to their original state, which could
be wrong if, for example, another push has happened in the meantime.
This will have a much bigger impact after the next commit, where *all*
labels are set every time, thus the `before` part must be accurate.
Fetching the current labels right before managing them reduces this risk
significantly.
This can only happen if the target branch's eval run failed and we're
trying to fix it. In this case, Eval should not fail, even though it
might not be able to do a comparison and add the correct rebuild labels.
But if we failed here, we wouldn't be able to merge the fix once we have
required status checks.
This allows *not* depending on those two jobs with the required status
checks in the next commit, which wouldn't really make sense. If labeling
or pinging maintainers fails for obscure reasons or because the GitHub
API is down, a PR might still pass all other tests and be
merge-eligible.
This fixes a problem where each workflow would get their own merge
commit. This happens frequently when the target branch is merged into a
the same time, different workflows in the same run will run
get-merge-commit at different times and thus have different merge
commits.
Since the jobs don't really depend on each other, this doesn't cause
practical problems, yet. But it has already led to strange CI failures
in a still unmerged PR, which can be prevented from happening with this
clean approach.
And yes, this saves a few API calls on every run.
When the job is run with the pull_request trigger for validation of
changes to the workflow itself, we need to run everything that can be
run without privileges - but not more.
We tried to do so for the three actions/labeler steps, but failed to set
up the condition correctly. We also need to exit early for our
JavaScript based labeler, just before making the mutation requests.
The overall idea is to use names short enough to fit into the status
checks list without shortening. This change mostly happened in the
commits before, here we just follow the same pattern for the remaining
workflows.
We previously moved this out of the main eval workflow to avoid running
it on push and/or undrafting the PR. The latter has been removed in the
meantime and the former can be checked with a simple condition. Thus we
move it back in, to make it part of the 4 main workflows, which will be
required before merge eventually.
Those two workflows bundle all the main jobs in two event-specific
wrapper workflows. This enables us to do two things later on:
- Synchronize the merge commits between most of the jobs run in a PR.
- Create a single "required" job to be targeted by GitHub's "required
status checks to pass" feature.
This can still be manually dispatched for testing in forks, but it's
entirely useless to keep running it on schedule.
Also removing the "skip treewide" condition, which was a left-over and
removed everywhere else already. We don't want to skip any jobs,
especially not when considering required status checks.
Due to a type mismatch, maintainer approvals were never counted as such.
The API returns integers for the user IDs, but the JSON file has strings
as object keys.
We don't need to handle the differently named artifacts in a special
way, because they have been expired anyway. But, we must handle the case
to not cause the job to fail.
Instead of relying on workflow_run events, we now trigger the labeling
workflow by schedule. This avoids all permission/secrets problems of
running in the pull_request_review context - and also gets rid of the
"waiting for approval to run workflows" button for new contributors that
sometimes comes up right now.
Also, it's more efficient. Previously, the labeling workflow would run
on *any* pull_request_review event, which happens for all comments, too.
So quite a few runs.
This will cause a delay of up to 1 hour with the current settings until
approval labels are set. Depending on how long the job normally runs we
can adjust the frequency. The workflow is written in a way that will
work no matter what the frequency ends up being, even when it's
interrupted by transient GHA failures: It will always look at all PRs
which were updated since the last time the workflow ran successfully.
We also add the ability to run it manually via UI. This is useful:
- When fixing bugs in the labeler workflow to run it all the way back to
where the bug was introduced.
- When introducing new labels, to get a head start for a reasonable
amount of PRs immediately.
Of course, the workflow is also still run directly after Eval itself.
This is also the only case that the actions/labeler steps will run,
since they depend on the `pull_request` context.
This currently fails with:
```
Method Set.prototype.has called on incompatible receiver undefined
```
Seems like my syntax test previously only hit the case without
maintainers, in which case it doesn't throw :/.
This didn't work as intended. When a workflow is run with
`workflow_call`, it will have `github.workflow` set to the *parent*
workflow. So the `caller` input that we passed, resulted in this
concurrency key:
```
Eval-Eval-...
```
But that's bad, because the labels and reviewers workflows will cancel
each other!
What we actually want is this:
- Label and Reviewers workflow should have different groups.
- Reviewers called via Eval and called directly via undraft should have
*different* groups.
We can't use the default condition we use everywhere else, because
`github.workflow` is the same for Label and Reviewers. Thus, we hardcode
the workflow's name as well. This essentially means we have this as a
key:
```
<name-of-running-workflow>-<name-of-triggering-workflow>-<name-of-event>-<name-of-head-branch>
```
This should do what we want.
Since workflows can be made reusable workflows later on, we add those
hardcoded names to *all* concurrency groups. This avoids copy&paste
errors later on.
This can happen when two PRs run at the same time, which come from
different forks, but have the same head branch name.
github.head_ref is suggested by GitHub's docs, but.. that's not really
useful for cases with forks.
This introduces "check" as another category of jobs suitable for the
"Require status checks to pass" feature.
Checks as a category would include everything that is done before even
looking at the code: Right branch? Commit messages? Cherry-picked
correctly?
(commit messages are not checked, yet)
This new workflow builds both manuals, the shell and the lib tests all
in a matrix of four jobs. This allows re-using the shared checkout and
the pinned nixpkgs download and saves time in the most likely cache: No
changes, just download from cache. Each step checks the cancelled
condition, which causes it to run even if the previous steps failed.
This way we get a full picture even if the first step fails immediately.
This could later be optimized to build more in parallel as well, but
we'll first need to clear the conditions on building the manuals on the
master branch only.
This reduces the number of jobs from up to 8 to 4 for this part.