Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/retire.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion members/Enzime
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
2025-08-20
1 change: 0 additions & 1 deletion members/LordGrimmauld
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
2025-08-20
1 change: 0 additions & 1 deletion members/MattSturgeon
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
2025-08-20
1 change: 0 additions & 1 deletion members/SigmaSquadron
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
2025-08-20
1 change: 0 additions & 1 deletion members/jmbaur
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
2025-08-20
1 change: 0 additions & 1 deletion members/m1cr0man
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
2025-08-20
37 changes: 21 additions & 16 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,32 @@ 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`

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
```
Expand All @@ -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
```
52 changes: 46 additions & 6 deletions scripts/retire.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 \
Expand Down
3 changes: 1 addition & 2 deletions scripts/sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down