Skip to content

Commit 91e10e8

Browse files
authored
add number assigning bot (#445)
1 parent c5073b4 commit 91e10e8

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Assign XLS numbers to new draft XLS proposals.
4+
5+
This script scans the repository for existing XLS directories,
6+
determines the next available XLS number, and outputs it for use
7+
in GitHub Actions.
8+
"""
9+
10+
import os
11+
import re
12+
import sys
13+
from pathlib import Path
14+
15+
16+
def get_existing_xls_numbers(repo_root: Path) -> set[int]:
17+
"""
18+
Scan the repository root for existing XLS directories and extract their numbers.
19+
20+
Returns a set of integers representing all claimed XLS numbers.
21+
"""
22+
xls_pattern = re.compile(r"^XLS-(\d{4})-")
23+
numbers = set()
24+
25+
for item in repo_root.iterdir():
26+
if item.is_dir():
27+
match = xls_pattern.match(item.name)
28+
if match:
29+
numbers.add(int(match.group(1)))
30+
31+
return numbers
32+
33+
34+
# Minimum XLS number to assign (to avoid filling old historical gaps)
35+
MIN_XLS_NUMBER = 96
36+
37+
38+
def get_next_xls_number(existing_numbers: set[int]) -> int:
39+
"""
40+
Determine the next available XLS number.
41+
42+
Returns the first unused number >= MIN_XLS_NUMBER.
43+
"""
44+
if not existing_numbers:
45+
return MIN_XLS_NUMBER
46+
47+
# Find the first available number starting from MIN_XLS_NUMBER
48+
max_num = max(existing_numbers)
49+
for num in range(MIN_XLS_NUMBER, max_num + 2):
50+
if num not in existing_numbers:
51+
return num
52+
53+
return max_num + 1
54+
55+
56+
def find_draft_xls_files(changed_files: list[str]) -> list[str]:
57+
"""
58+
Filter changed files to find new XLS draft README files.
59+
60+
Args:
61+
changed_files: List of file paths that were added in the PR
62+
63+
Returns:
64+
List of draft XLS directory names (e.g., ["XLS-draft-my-feature"])
65+
"""
66+
draft_pattern = re.compile(r"^(XLS-draft-[^/]+)/README\.md$")
67+
drafts = []
68+
69+
for file_path in changed_files:
70+
match = draft_pattern.match(file_path)
71+
if match:
72+
drafts.append(match.group(1))
73+
74+
return list(set(drafts)) # Remove duplicates
75+
76+
77+
def main():
78+
"""Main entry point for the script."""
79+
# Get repository root (parent of .github directory)
80+
script_dir = Path(__file__).resolve().parent
81+
repo_root = script_dir.parent.parent
82+
83+
# Get changed files from command line arguments or environment variable
84+
if len(sys.argv) > 1:
85+
changed_files = sys.argv[1:]
86+
else:
87+
# Try to get from environment variable (set by GitHub Actions)
88+
changed_files_env = os.environ.get("CHANGED_FILES", "")
89+
changed_files = changed_files_env.split() if changed_files_env else []
90+
91+
# Helper to set GitHub output
92+
def set_github_output(name: str, value: str):
93+
github_output = os.environ.get("GITHUB_OUTPUT")
94+
if github_output:
95+
with open(github_output, "a") as f:
96+
f.write(f"{name}={value}\n")
97+
else:
98+
print(f" {name}={value}")
99+
100+
if not changed_files:
101+
print("No changed files provided.")
102+
set_github_output("has_drafts", "false")
103+
return
104+
105+
# Find draft XLS files
106+
draft_dirs = find_draft_xls_files(changed_files)
107+
108+
if not draft_dirs:
109+
print("No XLS draft files found in changed files.")
110+
set_github_output("has_drafts", "false")
111+
return
112+
113+
# Get existing XLS numbers
114+
existing_numbers = get_existing_xls_numbers(repo_root)
115+
print(f"Found {len(existing_numbers)} existing XLS numbers.")
116+
print(f"Highest existing number: {max(existing_numbers) if existing_numbers else 0}")
117+
118+
# Assign numbers to each draft
119+
next_number = get_next_xls_number(existing_numbers)
120+
assignments = []
121+
122+
for draft_dir in sorted(draft_dirs):
123+
assigned_number = next_number
124+
new_dir_name = re.sub(r"^XLS-draft-", f"XLS-{assigned_number:04d}-", draft_dir)
125+
assignments.append({
126+
"draft": draft_dir,
127+
"number": assigned_number,
128+
"new_name": new_dir_name,
129+
})
130+
next_number += 1
131+
132+
# Output results
133+
print("\n=== XLS Number Assignments ===")
134+
for assignment in assignments:
135+
draft = assignment['draft']
136+
new_name = assignment['new_name']
137+
num = assignment['number']
138+
print(f" {draft} -> {new_name} (XLS-{num:04d})")
139+
140+
# Set GitHub Actions outputs
141+
set_github_output("has_drafts", "true")
142+
set_github_output("assignments", str(assignments))
143+
144+
# For single draft case, also output individual values for easy access
145+
if len(assignments) == 1:
146+
set_github_output("xls_number", f"{assignments[0]['number']:04d}")
147+
set_github_output("draft_dir", assignments[0]['draft'])
148+
set_github_output("new_dir_name", assignments[0]['new_name'])
149+
150+
151+
if __name__ == "__main__":
152+
main()
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: Assign XLS Number
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
jobs:
8+
assign-xls-number:
9+
runs-on: ubuntu-latest
10+
name: Assign XLS Number to Draft
11+
permissions:
12+
pull-requests: write
13+
contents: read
14+
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v6
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Get added files
22+
id: added-files
23+
uses: tj-actions/changed-files@v47
24+
with:
25+
files: |
26+
XLS-draft-*/README.md
27+
# Only look at added files, not modified ones
28+
include_all_old_new_renamed_files: false
29+
30+
- name: Check for draft XLS files
31+
id: check-drafts
32+
run: |
33+
ADDED_FILES="${{ steps.added-files.outputs.added_files }}"
34+
if [ -z "$ADDED_FILES" ]; then
35+
echo "No XLS draft files added in this PR"
36+
echo "has_drafts=false" >> $GITHUB_OUTPUT
37+
else
38+
echo "Found draft XLS files: $ADDED_FILES"
39+
echo "has_drafts=true" >> $GITHUB_OUTPUT
40+
echo "draft_files=$ADDED_FILES" >> $GITHUB_OUTPUT
41+
fi
42+
43+
- name: Setup Python
44+
if: steps.check-drafts.outputs.has_drafts == 'true'
45+
uses: actions/setup-python@v6
46+
with:
47+
python-version: "3.11"
48+
49+
- name: Assign XLS number
50+
if: steps.check-drafts.outputs.has_drafts == 'true'
51+
id: assign-number
52+
run: |
53+
python .github/scripts/assign_xls_number.py ${{ steps.check-drafts.outputs.draft_files }}
54+
55+
- name: Check for existing assignment comment
56+
if: steps.check-drafts.outputs.has_drafts == 'true'
57+
id: find-comment
58+
uses: peter-evans/find-comment@v3
59+
with:
60+
issue-number: ${{ github.event.pull_request.number }}
61+
comment-author: "github-actions[bot]"
62+
body-includes: "XLS Number Assignment"
63+
64+
- name: Post or update PR comment
65+
if: steps.check-drafts.outputs.has_drafts == 'true' && steps.find-comment.outputs.comment-id == ''
66+
uses: peter-evans/create-or-update-comment@v4
67+
with:
68+
issue-number: ${{ github.event.pull_request.number }}
69+
body: |
70+
## 🎫 XLS Number Assignment
71+
72+
This PR adds a new XLS draft. The next available XLS number has been determined:
73+
74+
| Draft Directory | Assigned Number | New Directory Name |
75+
|-----------------|-----------------|-------------------|
76+
| `${{ steps.assign-number.outputs.draft_dir }}` | **XLS-${{ steps.assign-number.outputs.xls_number }}** | `${{ steps.assign-number.outputs.new_dir_name }}` |
77+
78+
### Next Steps for XLS Editors
79+
80+
Before merging this PR, please:
81+
82+
1. **Rename the directory** from `${{ steps.assign-number.outputs.draft_dir }}` to `${{ steps.assign-number.outputs.new_dir_name }}`
83+
2. **Update the preamble** in the README.md:
84+
- Set `xls:` to `${{ steps.assign-number.outputs.xls_number }}`
85+
- Set `status:` to `Draft`
86+
87+
---
88+
*This comment was automatically generated. The XLS number is based on the highest existing number in the repository at the time this PR was opened.*

0 commit comments

Comments
 (0)