ci: use bisect flake lock workflow
This commit is contained in:
parent
d4776dc2b8
commit
e57c9a1c22
7 changed files with 304 additions and 8 deletions
15
.github/workflows/auto-merge.yaml
vendored
15
.github/workflows/auto-merge.yaml
vendored
|
|
@ -23,7 +23,7 @@ on:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
automerge:
|
automerge-rebase:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: reitermarkus/automerge@v2
|
- uses: reitermarkus/automerge@v2
|
||||||
|
|
@ -35,3 +35,16 @@ jobs:
|
||||||
pull-request: ${{ github.event.inputs.pull-request }}
|
pull-request: ${{ github.event.inputs.pull-request }}
|
||||||
review: ${{ github.event.inputs.review }}
|
review: ${{ github.event.inputs.review }}
|
||||||
dry-run: false
|
dry-run: false
|
||||||
|
|
||||||
|
automerge-merge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: reitermarkus/automerge@v2
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
|
||||||
|
merge-method: merge
|
||||||
|
do-not-merge-labels: never-merge
|
||||||
|
required-labels: automerge-merge
|
||||||
|
pull-request: ${{ github.event.inputs.pull-request }}
|
||||||
|
review: ${{ github.event.inputs.review }}
|
||||||
|
dry-run: false
|
||||||
|
|
|
||||||
24
.github/workflows/lock-update.yaml
vendored
24
.github/workflows/lock-update.yaml
vendored
|
|
@ -1,9 +1,16 @@
|
||||||
|
# See shb.skarabox.com/misc.html
|
||||||
name: Update Flake Lock
|
name: Update Flake Lock
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * *' # runs daily at 00:00
|
- cron: '0 */3 * * *' # runs every 3 hours at :00
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
bisect_future:
|
||||||
|
description: "Bisect in the future instead of the past"
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lockfile:
|
lockfile:
|
||||||
|
|
@ -15,9 +22,12 @@ jobs:
|
||||||
uses: cachix/install-nix-action@v31
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
github_access_token: ${{ secrets.GITHUB_TOKEN }}
|
github_access_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Update flake.lock
|
- name: Cache nixpkgs mirror
|
||||||
uses: DeterminateSystems/update-flake-lock@main
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
|
path: .cache/nixpkgs.git
|
||||||
pr-labels: |
|
key: nixpkgs-mirror-v1
|
||||||
automerge
|
- name: Update flake.lock
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
|
||||||
|
script: nix .#update-flake-lock-pr
|
||||||
|
|
|
||||||
219
.github/workflows/update-flake-lock-pr.nix
vendored
Normal file
219
.github/workflows/update-flake-lock-pr.nix
vendored
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
{
|
||||||
|
gh,
|
||||||
|
writeShellApplication,
|
||||||
|
}:
|
||||||
|
writeShellApplication {
|
||||||
|
name = "update-flake-lock-pr";
|
||||||
|
runtimeInputs = [
|
||||||
|
gh
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
branch=ci/nixpkgs-update
|
||||||
|
if [ "''${GITHUB_EVENT_NAME:-}" = "schedule" ]; then
|
||||||
|
branch=ci/nixpkgs-update-auto
|
||||||
|
fi
|
||||||
|
|
||||||
|
goto_future=no
|
||||||
|
if [ -n "''${1:-}" ]; then
|
||||||
|
goto_future=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
main () {
|
||||||
|
PR=$(get_pr)
|
||||||
|
|
||||||
|
if [ -z "$PR" ]; then
|
||||||
|
create_pr
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$(get_pr_check_status "$PR")" in
|
||||||
|
pending)
|
||||||
|
echo "Checks are running on PR $PR, nothing to do yet."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
succeeded)
|
||||||
|
echo "Checks succeeded, nothing to do."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
failing)
|
||||||
|
echo "Checks failed, updating PR to midpoint commit."
|
||||||
|
|
||||||
|
local CURRENT_COMMIT
|
||||||
|
local LAST_WORKING_COMMIT
|
||||||
|
local FAILING_COMMIT
|
||||||
|
local NEW_COMMIT
|
||||||
|
|
||||||
|
CURRENT_COMMIT="$(get_main_branch_commit)"
|
||||||
|
if [ "$goto_future" = "no" ]; then
|
||||||
|
LAST_WORKING_COMMIT="$CURRENT_COMMIT"
|
||||||
|
FAILING_COMMIT="$(get_pr_commit "$PR")"
|
||||||
|
else
|
||||||
|
LAST_WORKING_COMMIT="$(get_pr_commit "$PR")"
|
||||||
|
FAILING_COMMIT="$(get_latest_nixpkgs_commit)"
|
||||||
|
fi
|
||||||
|
NEW_COMMIT="$(midpoint_commit "$LAST_WORKING_COMMIT" "$FAILING_COMMIT")"
|
||||||
|
|
||||||
|
if [ "$NEW_COMMIT" = "$LAST_WORKING_COMMIT" ] || [ "$NEW_COMMIT" = "$FAILING_COMMIT" ]; then
|
||||||
|
NEW_COMMIT="$(get_latest_nixpkgs_commit)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$NEW_COMMIT" = "$FAILING_COMMIT" ]; then
|
||||||
|
echo "Latest nixpkgs commit is still same failing commit, will retry later."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
update_pr "$PR" "$CURRENT_COMMIT" "$NEW_COMMIT"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
get_main_branch_commit() {
|
||||||
|
git fetch origin main
|
||||||
|
|
||||||
|
git show origin/main:flake.lock \
|
||||||
|
| jq -r '.nodes.nixpkgs.locked.rev'
|
||||||
|
}
|
||||||
|
|
||||||
|
midpoint_commit() {
|
||||||
|
local good="$1"
|
||||||
|
local bad="$2"
|
||||||
|
|
||||||
|
mkdir -p .cache
|
||||||
|
if [ ! -d .cache/nixpkgs.git ]; then
|
||||||
|
git clone --mirror https://github.com/NixOS/nixpkgs.git .cache/nixpkgs.git
|
||||||
|
else
|
||||||
|
git --git-dir=.cache/nixpkgs.git fetch origin
|
||||||
|
fi
|
||||||
|
|
||||||
|
local commits=()
|
||||||
|
|
||||||
|
mapfile -t commits < <(
|
||||||
|
git --git-dir=.cache/nixpkgs.git \
|
||||||
|
rev-list \
|
||||||
|
--reverse \
|
||||||
|
--ancestry-path \
|
||||||
|
"''${good}..''${bad}"
|
||||||
|
)
|
||||||
|
|
||||||
|
local count="''${#commits[@]}"
|
||||||
|
|
||||||
|
if [ "$count" -eq 0 ]; then
|
||||||
|
echo "$bad"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local midpoint_index=$((count / 2))
|
||||||
|
|
||||||
|
echo "''${commits[$midpoint_index]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_latest_nixpkgs_commit () {
|
||||||
|
git ls-remote https://github.com/NixOS/nixpkgs nixos-unstable | cut -f1
|
||||||
|
}
|
||||||
|
|
||||||
|
get_pr () {
|
||||||
|
gh pr list \
|
||||||
|
--head "$branch" \
|
||||||
|
--state open \
|
||||||
|
--json number \
|
||||||
|
--jq '.[0].number // empty'
|
||||||
|
}
|
||||||
|
|
||||||
|
create_pr() {
|
||||||
|
local test_commit
|
||||||
|
|
||||||
|
test_commit="$(get_latest_nixpkgs_commit)"
|
||||||
|
echo "Creating PR on nixpkgs' latest commit $test_commit"
|
||||||
|
|
||||||
|
git checkout -B "$branch"
|
||||||
|
|
||||||
|
nix flake lock \
|
||||||
|
--override-input nixpkgs "github:NixOS/nixpkgs/$test_commit"
|
||||||
|
|
||||||
|
git add flake.lock
|
||||||
|
|
||||||
|
git commit -m "update nixpkgs to $test_commit"
|
||||||
|
|
||||||
|
git push -u origin "$branch" --force
|
||||||
|
|
||||||
|
current_commit="$(get_main_branch_commit)"
|
||||||
|
gh pr create \
|
||||||
|
--title "Update nixpkgs" \
|
||||||
|
--body "$(printf "%s\n\n%s" "Automated nixpkgs update. Latest tries:" " - https://github.com/NixOS/nixpkgs/compare/$current_commit...$test_commit")" \
|
||||||
|
--label automerge-merge
|
||||||
|
}
|
||||||
|
|
||||||
|
append_pr_body() {
|
||||||
|
local pr="$1"
|
||||||
|
local text="$2"
|
||||||
|
|
||||||
|
local current_body
|
||||||
|
|
||||||
|
current_body="$(gh pr view "$pr" --json body --jq .body)"
|
||||||
|
|
||||||
|
gh pr edit "$pr" \
|
||||||
|
--body "$(printf '%s%b' "$current_body" "$text")"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_pr() {
|
||||||
|
local pr="$1"
|
||||||
|
local current_commit="$2"
|
||||||
|
local test_commit="$3"
|
||||||
|
|
||||||
|
echo "Updating PR to nixpkgs' commit $test_commit"
|
||||||
|
|
||||||
|
git checkout "$branch"
|
||||||
|
|
||||||
|
nix flake lock \
|
||||||
|
--override-input nixpkgs "github:NixOS/nixpkgs/$test_commit"
|
||||||
|
|
||||||
|
git add flake.lock
|
||||||
|
|
||||||
|
git commit -m "update nixpkgs to $test_commit"
|
||||||
|
|
||||||
|
git push --force-with-lease origin "$branch"
|
||||||
|
|
||||||
|
local future_text
|
||||||
|
if [ "$goto_future" = "yes" ]; then
|
||||||
|
future_text="bisected in the future"
|
||||||
|
else
|
||||||
|
future_text="bisected in the past"
|
||||||
|
fi
|
||||||
|
append_pr_body "$pr" \
|
||||||
|
" ❌\n - https://github.com/NixOS/nixpkgs/compare/$current_commit...$test_commit ($future_text)"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_pr_check_status() {
|
||||||
|
local pr="$1"
|
||||||
|
|
||||||
|
local status
|
||||||
|
status="$(gh pr checks "$pr" --json state --jq '.[].state' || true)"
|
||||||
|
|
||||||
|
if echo "$status" | grep -qE 'PENDING|QUEUED|IN_PROGRESS'; then
|
||||||
|
echo "pending"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$status" | grep -qE 'FAILURE|TIMED_OUT|CANCELLED'; then
|
||||||
|
echo "failing"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_pr_commit() {
|
||||||
|
local pr="$1"
|
||||||
|
|
||||||
|
git fetch origin "$branch"
|
||||||
|
|
||||||
|
git show "origin/$branch:flake.lock" \
|
||||||
|
| jq -r '.nodes.nixpkgs.locked.rev'
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,10 @@ blocks.md
|
||||||
recipes.md
|
recipes.md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```{=include=} chapters html:into-file=//misc.html
|
||||||
|
misc.md
|
||||||
|
```
|
||||||
|
|
||||||
```{=include=} chapters html:into-file=//demos.html
|
```{=include=} chapters html:into-file=//demos.html
|
||||||
demos.md
|
demos.md
|
||||||
```
|
```
|
||||||
|
|
|
||||||
39
docs/misc.md
Normal file
39
docs/misc.md
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<!-- Read these docs at https://shb.skarabox.com -->
|
||||||
|
# Miscellaneous {#misc}
|
||||||
|
|
||||||
|
Here goes meta-discussions around the repository and other topics not related directly to the usage of SHB.
|
||||||
|
|
||||||
|
## Lock file update {#misc-lock-file-update}
|
||||||
|
|
||||||
|
*SHB has an unusual strategy to keep up with its flake inputs. This section explains why.*
|
||||||
|
|
||||||
|
SHB only depends on `nixpkgs` as far as flake inputs goes.
|
||||||
|
There are others but they only matter for tasks around taking care of the repository itself.
|
||||||
|
So only the `nixpkgs` input is important for downstream consumers of SHB.
|
||||||
|
|
||||||
|
To keep up to date with nixpkgs unstable,
|
||||||
|
initially a job was updating the nixpkgs input by simply updating the lock file and creating a PR.
|
||||||
|
Now, this job failed most of the time because the tip of unstable often breaks modules and packages, resulting in failing SHB tests.
|
||||||
|
To fix this, we usually needed to choose a commit around 2 weeks prior to the latest unstable commit.
|
||||||
|
This usually did not lead to successful tests but the reason was then not
|
||||||
|
because of failing packages but because nixpkgs modules evolved and SHB needs to adapt to that.
|
||||||
|
The net effect was SHB was lagging too far behind unstable and updating it was becoming annoying.
|
||||||
|
|
||||||
|
The new strategy now is as follows. On every job run:
|
||||||
|
|
||||||
|
- If there is no PR, update nixpkgs input to latest unstable commit and create a PR which auto-merges when tests are successful.
|
||||||
|
- If there is a PR:
|
||||||
|
- If the checks succeeded, do nothing because the PR will auto-merge.
|
||||||
|
- If the checks are pending, do nothing yet.
|
||||||
|
- If the checks failed, bisect and update nixpkgs input to between the commit on main and the commit in the PR.
|
||||||
|
|
||||||
|
The effect here is as long as the tests are failing, we'll try a commit further in the past from nixpkgs unstable
|
||||||
|
and closer to the tip of main branch.
|
||||||
|
|
||||||
|
This could be made smarter by distinguishing between types of failures.
|
||||||
|
We will see if this is needed.
|
||||||
|
|
||||||
|
One can also run the bisect manually with `nix run .#update-flake-lock-pr`.
|
||||||
|
This will create a PR on a different branch than the one used for the automated workflow.
|
||||||
|
It accepts also one argument `future` which instead of trying a commit in between the tip of SHB main and the PR's failing one,
|
||||||
|
it tries a commit between the PR's failing one and the nixpkgs unstable latest commit.
|
||||||
|
|
@ -926,6 +926,9 @@
|
||||||
"blocks-mitmdump-options-shb.mitmdump.instances._name_.serviceName": [
|
"blocks-mitmdump-options-shb.mitmdump.instances._name_.serviceName": [
|
||||||
"blocks-mitmdump.html#blocks-mitmdump-options-shb.mitmdump.instances._name_.serviceName"
|
"blocks-mitmdump.html#blocks-mitmdump-options-shb.mitmdump.instances._name_.serviceName"
|
||||||
],
|
],
|
||||||
|
"blocks-mitmdump-options-shb.mitmdump.instances._name_.timeout": [
|
||||||
|
"blocks-mitmdump.html#blocks-mitmdump-options-shb.mitmdump.instances._name_.timeout"
|
||||||
|
],
|
||||||
"blocks-mitmdump-options-shb.mitmdump.instances._name_.upstreamHost": [
|
"blocks-mitmdump-options-shb.mitmdump.instances._name_.upstreamHost": [
|
||||||
"blocks-mitmdump.html#blocks-mitmdump-options-shb.mitmdump.instances._name_.upstreamHost"
|
"blocks-mitmdump.html#blocks-mitmdump-options-shb.mitmdump.instances._name_.upstreamHost"
|
||||||
],
|
],
|
||||||
|
|
@ -2387,6 +2390,12 @@
|
||||||
"local-testing": [
|
"local-testing": [
|
||||||
"service-implementation-guide.html#local-testing"
|
"service-implementation-guide.html#local-testing"
|
||||||
],
|
],
|
||||||
|
"misc": [
|
||||||
|
"misc.html#misc"
|
||||||
|
],
|
||||||
|
"misc-lock-file-update": [
|
||||||
|
"misc.html#misc-lock-file-update"
|
||||||
|
],
|
||||||
"monitoring-failures": [
|
"monitoring-failures": [
|
||||||
"service-implementation-guide.html#monitoring-failures"
|
"service-implementation-guide.html#monitoring-failures"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,8 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
packages.update-flake-lock-pr = pkgs.callPackage ./.github/workflows/update-flake-lock-pr.nix { };
|
||||||
|
|
||||||
lib = (pkgs.callPackage ./lib { }) // {
|
lib = (pkgs.callPackage ./lib { }) // {
|
||||||
test = pkgs.callPackage ./test/common.nix { };
|
test = pkgs.callPackage ./test/common.nix { };
|
||||||
contracts = pkgs.callPackage ./modules/contracts {
|
contracts = pkgs.callPackage ./modules/contracts {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue