diff --git a/action.yml b/action.yml index e00ef3e3..3ada4df8 100644 --- a/action.yml +++ b/action.yml @@ -113,6 +113,10 @@ inputs: changelog_ignore: description: Labels for issues and pull requests to be ignored (comma-delimited) required: false + changelog_format: + description: "Changelog format: custom (default), github (auto-generated), or conventional (conventional commits)" + required: false + default: custom runs: using: docker image: docker://ghcr.io/juliaregistries/tagbot:1.23.5 diff --git a/tagbot/action/__main__.py b/tagbot/action/__main__.py index 4e198176..37919930 100644 --- a/tagbot/action/__main__.py +++ b/tagbot/action/__main__.py @@ -49,6 +49,16 @@ def get_input(key: str, default: str = "") -> str: else: ignore = Changelog.DEFAULT_IGNORE + changelog_format = get_input("changelog_format", "custom").lower() + # Validate changelog_format + valid_formats = ["custom", "github", "conventional"] + if changelog_format not in valid_formats: + logger.warning( + f"Invalid changelog_format '{changelog_format}', using 'custom'. " + f"Valid formats: {', '.join(valid_formats)}" + ) + changelog_format = "custom" + repo = Repo( repo=os.getenv("GITHUB_REPOSITORY", ""), registry=get_input("registry"), @@ -57,6 +67,7 @@ def get_input(key: str, default: str = "") -> str: token=token, changelog=get_input("changelog"), changelog_ignore=ignore, + changelog_format=changelog_format, ssh=bool(ssh), gpg=bool(gpg), draft=get_input("draft").lower() in ["true", "yes"], diff --git a/tagbot/action/repo.py b/tagbot/action/repo.py index 0c0d671d..c3580017 100644 --- a/tagbot/action/repo.py +++ b/tagbot/action/repo.py @@ -26,6 +26,7 @@ Mapping, MutableMapping, Optional, + Tuple, TypeVar, Union, cast, @@ -122,6 +123,7 @@ def __init__( token: str, changelog: str, changelog_ignore: List[str], + changelog_format: str, ssh: bool, gpg: bool, draft: bool, @@ -190,7 +192,13 @@ def __init__( self._clone_registry = False self._token = token self.__versions_toml_cache: Optional[Dict[str, Any]] = None - self._changelog = Changelog(self, changelog, changelog_ignore) + self._changelog_format = changelog_format + # Only initialize Changelog if using custom format + self._changelog = ( + None + if changelog_format in ["github", "conventional"] + else Changelog(self, changelog, changelog_ignore) + ) self._ssh = ssh self._gpg = gpg self._draft = draft @@ -983,6 +991,141 @@ def _tag_exists(self, version: str) -> bool: # If we can't check, assume it doesn't exist return False + def _generate_conventional_changelog( + self, version_tag: str, sha: str, previous_tag: Optional[str] = None + ) -> str: + """Generate changelog from conventional commits. + + Args: + version_tag: The version tag being released + sha: Commit SHA for the release + previous_tag: Previous release tag to generate changelog from + + Returns: + Formatted changelog based on conventional commits + """ + # Determine commit range + if previous_tag: + commit_range = f"{previous_tag}..{sha}" + else: + # For first release, get all commits up to this one + commit_range = sha + + # Get commit messages + try: + log_output = self._git.command( + "log", + commit_range, + "--format=%s|%h|%an", + "--no-merges", + ) + except Exception as e: + logger.warning(f"Could not get commits for conventional changelog: {e}") + return f"## {version_tag}\n\nRelease created.\n" + + # Parse commits into categories based on conventional commit format + # Format: type(scope): description + categories: Dict[str, List[Tuple[str, str, str]]] = { + "breaking": [], # BREAKING CHANGE or ! + "feat": [], # Features + "fix": [], # Bug fixes + "perf": [], # Performance improvements + "refactor": [], # Refactoring + "docs": [], # Documentation + "test": [], # Tests + "build": [], # Build system + "ci": [], # CI/CD + "chore": [], # Chores + "style": [], # Code style + "revert": [], # Reverts + "other": [], # Non-conventional commits + } + + for line in log_output.strip().split("\n"): + if not line: + continue + parts = line.split("|", 2) + if len(parts) < 3: + continue + message, commit_hash, author = parts + + # Check for breaking (keep commit in both breaking and its type category) + if "BREAKING CHANGE" in message or re.match(r"^\w+!:", message): + categories["breaking"].append((message, commit_hash, author)) + + # Parse conventional commit format (supports optional "!" for breaking) + match = re.match(r"^(\w+)(\(.+\))?(!)?: (.+)$", message) + if match: + commit_type = match.group(1).lower() + if commit_type in categories: + categories[commit_type].append((message, commit_hash, author)) + else: + categories["other"].append((message, commit_hash, author)) + else: + categories["other"].append((message, commit_hash, author)) + + # Build changelog + changelog = f"## {version_tag}\n\n" + + # Section configurations (type: title) + sections = [ + ("breaking", "Breaking Changes"), + ("feat", "Features"), + ("fix", "Bug Fixes"), + ("perf", "Performance Improvements"), + ("refactor", "Code Refactoring"), + ("docs", "Documentation"), + ("test", "Tests"), + ("build", "Build System"), + ("ci", "CI/CD"), + ("style", "Code Style"), + ("chore", "Chores"), + ("revert", "Reverts"), + ] + + has_any_commits = ( + any(categories[cat_key] for cat_key, _ in sections) or categories["other"] + ) + + repo_url = f"{self._gh_url}/{self._repo.full_name}" + + for cat_key, title in sections: + commits = categories[cat_key] + if commits: + changelog += f"### {title}\n\n" + for message, commit_hash, author in commits: + changelog += ( + f"- {message} ([`{commit_hash}`]" + f"({repo_url}/commit/{commit_hash})) - {author}\n" + ) + changelog += "\n" + + # Add other commits if any + if categories["other"]: + changelog += "### Other Changes\n\n" + for message, commit_hash, author in categories["other"]: + changelog += ( + f"- {message} ([`{commit_hash}`]" + f"({repo_url}/commit/{commit_hash})) - {author}\n" + ) + changelog += "\n" + + # If no commits were found, add an informative message + if not has_any_commits: + if previous_tag: + changelog += "No new commits since the previous release.\n" + else: + changelog += "Initial release.\n" + + # Add compare link if we have a previous tag + if previous_tag: + changelog += ( + f"**Full Changelog**: {repo_url}/compare/" + f"{previous_tag}...{version_tag}\n" + ) + + return changelog + def create_issue_for_manual_tag(self, failures: list[tuple[str, str, str]]) -> None: """Create an issue requesting manual intervention for failed releases. @@ -1286,8 +1429,11 @@ def create_release(self, version: str, sha: str, is_latest: bool = True) -> None version_tag = self._get_version_tag(version) logger.debug(f"Release {version_tag} target: {target}") # Check if a release for this tag already exists before doing work + # Also fetch releases list for later use in changelog generation + releases = [] try: - for release in self._repo.get_releases(): + releases = list(self._repo.get_releases()) + for release in releases: if release.tag_name == version_tag: logger.info( f"Release for tag {version_tag} already exists, skipping" @@ -1295,7 +1441,26 @@ def create_release(self, version: str, sha: str, is_latest: bool = True) -> None return except GithubException as e: logger.warning(f"Could not check for existing releases: {e}") - log = self._changelog.get(version_tag, sha) + + # Generate release notes based on format + if self._changelog_format == "github": + log = "" # Empty body triggers GitHub to auto-generate notes + logger.info("Using GitHub auto-generated release notes") + elif self._changelog_format == "conventional": + # Find previous release for conventional changelog + previous_tag = None + if releases: + # Find the most recent release before this one + for release in releases: + if release.tag_name != version_tag: + previous_tag = release.tag_name + break + + logger.info("Generating conventional commits changelog") + log = self._generate_conventional_changelog(version_tag, sha, previous_tag) + else: # custom format + log = self._changelog.get(version_tag, sha) if self._changelog else "" + if not self._draft: # Always create tags via the CLI as the GitHub API has a bug which # only allows tags to be created for SHAs which are the the HEAD @@ -1313,6 +1478,7 @@ def create_release(self, version: str, sha: str, is_latest: bool = True) -> None target_commitish=target, draft=self._draft, make_latest=make_latest_str, + generate_release_notes=(self._changelog_format == "github"), ) logger.info(f"GitHub release {version_tag} created successfully") diff --git a/tagbot/local/__main__.py b/tagbot/local/__main__.py index 327efd4a..24b67e43 100644 --- a/tagbot/local/__main__.py +++ b/tagbot/local/__main__.py @@ -47,6 +47,7 @@ def main( token=token, changelog=changelog, changelog_ignore=[], + changelog_format="custom", ssh=False, gpg=False, draft=draft, diff --git a/test/action/test_backfilling.py b/test/action/test_backfilling.py index 13cdacb4..52d39489 100644 --- a/test/action/test_backfilling.py +++ b/test/action/test_backfilling.py @@ -18,6 +18,7 @@ def _repo( token="x", changelog="", ignore=[], + changelog_format="custom", ssh=False, gpg=False, draft=False, @@ -36,6 +37,7 @@ def _repo( token=token, changelog=changelog, changelog_ignore=ignore, + changelog_format=changelog_format, ssh=ssh, gpg=gpg, draft=draft, diff --git a/test/action/test_changelog.py b/test/action/test_changelog.py index 73b16064..a86793b2 100644 --- a/test/action/test_changelog.py +++ b/test/action/test_changelog.py @@ -21,6 +21,7 @@ def _changelog(*, template="", ignore=set(), subdir=None): token="x", changelog=template, changelog_ignore=ignore, + changelog_format="custom", ssh=False, gpg=False, draft=False, diff --git a/test/action/test_changelog_formats.py b/test/action/test_changelog_formats.py new file mode 100644 index 00000000..9dc5f3a8 --- /dev/null +++ b/test/action/test_changelog_formats.py @@ -0,0 +1,358 @@ +"""Tests for multiple changelog format support (issues #216, #402).""" + +from unittest.mock import Mock, patch + +from tagbot.action.repo import Repo + + +def _repo( + *, + repo="", + registry="", + github="", + github_api="", + token="x", + changelog="", + ignore=None, + changelog_format="custom", + ssh=False, + gpg=False, + draft=False, + registry_ssh="", + user="", + email="", + branch=None, + subdir=None, + tag_prefix=None, +): + return Repo( + repo=repo, + registry=registry, + github=github, + github_api=github_api, + token=token, + changelog=changelog, + changelog_ignore=ignore if ignore is not None else [], + changelog_format=changelog_format, + ssh=ssh, + gpg=gpg, + draft=draft, + registry_ssh=registry_ssh, + user=user, + email=email, + branch=branch, + subdir=subdir, + tag_prefix=tag_prefix, + ) + + +@patch("tagbot.action.repo.Github") +def test_changelog_format_custom_by_default(mock_github): + """Test that changelog_format is 'custom' by default.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + mock_gh_instance.get_repo.return_value = Mock() + + r = _repo(repo="test/repo", registry="test/registry") + assert r._changelog_format == "custom" + assert r._changelog is not None + + +@patch("tagbot.action.repo.Github") +def test_changelog_format_github(mock_github): + """Test that changelog_format can be set to 'github'.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + mock_gh_instance.get_repo.return_value = Mock() + + r = _repo(repo="test/repo", registry="test/registry", changelog_format="github") + assert r._changelog_format == "github" + assert r._changelog is None + + +@patch("tagbot.action.repo.Github") +def test_changelog_format_conventional(mock_github): + """Test that changelog_format can be set to 'conventional'.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + mock_gh_instance.get_repo.return_value = Mock() + + r = _repo( + repo="test/repo", registry="test/registry", changelog_format="conventional" + ) + assert r._changelog_format == "conventional" + assert r._changelog is None + + +@patch("tagbot.action.repo.logger") +@patch("tagbot.action.repo.Github") +def test_create_release_with_github_format(mock_github, mock_logger): + """Test uses GitHub's auto-generated notes with github format.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.get_releases.return_value = [] + + r = _repo(repo="test/repo", registry="test/registry", changelog_format="github") + r._git = Mock() + r._git.create_tag = Mock() + + r.create_release("v1.0.0", "abc123") + + # Verify create_git_release was called with generate_release_notes=True + mock_repo.create_git_release.assert_called_once() + call_args = mock_repo.create_git_release.call_args + assert call_args.kwargs["generate_release_notes"] is True + # Body should be empty when using auto-generated notes + assert call_args.args[2] == "" + + +@patch("tagbot.action.repo.logger") +@patch("tagbot.action.repo.Github") +def test_create_release_with_custom_format(mock_github, mock_logger): + """Test that create_release uses custom changelog with custom format.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.get_releases.return_value = [] + + r = _repo(repo="test/repo", registry="test/registry", changelog_format="custom") + r._git = Mock() + r._git.create_tag = Mock() + + # Mock the changelog generation + r._changelog = Mock() + r._changelog.get = Mock(return_value="Custom changelog content") + + r.create_release("v1.0.0", "abc123") + + # Verify changelog.get was called + r._changelog.get.assert_called_once_with("v1.0.0", "abc123") + + # Verify create_git_release was called with generate_release_notes=False + mock_repo.create_git_release.assert_called_once() + call_args = mock_repo.create_git_release.call_args + assert call_args.kwargs["generate_release_notes"] is False + # Body should contain custom changelog + assert call_args.args[2] == "Custom changelog content" + + +@patch("tagbot.action.repo.logger") +@patch("tagbot.action.repo.Github") +def test_create_release_with_conventional_format(mock_github, mock_logger): + """Test that create_release generates conventional commits changelog.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.get_releases.return_value = [] + mock_repo.full_name = "test/repo" + + r = _repo( + repo="test/repo", registry="test/registry", changelog_format="conventional" + ) + r._git = Mock() + r._git.create_tag = Mock() + # Mock git log output with conventional commits + r._git.command = Mock( + return_value=( + "feat: add new feature|abc123|johndoe\n" + "fix: fix bug|def456|janedoe\n" + "chore: update deps|ghi789|bob" + ) + ) + + r.create_release("v1.0.0", "abc123") + + # Verify git command was called to get commits + r._git.command.assert_called_once() + + # Verify create_git_release was called with generate_release_notes=False + mock_repo.create_git_release.assert_called_once() + call_args = mock_repo.create_git_release.call_args + assert call_args.kwargs["generate_release_notes"] is False + + # Body should contain conventional changelog + changelog_body = call_args.args[2] + assert "## v1.0.0" in changelog_body + assert "Features" in changelog_body or "feat:" in changelog_body + assert "Bug Fixes" in changelog_body or "fix:" in changelog_body + + +@patch("tagbot.action.repo.Github") +def test_conventional_changelog_parsing(mock_github): + """Test that conventional commits are parsed correctly through create_release. + + This tests the internal conventional changelog generation by calling through + the public create_release method, making it more robust to internal refactoring. + """ + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.full_name = "test/repo" + mock_repo.get_releases.return_value = [] + mock_repo.create_git_release = Mock() + + r = _repo( + repo="test/repo", registry="test/registry", changelog_format="conventional" + ) + r._git = Mock() + r._git.create_tag = Mock() + + # Test various conventional commit formats + r._git.command = Mock( + return_value=( + "feat(api): add new endpoint|abc123|dev1\n" + "fix!: critical security fix|def456|dev2\n" + "docs: update README|ghi789|dev3\n" + "test: add unit tests|jkl012|dev4\n" + "not conventional commit|mno345|dev5" + ) + ) + + r.create_release("v1.0.0", "abc123") + + # Verify create_git_release was called + mock_repo.create_git_release.assert_called_once() + + # Check the generated changelog body + call_args = mock_repo.create_git_release.call_args + changelog = call_args.args[2] + + # Check structure + assert "## v1.0.0" in changelog + assert "Features" in changelog + assert "Breaking Changes" in changelog or "fix!" in changelog + assert "Documentation" in changelog + assert "Tests" in changelog + assert "Other Changes" in changelog + + +@patch("tagbot.action.repo.Github") +def test_github_format_logging(mock_github, caplog): + """Test that github format logs appropriate message.""" + import logging + + caplog.set_level(logging.INFO) + + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.get_releases.return_value = [] + + r = _repo(repo="test/repo", registry="test/registry", changelog_format="github") + r._git = Mock() + r._git.create_tag = Mock() + + r.create_release("v1.0.0", "abc123") + + # Check that the log message about auto-generated notes was logged + assert "Using GitHub auto-generated release notes" in caplog.text + + +@patch("tagbot.action.repo.Github") +def test_conventional_format_logging(mock_github, caplog): + """Test that conventional format logs appropriate message.""" + import logging + + caplog.set_level(logging.INFO) + + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.get_releases.return_value = [] + mock_repo.full_name = "test/repo" + + r = _repo( + repo="test/repo", registry="test/registry", changelog_format="conventional" + ) + r._git = Mock() + r._git.create_tag = Mock() + r._git.command = Mock(return_value="feat: test|abc|dev") + + r.create_release("v1.0.0", "abc123") + + # Check that the log message about conventional commits was logged + assert "Generating conventional commits changelog" in caplog.text + + +@patch("tagbot.action.repo.Github") +def test_conventional_changelog_no_commits_first_release(mock_github): + """Test conventional changelog with no commits (initial release).""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.get_releases.return_value = [] + mock_repo.create_git_release = Mock() + + r = _repo( + repo="test/repo", registry="test/registry", changelog_format="conventional" + ) + r._git = Mock() + r._git.create_tag = Mock() + # Simulate no commits found + r._git.command = Mock(return_value="") + + r.create_release("v1.0.0", "abc123") + + # Verify create_git_release was called + mock_repo.create_git_release.assert_called_once() + + # Check the generated changelog body + call_args = mock_repo.create_git_release.call_args + changelog = call_args.args[2] + + # Should have version header and initial release message + assert "## v1.0.0" in changelog + assert "Initial release" in changelog + + +@patch("tagbot.action.repo.Github") +def test_conventional_changelog_no_commits_since_previous(mock_github): + """Test conventional changelog with no new commits since previous release.""" + mock_gh_instance = Mock() + mock_github.return_value = mock_gh_instance + + mock_repo = Mock() + mock_gh_instance.get_repo.return_value = mock_repo + mock_repo.create_git_release = Mock() + mock_repo.full_name = "test/repo" + + # Mock a previous release + mock_previous_release = Mock() + mock_previous_release.tag_name = "v1.0.0" + mock_repo.get_releases.return_value = [mock_previous_release] + + r = _repo( + repo="test/repo", registry="test/registry", changelog_format="conventional" + ) + r._git = Mock() + r._git.create_tag = Mock() + # Simulate no commits found between v1.0.0 and v1.1.0 + r._git.command = Mock(return_value="") + + r.create_release("v1.1.0", "abc123") + + # Verify create_git_release was called + mock_repo.create_git_release.assert_called_once() + + # Check the generated changelog body + call_args = mock_repo.create_git_release.call_args + changelog = call_args.args[2] + + # Should have version header and no new commits message + assert "## v1.1.0" in changelog + assert "No new commits since the previous release" in changelog diff --git a/test/action/test_repo.py b/test/action/test_repo.py index aa496e90..73f27b14 100644 --- a/test/action/test_repo.py +++ b/test/action/test_repo.py @@ -27,6 +27,7 @@ def _repo( token="x", changelog="", ignore=[], + changelog_format="custom", ssh=False, gpg=False, draft=False, @@ -45,6 +46,7 @@ def _repo( token=token, changelog=changelog, changelog_ignore=ignore, + changelog_format=changelog_format, ssh=ssh, gpg=gpg, draft=draft, @@ -1026,11 +1028,23 @@ def test_create_release(): r.create_release("v1", "a") r._git.create_tag.assert_called_with("v1", "a", "l") r._repo.create_git_release.assert_called_with( - "v1", "v1", "l", target_commitish="default", draft=False, make_latest="true" + "v1", + "v1", + "l", + target_commitish="default", + draft=False, + make_latest="true", + generate_release_notes=False, ) r.create_release("v1", "b") r._repo.create_git_release.assert_called_with( - "v1", "v1", "l", target_commitish="b", draft=False, make_latest="true" + "v1", + "v1", + "l", + target_commitish="b", + draft=False, + make_latest="true", + generate_release_notes=False, ) r.create_release("v1", "c") r._git.create_tag.assert_called_with("v1", "c", "l") @@ -1039,13 +1053,25 @@ def test_create_release(): r.create_release("v1", "d") r._git.create_tag.assert_not_called() r._repo.create_git_release.assert_called_with( - "v1", "v1", "l", target_commitish="d", draft=True, make_latest="true" + "v1", + "v1", + "l", + target_commitish="d", + draft=True, + make_latest="true", + generate_release_notes=False, ) # Test is_latest=False r._draft = False r.create_release("v0.9", "e", is_latest=False) r._repo.create_git_release.assert_called_with( - "v0.9", "v0.9", "l", target_commitish="e", draft=False, make_latest="false" + "v0.9", + "v0.9", + "l", + target_commitish="e", + draft=False, + make_latest="false", + generate_release_notes=False, ) @@ -1093,10 +1119,17 @@ def test_create_release_subdir(): target_commitish="default", draft=False, make_latest="true", + generate_release_notes=False, ) r.create_release("v1", "b") r._repo.create_git_release.assert_called_with( - "Foo-v1", "Foo-v1", "l", target_commitish="b", draft=False, make_latest="true" + "Foo-v1", + "Foo-v1", + "l", + target_commitish="b", + draft=False, + make_latest="true", + generate_release_notes=False, ) r.create_release("v1", "c") r._git.create_tag.assert_called_with("Foo-v1", "c", "l") @@ -1105,7 +1138,13 @@ def test_create_release_subdir(): r.create_release("v1", "d") r._git.create_tag.assert_not_called() r._repo.create_git_release.assert_called_with( - "Foo-v1", "Foo-v1", "l", target_commitish="d", draft=True, make_latest="true" + "Foo-v1", + "Foo-v1", + "l", + target_commitish="d", + draft=True, + make_latest="true", + generate_release_notes=False, ) @@ -1140,7 +1179,7 @@ def test_check_rate_limit_error(logger): @patch("traceback.format_exc", return_value="ahh") @patch("tagbot.action.repo.logger") -def test_handle_error(logger, format_exc): +def test_handle_error(mock_logger, format_exc): r = _repo() r._report_error = Mock(side_effect=[None, RuntimeError("!")]) r._check_rate_limit = Mock() @@ -1162,12 +1201,12 @@ def test_handle_error(logger, format_exc): else: assert False r._report_error.assert_called_with("ahh") - logger.error.assert_called_with("Issue reporting failed") + mock_logger.error.assert_called_with("Issue reporting failed") @patch("traceback.format_exc", return_value="ahh") @patch("tagbot.action.repo.logger") -def test_handle_error_403_checks_rate_limit(logger, format_exc): +def test_handle_error_403_checks_rate_limit(mock_logger, format_exc): r = _repo() r._report_error = Mock() r._check_rate_limit = Mock() @@ -1176,7 +1215,7 @@ def test_handle_error_403_checks_rate_limit(logger, format_exc): except Abort: pass r._check_rate_limit.assert_called_once() - assert any("403" in str(call) for call in logger.error.call_args_list) + assert any("403" in str(call) for call in mock_logger.error.call_args_list) def test_commit_sha_of_version(): diff --git a/test/action/test_repo_gitlab.py b/test/action/test_repo_gitlab.py index 46d4507b..0d54988b 100644 --- a/test/action/test_repo_gitlab.py +++ b/test/action/test_repo_gitlab.py @@ -15,6 +15,7 @@ def _repo( token="x", changelog="", ignore=None, + changelog_format="custom", ssh=False, gpg=False, draft=False, @@ -33,6 +34,7 @@ def _repo( token=token, changelog=changelog, changelog_ignore=ignore if ignore is not None else [], + changelog_format=changelog_format, ssh=ssh, gpg=gpg, draft=draft,