Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
194 lines (170 loc) · 8.38 KB
/
Copy pathMakefile
File metadata and controls
194 lines (170 loc) · 8.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
.PHONY: test lint format check check-reviewdog check-reviewdog-full setup schedules schedules-run remove-schedules remove-schedules-run view-schedules clean archive archive-progress archive-prd backlog backlog-dry-run worktree rebase approve merge unmount-worktrees
# Prefer .venv when it exists so no target needs an activated shell. PEP 668
# interpreters (Homebrew, recent Debian) refuse a system-wide pytest install, so
# a venv is the usual outcome of `make setup` -- but a system pytest/ruff still
# works, hence the fallback rather than a hard dependency.
VENV := $(CURDIR)/.venv
PYTHON := $(if $(wildcard $(VENV)/bin/python),$(VENV)/bin/python,python3)
RUFF := $(if $(wildcard $(VENV)/bin/ruff),$(VENV)/bin/ruff,ruff)
# Run the test suite
test:
$(PYTHON) -m pytest tests/ -v
# Lint Python files (check only)
lint:
$(RUFF) check .
$(RUFF) format --check .
# Lint and auto-fix Python files
format:
$(RUFF) check --fix .
$(RUFF) format .
# The whole local pass, in one target. All three run on a pull request too --
# lint and the tests from .github/workflows/lint-and-test.yml, the security scan
# from an organization-level workflow -- so this is the same pass, before the
# push rather than after it. Run it anyway: it is minutes faster than waiting.
check: lint test check-reviewdog
# The security scan that comments on our pull requests, before pushing rather
# than after. Nothing here configures it: it arrives as an organization-level
# workflow calling brave/security-action, so scripts/check-reviewdog.sh clones
# that repository and drives its reviewdog runners against this checkout,
# pinning the tool versions its action.yml pins. First run downloads opengrep,
# reviewdog and the rule set into ~/.cache; later runs re-use them and take
# about half a minute.
#
# The two targets are the action's own two modes. On a pull request it scans
# what the branch changed; on workflow_dispatch it scans everything. A finding
# here is one the bot would post, so the full scan reports plenty that predates
# any given branch -- check-reviewdog is the one to run before pushing.
#
# No model is involved, so both are deterministic.
check-reviewdog:
@./scripts/check-reviewdog.sh
check-reviewdog-full:
@./scripts/check-reviewdog.sh --full
# Install dev dependencies and run project setup
setup:
@./scripts/install-dev-deps.sh
@rm -rf *.egg-info
./scripts/setup.sh
# Install/update every cron schedule for this project: run, maintenance
schedules:
./scripts/sync-schedules.sh
# Install/update only the schedules that start run.sh (and the PRD sync feeding it)
schedules-run:
./scripts/sync-schedules.sh --group run
# Remove this project's cron schedules, leaving every other crontab line alone
remove-schedules:
./scripts/remove-schedules.sh
# Remove only the run.sh schedules
remove-schedules-run:
./scripts/remove-schedules.sh --group run
# Show schedule summary
view-schedules:
./scripts/view-schedules.sh
# Archive progress.txt (append to progress.archived.txt, reset progress.txt)
archive-progress:
@if [ ! -f data/progress.txt ]; then echo "No progress.txt to archive."; exit 0; fi
@echo "Archiving progress.txt..."
@cat data/progress.txt >> data/progress.archived.txt
@echo "" >> data/progress.archived.txt
@echo "# Progress Log" > data/progress.txt
@echo "Started: $$(date)" >> data/progress.txt
@echo "---" >> data/progress.txt
@echo "Archived $$(wc -l < data/progress.archived.txt) lines to progress.archived.txt"
# Sync open issues assigned to the bot into the PRD backlog (no LLM involved)
backlog:
python3 scripts/add-backlog-to-prd.py
# Show which assigned issues would be added, without writing prd.json
backlog-dry-run:
python3 scripts/add-backlog-to-prd.py --dry-run
# Archive completed PRD stories (merged/invalid → prd.archived.json)
archive-prd:
python3 scripts/archive-prd.py data/prd.json
# Archive both progress.txt and completed PRD stories
archive: archive-progress archive-prd
# Open a shell in the worktree for a pull request:
#
# make worktree PR=https://github.com/brave/bravebot/pull/351
# make worktree PR=351
# make worktree # asks which pull request
#
# An existing worktree for the pull request's branch is reused -- the branch is
# what identifies it, since a worktree's directory name follows the story's
# issue and not the branch. Otherwise one is created from the pull request's
# head. Either way the tree is brought up to that head when doing so is a
# fast-forward of a clean tree, so what you land on is what the pull request
# shows; a tree holding uncommitted changes or a commit the head does not have
# stays where it is and says so. Either way the main checkout's .envrc is copied
# in and allowed, because untracked files are not shared between worktrees and a
# fresh one would otherwise have no environment at all. No model is involved.
#
# The cd happens here rather than in the script because a child process cannot
# change its parent's directory: the only way to leave you somewhere is to open
# a shell there. Exit that shell to come back.
#
# make reserves the name SHELL for the shell that runs recipes and refuses to
# read it from the environment, so the user's own shell is read explicitly.
USER_SHELL := $(shell printenv SHELL 2>/dev/null)
worktree:
@dir=$$(python3 scripts/worktree-for-pr.py $(if $(PR),"$(PR)")) || exit $$?; \
echo "--> $$dir" >&2; \
cd "$$dir" && { $(or $(USER_SHELL),/bin/sh) -i || true; }
# Rebase a pull request onto the branch it will be merged into, and force-push:
#
# make rebase PR=https://github.com/brave/bravebot/pull/351
# make rebase PR=351
# make rebase # asks which pull request
#
# The same worktree `make worktree` opens does the rebase, and nothing checks a
# branch out anywhere, so the main checkout stays on the branch it is already on
# -- normally the default branch every other worktree borrows from. Where the
# project works through a fork, `upstream` is the pull request's repository and
# the base is `upstream/<project.defaultBranch>`, while the push goes back to the
# fork the branch came from; with no fork both halves are the one remote.
#
# A conflict aborts the rebase and pushes nothing, so the worktree is left where
# the next session can use it. A tree with uncommitted changes, or with commits
# the pull request has never had, stops the command instead of force-pushing
# work nobody reviewed. Where the repository signs commits, the rebase writes
# new ones and needs the signing key -- for this bot, an ssh-agent holding it.
#
# No model is involved.
rebase:
@python3 scripts/rebase-pr.py $(if $(PR),"$(PR)")
# Approve a pull request, and optionally merge it:
#
# make approve PR=https://github.com/brave/bravebot/pull/351
# make merge PR=351 # approve, then squash and merge
# make merge # asks which pull request
#
# Both act as project.botOwnerGithubHandle, not as the bot, whatever gh account
# or GH_TOKEN this shell has. `merge` uses the project's merge method, squash,
# pinned to the commit it approved, and forces nothing: a pull request GitHub
# will not merge yet is reported as it words it, with the approval left in place.
# No model is involved.
approve:
@python3 scripts/merge-pr.py approve $(if $(PR),"$(PR)")
merge:
@python3 scripts/merge-pr.py merge $(if $(PR),"$(PR)")
# Remove the target repository's story worktrees and the directories they live
# in -- the `../<repo>-<issue>` checkouts a worktree profile leaves behind, each
# one carrying a build directory of a few gigabytes:
#
# make unmount-worktrees # every one idle for over 24 hours
# make unmount-worktrees ALL=1 # every one, whatever it holds
# make unmount-worktrees DRY_RUN=1
#
# The default is the pass run.sh makes at the start of a run, so it keeps what
# that keeps: anything used in the last day, and anything holding uncommitted
# changes. ALL=1 drops both -- for emptying the directory rather than collecting
# after a run. Uncommitted changes are what that loses and it names each one as
# it goes; the branches are the repository's, not the worktrees', so unpushed
# commits survive either way and `git checkout <branch>` still finds them.
#
# Either way a worktree a live run claims, or one git has locked, stays: pulling
# the directory out from under a running session breaks it. No model is involved.
unmount-worktrees:
@python3 scripts/clean-worktrees.py \
$(if $(ALL),--all,--max-age-hours 24) $(if $(DRY_RUN),--dry-run) >/dev/null
# Clean up generated/temporary files
clean:
rm -f .run.lock