-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJustfile
More file actions
162 lines (136 loc) · 5.68 KB
/
Justfile
File metadata and controls
162 lines (136 loc) · 5.68 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
# Set up the Python environment, done automatically for you when using direnv
setup:
[ -f .env ] || cp .env-example .env
uv venv && uv sync
@echo "activate: source ./.venv/bin/activate"
# Start docker services
docker_up:
docker compose up -d --wait
docker_down:
docker compose down
# Run tests
test:
uv run pytest -v
# python linting checks
[script]
lint FILES=".":
set +e
exit_code=0
if [ -n "${CI:-}" ]; then
# CI mode: GitHub-friendly output
uv run ruff check --output-format=github {{FILES}} || exit_code=$?
uv run ruff format --check {{FILES}} || exit_code=$?
uv run pyright {{FILES}} --outputjson > pyright_report.json || exit_code=$?
jq -r \
--arg root "$GITHUB_WORKSPACE/" \
'
.generalDiagnostics[] |
.file as $file |
($file | sub("^\\Q\($root)\\E"; "")) as $rel_file |
"::\(.severity) file=\($rel_file),line=\(.range.start.line),endLine=\(.range.end.line),col=\(.range.start.character),endColumn=\(.range.end.character)::\($rel_file):\(.range.start.line): \(.message)"
' < pyright_report.json
rm pyright_report.json
else
# Local mode: regular output
uv run ruff check {{FILES}} || exit_code=$?
uv run ruff format --check {{FILES}} || exit_code=$?
uv run pyright {{FILES}} || exit_code=$?
fi
if [ $exit_code -ne 0 ]; then
echo "One or more linting checks failed"
exit 1
fi
# Automatically fix linting errors
lint-fix:
uv run ruff check . --fix
uv run ruff format .
# Clean build artifacts and cache
clean:
rm -rf *.egg-info .venv || true
find . -type f -name "*.pyc" -delete
find . -type d -name "__pycache__" -delete || true
# Update copier template
update_from_upstream_template:
uv tool run --with jinja2_shell_extension \
copier@latest update --vcs-ref=HEAD --trust --skip-tasks --skip-answered
# set publish permissions, update metadata, and protect master; all in one command
github_setup: github_repo_permissions_create github_repo_set_metadata github_ruleset_protect_master_create
GITHUB_PROTECT_MASTER_RULESET := """
{
"name": "Protect master from force pushes",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["refs/heads/master"],
"exclude": []
}
},
"rules": [
{
"type": "non_fast_forward"
}
]
}
"""
_github_repo:
gh repo view --json nameWithOwner -q .nameWithOwner
# TODO this only supports deleting the single ruleset specified above
github_ruleset_protect_master_delete:
repo=$(just _github_repo) && \
ruleset_name=$(echo '{{GITHUB_PROTECT_MASTER_RULESET}}' | jq -r .name) && \
ruleset_id=$(gh api repos/$repo/rulesets --jq ".[] | select(.name == \"$ruleset_name\") | .id") && \
(([ -n "${ruleset_id}" ] || (echo "No ruleset found" && exit 0)) || gh api --method DELETE repos/$repo/rulesets/$ruleset_id)
# adds github ruleset to prevent --force and other destructive actions on the github main branch
github_ruleset_protect_master_create: github_ruleset_protect_master_delete
gh api --method POST repos/$(just _github_repo)/rulesets --input - <<< '{{GITHUB_PROTECT_MASTER_RULESET}}'
# Output logs of the last failed 'build' workflow for the current branch
[script]
github_last_build_failure:
BRANCH=$(git branch --show-current)
# 1. Fetch last 20 runs (to skip over 'Metadata Sync', 'Dependabot', etc.)
JSON=$(gh run list -b "$BRANCH" -L 20 --json databaseId,conclusion,workflowName)
# 2. Filter: Find the latest run where name contains "build" (case-insensitive)
TARGET=$(echo "$JSON" | jq 'map(select(.workflowName | test("build"; "i"))) | .[0]')
# 3. Handle case where no build run is found
if [[ "$TARGET" == "null" ]]; then
echo "No 'build' workflows found in the last 20 runs for $BRANCH."
exit 0
fi
# 4. Extract Status and ID
CONCLUSION=$(echo "$TARGET" | jq -r .conclusion)
ID=$(echo "$TARGET" | jq -r .databaseId)
# 5. Check Success vs Failure
if [[ "$CONCLUSION" == "success" ]]; then
echo "latest build succeeded"
else
# Force cat pager to output logs directly to terminal
GH_PAGER=cat gh run view "$ID" --log-failed
fi
# Rerun only failed jobs for the last failed 'build' workflow for the current branch
[script]
github_rerun_failed:
BRANCH=$(git branch --show-current)
# Filter for runs on current branch with failure status, limit to most recent 20
JSON=$(gh run list -b "$BRANCH" -s failure -L 20 --json databaseId,workflowName)
# Find the latest failure where workflow name contains "build"
ID=$(echo "$JSON" | jq -r 'map(select(.workflowName | test("build"; "i"))) | .[0].databaseId')
if [[ "$ID" == "null" ]]; then
echo "No failed 'build' workflows found for $BRANCH."
exit 0
fi
echo "Rerunning failed jobs for run $ID..."
gh run rerun "$ID" --failed
# Set GitHub Actions permissions for the repository to allow workflows to write and approve PR reviews
# This enables release-please to run without a personal access token
github_repo_permissions_create:
repo_path=$(gh repo view --json nameWithOwner --jq '.nameWithOwner') && \
gh api --method PUT "/repos/${repo_path}/actions/permissions/workflow" \
-f default_workflow_permissions=write \
-F can_approve_pull_request_reviews=true && \
gh api "/repos/${repo_path}/actions/permissions/workflow"
github_repo_set_metadata:
gh repo edit \
--description "$(yq '.project.description' pyproject.toml)" \
--homepage "$(yq '.project.urls.Repository' pyproject.toml)" \
--add-topic "$(yq '.project.keywords | join(",")' pyproject.toml)"