From 4d5ec7f934bc094b032f43856bbf0bb86fa39239 Mon Sep 17 00:00:00 2001 From: marwin1991 Date: Sun, 4 Oct 2026 20:00:10 +0200 Subject: [PATCH 1/2] add support for creating empty commits to enable pull requests with no changes, update related tests and modules --- test/ci_provider/github/merge_request_test.py | 42 +++++++++++++++++++ valhalla/ci_provider/github/merge_request.py | 12 ++++++ valhalla/commit/commit.py | 5 +++ 3 files changed, 59 insertions(+) diff --git a/test/ci_provider/github/merge_request_test.py b/test/ci_provider/github/merge_request_test.py index 5ad371f..98e3172 100644 --- a/test/ci_provider/github/merge_request_test.py +++ b/test/ci_provider/github/merge_request_test.py @@ -320,3 +320,45 @@ def test_enable_auto_merge_exception(self, mock_warn, mock_info, mock_resolve, m # then mock_warn.assert_any_call("Could not enable auto-merge for pull request because: Network error") + + +class GitHubMergeRequestEmptyCommitTest(unittest.TestCase): + + @patch("valhalla.ci_provider.github.merge_request.get_valhalla_token", return_value="token") + @patch("valhalla.ci_provider.github.merge_request.GitRepository") + @patch("valhalla.ci_provider.github.merge_request.GitHubClient") + @patch("valhalla.ci_provider.github.merge_request.resolve") + @patch("valhalla.ci_provider.github.merge_request.info") + @patch("valhalla.ci_provider.github.merge_request.warn") + def test_create_empty_commit_and_retry_when_no_commits_between(self, mock_warn, mock_info, mock_resolve, + mock_client_cls, mock_git_cls, mock_token): + # given + with patch.dict('os.environ', {'GITHUB_REF_NAME': 'release-1.0.0'}): + mock_resolve.side_effect = lambda x: x + mock_client = MagicMock() + mock_client.api_url = "https://api.github.com" + mock_client.repo = "owner/repo" + + no_commits_response = MagicMock() + no_commits_response.status_code = 422 + no_commits_response.text = '{"errors":[{"message":"No commits between main and release-1.0.0"}]}' + pr_response = MagicMock() + pr_response.status_code = 201 + pr_response.json.return_value = {"html_url": "https://github.com/owner/repo/pull/3", "number": 3} + + mock_client.post.side_effect = [no_commits_response, pr_response] + mock_client_cls.return_value = mock_client + mock_git = mock_git_cls.return_value + + pr = GitHubValhallaPullRequest() + config = MergeRequestConfig(enabled=True, target_branch="main", title="t", description="d", reviewers=[]) + + # when + pr.create(config) + + # then + mock_git.commit_empty.assert_called_once() + mock_git.push.assert_called_once_with("token") + self.assertEqual(2, mock_client.post.call_count) + mock_info.assert_any_call("Created pull request: https://github.com/owner/repo/pull/3") + mock_warn.assert_not_called() diff --git a/valhalla/ci_provider/github/merge_request.py b/valhalla/ci_provider/github/merge_request.py index d00e59d..59112f8 100644 --- a/valhalla/ci_provider/github/merge_request.py +++ b/valhalla/ci_provider/github/merge_request.py @@ -1,6 +1,8 @@ import os +from valhalla.ci_provider.get_token import get_valhalla_token from valhalla.ci_provider.github.common import get_default_branch_fallback, GitHubClient +from valhalla.commit.commit import GitRepository from valhalla.common.get_config import MergeRequestConfig from valhalla.common.logger import info, warn from valhalla.common.resolver import resolve @@ -8,6 +10,9 @@ from valhalla.ci_provider.merge_request_hook import MergeRequestHook +EMPTY_COMMIT_MSG = ("Empty commit created by Valhalla to open pull request before release changes, " + "see: https://stackoverflow.com/questions/46577500/why-cant-i-create-an-empty-pull-request-for-discussion-prior-to-developing-chan") + class GitHubValhallaPullRequest: def __init__(self): @@ -39,6 +44,13 @@ def create(self, merge_request_config: MergeRequestConfig): } resp = self.client.post(url, json=payload) + if resp.status_code == 422 and "No commits between" in resp.text: + info("GitHub does not allow creating pull request without commits, creating empty commit") + git = GitRepository(None, None) + git.commit_empty(EMPTY_COMMIT_MSG) + git.push(get_valhalla_token()) + resp = self.client.post(url, json=payload) + if resp.status_code >= 300: warn(f"Failed to create pull request: {resp.status_code} {resp.text}") return MergeRequestHook.Skip() diff --git a/valhalla/commit/commit.py b/valhalla/commit/commit.py index fc44d80..bfb982e 100644 --- a/valhalla/commit/commit.py +++ b/valhalla/commit/commit.py @@ -74,6 +74,11 @@ def commit(self, msg: str, add=True) -> bool: self.status() return True + def commit_empty(self, msg: str): + msg += " [VALHALLA SKIP]" + self.repository.git.commit("--allow-empty", "-m", resolve(msg)) + info(f"Created empty commit: {self.repository.head.commit}") + def push(self, token): info("Preparing to push") branch = self.repository.active_branch From fa822abd3db02ffb77ea5da9ca1f32a791614a11 Mon Sep 17 00:00:00 2001 From: marwin1991 Date: Sun, 4 Oct 2026 22:19:26 +0200 Subject: [PATCH 2/2] add support for creating empty commits to enable pull requests with no changes, update related tests and modules --- valhalla/ci_provider/github/merge_request.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/valhalla/ci_provider/github/merge_request.py b/valhalla/ci_provider/github/merge_request.py index 59112f8..e16f5f5 100644 --- a/valhalla/ci_provider/github/merge_request.py +++ b/valhalla/ci_provider/github/merge_request.py @@ -10,8 +10,7 @@ from valhalla.ci_provider.merge_request_hook import MergeRequestHook -EMPTY_COMMIT_MSG = ("Empty commit created by Valhalla to open pull request before release changes, " - "see: https://stackoverflow.com/questions/46577500/why-cant-i-create-an-empty-pull-request-for-discussion-prior-to-developing-chan") +EMPTY_COMMIT_MSG = "Empty commit to create PR to start release" class GitHubValhallaPullRequest: @@ -44,6 +43,8 @@ def create(self, merge_request_config: MergeRequestConfig): } resp = self.client.post(url, json=payload) + # GitHub does not allow empty pull requests, see: + # https://stackoverflow.com/questions/46577500/why-cant-i-create-an-empty-pull-request-for-discussion-prior-to-developing-chan if resp.status_code == 422 and "No commits between" in resp.text: info("GitHub does not allow creating pull request without commits, creating empty commit") git = GitRepository(None, None)