fix: use 1-based runner indices for Gitea Actions compatibility

This commit is contained in:
2026-06-22 02:31:20 +00:00
parent 8c16703106
commit 1f75017395
4 changed files with 21 additions and 15 deletions
+7 -5
View File
@@ -112,13 +112,15 @@ def get_runner_count(api_url: str, token: str, owner: str, repo: str) -> int:
def generate_indices(count: int) -> list[str]: def generate_indices(count: int) -> list[str]:
"""Generate a list of runner indices ["0", "1", ..., "N-1"]. """Generate a list of runner indices ["1", "2", ..., "N"].
Uses strings instead of ints because Gitea Actions renders Uses 1-based string indices because Gitea Actions renders
integer 0 as empty in ${{ matrix.runner-index }} expressions, integer 0 and string "0" as empty in ${{ matrix.runner-index }}
causing --runner-index to be passed without a value. expressions, causing --runner-index to be passed without a value.
The distribute_molecule.py script converts these back to 0-based
internally.
""" """
return [str(i) for i in range(count)] return [str(i + 1) for i in range(count)]
@click.command() @click.command()
+6 -3
View File
@@ -9,7 +9,7 @@ Each pair is printed as ``scenario|platform_name|platform_image|platform_command
so the CI workflow can set the appropriate environment variables. so the CI workflow can set the appropriate environment variables.
Usage: Usage:
python3 scripts/distribute_molecule.py --runner-index 0 --max-runners 3 python3 scripts/distribute_molecule.py --runner-index 1 --max-runners 3
# prints: default|ubuntu-2204|ubuntu:22.04| lifecycle|ubuntu-2204|ubuntu:22.04| ... # prints: default|ubuntu-2204|ubuntu:22.04| lifecycle|ubuntu-2204|ubuntu:22.04| ...
python3 scripts/distribute_molecule.py --list python3 scripts/distribute_molecule.py --list
# prints all scenarios, one per line # prints all scenarios, one per line
@@ -105,7 +105,8 @@ def pairs_for_runner(pairs: list[TestPair], runner_index: int, max_runners: int)
"--runner-index", "--runner-index",
type=int, type=int,
default=None, default=None,
help="Zero-based runner index. If omitted, prints all groups.", help="One-based runner index (Gitea Actions renders 0 as empty). "
"Converted to zero-based internally. If omitted, prints all groups.",
) )
@click.option( @click.option(
"--max-runners", "--max-runners",
@@ -143,7 +144,9 @@ def cli(runner_index: int | None, max_runners: int, list_all: bool, list_platfor
labels = " ".join(p.encode() for p in group) if group else "(none)" labels = " ".join(p.encode() for p in group) if group else "(none)"
click.echo(f"Runner {i}: {labels}") click.echo(f"Runner {i}: {labels}")
return return
assigned = pairs_for_runner(pairs, runner_index, max_runners) # Convert 1-based CLI index to 0-based internal index
zero_based = runner_index - 1
assigned = pairs_for_runner(pairs, zero_based, max_runners)
click.echo(" ".join(p.encode() for p in assigned)) click.echo(" ".join(p.encode() for p in assigned))
+6 -6
View File
@@ -19,13 +19,13 @@ class TestGenerateIndices:
assert generate_indices(0) == [] assert generate_indices(0) == []
def test_one(self) -> None: def test_one(self) -> None:
assert generate_indices(1) == ["0"] assert generate_indices(1) == ["1"]
def test_three(self) -> None: def test_three(self) -> None:
assert generate_indices(3) == ["0", "1", "2"] assert generate_indices(3) == ["1", "2", "3"]
def test_five(self) -> None: def test_five(self) -> None:
assert generate_indices(5) == ["0", "1", "2", "3", "4"] assert generate_indices(5) == ["1", "2", "3", "4", "5"]
class TestQueryRunners: class TestQueryRunners:
@@ -166,7 +166,7 @@ class TestMain:
result = runner.invoke(main, []) result = runner.invoke(main, [])
assert result.exit_code == 0 assert result.exit_code == 0
assert "count=3" in result.output assert "count=3" in result.output
assert 'indices=["0", "1", "2"]' in result.output assert 'indices=["1", "2", "3"]' in result.output
@patch("scripts.ci.discover_runners.get_runner_count", return_value=5) @patch("scripts.ci.discover_runners.get_runner_count", return_value=5)
def test_count_only(self, mock_count: MagicMock) -> None: def test_count_only(self, mock_count: MagicMock) -> None:
@@ -180,11 +180,11 @@ class TestMain:
runner = CliRunner() runner = CliRunner()
result = runner.invoke(main, ["--indices"]) result = runner.invoke(main, ["--indices"])
assert result.exit_code == 0 assert result.exit_code == 0
assert json.loads(result.output.strip()) == ["0", "1", "2", "3"] assert json.loads(result.output.strip()) == ["1", "2", "3", "4"]
@patch("scripts.ci.discover_runners.get_runner_count", return_value=1) @patch("scripts.ci.discover_runners.get_runner_count", return_value=1)
def test_single_runner(self, mock_count: MagicMock) -> None: def test_single_runner(self, mock_count: MagicMock) -> None:
runner = CliRunner() runner = CliRunner()
result = runner.invoke(main, ["--indices"]) result = runner.invoke(main, ["--indices"])
assert result.exit_code == 0 assert result.exit_code == 0
assert json.loads(result.output.strip()) == ["0"] assert json.loads(result.output.strip()) == ["1"]
+2 -1
View File
@@ -184,7 +184,8 @@ class TestCli:
(root / "alpha").mkdir(parents=True) (root / "alpha").mkdir(parents=True)
with patch("scripts.ci.distribute_molecule.MOLECULE_ROOT", root): with patch("scripts.ci.distribute_molecule.MOLECULE_ROOT", root):
runner = CliRunner() runner = CliRunner()
result = runner.invoke(cli, ["--runner-index", "0", "--max-runners", "3"]) # 1-based index: "1" maps to internal 0
result = runner.invoke(cli, ["--runner-index", "1", "--max-runners", "3"])
assert result.exit_code == 0 assert result.exit_code == 0
# Output should contain encoded pairs with platform info # Output should contain encoded pairs with platform info
assert "alpha|" in result.output assert "alpha|" in result.output