Skip to content

Commit 6bb3a5d

Browse files
committed
Add tests for publish-docs ref validation error messages
1 parent 5df9f7f commit 6bb3a5d

1 file changed

Lines changed: 105 additions & 0 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
from __future__ import annotations
18+
19+
import json
20+
from subprocess import CompletedProcess
21+
from unittest.mock import MagicMock, call, patch
22+
23+
import pytest
24+
from click.testing import CliRunner
25+
26+
from airflow_breeze.commands.workflow_commands import workflow_run_publish
27+
28+
29+
def _make_gh_response(ref: str | None) -> CompletedProcess:
30+
"""Return a fake CompletedProcess whose stdout mimics a gh api response."""
31+
body = {"ref": ref} if ref else {"message": "Not Found"}
32+
return MagicMock(spec=CompletedProcess, stdout=json.dumps(body).encode())
33+
34+
35+
class TestPublishDocsTagValidation:
36+
"""Tests for the ref validation logic in `breeze workflow-run publish-docs`."""
37+
38+
@pytest.fixture()
39+
def runner(self):
40+
return CliRunner()
41+
42+
def _invoke(self, runner: CliRunner, ref: str, extra_args: list[str] | None = None) -> object:
43+
args = ["--ref", ref, "--site-env", "staging", "apache-airflow"]
44+
if extra_args:
45+
args = extra_args + args
46+
return runner.invoke(workflow_run_publish, args, catch_exceptions=False)
47+
48+
@patch("airflow_breeze.commands.workflow_commands.run_command")
49+
def test_ref_is_valid_tag_passes_validation(self, mock_run_command, runner):
50+
"""When the ref exists as a tag, validation passes and the workflow is triggered."""
51+
tag_response = _make_gh_response("refs/tags/providers/2026-04-26")
52+
mock_run_command.return_value = tag_response
53+
54+
with patch(
55+
"airflow_breeze.commands.workflow_commands.trigger_workflow_and_monitor"
56+
) as mock_trigger:
57+
result = self._invoke(runner, "providers/2026-04-26")
58+
59+
assert result.exit_code == 0
60+
mock_trigger.assert_called()
61+
# Only one gh api call (tag check), no branch check needed
62+
mock_run_command.assert_called_once()
63+
64+
@patch("airflow_breeze.commands.workflow_commands.run_command")
65+
def test_ref_is_branch_shows_actionable_message(self, mock_run_command, runner):
66+
"""When the ref exists as a branch but not a tag, the error names the branch
67+
and points to --skip-tag-validation."""
68+
tag_response = _make_gh_response(None)
69+
branch_response = _make_gh_response("refs/heads/main")
70+
mock_run_command.side_effect = [tag_response, branch_response]
71+
72+
result = self._invoke(runner, "main")
73+
74+
assert result.exit_code == 1
75+
assert "exists as a branch but not as a tag" in result.output
76+
assert "--skip-tag-validation" in result.output
77+
# Both tag and branch checks must have been made
78+
assert mock_run_command.call_count == 2
79+
calls = mock_run_command.call_args_list
80+
assert "refs/tags/main" in calls[0][0][0][2]
81+
assert "refs/heads/main" in calls[1][0][0][2]
82+
83+
@patch("airflow_breeze.commands.workflow_commands.run_command")
84+
def test_ref_not_found_anywhere_shows_generic_message(self, mock_run_command, runner):
85+
"""When the ref exists neither as a tag nor a branch, a generic error is shown."""
86+
mock_run_command.return_value = _make_gh_response(None)
87+
88+
result = self._invoke(runner, "nonexistent-ref-xyz")
89+
90+
assert result.exit_code == 1
91+
assert "does not exist as a tag or branch" in result.output
92+
assert "--skip-tag-validation" in result.output
93+
assert mock_run_command.call_count == 2
94+
95+
@patch("airflow_breeze.commands.workflow_commands.run_command")
96+
def test_skip_tag_validation_bypasses_checks(self, mock_run_command, runner):
97+
"""With --skip-tag-validation, no gh api calls are made and the workflow proceeds."""
98+
with patch(
99+
"airflow_breeze.commands.workflow_commands.trigger_workflow_and_monitor"
100+
) as mock_trigger:
101+
result = self._invoke(runner, "some-branch", extra_args=["--skip-tag-validation"])
102+
103+
assert result.exit_code == 0
104+
mock_run_command.assert_not_called()
105+
mock_trigger.assert_called()

0 commit comments

Comments
 (0)