diff --git a/.github/renovate.json b/.github/renovate.json index f78f8302..3ed3ef3a 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -12,10 +12,11 @@ "packageRules": [ { "additionalBranchPrefix": "{{#if (equals manager 'github-actions')}}gh-actions{{else}}{{categories}}{{/if}}-deps/", - "description": "Set the branch prefix for all updates", + "description": "Set the branch prefix and minimum release age for all updates", "matchPackageNames": [ "*" - ] + ], + "minimumReleaseAge": "5 days" }, { "addLabels": [ diff --git a/.github/workflows/package-release.yml b/.github/workflows/package-release.yml index 881da477..913e88a9 100644 --- a/.github/workflows/package-release.yml +++ b/.github/workflows/package-release.yml @@ -13,7 +13,7 @@ on: major for non-backward compatible changes. options: [patch, minor, major] schedule: - - cron: 0 16 * * 2 + - cron: 0 16 1-7 * 2 # Run at 16:00 UTC on the first Tuesday of each month concurrency: group: pypi jobs: diff --git a/.github/workflows/test-actions.yml b/.github/workflows/test-actions.yml index de8a77b2..f809d3df 100644 --- a/.github/workflows/test-actions.yml +++ b/.github/workflows/test-actions.yml @@ -30,6 +30,8 @@ jobs: fi test-find_unreleased_changelog_items: runs-on: ubuntu-latest + env: + UNIT_TESTING_FIND_UNRELEASED_CHANGELOG_ITEMS_ACTION: true steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Overwrite CHANGELOG.md with dummy data diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d15e951..4f465ab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Things to be included in the next release go here. - Bumped dependency versions. - Changed the `_reusable-update-python-and-pre-commit-dependencies.yml` workflow to no longer only work on PRs from Dependabot, users will now need to apply any conditional login in the calling workflow. - Updated the `_reusable-update-python-and-pre-commit-dependencies.yml` workflow to allow using [`renovate`](https://docs.renovatebot.com/) instead of Dependabot to update dependencies. +- Updated the `find_unreleased_changelog_items` action to check for merged PRs since the last release and fail if none are found. --- diff --git a/actions/find_unreleased_changelog_items/main.py b/actions/find_unreleased_changelog_items/main.py index 9d48c27c..e231d2f6 100644 --- a/actions/find_unreleased_changelog_items/main.py +++ b/actions/find_unreleased_changelog_items/main.py @@ -77,6 +77,7 @@ def main() -> None: # Set the filepaths for the template files template_changelog_filepath = pathlib.Path(filepath_for_previous_changelog) template_release_notes_filepath = pathlib.Path(filepath_for_previous_release_notes) + root_dir = pathlib.Path.cwd() release_notes_content = "" found_entries = False @@ -109,6 +110,17 @@ def main() -> None: msg = f"No unreleased entries were found in {CHANGELOG_FILE}." raise SystemExit(msg) + # Check for merged PRs since the last release + run_cmd_in_subprocess( + f'git config --global --add safe.directory "{root_dir.resolve().as_posix()}"' + ) + commit_messages = get_commit_messages(since_tag=get_latest_tag()) + pr_regex = re.compile(r"\(#\d+\)$") + pr_descriptions = "\n".join([f"- {msg}" for msg in commit_messages if pr_regex.search(msg)]) + if not pr_descriptions and not os.getenv("UNIT_TESTING_FIND_UNRELEASED_CHANGELOG_ITEMS_ACTION"): + msg = "No PRs have been merged since the last release." + raise SystemExit(msg) + # Copy the files to the correct location shutil.copy(CHANGELOG_FILE, template_changelog_filepath) with template_release_notes_filepath.open("w", encoding="utf-8") as template_release_notes: @@ -117,14 +129,6 @@ def main() -> None: # If running in GitHub Actions, and the release_level is set, send the release level and # incoming changes to the GitHub Summary if release_level: - root_dir = pathlib.Path.cwd() - run_cmd_in_subprocess( - f'git config --global --add safe.directory "{root_dir.resolve().as_posix()}"' - ) - commit_messages = get_commit_messages(since_tag=get_latest_tag()) - - pr_regex = re.compile(r"\(#\d+\)$") - pr_descriptions = "\n".join([f"- {msg}" for msg in commit_messages if pr_regex.search(msg)]) summary_contents = ( f"## Workflow Inputs\n- release-level: {release_level}\n" f"## PRs Merged Since Last Release\n{pr_descriptions}\n" diff --git a/actions/find_unreleased_changelog_items/readme.md b/actions/find_unreleased_changelog_items/readme.md index 23be9324..9d42251e 100644 --- a/actions/find_unreleased_changelog_items/readme.md +++ b/actions/find_unreleased_changelog_items/readme.md @@ -2,7 +2,9 @@ This action will parse the repository's `CHANGELOG.md` file to determine if there are any unreleased items. It will fail if it cannot find any unreleased -items, as this means that the package is not ready for a new release. +items, as this means that the package is not ready for a new release. This action will also +fail if it cannot find any merged PRs since the last release, as this also means that the +package is not ready for a new release. This action will populate two files in the [`python-semantic-release` templates directory](https://python-semantic-release.readthedocs.io/en/latest/configuration.html#config-changelog-template-dir). @@ -13,7 +15,7 @@ will be used to fill in the GitHub Release Notes. > [!IMPORTANT] > This action requires that the `pyproject.toml` and `CHANGELOG.md` files exist in the -> current working directory. +> current working directory and that all tags are fetched from the remote repository. > [!IMPORTANT] > This action requires the `CHANGELOG.md` file to be in a format that is based on @@ -48,6 +50,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + with: + fetch-depth: 0 + fetch-tags: true - uses: tektronix/python-package-ci-cd/actions/find_unreleased_changelog_items@v1.2.0 with: release-level: ${{ inputs.release-level }} # optional diff --git a/tests/test_find_unreleased_changelog_items.py b/tests/test_find_unreleased_changelog_items.py index b6b6f103..9ac474ee 100644 --- a/tests/test_find_unreleased_changelog_items.py +++ b/tests/test_find_unreleased_changelog_items.py @@ -137,6 +137,31 @@ def test_main_no_unreleased_entries( main() +def test_main_with_no_merged_prs( + mock_env_vars: None, # noqa: ARG001 + mock_changelog_file: Path, # noqa: ARG001 + fake_process: FakeProcess, +) -> None: + """Test the main function when unreleased entries are found. + + Args: + mock_env_vars: Mock the environment variables. + mock_changelog_file: Mock the changelog file. + fake_process: The fake_process fixture, used to register commands that will be mocked. + """ + fake_process.register( # pyright: ignore[reportUnknownMemberType] + shlex.split("git log v1.0.0..HEAD --pretty=format:%s"), + stdout=b"Initial commit\n", + ) + with fake_process.context() as nested_process: + nested_process.register( # pyright: ignore[reportUnknownMemberType] + shlex.split("git log v1.0.0..HEAD --pretty=format:%s"), + stdout=b"Initial commit\n", + ) + with pytest.raises(SystemExit, match="No PRs have been merged since the last release\\."): + main() + + def test_main_with_unreleased_entries( mock_env_vars: None, # noqa: ARG001 mock_changelog_file: Path,