-
Notifications
You must be signed in to change notification settings - Fork 26
Implement Schema Version Update Automation #276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: ImJustHenry <[email protected]>
Signed-off-by: ImJustHenry <[email protected]>
|
Thanks @ImJustHenry for your contribution! A couple of comments:
|
xibz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! Overall it looks good, but just had a few minor comments.
| return major, minor, patch, suffix | ||
|
|
||
|
|
||
| def bump_version(major, minor, patch): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe instead we could have just 3 new variables, and we should probably throw an exception for unknown LABELs
new_patch = 0
new_minor = 0
new_major = 0
if LABEL == "patch":
new_patch = patch + 1
elif LABEL == "minor":
new_minor = minor + 1
elif LABEL == "major":
new_major = major + 1
else
raise ExceptionType(f"invalid LABEL: {LABEL}")
return new_major, new_minor, new_patch
Additionally, we may need a suffix or prefix potentially, e.g. "v1.0.0-beta". But I think that can come when we need it. It looks like you started some functionality for suffix, but I dont think it's done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks you for the feedback!
I understand the suggestion to use three new variables, it does make the bump logic more explicit and clear. I also see your point about throwing an exception for unknown labels. In the current setup, the GitHub workflow only passes predefined labels (patch, minor, major, release), so in practice an exception isn’t strictly necessary.
That said, adding an exception could serve as a useful safeguard if someone were to run the script manually with an invalid label. I’ll update the script to incorporate both of these suggestions.
tools/bump_version.py
Outdated
| old_version = read_version() | ||
|
|
||
| # Parse current version | ||
| major, minor, patch, suffix = parse_version(old_version) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens to suffix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the question! The suffix is parsed so that I can correctly separate the numeric patch value from any trailing suffix such as -draft. I designed the logic under the assumption that versions should always include -draft unless the label is release, in which case the suffix is intentionally removed.
So the suffix is extracted purely so the script can reliably parse versions like 0.5.0-draft without errors, and so a release label can strip the suffix. Outside of that case, the script intentionally replaces the suffix with -draft on all non-release bumps.
tools/bump_version.py
Outdated
| else: | ||
| # Otherwise, bump version according to label | ||
| new_major, new_minor, new_patch = bump_version(major, minor, patch) | ||
| new_version = f"{new_major}.{new_minor}.{new_patch}-draft" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we use suffix here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned, the original assumption was that only finalized releases should omit the -draft suffix. That’s why I intentionally append -draft during version bumps, so all non-release versions are clearly marked.
If the goal is to preserve existing suffixes (potentially for more complex cases in the future like -beta) the logic can certainly be updated to consistently use the parsed suffix instead of forcing -draft. The current implementation mainly ensures that non-release versions are easily distinguishable from official releases.
|
@afrittoli - The shell script seems a little larger in scope. This doesn't do version file replacement in JSON, for example, but to manage the version specifically. I think we can use the shell script and this in conjunction. So I think we will need to update the shell script as well or move the rest of it to the python script. @ImJustHenry - Can you take a look at that shell script? I think we may be able to utilize both of the files to do a release, or we can completely replace the shell script with full python, but that requires doing the file version replacement to also be added. |
|
The main problem I see with this approach is that it will attempt to create a new PR to update versions every time a PR is labelled. I think we should execute this at release time, not on every PR. Even if we wanted to update versions every PR, we shouldn't do it with an extra PR, there would be no easy way to coordinate merging the PRs in the right order then.
But again, I don't think we should update versions for every single PR. @xibz @davidB thoughts? |
|
@xibz - I’ve reviewed the shell script. Please correct me if I miss anything but the shell script basically manages releases by updating all version references across the repository, including JSON schemas, conformance files, and documentation, based on the version specified in version.txt. The approach could be that we can utilize both scripts, the Python script calculates the next version based on the label and updates version.txt, while the shell script reads version.txt and updates all references across the repository. Or alternatively, if you prefer having everything in a single language, I can convert the shell script’s functionality into the Python script. I’m happy to proceed with whichever approach is preferred. @afrittoli - Thank you for the feedback! I actually modeled the workflow after what I observed with Dependabot, which creates a new PR every time it bumps a dependency version. My assumption was that each merged PR into main would correspond to either a minor, major, or patch change, and thought that the repository should have a PR for every version commit for consistency. I understand your concern about creating a PR on every labeled PR and the potential coordination issues. To address this, the approach you mentioned of using manual dispatch to create releases makes sense. This way it does ensure that the version bumps only happen intentionally, instead of triggering on every PR. I can start updating the code and incorporate all the feedback if there are no other issues that haven’t been addressed. |
Exactly
This is probably the right move. Also, if you could add some tests now that we are using a proper language, that would be great. |
|
@xibz Thanks for the feedback, and sorry for the delayed reply (its finals week for me😅). My capstone is focused on CI/CD automation within SLU’s Open Source program. A major part of the assignment involves contributing automation, release workflows, and documentation improvements across multiple OSS SLU repositories. As part of the capstone, I’m also doing excellence activities, which involve contributing externally like submitting and merging pull requests to projects outside of OSS SLU. So your proposal doesn’t conflict with my capstone at all. I’ll go ahead and implement and fix this PR as suggested if there is no other concerns! |
|
@ImJustHenry - No worries! And great to hear that your capstone is around CI/CD automation. That's a great area to dive into for a contribution given most open source projects have some form of CI/CD. When you have the changes ready, feel free to ping me on Slack or just drop a comment here. As a small piece of advice for next time: before opening a PR, it’s generally best to first create an issue. The reason is that it gives the project maintainers a chance to provide context or guidance. For example, if there are existing scripts or plans you might not be aware of. Imagine if the team was planning to move away from GitHub Actions (we’re not, but just as an example), then updating the workflow wouldn’t have been the right direction, and that PR likely wouldn’t be accepted. Creating an issue first helps surface that kind of context early on. It also helps prevent overlapping work and lets everyone know you’re taking it on. Open-source maintainers love contributors who jump in :), and starting with an issue makes the whole experience smoother for both sides. Luckily, this PR is super straightforward, so no worries here. Just something to keep in mind for future contributions. You’ll get a lot more out of the experience that way 👍 |
…ded exception if Label is invalid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements automated schema version bumping through a Python script and GitHub Actions workflow. When a PR is labeled with patch, minor, or major, the workflow automatically creates a new PR with the updated version. However, the implementation has critical issues that need to be addressed before merging.
Key Changes
- Python script to parse and bump semantic versions based on PR labels
- GitHub Actions workflow triggered by PR labeling events
- Automated PR creation for version updates
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| tools/bump_version.py | Core version bumping logic that parses version.txt and increments version numbers based on label type |
| .github/workflows/version-bump.yml | Workflow automation that triggers version bump script when patch/minor/major labels are applied to PRs |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import sys | ||
|
|
||
| # The GitHub label passed as an argument: patch, minor, major | ||
| LABEL = sys.argv[1] |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling for command-line arguments. If the script is invoked without arguments, it will crash with an IndexError. The script should validate that sys.argv has the required number of arguments and provide a helpful error message if not.
| with open(VERSION_FILE, "r") as f: | ||
| return f.read().strip() |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling for file operations. If version.txt does not exist or is not readable, the script will crash with a FileNotFoundError. Consider adding try-except blocks to handle these cases gracefully and provide helpful error messages.
| with open(VERSION_FILE, "r") as f: | |
| return f.read().strip() | |
| try: | |
| with open(VERSION_FILE, "r") as f: | |
| return f.read().strip() | |
| except FileNotFoundError: | |
| print(f"Error: {VERSION_FILE} not found. Please ensure the version file exists.", file=sys.stderr) | |
| sys.exit(1) | |
| except OSError as e: | |
| print(f"Error reading {VERSION_FILE}: {e}", file=sys.stderr) | |
| sys.exit(1) |
| parts = v.split(".") # Split into ['0', '5', '0'] | ||
|
|
||
| major = int(parts[0]) | ||
| minor = int(parts[1]) | ||
| patch = int(parts[2]) |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling for malformed version strings. If version.txt contains a version string that doesn't have exactly 3 parts separated by dots (e.g., "0.5" or "0.5.0.1"), the script will crash with an IndexError when trying to access parts[2]. Add validation to ensure the version string is well-formed before parsing.
| new_major, new_minor, new_patch = bump_version(major, minor, patch) | ||
| new_version = f"{new_major}.{new_minor}.{new_patch}" |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version suffix is being lost during the bump process. The PR description states "Non-release bumps retain any existing suffix (e.g., -draft) while incrementing the appropriate version component," but the current implementation removes the suffix in parse_version (line 25) and never restores it when constructing the new version (line 68). The suffix should be preserved and appended back to the new version string.
| if LABEL == "patch": | ||
| new_patch = patch + 1 | ||
| elif LABEL == "minor": | ||
| new_minor = minor + 1 | ||
| new_patch = 0 | ||
| elif LABEL == "major": | ||
| new_major = major + 1 | ||
| new_minor = 0 | ||
| new_patch = 0 | ||
| else: | ||
| raise ValueError(f"Invalid Label: {LABEL}") | ||
| return new_major, new_minor, new_patch |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing implementation for 'release' label handling. The PR description states "For release labels, the workflow removes the -draft suffix from the version," but there is no code to handle the 'release' label. The script only processes 'patch', 'minor', and 'major' labels, and will raise a ValueError if 'release' is passed.
| new_major, new_minor, new_patch = bump_version(major, minor, patch) | ||
| new_version = f"{new_major}.{new_minor}.{new_patch}" | ||
|
|
||
| # Prevent race conditions by only writing if version changed |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misleading comment about race condition prevention. The comment claims this check "prevents race conditions," but comparing version strings doesn't prevent race conditions in concurrent workflows. The check only avoids unnecessary writes when the version hasn't changed (which shouldn't happen in normal operation). Consider updating the comment to accurately describe what this check does.
| # Prevent race conditions by only writing if version changed | |
| # Only write if the version has changed to avoid unnecessary writes |
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent checkout action version. This workflow uses actions/checkout@v4, but the existing workflow in .github/workflows/main.yml uses actions/checkout@v5. For consistency and to ensure the latest features and security fixes, consider using v5 here as well.
| uses: actions/checkout@v4 | |
| uses: actions/checkout@v5 |
| """ | ||
| new_major = major | ||
| new_minor = minor | ||
| new_patch = patch |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to 'new_patch' is unnecessary as it is redefined before this value is used.
This assignment to 'new_patch' is unnecessary as it is redefined before this value is used.
This assignment to 'new_patch' is unnecessary as it is redefined before this value is used.
| new_patch = patch |
Changes
tools/bump_version.py) to automate version bumps based on PR labels (patch,minor,major,release)..github/workflows/version-bump.yml) that triggers on PR labeling.releaselabels, the workflow removes the-draftsuffix from the version.-draft) while incrementing the appropriate version component.Related Issue
Partially fixes #218
Submitter Checklist
As the author of this PR, please check off the items in this checklist: