Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion draft-release/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ Input files:
chronological order. The newest entry should contain a header with the
phrase “development version”.
- `VERSION` - a single-source version file.
- `CITATION.cff` - a citation file. (optional)
- `CITATION.cff` - a citation file.

For a repository’s first release, set `version-tag` manually (for
example `v0.1.0`), because conventional-commit version detection may not
have a previous release to compare against.

When you’re ready to draft a new release, [run the workflow
manually](https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/manually-running-a-workflow).
Expand Down
6 changes: 5 additions & 1 deletion draft-release/README.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ Input files:

- `CHANGELOG.md` - a changelog or news file with entries in reverse chronological order. The newest entry should contain a header with the phrase “development version”.
- `VERSION` - a single-source version file.
- `CITATION.cff` - a citation file. (optional)
- `CITATION.cff` - a citation file.

For a repository's first release, set `version-tag` manually (for example
`v0.1.0`), because conventional-commit version detection may not have a
previous release to compare against.

When you're ready to draft a new release,
[run the workflow manually](https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/manually-running-a-workflow). After the workflow completes, there will be a new draft release that you can review and choose to publish.
Expand Down
1 change: 1 addition & 0 deletions draft-release/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ runs:
- name: Get current and next versions
id: semver
uses: ietf-tools/semver-action@v1
continue-on-error: true
with:
token: ${{ inputs.github-token }}
branch: ${{ github.ref_name }}
Expand Down
47 changes: 41 additions & 6 deletions src/ccbr_actions/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,23 @@ def prepare_draft_release(
changelog_filepath = path_resolve(changelog_filepath)
version_filepath = path_resolve(version_filepath)
citation_filepath = path_resolve(citation_filepath)
assert all([f.is_file() for f in (changelog_filepath, version_filepath)])
required_files = {
"changelog": changelog_filepath,
"version": version_filepath,
"citation": citation_filepath,
}
missing_required_files = [
f"{name} ({filepath})"
for name, filepath in required_files.items()
if not filepath.is_file()
]
if missing_required_files:
missing_required_files_str = ", ".join(missing_required_files)
raise FileNotFoundError(
"Missing required release file(s): "
f"{missing_required_files_str}. "
"Please create these files or update draft-release inputs."
)

next_version = get_release_version(
next_version_manual=next_version_manual,
Expand All @@ -234,7 +250,7 @@ def prepare_draft_release(
set_output("NEXT_VERSION", next_version)

changelog_lines, next_release_lines = get_changelog_lines(
latest_version_strict=current_version.lstrip("v"),
latest_version_strict=current_version.lstrip("v") if current_version else "",
next_version_strict=next_version_strict,
changelog_filepath=changelog_filepath,
dev_header=dev_header,
Expand Down Expand Up @@ -480,14 +496,27 @@ def get_release_version(
)
else:
next_version = next_version_convco
if not next_version:
raise ValueError(
"Unable to determine next release version. "
"If this is the first release for this repository, provide a manual next version "
"(draft-release input: version-tag)."
)
if not is_strict_semver(next_version, with_leading_v=with_leading_v):
raise ValueError(
f"Tag {next_version} does not match semantic versioning guidelines.\nView the guidelines here: https://semver.org/"
)
# assert semantic version pattern
check_version_increments_by_one(
current_version, next_version, with_leading_v=with_leading_v
)
if current_version:
if not is_strict_semver(current_version, with_leading_v=with_leading_v):
raise ValueError(
f"Current version {current_version} does not match semantic versioning guidelines.\n"
"If this is the first release for this repository, set current version to blank "
"and provide a manual next version (draft-release input: version-tag)."
)
check_version_increments_by_one(
current_version, next_version, with_leading_v=with_leading_v
)
return next_version


Expand Down Expand Up @@ -549,6 +578,8 @@ def get_changelog_lines(
ValueError: If any of the provided version strings do not match the semantic versioning pattern.
"""
for version in [latest_version_strict, next_version_strict]:
if not version:
continue
if not match_semver(version):
Comment thread
kelly-sovacool marked this conversation as resolved.
Outdated
raise ValueError(
f"Version {version} does not match semantic versioning pattern"
Expand All @@ -560,7 +591,11 @@ def get_changelog_lines(
for line in infile:
if line.startswith("#") and dev_header in line:
line = line.replace(dev_header, next_version_strict)
elif latest_version_strict in line:
elif (
latest_version_strict
and line.startswith("#")
and latest_version_strict in line
):
for_next = False

changelog_lines.append(line)
Expand Down
81 changes: 60 additions & 21 deletions tests/test_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,25 @@ def test_prepare_draft_release(tmp_path, github_output_file, data_dir):
)


def test_prepare_draft_release_no_citation(github_output_file, data_dir_rel):
output = exec_in_context(
prepare_draft_release,
next_version_manual="v1.0.0",
next_version_convco="v1.0.0",
current_version="v0.9.10",
gh_event_name="push",
changelog_filepath=str(data_dir_rel / "example_changelog.md"),
dev_header="development version",
release_notes_filepath=str(data_dir_rel / "latest-release.md"),
version_filepath=str(data_dir_rel / "VERSION"),
citation_filepath="not/a/file.cff",
release_branch="release-draft",
pr_ref_name="PR_BRANCH_NAME",
repo="CCBR/actions",
debug=True,
)
assert "git add" in output
assert ".cff" not in output
def test_prepare_draft_release_missing_required_file(github_output_file, data_dir_rel):
with pytest.raises(FileNotFoundError) as exc_info:
prepare_draft_release(
next_version_manual="v1.0.0",
next_version_convco="v1.0.0",
current_version="v0.9.10",
gh_event_name="push",
changelog_filepath=str(data_dir_rel / "example_changelog.md"),
dev_header="development version",
release_notes_filepath=str(data_dir_rel / "latest-release.md"),
version_filepath=str(data_dir_rel / "VERSION"),
citation_filepath="not/a/file.cff",
release_branch="release-draft",
pr_ref_name="PR_BRANCH_NAME",
repo="CCBR/actions",
debug=True,
)
assert "Missing required release file(s)" in str(exc_info.value)
assert "citation" in str(exc_info.value)


def test_create_release_draft(data_dir_rel):
Expand Down Expand Up @@ -136,6 +136,17 @@ def test_get_changelog_lines(data_dir_rel):
assert release_notes == ["\n", "development version notes go here\n", "\n"]


def test_get_changelog_lines_first_release(data_dir_rel):
new_changelog, release_notes = get_changelog_lines(
"",
"0.2.0",
changelog_filepath=str(data_dir_rel / "example_changelog.md"),
)
assert new_changelog[0] == "## actions 0.2.0\n"
assert release_notes[:3] == ["\n", "development version notes go here\n", "\n"]
assert "## actions 0.1.0\n" in release_notes


def test_get_changelog_lines_sinclair(data_dir_rel):
new_changelog, release_notes = get_changelog_lines(
"0.3.0",
Expand Down Expand Up @@ -176,6 +187,22 @@ def test_get_release_version():
)
== "v1.10.0"
)
assert (
get_release_version(
next_version_manual="v0.1.0",
next_version_convco="",
current_version="",
)
== "v0.1.0"
)
assert (
get_release_version(
next_version_manual="",
next_version_convco="v0.1.0",
current_version="",
)
== "v0.1.0"
)
assert (
get_release_version(
next_version_manual="v1.10.0",
Expand All @@ -186,6 +213,16 @@ def test_get_release_version():
)


def test_get_release_version_first_release_missing_manual():
with pytest.raises(ValueError) as exc_info:
get_release_version(
next_version_manual="",
next_version_convco="",
current_version="",
)
assert "Unable to determine next release version" in str(exc_info.value)


def test_get_release_version_warning():
with warnings.catch_warnings():
warnings.simplefilter("error")
Expand Down Expand Up @@ -351,15 +388,17 @@ def test_prepare_draft_release_r_package(github_output_file, tmp_path, data_dir)


def test_prepare_draft_release_warns_on_autoformat_trigger_failure(
github_output_file, tmp_path, monkeypatch
github_output_file, tmp_path, monkeypatch, data_dir
):
changelog_file = tmp_path / "CHANGELOG.md"
version_file = tmp_path / "VERSION"
citation_file = tmp_path / "CITATION.cff"
notes_file = tmp_path / "latest-release.md"
changelog_file.write_text(
"## actions development version\n\nnotes\n\n## actions 0.1.0\n"
)
version_file.write_text("0.1.0\n")
citation_file.write_text((data_dir / "CITATION.cff").read_text())

monkeypatch.setattr("ccbr_actions.release.precommit_run", lambda *_: None)
monkeypatch.setattr(
Expand Down Expand Up @@ -388,7 +427,7 @@ def _trigger_workflow_raises(**_):
changelog_filepath=str(changelog_file),
release_notes_filepath=str(notes_file),
version_filepath=str(version_file),
citation_filepath="not/a/file/CITATION.cff",
citation_filepath=str(citation_file),
release_branch="release-draft",
pr_ref_name="feature/branch",
repo="CCBR/actions",
Expand Down
Loading