From e2fb00c2c3e80ee4bb44070a5a12ecc3b45a2381 Mon Sep 17 00:00:00 2001 From: Benjamin Morris Date: Mon, 1 Jul 2024 12:39:37 -0700 Subject: [PATCH 1/6] use plugin configuration --- .bumpversion.cfg | 8 -- .github/workflows/create_publish_pr.yaml | 64 ++++++++++++++ pyproject.toml | 14 +++ scripts/publish_bumpver_handler.py | 103 +++++++++++++++++++++++ scripts/tag_with_current_version.py | 16 ++++ version.toml | 4 + 6 files changed, 201 insertions(+), 8 deletions(-) delete mode 100644 .bumpversion.cfg create mode 100644 .github/workflows/create_publish_pr.yaml create mode 100644 scripts/publish_bumpver_handler.py create mode 100644 scripts/tag_with_current_version.py create mode 100644 version.toml diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 8b386bdaf..000000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[bumpversion] -current_version = 0.1.7 -tag = True -commit = True - -[bumpversion:file:pyproject.toml] - -[bumpversion:file:cyto_dl/__init__.py] diff --git a/.github/workflows/create_publish_pr.yaml b/.github/workflows/create_publish_pr.yaml new file mode 100644 index 000000000..3503574a6 --- /dev/null +++ b/.github/workflows/create_publish_pr.yaml @@ -0,0 +1,64 @@ +# takes the most recent commit on main, bumps version based on +# semver_component input, and PRs change back to main +name: Bump version and PR + +on: + workflow_dispatch: + inputs: + semver_component: + description: "Semantic versioning component to bump" + required: true + type: choice + default: "patch" + options: + - major + - minor + - patch + - dev + +jobs: + publish: + name: Bump and PR + runs-on: ubuntu-latest + permissions: + id-token: write + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install bumpver + + - name: Bump version + run: | + git config --global user.name 'aicsgithub' + git config --global user.email 'aicsgithub@alleninstitute.org' + python scripts/publish_bumpver_handler.py ${{ inputs.semver_component }} + + # takes the commit from the last step, pushes to new branch, release, and creates PR + - name: Create pull request + uses: peter-evans/create-pull-request@v6 + with: + branch: workflow-release + base: main + title: Bump version and publish + body: See commit message or diff for new version number + + - name: Tag version + run: | + git checkout workflow-release + python scripts/tag_with_current_version.py + git push origin --tags + + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 8e403b92c..f9a98ac0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,3 +136,17 @@ exclude_lines = [ "raise NotImplementedError()", "if __name__ == .__main__.:", ] + +# https://pypi.org/project/bumpver +[tool.bumpver] +current_version = "0.2.1" +version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]" +commit_message = "Bump version {old_version} -> {new_version}" +commit = true +tag = false # no longer useful to tag here, must happen in create_publish_pr.yaml +push = false + +[tool.bumpver.file_patterns] +"pyproject.toml" = ['current_version = "{version}"', 'version = "{version}"'] +"version.toml" = ['version = "{version}"'] +"cyto_dl/__init__.py" = ['__version__ = "{version}"'] \ No newline at end of file diff --git a/scripts/publish_bumpver_handler.py b/scripts/publish_bumpver_handler.py new file mode 100644 index 000000000..b34d367e8 --- /dev/null +++ b/scripts/publish_bumpver_handler.py @@ -0,0 +1,103 @@ +# this file is intended to be called by a github workflow (.github/workflows/publish_to_pypi.yaml) +# it makes decisions based on the current version and the component specified for bumping, +# which the workflow cannot do +import subprocess +import sys +from typing import Set, List +import toml + + +def main(): + if len(sys.argv) < 2: + raise ValueError("No component specified for bumping version") + + component: str = sys.argv[1].lower() + valid_options: Set[str] = {"major", "minor", "patch", "dev"} + + if component not in valid_options: + raise ValueError(f"Component must be one of {valid_options}") + + version: str = toml.load("pyproject.toml")["project"]["version"] + version_components: List[str] = version.split(".") + + update_output: subprocess.CompletedProcess = None + # 4 components means we currently have a dev version + if len(version_components) == 4: + if component == "dev": + # increment the dev tag (e.g. 1.0.0.dev0 -> 1.0.0.dev1) + update_output = subprocess.run( + ["bumpver", "update", "--tag-num", "-n"] + ) + elif component == "patch": + # finalize the patch by removing dev tag (e.g. 1.0.0.dev1 -> 1.0.0) + update_output = subprocess.run( + ["bumpver", "update", "--tag=final", "-n"] + ) + else: + raise ValueError( + "Cannot update major or minor version while dev version is current" + ) + + elif len(version_components) == 3: + if component == "dev": + # increment patch and begin at dev0 (e.g. 1.0.0 -> 1.0.1.dev0) + update_output = subprocess.run( + ["bumpver", "update", "--patch", "--tag=dev", "-n"] + ) + else: + update_output = subprocess.run( + ["bumpver", "update", f"--{component}", "-n"] + ) + + else: + raise ValueError( + f"Unknown version format: {version}. Expected MAJOR.MINOR.PATCH[.PYTAGNUM]" + ) + + if update_output.returncode != 0: + raise RuntimeError( + f"bumpver exited with code {update_output.returncode}" + ) + + +if __name__ == "__main__": + main() + +""" +TESTING: +- add and commit any changes (keep track of this commit hash) +- bumpver update --set-version 1.0.0 + +- python publish_bumpver_handler.py + - expect: ValueError + +- python publish_bumpver_handler.py fake + - expect: ValueError + +- python publish_bumpver_handler.py major + - expect: version updated to 2.0.0 + +- python publish_bumpver_handler.py minor + - expect: version updated to 2.1.0 + +- python publish_bumpver_handler.py patch + - expect: version updated to 2.1.1 + +- python publish_bumpver_handler.py dev + - expect: version updated to 2.1.2.dev0 + +- python publish_bumpver_handler.py dev + - expect: version updated to 2.1.2.dev1 + +- python publish_bumpver_handler.py major + - expect: ValueError + +- python publish_bumpver_handler.py minor + - expect: ValueError + +- python publish_bumpver_handler.py patch + - expect: version updated to 2.1.2 + +- git reset --hard {hash of the commit made at the beginning} +- git tag --delete 1.0.0 2.0.0 2.1.0 2.1.1 2.1.2 2.1.2.dev0 2.1.2.dev1 +""" \ No newline at end of file diff --git a/scripts/tag_with_current_version.py b/scripts/tag_with_current_version.py new file mode 100644 index 000000000..90990cabd --- /dev/null +++ b/scripts/tag_with_current_version.py @@ -0,0 +1,16 @@ +# This file is intended to be called by a github workflow +import subprocess +import toml + + +def main(): + version: str = toml.load("pyproject.toml")["project"]["version"] + tag_output: subprocess.CompletedProcess = subprocess.run( + ["git", "tag", f"v{version}"] + ) + if tag_output.returncode != 0: + raise RuntimeError("failed to tag") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/version.toml b/version.toml new file mode 100644 index 000000000..ae111fc09 --- /dev/null +++ b/version.toml @@ -0,0 +1,4 @@ +# -----DO NOT MODIFY THIS FILE----- +# This file should only be modified by bumpver, which should in turn only be ran +# via a GH Action +version = "0.1.7" \ No newline at end of file From 2427360a7946efc6ce76c780504df246cabd0171 Mon Sep 17 00:00:00 2001 From: Benjamin Morris Date: Mon, 1 Jul 2024 16:18:43 -0700 Subject: [PATCH 2/6] precommit --- .github/workflows/create_publish_pr.yaml | 6 +- pyproject.toml | 2 +- scripts/publish_bumpver_handler.py | 106 ++++++++++------------- scripts/tag_with_current_version.py | 7 +- version.toml | 2 +- 5 files changed, 55 insertions(+), 68 deletions(-) diff --git a/.github/workflows/create_publish_pr.yaml b/.github/workflows/create_publish_pr.yaml index 3503574a6..7e71751aa 100644 --- a/.github/workflows/create_publish_pr.yaml +++ b/.github/workflows/create_publish_pr.yaml @@ -45,7 +45,7 @@ jobs: git config --global user.name 'aicsgithub' git config --global user.email 'aicsgithub@alleninstitute.org' python scripts/publish_bumpver_handler.py ${{ inputs.semver_component }} - + # takes the commit from the last step, pushes to new branch, release, and creates PR - name: Create pull request uses: peter-evans/create-pull-request@v6 @@ -54,11 +54,9 @@ jobs: base: main title: Bump version and publish body: See commit message or diff for new version number - + - name: Tag version run: | git checkout workflow-release python scripts/tag_with_current_version.py git push origin --tags - - \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index f9a98ac0d..3679dd06f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -149,4 +149,4 @@ push = false [tool.bumpver.file_patterns] "pyproject.toml" = ['current_version = "{version}"', 'version = "{version}"'] "version.toml" = ['version = "{version}"'] -"cyto_dl/__init__.py" = ['__version__ = "{version}"'] \ No newline at end of file +"cyto_dl/__init__.py" = ['__version__ = "{version}"'] diff --git a/scripts/publish_bumpver_handler.py b/scripts/publish_bumpver_handler.py index b34d367e8..98419cb19 100644 --- a/scripts/publish_bumpver_handler.py +++ b/scripts/publish_bumpver_handler.py @@ -1,9 +1,50 @@ # this file is intended to be called by a github workflow (.github/workflows/publish_to_pypi.yaml) # it makes decisions based on the current version and the component specified for bumping, # which the workflow cannot do + +""" +TESTING: +- add and commit any changes (keep track of this commit hash) +- bumpver update --set-version 1.0.0 + +- python publish_bumpver_handler.py + - expect: ValueError + +- python publish_bumpver_handler.py fake + - expect: ValueError + +- python publish_bumpver_handler.py major + - expect: version updated to 2.0.0 + +- python publish_bumpver_handler.py minor + - expect: version updated to 2.1.0 + +- python publish_bumpver_handler.py patch + - expect: version updated to 2.1.1 + +- python publish_bumpver_handler.py dev + - expect: version updated to 2.1.2.dev0 + +- python publish_bumpver_handler.py dev + - expect: version updated to 2.1.2.dev1 + +- python publish_bumpver_handler.py major + - expect: ValueError + +- python publish_bumpver_handler.py minor + - expect: ValueError + +- python publish_bumpver_handler.py patch + - expect: version updated to 2.1.2 + +- git reset --hard {hash of the commit made at the beginning} +- git tag --delete 1.0.0 2.0.0 2.1.0 2.1.1 2.1.2 2.1.2.dev0 2.1.2.dev1 +""" + import subprocess import sys -from typing import Set, List +from typing import List, Set + import toml @@ -25,29 +66,19 @@ def main(): if len(version_components) == 4: if component == "dev": # increment the dev tag (e.g. 1.0.0.dev0 -> 1.0.0.dev1) - update_output = subprocess.run( - ["bumpver", "update", "--tag-num", "-n"] - ) + update_output = subprocess.run(["bumpver", "update", "--tag-num", "-n"]) elif component == "patch": # finalize the patch by removing dev tag (e.g. 1.0.0.dev1 -> 1.0.0) - update_output = subprocess.run( - ["bumpver", "update", "--tag=final", "-n"] - ) + update_output = subprocess.run(["bumpver", "update", "--tag=final", "-n"]) else: - raise ValueError( - "Cannot update major or minor version while dev version is current" - ) + raise ValueError("Cannot update major or minor version while dev version is current") elif len(version_components) == 3: if component == "dev": # increment patch and begin at dev0 (e.g. 1.0.0 -> 1.0.1.dev0) - update_output = subprocess.run( - ["bumpver", "update", "--patch", "--tag=dev", "-n"] - ) + update_output = subprocess.run(["bumpver", "update", "--patch", "--tag=dev", "-n"]) else: - update_output = subprocess.run( - ["bumpver", "update", f"--{component}", "-n"] - ) + update_output = subprocess.run(["bumpver", "update", f"--{component}", "-n"]) else: raise ValueError( @@ -55,49 +86,8 @@ def main(): ) if update_output.returncode != 0: - raise RuntimeError( - f"bumpver exited with code {update_output.returncode}" - ) + raise RuntimeError(f"bumpver exited with code {update_output.returncode}") if __name__ == "__main__": main() - -""" -TESTING: -- add and commit any changes (keep track of this commit hash) -- bumpver update --set-version 1.0.0 - -- python publish_bumpver_handler.py - - expect: ValueError - -- python publish_bumpver_handler.py fake - - expect: ValueError - -- python publish_bumpver_handler.py major - - expect: version updated to 2.0.0 - -- python publish_bumpver_handler.py minor - - expect: version updated to 2.1.0 - -- python publish_bumpver_handler.py patch - - expect: version updated to 2.1.1 - -- python publish_bumpver_handler.py dev - - expect: version updated to 2.1.2.dev0 - -- python publish_bumpver_handler.py dev - - expect: version updated to 2.1.2.dev1 - -- python publish_bumpver_handler.py major - - expect: ValueError - -- python publish_bumpver_handler.py minor - - expect: ValueError - -- python publish_bumpver_handler.py patch - - expect: version updated to 2.1.2 - -- git reset --hard {hash of the commit made at the beginning} -- git tag --delete 1.0.0 2.0.0 2.1.0 2.1.1 2.1.2 2.1.2.dev0 2.1.2.dev1 -""" \ No newline at end of file diff --git a/scripts/tag_with_current_version.py b/scripts/tag_with_current_version.py index 90990cabd..ea28e6175 100644 --- a/scripts/tag_with_current_version.py +++ b/scripts/tag_with_current_version.py @@ -1,16 +1,15 @@ # This file is intended to be called by a github workflow import subprocess + import toml def main(): version: str = toml.load("pyproject.toml")["project"]["version"] - tag_output: subprocess.CompletedProcess = subprocess.run( - ["git", "tag", f"v{version}"] - ) + tag_output: subprocess.CompletedProcess = subprocess.run(["git", "tag", f"v{version}"]) if tag_output.returncode != 0: raise RuntimeError("failed to tag") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/version.toml b/version.toml index ae111fc09..6739349e1 100644 --- a/version.toml +++ b/version.toml @@ -1,4 +1,4 @@ # -----DO NOT MODIFY THIS FILE----- # This file should only be modified by bumpver, which should in turn only be ran # via a GH Action -version = "0.1.7" \ No newline at end of file +version = "0.1.7" From 8ba86d5e1ae2984941cbd86fbfe864dd7c4aebfd Mon Sep 17 00:00:00 2001 From: Benjamin Morris Date: Mon, 1 Jul 2024 16:23:15 -0700 Subject: [PATCH 3/6] banditignore subprocess --- scripts/publish_bumpver_handler.py | 8 ++++---- scripts/tag_with_current_version.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/publish_bumpver_handler.py b/scripts/publish_bumpver_handler.py index 98419cb19..228a1c353 100644 --- a/scripts/publish_bumpver_handler.py +++ b/scripts/publish_bumpver_handler.py @@ -66,19 +66,19 @@ def main(): if len(version_components) == 4: if component == "dev": # increment the dev tag (e.g. 1.0.0.dev0 -> 1.0.0.dev1) - update_output = subprocess.run(["bumpver", "update", "--tag-num", "-n"]) + update_output = subprocess.run(["bumpver", "update", "--tag-num", "-n"]) #nosec elif component == "patch": # finalize the patch by removing dev tag (e.g. 1.0.0.dev1 -> 1.0.0) - update_output = subprocess.run(["bumpver", "update", "--tag=final", "-n"]) + update_output = subprocess.run(["bumpver", "update", "--tag=final", "-n"]) #nosec else: raise ValueError("Cannot update major or minor version while dev version is current") elif len(version_components) == 3: if component == "dev": # increment patch and begin at dev0 (e.g. 1.0.0 -> 1.0.1.dev0) - update_output = subprocess.run(["bumpver", "update", "--patch", "--tag=dev", "-n"]) + update_output = subprocess.run(["bumpver", "update", "--patch", "--tag=dev", "-n"]) #nosec else: - update_output = subprocess.run(["bumpver", "update", f"--{component}", "-n"]) + update_output = subprocess.run(["bumpver", "update", f"--{component}", "-n"]) #nosec else: raise ValueError( diff --git a/scripts/tag_with_current_version.py b/scripts/tag_with_current_version.py index ea28e6175..4a6b53433 100644 --- a/scripts/tag_with_current_version.py +++ b/scripts/tag_with_current_version.py @@ -6,7 +6,7 @@ def main(): version: str = toml.load("pyproject.toml")["project"]["version"] - tag_output: subprocess.CompletedProcess = subprocess.run(["git", "tag", f"v{version}"]) + tag_output: subprocess.CompletedProcess = subprocess.run(["git", "tag", f"v{version}"]) #nosec if tag_output.returncode != 0: raise RuntimeError("failed to tag") From 7353023a617e806f448443bbc903c32445b0fb3d Mon Sep 17 00:00:00 2001 From: Benjamin Morris Date: Mon, 1 Jul 2024 16:25:43 -0700 Subject: [PATCH 4/6] precommit --- scripts/publish_bumpver_handler.py | 10 ++++++---- scripts/tag_with_current_version.py | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/publish_bumpver_handler.py b/scripts/publish_bumpver_handler.py index 228a1c353..1d8def6d3 100644 --- a/scripts/publish_bumpver_handler.py +++ b/scripts/publish_bumpver_handler.py @@ -66,19 +66,21 @@ def main(): if len(version_components) == 4: if component == "dev": # increment the dev tag (e.g. 1.0.0.dev0 -> 1.0.0.dev1) - update_output = subprocess.run(["bumpver", "update", "--tag-num", "-n"]) #nosec + update_output = subprocess.run(["bumpver", "update", "--tag-num", "-n"]) # nosec elif component == "patch": # finalize the patch by removing dev tag (e.g. 1.0.0.dev1 -> 1.0.0) - update_output = subprocess.run(["bumpver", "update", "--tag=final", "-n"]) #nosec + update_output = subprocess.run(["bumpver", "update", "--tag=final", "-n"]) # nosec else: raise ValueError("Cannot update major or minor version while dev version is current") elif len(version_components) == 3: if component == "dev": # increment patch and begin at dev0 (e.g. 1.0.0 -> 1.0.1.dev0) - update_output = subprocess.run(["bumpver", "update", "--patch", "--tag=dev", "-n"]) #nosec + update_output = subprocess.run( + ["bumpver", "update", "--patch", "--tag=dev", "-n"] + ) # nosec else: - update_output = subprocess.run(["bumpver", "update", f"--{component}", "-n"]) #nosec + update_output = subprocess.run(["bumpver", "update", f"--{component}", "-n"]) # nosec else: raise ValueError( diff --git a/scripts/tag_with_current_version.py b/scripts/tag_with_current_version.py index 4a6b53433..6cfbb90b3 100644 --- a/scripts/tag_with_current_version.py +++ b/scripts/tag_with_current_version.py @@ -6,7 +6,9 @@ def main(): version: str = toml.load("pyproject.toml")["project"]["version"] - tag_output: subprocess.CompletedProcess = subprocess.run(["git", "tag", f"v{version}"]) #nosec + tag_output: subprocess.CompletedProcess = subprocess.run( + ["git", "tag", f"v{version}"] + ) # nosec if tag_output.returncode != 0: raise RuntimeError("failed to tag") From 5dd1ee39d15f705f566e055fa69a926876263954 Mon Sep 17 00:00:00 2001 From: Benjamin Morris Date: Mon, 1 Jul 2024 16:32:07 -0700 Subject: [PATCH 5/6] nosec multiline and imports --- scripts/publish_bumpver_handler.py | 6 +++--- scripts/tag_with_current_version.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/publish_bumpver_handler.py b/scripts/publish_bumpver_handler.py index 1d8def6d3..0b2a51ada 100644 --- a/scripts/publish_bumpver_handler.py +++ b/scripts/publish_bumpver_handler.py @@ -41,7 +41,7 @@ - git tag --delete 1.0.0 2.0.0 2.1.0 2.1.1 2.1.2 2.1.2.dev0 2.1.2.dev1 """ -import subprocess +import subprocess # nosec import sys from typing import List, Set @@ -76,9 +76,9 @@ def main(): elif len(version_components) == 3: if component == "dev": # increment patch and begin at dev0 (e.g. 1.0.0 -> 1.0.1.dev0) - update_output = subprocess.run( + update_output = subprocess.run( # nosec ["bumpver", "update", "--patch", "--tag=dev", "-n"] - ) # nosec + ) else: update_output = subprocess.run(["bumpver", "update", f"--{component}", "-n"]) # nosec diff --git a/scripts/tag_with_current_version.py b/scripts/tag_with_current_version.py index 6cfbb90b3..49feb58e9 100644 --- a/scripts/tag_with_current_version.py +++ b/scripts/tag_with_current_version.py @@ -1,14 +1,14 @@ # This file is intended to be called by a github workflow -import subprocess +import subprocess # nosec import toml def main(): version: str = toml.load("pyproject.toml")["project"]["version"] - tag_output: subprocess.CompletedProcess = subprocess.run( + tag_output: subprocess.CompletedProcess = subprocess.run( # nosec ["git", "tag", f"v{version}"] - ) # nosec + ) if tag_output.returncode != 0: raise RuntimeError("failed to tag") From f4f48f1f0a744a88d284fed976096361ebdd25df Mon Sep 17 00:00:00 2001 From: Benjamin Morris Date: Tue, 2 Jul 2024 14:40:50 -0700 Subject: [PATCH 6/6] run publish on changes to version.toml --- .github/workflows/publish.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f29a1dc18..039be6dae 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,13 +1,13 @@ --- name: publish on: - pull_request: - types: [closed] - branches: [main] + push: + branches: + - main + paths: + - version.toml jobs: publish: - # only publish when the PR is a version bump PR and the pr is merged to main - if: github.event.pull_request.title == 'admin/version-bump' && github.event.pull_request.merged == true runs-on: ubuntu-latest environment: release permissions: