diff --git a/.copier-answers.yml b/.copier-answers.yml index c456fbe..172d0f6 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,6 +1,6 @@ # Autogenerated. Do not edit this by hand, use `copier update`. --- -_commit: 0.5.2 +_commit: 0.6.0 _src_path: https://github.com/lkubb/salt-extension-copier author: Salt Core Team author_email: saltproject@vmware.com diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b529c1..e6298d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,13 +47,53 @@ jobs: - pre-commit uses: ./.github/workflows/docs-action.yml + check-prepare-release: + name: Check if we can prepare release PR + if: >- + github.event_name == 'push' && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + needs: + - docs + - test + runs-on: ubuntu-24.04 + outputs: + news-fragments-available: ${{ steps.check-available.outputs.available }} + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Check if news fragments are available + id: check-available + run: | + if [ -n "$(find changelog -type f -not -name '.*' -print -quit)" ]; then + echo "available=1" >> "$GITHUB_OUTPUT" + else + echo "available=0" >> "$GITHUB_OUTPUT" + fi + + prepare-release: + name: Prepare Release PR + if: ${{ needs.check-prepare-release.outputs.news-fragments-available == '1' }} + needs: + - check-prepare-release + - docs + - test + permissions: + contents: write + pull-requests: write + uses: ./.github/workflows/prepare-release-action.yml + deploy-docs: name: Deploy Docs uses: ./.github/workflows/deploy-docs-action.yml - # Only build doc deployments from the default branch of the repo and never for PRs. + # Only build doc deployments from the default branch of the repo and never for PRs, + # unless the triggering event was the release PR being merged. if: >- - github.event_name != 'pull_request' && inputs.deploy-docs && + ( + github.event_name != 'pull_request' || + inputs.release + ) && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) needs: - docs diff --git a/.github/workflows/deploy-package-action.yml b/.github/workflows/deploy-package-action.yml index 9f1d6ba..3a702d7 100644 --- a/.github/workflows/deploy-package-action.yml +++ b/.github/workflows/deploy-package-action.yml @@ -30,7 +30,7 @@ jobs: path: dist - name: Publish distribution to Test PyPI - uses: pypa/gh-action-pypi-publish@c44d2f0e52f028349e3ecafbf7f32561da677277 # v1.10.3 + uses: pypa/gh-action-pypi-publish@1bb664cc2ddedbbfdde43d4ac135d5836b7bf40f # v1.11.0 if: ${{ inputs.test }} with: password: ${{ secrets.TEST_PYPI_API_TOKEN }} @@ -41,14 +41,14 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh release create "$GITHUB_REF_NAME" \ + gh release create "v${{ inputs.version }}" \ --repo="$GITHUB_REPOSITORY" \ --title="${GITHUB_REPOSITORY#*/} ${{ inputs.version }}" \ --generate-notes \ dist/* - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@c44d2f0e52f028349e3ecafbf7f32561da677277 # v1.10.3 + uses: pypa/gh-action-pypi-publish@1bb664cc2ddedbbfdde43d4ac135d5836b7bf40f # v1.11.0 if: ${{ !inputs.test }} with: password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/docs-action.yml b/.github/workflows/docs-action.yml index 8d284ec..9e7775d 100644 --- a/.github/workflows/docs-action.yml +++ b/.github/workflows/docs-action.yml @@ -10,12 +10,12 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set up Python 3.10 For Nox - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: "3.10" diff --git a/.github/workflows/get-changed-files.yml b/.github/workflows/get-changed-files.yml index 3d61e7e..79e9498 100644 --- a/.github/workflows/get-changed-files.yml +++ b/.github/workflows/get-changed-files.yml @@ -17,7 +17,7 @@ jobs: changed-files: ${{ toJSON(steps.changed-files.outputs) }} steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get Changed Files id: changed-files diff --git a/.github/workflows/package-action.yml b/.github/workflows/package-action.yml index 80b656c..472fa18 100644 --- a/.github/workflows/package-action.yml +++ b/.github/workflows/package-action.yml @@ -14,12 +14,12 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set up Python 3.10 - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: "3.10" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 403a722..64a9470 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -10,8 +10,42 @@ on: pull_request: jobs: + # After merging the release PR, we don't want to trigger + # this workflow in addition to the Tagged Releases one. + # This pauses CI on pushes to the main branch completely. + check_release_in_progress: + name: Skip CI While Releasing + runs-on: ubuntu-24.04 + if: github.event_name == 'push' + outputs: + count: ${{ steps.workflow_count.outputs.count }} + + steps: + - name: Count Running Release Workflows Triggered by Automated PR + id: workflow_count + env: + GH_TOKEN: ${{ github.token }} + run: | + count="$(gh run list \ + --repo "$GITHUB_REPOSITORY" \ + --event pull_request \ + --branch release/auto \ + --workflow 'Tagged Releases' \ + --json status \ + --jq 'map(select(.status == ("queued","in_progress"))) | length')" + echo "count=$count" >> "$GITHUB_OUTPUT" + call_central_workflow: name: CI + needs: + - check_release_in_progress + if: > + always() && + github.event_name != 'push' || + ( + needs.check_release_in_progress.result == 'success' && + needs.check_release_in_progress.outputs.count == '0' + ) uses: ./.github/workflows/ci.yml with: deploy-docs: true @@ -19,4 +53,4 @@ jobs: contents: write id-token: write pages: write - pull-requests: read + pull-requests: write diff --git a/.github/workflows/pre-commit-action.yml b/.github/workflows/pre-commit-action.yml index cbdfdb4..813992c 100644 --- a/.github/workflows/pre-commit-action.yml +++ b/.github/workflows/pre-commit-action.yml @@ -14,7 +14,7 @@ jobs: name: Pre-Commit runs-on: ubuntu-24.04 container: - image: docker.io/library/python:3.10.15-slim-bookworm@sha256:1eb5d76bf3e9e612176ebf5eadf8f27ec300b7b4b9a99f5856f8232fd33aa16e + image: docker.io/library/python:3.10.15-slim-bookworm@sha256:eb9ca77b1a0ffbde84c1dc333beb3490a2638813cc25a339f8575668855b9ff1 steps: - name: Install System Deps @@ -23,7 +23,7 @@ jobs: apt-get install -y enchant-2 git gcc make zlib1g-dev libc-dev libffi-dev g++ libxml2 libxml2-dev libxslt-dev libcurl4-openssl-dev libssl-dev libgnutls28-dev git config --global --add safe.directory "$(pwd)" - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install Pre-Commit run: | diff --git a/.github/workflows/prepare-release-action.yml b/.github/workflows/prepare-release-action.yml new file mode 100644 index 0000000..f3c8f83 --- /dev/null +++ b/.github/workflows/prepare-release-action.yml @@ -0,0 +1,65 @@ +--- +name: Prepare Release PR + +on: + workflow_call: + workflow_dispatch: + inputs: + version: + description: Override the autogenerated version. + required: false + default: '' + type: string + +jobs: + update-release: + name: Render changelog and create/update PR + runs-on: ubuntu-24.04 + if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Python 3.10 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: '3.10' + + - name: Install project + run: | + python -m pip install --upgrade pip + python -m pip install '.[changelog]' pre-commit + + - name: Get next version + if: github.event_name == 'push' || inputs.version == '' + id: next-version + run: echo "version=$(python tools/version.py next)" >> "$GITHUB_OUTPUT" + + - name: Update CHANGELOG.md + env: + NEXT_VERSION: ${{ (github.event_name == 'workflow_dispatch' && inputs.version != '') && inputs.version || steps.next-version.outputs.version }} + run: towncrier build --yes --version "${NEXT_VERSION}" + + - name: Run pre-commit once to remove trailing whitespace + run: | + python -m pre_commit run --files=CHANGELOG.md || true + + - name: Create/update release PR + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 + with: + commit-message: Release v${{ (github.event_name == 'workflow_dispatch' && inputs.version != '') && inputs.version || steps.next-version.outputs.version }} + branch: release/auto + sign-commits: true + title: Release v${{ (github.event_name == 'workflow_dispatch' && inputs.version != '') && inputs.version || steps.next-version.outputs.version }} + body: | + This automated PR builds the latest changelog. When merged, a new release is published automatically. + + Before merging, please ensure it's based on the most recent default branch HEAD. + + If you want to rebuild this PR with a custom version or the current date, you can also trigger the corresponding workflow manually in `Actions` > `Prepare Release PR` > `Run workflow`. + + You can still follow the manual release procedure outlined in: https://salt-extensions.github.io/salt-extension-copier/topics/publishing.html diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index bb0bfa2..d673287 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -5,30 +5,124 @@ on: push: tags: - "v*" # Only tags starting with "v" for "v1.0.0", etc. + pull_request: + types: + - closed + paths: + - CHANGELOG.md jobs: - get_tag_version: + get_version_tag: + name: Extract version from tag runs-on: ubuntu-24.04 + if: github.event_name == 'push' outputs: - version: ${{ steps.get_version.outputs.version }} + version: ${{ steps.get_version_tag.outputs.version }} + steps: - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Extract tag name - id: get_version + id: get_version_tag run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT" + - name: Ensure changelog was rendered + run: | + test "${{ steps.get_version_tag.outputs.version }}" = "$(python tools/version.py)" && \ + test -z "$(find changelog -type f -not -name '.*' -print -quit)" + + close_autopr_on_tag: + name: Close release PR on manual tag + runs-on: ubuntu-24.04 + if: github.event_name == 'push' + needs: + - get_version_tag + + steps: + - name: Find Pull Request + uses: juliangruber/find-pull-request-action@2f36c5fe1abfda4745dfab4f38217ebad8ded4eb # v1.9.0 + id: find-pull-request + with: + branch: release/auto + base: ${{ github.event.repository.default_branch }} + state: open + + - name: Close release PR + if: steps.find-pull-request.outputs.number != '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr close \ + --comment "This release was triggered manually as v${{ needs.get_version_tag.outputs.version }}" \ + --delete-branch \ + --repo "$GITHUB_REPOSITORY" \ + "${{ steps.find-pull-request.outputs.number }}" + + get_version_pr: + name: Extract version from merged release PR + runs-on: ubuntu-24.04 + permissions: + contents: write # To push the new tag. This does not cause a tag event. + + # Only trigger this on closed pull requests if: + # - The originating branch is from the same repository as the one running this workflow. + # - The originating branch is called `release/auto` + # - The PR was merged, not just closed. + # - The PR targeted the default branch of the repository this workflow is running from. + if: >- + github.event_name == 'pull_request' && + github.repository == github.event.pull_request.head.repo.full_name && + github.head_ref == 'release/auto' && + github.event.pull_request.merged == true && + github.base_ref == github.event.repository.default_branch + + outputs: + version: ${{ steps.get_version_pr.outputs.version }} + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Extract version of merged release PR + id: get_version_pr + run: echo "version=$(python tools/version.py)" >> "$GITHUB_OUTPUT" + + - name: Ensure no news fragments are left + run: test -z "$(find changelog -type f -not -path '*/.*' -print -quit)" + + - name: Check extracted version matches PR title + env: + TITLE: ${{ github.event.pull_request.title }} + run: >- + [[ "$TITLE" == "Release v${{ steps.get_version_pr.outputs.version }}" ]] || exit 1 + + - name: Create tag for release + uses: mathieudutour/github-tag-action@d28fa2ccfbd16e871a4bdf35e11b3ad1bd56c0c1 # v6.2 + with: + github_token: ${{ github.token }} + custom_tag: ${{ steps.get_version_pr.outputs.version }} + create_annotated_tag: true + call_central_workflow: - needs: get_tag_version + # Only call the central workflow if either of the above jobs report success. + if: >- + always() && + ( + needs.get_version_tag.result == 'success' || + needs.get_version_pr.result == 'success' + ) + needs: + - get_version_tag + - get_version_pr uses: ./.github/workflows/ci.yml with: deploy-docs: true release: true - version: ${{ needs.get_tag_version.outputs.version }} + version: ${{ github.event_name == 'push' && needs.get_version_tag.outputs.version || needs.get_version_pr.outputs.version }} permissions: contents: write id-token: write pages: write - pull-requests: read + pull-requests: write secrets: inherit diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml index 301f021..03611f7 100644 --- a/.github/workflows/test-action.yml +++ b/.github/workflows/test-action.yml @@ -20,7 +20,7 @@ jobs: - {salt-version: "3007.1", python-version: "3.10"} steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 # coverage: Issue detecting commit SHA @@ -31,7 +31,7 @@ jobs: vault_version: 1.15.4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ matrix.python-version }} @@ -68,7 +68,7 @@ jobs: flags: ${{ steps.codecov-flags.outputs.flags }},project name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-project use_oidc: true - version: v0.7.6 + version: v0.8.0 - name: Upload Tests Code Coverage uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 @@ -79,7 +79,7 @@ jobs: flags: ${{ steps.codecov-flags.outputs.flags }},tests name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-tests use_oidc: true - version: v0.7.6 + version: v0.8.0 - name: Upload Logs if: always() @@ -115,27 +115,15 @@ jobs: - {salt-version: "3007.1", python-version: "3.9"} steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ matrix.python-version }} - - name: Download libeay32.dll - run: | - PY_LOC="$(which python.exe)" - export PY_LOC - echo "${PY_LOC}" - PY_DIR="$(dirname "${PY_LOC}")" - export PY_DIR - echo "${PY_DIR}" - curl https://repo.saltproject.io/windows/dependencies/64/libeay32.dll --output "${PY_DIR}/libeay32.dll" - ls -l "${PY_DIR}" - shell: bash - - name: Install Nox run: | python -m pip install --upgrade pip @@ -174,7 +162,7 @@ jobs: flags: ${{ steps.codecov-flags.outputs.flags }},project name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-project use_oidc: true - version: v0.7.6 + version: v0.8.0 - name: Upload Tests Code Coverage uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 @@ -185,7 +173,7 @@ jobs: flags: ${{ steps.codecov-flags.outputs.flags }},tests name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-tests use_oidc: true - version: v0.7.6 + version: v0.8.0 - name: Upload Logs if: always() @@ -221,12 +209,12 @@ jobs: - {salt-version: "3007.1", python-version: "3.10"} steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ matrix.python-version }} @@ -263,7 +251,7 @@ jobs: flags: ${{ steps.codecov-flags.outputs.flags }},project name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-project use_oidc: true - version: v0.7.6 + version: v0.8.0 - name: Upload Tests Code Coverage uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 @@ -274,7 +262,7 @@ jobs: flags: ${{ steps.codecov-flags.outputs.flags }},tests name: ${{ runner.os }}-Py${{ matrix.python-version }}-Salt${{ matrix.salt-version }}-tests use_oidc: true - version: v0.7.6 + version: v0.8.0 - name: Upload Logs if: always() diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91ddbd2..b61a09d 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,7 +82,7 @@ repos: exclude: src/saltext/vault/version.py - repo: https://github.com/adamchainz/blacken-docs - rev: d4e2940d27621c7f20215459be05703947618b7b # 1.19.0 + rev: 78a9dcbecf4f755f65d1f3dec556bc249d723600 # 1.19.1 hooks: - id: blacken-docs args: [--skip-errors] @@ -124,7 +124,7 @@ repos: require_serial: true additional_dependencies: - nox==2024.10.9 - - uv==0.4.22 # Makes this hook much faster + - uv==0.4.29 # Makes this hook much faster - id: nox alias: lint-tests @@ -135,7 +135,7 @@ repos: require_serial: true additional_dependencies: - nox==2024.10.9 - - uv==0.4.22 # Makes this hook much faster + - uv==0.4.29 # Makes this hook much faster - repo: https://github.com/Mateusz-Grzelinski/actionlint-py rev: 27445053da613c660ed5895d9616662059a53ca7 # v1.7.3.17 diff --git a/noxfile.py b/noxfile.py index 744321a..94cc665 100755 --- a/noxfile.py +++ b/noxfile.py @@ -30,7 +30,7 @@ SKIP_REQUIREMENTS_INSTALL = os.environ.get("SKIP_REQUIREMENTS_INSTALL", "0") == "1" EXTRA_REQUIREMENTS_INSTALL = os.environ.get("EXTRA_REQUIREMENTS_INSTALL") -COVERAGE_REQUIREMENT = os.environ.get("COVERAGE_REQUIREMENT") or "coverage==7.6.3" +COVERAGE_REQUIREMENT = os.environ.get("COVERAGE_REQUIREMENT") or "coverage==7.6.4" SALT_REQUIREMENT = os.environ.get("SALT_REQUIREMENT") or "salt>=3006" if SALT_REQUIREMENT == "salt==master": SALT_REQUIREMENT = "git+https://github.com/saltstack/salt.git@master" diff --git a/pyproject.toml b/pyproject.toml index 1c82184..e93cf05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,6 +120,11 @@ underlines = ["", "", ""] title_format = "## {version} ({project_date})" issue_format = "[#{issue}](https://github.com/salt-extensions/saltext-vault/issues/{issue})" +[[tool.towncrier.type]] +directory = "breaking" +name = "Breaking changes" +showcontent = true + [[tool.towncrier.type]] directory = "removed" name = "Removed" diff --git a/tools/version.py b/tools/version.py new file mode 100644 index 0000000..d79b1f7 --- /dev/null +++ b/tools/version.py @@ -0,0 +1,92 @@ +""" +Very simple heuristic to generate the next version number +based on the current changelog news fragments. + +This looks for the most recent version by parsing the +CHANGELOG.md file and increments a specific part, +depending on the fragment types present and their contents. + +Major bumps are caused by: + * files named `.removed.md` + * files named `.breaking.md` + * files containing `BREAKING:` + +Minor bumps are caused by: + * files named `.added.md` + +Otherwise, only the patch version is bumped. +""" + +import re +import sys +from pathlib import Path + +PROJECT_ROOT = Path(".").resolve() +CHANGELOG_DIR = PROJECT_ROOT / "changelog" +CHANGELOG_FILE = PROJECT_ROOT / "CHANGELOG.md" + + +class Version: + def __init__(self, version): + match = re.search(r"v?(?P[0-9]+(?:\.[0-9]+)*)", version) + if not match: + raise ValueError(f"Invalid version: '{version}'") + self.release = tuple(int(i) for i in match.group("release").split(".")) + + @property + def major(self): + return self._ret(0) + + @property + def minor(self): + return self._ret(1) + + @property + def patch(self): + return self._ret(2) + + def __str__(self): + return ".".join(str(i) for i in self.release) + + def _ret(self, cnt): + try: + return self.release[cnt] + except IndexError: + return 0 + + +def last_release(): + for line in CHANGELOG_FILE.read_text(encoding="utf-8").splitlines(): + if line.startswith("## "): + return Version(line.split(" ")[1]) + return Version("0.0.0") + + +def get_next_version(last): + major = minor = False + + for fragment in CHANGELOG_DIR.glob("[!.]*"): + name = fragment.name.lower() + if ".added" in name: + minor = True + elif ".breaking" in name or ".removed" in name: + major = True + break + if "breaking:" in fragment.read_text(encoding="utf-8").lower(): + major = True + break + if major: + return Version(f"{last.major + 1}.0.0") + if minor: + return Version(f"{last.major}.{last.minor + 1}.0") + return Version(f"{last.major}.{last.minor}.{last.patch + 1}") + + +if __name__ == "__main__": + try: + if sys.argv[1] == "next": + print(get_next_version(last_release())) + raise SystemExit(0) + except IndexError: + pass + print(last_release())