diff --git a/.github/workflows/retire.yml b/.github/workflows/retire.yml index e45eaee..e311ba8 100644 --- a/.github/workflows/retire.yml +++ b/.github/workflows/retire.yml @@ -34,6 +34,8 @@ jobs: uses: actions/checkout@v4 with: token: ${{ steps.app-token.outputs.token }} + # Fetch full history to determine when committers were added + fetch-depth: 0 - name: Run script # One month plus a bit of leeway run: scripts/retire.sh NixOS nixpkgs nixpkgs-committers members "yesterday 1 month ago" diff --git a/members/Enzime b/members/Enzime index 3fb16d6..e69de29 100644 --- a/members/Enzime +++ b/members/Enzime @@ -1 +0,0 @@ -2025-08-20 diff --git a/members/LordGrimmauld b/members/LordGrimmauld index 3fb16d6..e69de29 100644 --- a/members/LordGrimmauld +++ b/members/LordGrimmauld @@ -1 +0,0 @@ -2025-08-20 diff --git a/members/MattSturgeon b/members/MattSturgeon index 3fb16d6..e69de29 100644 --- a/members/MattSturgeon +++ b/members/MattSturgeon @@ -1 +0,0 @@ -2025-08-20 diff --git a/members/SigmaSquadron b/members/SigmaSquadron index 3fb16d6..e69de29 100644 --- a/members/SigmaSquadron +++ b/members/SigmaSquadron @@ -1 +0,0 @@ -2025-08-20 diff --git a/members/jmbaur b/members/jmbaur index 3fb16d6..e69de29 100644 --- a/members/jmbaur +++ b/members/jmbaur @@ -1 +0,0 @@ -2025-08-20 diff --git a/members/m1cr0man b/members/m1cr0man index 3fb16d6..e69de29 100644 --- a/members/m1cr0man +++ b/members/m1cr0man @@ -1 +0,0 @@ -2025-08-20 diff --git a/scripts/README.md b/scripts/README.md index 5c0e41f..f99d599 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -36,10 +36,10 @@ Once you have the above setup (or got @infinisil to add yourself to his), you ha This script has no external effects and as such can be easily tested by running: ```bash -scripts/sync.sh infinisil-test-org actors members +scripts/sync.sh infinisil-test-org actors members-test ``` -Check that it synchronises the files in the `members` directory with the team members of the `actors` team. +Check that it synchronises the files in the `members-test` directory with the team members of the `actors` team. ## `retire.sh` @@ -47,16 +47,21 @@ This script has external effects and as such needs a bit more care when testing. ### Setup (important!) -To avoid other users getting pings, ensure that the `members` directory contains only a simulated new user and your own user (simulated to have been added over a year ago), then commit and push it for testing: +To avoid other users getting pings, ensure that the `members-test` directory contains only simulated new users and your own user (simulated to have been added over a year ago), then commit and push it for testing: ```bash me=$(gh api /user --jq .login) git switch -C "test-$me" -rm -rf members -mkdir members -date +%F > "members/github" -date --date="1 year ago 1 day ago" +%F > "members/$me" -git add members +rm -rf members-test +mkdir -p members-test + +touch members-test/"$me" +date +%F > "members-test/new-committer-1" +git add members-test +GIT_COMMITTER_DATE=$(date --date @0) git commit -m testing + +touch "members-test/new-committer-2" +git add members-test git commit -m testing git push -f -u origin HEAD ``` @@ -67,40 +72,40 @@ The following sequence tests all code paths: 1. Run the script with the `active` repo argument to simulate CI running without inactive users: ```bash - scripts/retire.sh infinisil-test-org active nixpkgs-committers members 'yesterday 1 month ago' + scripts/retire.sh infinisil-test-org active nixpkgs-committers members-test 'yesterday 1 month ago' ``` Check that no PR would be opened. 2. Run the script with the `empty` repo argument to simulate CI running with inactive users: ```bash - scripts/retire.sh infinisil-test-org empty nixpkgs-committers members 'yesterday 1 month ago' + scripts/retire.sh infinisil-test-org empty nixpkgs-committers members-test 'yesterday 1 month ago' ``` - Check that it would only create a PR for your own user and not the "github" user before running it again with `PROD=1` to actually do it: + Check that it would only create a PR for your own user and not the "new-committer-1" or "new-committer-2" user before running it again with `PROD=1` to actually do it: ```bash - PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members 'yesterday 1 month ago' + PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members-test 'yesterday 1 month ago' ``` Check that it created the PR appropriately. You can undo this step by closing the PR. 3. Run it again to simulate CI running again later: ```bash - PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members 'yesterday 1 month ago' + PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members-test 'yesterday 1 month ago' ``` Check that no other PR is opened. 4. Run it again with `now` as the date to simulate the time interval passing: ```bash - PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members now + PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members-test now ``` Check that it undrafted the previous PR and posted an appropriate comment. 5. Run it again to simulate CI running again later: ```bash - PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members now + PROD=1 scripts/retire.sh infinisil-test-org empty nixpkgs-committers members-test now ``` 6. Reset by marking the PR as a draft again. 7. Run it again with the `active` repo argument to simulate activity during the time interval: ```bash - PROD=1 scripts/retire.sh infinisil-test-org active nixpkgs-committers members now + PROD=1 scripts/retire.sh infinisil-test-org active nixpkgs-committers members-test now ``` diff --git a/scripts/retire.sh b/scripts/retire.sh index bffd73a..cdac339 100755 --- a/scripts/retire.sh +++ b/scripts/retire.sh @@ -37,9 +37,31 @@ DIR=${4:-$(usage)} NOTICE_CUTOFF=${5:-$(usage)} mainBranch=$(git branch --show-current) -newCutoff=$(date --date="1 year ago" +%s) noticeCutoff=$(date --date="$NOTICE_CUTOFF" +%s) +# People that received the commit bit after this date won't be retired +newCutoff=$(date --date="1 year ago" +%s) + +# We need to know when people received their commit bit to avoid retiring them within the first year. +# For now this is done either with the git creation date of the file, or its contents: +# +# | commit bit reception date | file creation date | file contents | +# | -------------------------- | ------------------ | -------------- | +# | A) -∞ - 2024-10-06 | 2025-07-08 | empty | +# | B) 2024-10-07 - 2025-04-22 | 2025-07-08 | reception date | +# | C) 2025-08-13 - ∞ | reception date | empty | +# +# After 2026-04-23 (one year after C started), the file creation date +# for all first-year committers will match the reception date, +# while everybody else will have been a committer for more than one year. +# This means the code can then be simplified to just +# check if the file creation date is in the last year. +# +# For now however, the code needs to check if the file creation date +# is before 2025-07-09 to distinguish between periods A and C, +# so we hardcode that date for the code to use. +createdOnReceptionEpoch=$(date --date=2025-07-09 +%s) + if [[ -z "${PROD:-}" ]]; then tmp=$(git rev-parse --show-toplevel)/.tmp rm -rf "$tmp" @@ -54,12 +76,30 @@ mkdir -p "$DIR" cd "$DIR" for login in *; do - # Don't remove people that have been added recently - if [[ -s "$login" ]]; then - epochAdded=$(date --date="$(<"$login")" +%s) - if (( newCutoff < epochAdded )); then - continue + # Figure out when this person received the commit bit + # Get the unix epoch of the first commit that touched this file + # --first-parent is important to get the time of when the main branch was changed + fileCommitEpoch=$(git log --reverse --first-parent --format=%cd --date=unix -- "$login" | head -1) + if (( fileCommitEpoch < createdOnReceptionEpoch )); then + # If it was created before creation actually matched the reception date + # This branch can be removed after 2026-04-23 + + if [[ -s "$login" ]]; then + # If the file is non-empty it indicates an explicit reception date + receptionEpoch=$(date --date="$(<"$login")" +%s) + else + # Otherwise they received the commit bit more than a year ago (start of unix epoch, 1970) + receptionEpoch=0 fi + else + # Otherwise creation matches reception + receptionEpoch=$fileCommitEpoch + fi + + # If the commit bit was received after the cutoff date, don't retire in any case + if (( newCutoff < receptionEpoch )); then + log "$login became a committer less than 1 year ago, skipping retirement check" + continue fi trace gh api -X GET /repos/"$ORG"/"$ACTIVITY_REPO"/activity \ diff --git a/scripts/sync.sh b/scripts/sync.sh index 15b2271..0fa103b 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -17,8 +17,7 @@ gh api /orgs/"$ORG"/teams/"$TEAM"/members --paginate --jq '.[].login' | if [[ -f "$DIR/$login" ]]; then mv "$DIR/$login" "$DIR.new" else - # Keep track of when the user was added - date +%F > "$DIR.new/$login" + touch "$DIR.new/$login" fi done