diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 3161cb209..bb0921032 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -13,6 +13,7 @@ updates: include: "scope" labels: - dependencies + - dependabot open-pull-requests-limit: 10 rebase-strategy: auto versioning-strategy: "increase-if-necessary" @@ -27,6 +28,7 @@ updates: prefix: "ci" labels: - dependencies + - dependabot rebase-strategy: auto groups: github-actions: diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 68c4b43eb..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,58 +0,0 @@ -# Configuration for probot-stale # -# CAO: https://github.com/probot/stale/tree/4232daafc73492864b559b55c9cf2689d19d5b23 # -# ================================================================================== # -# Rule summary -# ---------------------------------------------------------------------------------- # -# Comment & mark 90-day old issues as stale -# Close stalled issues after 7 days -# Comment & mark 60-day old PR as stale -# Close stalled PRs after 10 days -# Any issue/pr with a planned milestone is exempt -# Issues/PRs with a confirmed label are exempt -# ================================================================================== # -# See repo url for descriptions of settings - -# ALL -staleLabel: stale -limitPerRun: 30 # numActions/hour - - -issues: - daysUntilStale: 90 - daysUntilClose: 7 - exemptProjects: false - exemptMilestones: true - exemptAssignees: false - exemptLabels: - - confirmed - - help-wanted - markComment: > - This issue is stale because it has been open 90 days with no recent activity. - It will be closed in 7 days, if no further activity occurs. Thank you for - your contributions. - unmarkComment: > - Thank you for the update and contribution! The stale label has been removed - and this issue will not be closed at this time. - closeComment: > - This issue was closed because activity was dormant for 97 days. - - -pulls: - daysUntilStale: 60 - daysUntilClose: 10 - exemptProjects: false - exemptMilestones: true - exemptAssignees: false - exemptLabels: - - confirmed - # Ignore PRs opened by Dependabot - - dependencies - markComment: > - This PR is stale because it has been open 60 days with no recent activity. - It will be closed in 10 days, if no further activity occurs. Thank you for - your contributions. - unmarkComment: > - Thank you for the update and contribution! The stale label has been removed - and this PR will not be closed at this time. - closeComment: > - This PR was closed because activity was dormant for 70 days. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bdab128aa..1cd893046 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,10 +20,12 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - uses: actions/cache@v4 with: path: ~/.cache/pip @@ -33,6 +35,7 @@ jobs: - name: Install dependencies run: | + python -m pip install --upgrade pip setuptools wheel python -m pip install .[test] python -m pip install pytest-github-actions-annotate-failures @@ -44,13 +47,17 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set up Python 3.8 uses: actions/setup-python@v5 with: python-version: 3.8 + - name: Install mypy & dev packages run: | + python -m pip install --upgrade pip setuptools wheel python -m pip install ".[dev, mypy]" + - name: ruff run: | python -m ruff check . \ @@ -58,6 +65,7 @@ jobs: --diff \ --show-source \ --exit-non-zero-on-fix + - name: mypy run: | python -m mypy --ignore-missing-imports semantic_release @@ -83,7 +91,9 @@ jobs: uses: actions/checkout@v4 - name: Install Ruff - run: python -m pip install ".[dev]" + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install ".[dev]" - name: Format run: | @@ -122,6 +132,7 @@ jobs: with: fetch-depth: 0 ref: ${{ github.ref_name }} + - name: Python Semantic Release id: release uses: ./ diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 72973afd2..b2d179487 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -17,10 +17,12 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - uses: actions/cache@v4 with: path: ~/.cache/pip @@ -30,6 +32,7 @@ jobs: - name: Install dependencies run: | + python -m pip install --upgrade pip setuptools wheel python -m pip install .[test] python -m pip install pytest-github-actions-annotate-failures @@ -41,13 +44,17 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set up Python 3.8 uses: actions/setup-python@v5 with: python-version: 3.8 + - name: Install mypy & dev packages run: | + python -m pip install --upgrade pip setuptools wheel python -m pip install ".[dev, mypy]" + - name: ruff run: | python -m ruff check . \ @@ -66,4 +73,5 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - uses: wagoid/commitlint-github-action@v5 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..207a6c61d --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,45 @@ +name: 'Stale Bot' +on: + schedule: + # Execute Daily at 7:15 AM UTC + - cron: '15 7 * * *' + +# Default token permissions = None +permissions: {} + + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + pull-requests: write + steps: + - uses: actions/stale@v9 + with: + # default: 30, GitHub Actions API Rate limit is 1000/hr + operations-per-run: 200 + exempt-all-milestones: true + # exempt-all-assignees: false (default) + stale-issue-label: stale + days-before-issue-stale: 90 + days-before-issue-close: 7 + exempt-issue-labels: confirmed, help-wanted + stale-issue-message: > + This issue is stale because it has not been confirmed or planned by the maintainers + and has been open 90 days with no recent activity. It will be closed in 7 days, + if no further activity occurs. Thank you for your contributions. + close-issue-message: > + This issue was closed because activity was dormant for 97 days. + # PR Configurations + stale-pr-label: stale + days-before-pr-stale: 60 + days-before-pr-close: 10 + exempt-pr-labels: confirmed, dependabot + stale-pr-message: > + This PR is stale because it has not been confirmed or planned by the maintainers + and had been open 60 days with no recent activity. It will be closed in 10 days, + if no further activity occurs. Thank you for your contributions. + close-pr-message: > + This PR was closed because activity was dormant for 70 days. diff --git a/CHANGELOG.md b/CHANGELOG.md index fb8217120..9180c34df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,96 @@ +## v9.4.0 (2024-03-31) + +### Build + +* build(deps-dev): bump responses from 0.24 to 0.25.0 (#842) + +Bumps [responses](https://github.com/getsentry/responses) from 0.24 to 0.25.0. +- [Release notes](https://github.com/getsentry/responses/releases) +- [Changelog](https://github.com/getsentry/responses/blob/master/CHANGES) +- [Commits](https://github.com/getsentry/responses/compare/0.24.0...0.25.0) + +--- +updated-dependencies: +- dependency-name: responses + dependency-type: direct:production + update-type: version-update:semver-minor +... + +Signed-off-by: dependabot[bot] <support@github.com> +Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ([`a1b2af6`](https://github.com/python-semantic-release/python-semantic-release/commit/a1b2af6272b362afe5334772f81a4be779be7ba6)) + +* build(deps-build): resolve build deps versions for `python3.12` ([`075daa4`](https://github.com/python-semantic-release/python-semantic-release/commit/075daa4205283414ea5e370da5e35690de12c9ab)) + +* build(deps-dev): bump responses from 0.23.3 to 0.24.1 ([`9210933`](https://github.com/python-semantic-release/python-semantic-release/commit/9210933be10532baa979e381126da4a477e82e2b)) + +* build(deps-dev): bump sphinxcontrib-apidoc from 0.3.0 to 0.5.0 ([`69f163b`](https://github.com/python-semantic-release/python-semantic-release/commit/69f163baefad6f45e3537814cae2be2481e3488a)) + +* build(deps-dev): bump sphinx-autobuild from 2021.03.14 to 2024.2.4 ([`9d30877`](https://github.com/python-semantic-release/python-semantic-release/commit/9d30877b8874a02056f2dee1e2f64c32efda4dc1)) + +* build(deps-dev): update pytest-cov requirement from ~=4.0 to ~=5.0 (#873) + +Updates the requirements on `pytest-cov` to permit the latest version. +- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) +- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v4.0.0...v5.0.0) + +--- +updated-dependencies: +- dependency-name: pytest-cov + dependency-type: direct:production +... + +Signed-off-by: dependabot[bot] <support@github.com> +Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ([`2ca6459`](https://github.com/python-semantic-release/python-semantic-release/commit/2ca6459131f677bffead21127f1feb05ae74b762)) + +* build(deps-dev): bump ruff from 0.3.3 to 0.3.4 (#872) + +Bumps [ruff](https://github.com/astral-sh/ruff) from 0.3.3 to 0.3.4. +- [Release notes](https://github.com/astral-sh/ruff/releases) +- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) +- [Commits](https://github.com/astral-sh/ruff/compare/v0.3.3...v0.3.4) + +--- +updated-dependencies: +- dependency-name: ruff + dependency-type: direct:production + update-type: version-update:semver-patch +... + +Signed-off-by: dependabot[bot] <support@github.com> +Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ([`6d7df6d`](https://github.com/python-semantic-release/python-semantic-release/commit/6d7df6d81b8775acac90956e5d8686460e6c2149)) + +### Chore + +* chore(stalebot): refactor to use CI action for stale issue/pr evaluation ([`a352050`](https://github.com/python-semantic-release/python-semantic-release/commit/a352050d506947db6890f5cc0d964e4a3850949d)) + +### Ci + +* ci(github): always update base env packages `pip`, `setuptools`, `wheel` ([`4748435`](https://github.com/python-semantic-release/python-semantic-release/commit/47484356569274d78508688521519972beae609f)) + +### Feature + +* feat(gitea): derives gitea api domain from base domain when unspecified (#675) + +* test(gitea): add test of custom server path & custom api domain + +* feat(gitea): derives gitea api domain from base domain when unspecified + +* refactor(hvcs-gitea): uniformly handle protocol prefixes + +--------- + +Co-authored-by: codejedi365 <codejedi365@gmail.com> ([`2ee3f8a`](https://github.com/python-semantic-release/python-semantic-release/commit/2ee3f8a918d2e5ea9ab64df88f52e62a1f589c38)) + +### Style + +* style: beautify 2ee3f8a918d2e5ea9ab64df88f52e62a1f589c38 ([`8b4fd3e`](https://github.com/python-semantic-release/python-semantic-release/commit/8b4fd3eab052cd1694274e0e6d8eaf77b658474d)) + +* style(deps): improve readability & flexibility of dependencies ([`8fdd582`](https://github.com/python-semantic-release/python-semantic-release/commit/8fdd5827fa5ea0140e6373060be14780d44bcf0f)) + + ## v9.3.1 (2024-03-24) ### Build diff --git a/pyproject.toml b/pyproject.toml index c562bc92c..fe6da67f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,12 @@ # Ref: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ # and https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html [build-system] -requires = ["setuptools>=61.0.0", "wheel"] +requires = ["setuptools ~= 69.0", "wheel ~= 0.42"] build-backend = "setuptools.build_meta" [project] name = "python-semantic-release" -version = "9.3.1" +version = "9.4.0" description = "Automatic Semantic Versioning for Python projects" requires-python = ">=3.8" license = { text = "MIT" } @@ -22,18 +22,18 @@ classifiers = [ readme = "README.rst" authors = [{ name = "Rolf Erik Lekang", email = "me@rolflekang.com" }] dependencies = [ - "click>=8,<9", - "click-option-group~=0.5", - "gitpython>=3.0.8,<4", - "requests>=2.25,<3", - "jinja2>=3.1.2,<4", - "python-gitlab>=2,<5", - "tomlkit~=0.11", - "dotty-dict>=1.3.0,<2", - "importlib-resources>=5.7,<7", - "pydantic>=2,<3", - "rich>=12.5.1", - "shellingham>=1.5.0.post1", + "click ~= 8.0", + "click-option-group ~= 0.5", + "gitpython ~= 3.0", + "requests ~= 2.25", + "jinja2 ~= 3.1", + "python-gitlab ~= 4.0", + "tomlkit ~= 0.11", + "dotty-dict ~= 1.3", + "importlib-resources ~= 6.0", + "pydantic ~= 2.0", + "rich ~= 12.5", + "shellingham ~= 1.5", ] [project.scripts] @@ -49,27 +49,34 @@ repository = "http://github.com/python-semantic-release/python-semantic-release. [project.optional-dependencies] docs = [ - "Sphinx<=6.0.0", - "sphinxcontrib-apidoc==0.3.0", - "sphinx-autobuild==2021.03.14", - "furo>=2023.3.27", + "Sphinx ~= 6.0", + "sphinxcontrib-apidoc == 0.5.0", + "sphinx-autobuild == 2024.2.4", + "furo ~= 2023.3", ] test = [ - "coverage[toml]>=6,<8", - "pytest>=7,<8", - "pytest-env~=1.0", - "pytest-xdist>=2,<4", - "pytest-mock>=3,<4", - "pytest-lazy-fixture~=0.6.3", - "pytest-cov>=4,<5", - "pytest-pretty>=1.2.0,<2", - "pytest-clarity>=1.0.1", - "responses==0.23.3", - "requests-mock>=1.10.0,<2", - "types-pytest-lazy-fixture>=0.6.3.3", + "coverage[toml] ~= 7.0", + "pytest ~= 7.0", + "pytest-env ~= 1.0", + "pytest-xdist ~= 3.0", + "pytest-mock ~= 3.0", + "pytest-lazy-fixture ~= 0.6.3", + "pytest-cov ~= 5.0", + "pytest-pretty ~= 1.2", + "pytest-clarity ~= 1.0", + "responses ~= 0.25.0", + "requests-mock ~= 1.10", + "types-pytest-lazy-fixture ~= 0.6.3", +] +dev = [ + "pre-commit ~= 3.5", + "tox ~= 4.11", + "ruff == 0.3.4" +] +mypy = [ + "mypy == 1.8.0", + "types-requests ~= 2.31.0" ] -dev = ["pre-commit", "tox", "ruff==0.3.3"] -mypy = ["mypy", "types-requests"] [tool.pytest.ini_options] env = [ diff --git a/semantic_release/__init__.py b/semantic_release/__init__.py index 29ae9f614..c3f947e38 100644 --- a/semantic_release/__init__.py +++ b/semantic_release/__init__.py @@ -24,7 +24,7 @@ tags_and_versions, ) -__version__ = "9.3.1" +__version__ = "9.4.0" def setup_hook(argv: list[str]) -> None: diff --git a/semantic_release/hvcs/gitea.py b/semantic_release/hvcs/gitea.py index 23adc3594..00179d3dd 100644 --- a/semantic_release/hvcs/gitea.py +++ b/semantic_release/hvcs/gitea.py @@ -8,6 +8,7 @@ import os from requests import HTTPError +from urllib3.util.url import Url, parse_url from semantic_release.helpers import logged_function from semantic_release.hvcs._base import HvcsBase @@ -49,13 +50,32 @@ def __init__( ) -> None: self._remote_url = remote_url - self.hvcs_domain = hvcs_domain or os.getenv( - "GITEA_SERVER_URL", self.DEFAULT_DOMAIN - ).replace("https://", "") + domain_url = parse_url( + hvcs_domain or os.getenv("GITEA_SERVER_URL", "") or self.DEFAULT_DOMAIN + ) + + # Strip any scheme, query or fragment from the domain + self.hvcs_domain = Url( + host=domain_url.host, port=domain_url.port, path=domain_url.path + ).url.rstrip("/") + + api_domain_parts = parse_url( + hvcs_api_domain + or os.getenv("GITEA_API_URL", "") + or Url( + # infer from Domain url and append the default api path + scheme=domain_url.scheme, + host=self.hvcs_domain, + path=self.DEFAULT_API_PATH, + ).url + ) - self.hvcs_api_domain = hvcs_api_domain or os.getenv( - "GITEA_API_URL", self.DEFAULT_API_DOMAIN - ).replace("https://", "") + # Strip any scheme, query or fragment from the api domain + self.hvcs_api_domain = Url( + host=api_domain_parts.host, + port=api_domain_parts.port, + path=api_domain_parts.path, + ).url.rstrip("/") self.api_url = f"https://{self.hvcs_api_domain}" diff --git a/tests/unit/semantic_release/hvcs/test_gitea.py b/tests/unit/semantic_release/hvcs/test_gitea.py index 9c47d7550..659100eca 100644 --- a/tests/unit/semantic_release/hvcs/test_gitea.py +++ b/tests/unit/semantic_release/hvcs/test_gitea.py @@ -29,9 +29,15 @@ def default_gitea_client(): @pytest.mark.parametrize( - ( - "patched_os_environ, hvcs_domain, hvcs_api_domain, " - "expected_hvcs_domain, expected_hvcs_api_domain" + str.join( + ", ", + [ + "patched_os_environ", + "hvcs_domain", + "hvcs_api_domain", + "expected_hvcs_domain", + "expected_hvcs_api_domain", + ], ), [ ({}, None, None, Gitea.DEFAULT_DOMAIN, Gitea.DEFAULT_API_DOMAIN), @@ -39,29 +45,29 @@ def default_gitea_client(): {"GITEA_SERVER_URL": "https://special.custom.server/vcs/"}, None, None, - "special.custom.server/vcs/", - Gitea.DEFAULT_API_DOMAIN, + "special.custom.server/vcs", + "special.custom.server/vcs/api/v1", ), ( {"GITEA_API_URL": "https://api.special.custom.server/"}, None, None, Gitea.DEFAULT_DOMAIN, - "api.special.custom.server/", + "api.special.custom.server", ), ( {"GITEA_SERVER_URL": "https://special.custom.server/vcs/"}, "https://example.com", None, - "https://example.com", - Gitea.DEFAULT_API_DOMAIN, + "example.com", + "example.com/api/v1", ), ( {"GITEA_API_URL": "https://api.special.custom.server/"}, None, "https://api.example.com", Gitea.DEFAULT_DOMAIN, - "https://api.example.com", + "api.example.com", ), ], ) @@ -90,11 +96,11 @@ def test_gitea_client_init( token=token, ) - assert client.hvcs_domain == expected_hvcs_domain - assert client.hvcs_api_domain == expected_hvcs_api_domain - assert client.api_url == f"https://{client.hvcs_api_domain}" - assert client.token == token - assert client._remote_url == remote_url + assert expected_hvcs_domain == client.hvcs_domain + assert expected_hvcs_api_domain == client.hvcs_api_domain + assert f"https://{expected_hvcs_api_domain}" == client.api_url + assert token == client.token + assert remote_url == client._remote_url assert hasattr(client, "session") assert isinstance(getattr(client, "session", None), Session)