diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3d0ec47..332a71df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,9 @@ jobs: - name: Test Report - if: always() + # Not on a cancelled run (a newer run of the same branch replaced it): it has no results + # file, and failing here would show a red X for tests that never ran. + if: ${{ !cancelled() }} uses: pmeier/pytest-results-action@main with: path: test-results.xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a14d6997..bc61048f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -98,34 +98,6 @@ jobs: git tag -a "v${{ steps.bump_version.outputs.new_version }}" -m "Release v${{ steps.bump_version.outputs.new_version }}" $MERGE_COMMIT_SHA git push origin "v${{ steps.bump_version.outputs.new_version }}" - - name: Bump dependent repositories - if: success() && steps.bump_version.outputs.new_version != '' - run: | - NEW_VERSION=${{ steps.bump_version.outputs.new_version }} - for REPO in $DEPENDENT_REPOS; do - echo "Updating dependency in $REPO..." - - git clone "https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/$REPO.git" - cd "$(basename "$REPO")" - - # Example: update version reference inside pyproject.toml or pixi.toml - # Adjust search/replace as needed for your dependency structure - if grep -q 'utama_core' pixi.toml; then - toml set --toml-path pixi.toml pypi-dependencies."utama-core".rev "v${NEW_VERSION}" - pixi update - fi - - git config user.name "utama-release-manager[bot]" - git config user.email "232491996+utama-release-manager[bot]@users.noreply.github.com" - git add . - git commit -m "chore(deps): bump utama_core to v${NEW_VERSION}" || echo "No changes to commit" - git push origin main || echo "No push needed" - - cd .. - rm -rf "$(basename "$REPO")" - done - echo "Dependent repositories updated." - - name: Create GitHub Release uses: softprops/action-gh-release@v2.3.3 with: @@ -134,7 +106,3 @@ jobs: draft: false prerelease: false - -env: - DEPENDENT_REPOS: | - First-Order-RoboCup-SSL/Utama-Strategy \ No newline at end of file diff --git a/tools/tournament/round_robin.py b/tools/tournament/round_robin.py index 31e220d0..b3a223ff 100644 --- a/tools/tournament/round_robin.py +++ b/tools/tournament/round_robin.py @@ -8,7 +8,19 @@ `full_match_tournament.py` — see that module's own docstring for why. Run: - pixi run python tools/tournament/round_robin.py + pixi run python tools/tournament/round_robin.py [config ...] [flags] + +Configs are short names (`tiki_taka`); none means every config. Flags: + --pair A B one match, A as config_a + --reuse take unchanged matches from replays/match_cache/; check the + "N reused ... M to play" line it prints before waiting on M + --spot-check F with --reuse, replay this fraction of reused matches to verify + --strict fail on any stall + --stop-at-first-stall stop the run at the first stall + --both-sides play each pair twice, sides swapped + --control-scheme NAME planner (fpp, trajsample, ...) + --fuzz-restarts SEED inject random legal restarts; --fuzz-interval LO HI sets the gap + --max-workers N, --sequential, --no-save, -v/--verbose, -h/--help What this does -------------- @@ -186,6 +198,9 @@ def main() -> None: # them with their stored records: a difference means the fingerprint missed # a dependency, is printed loudly, evicts those records, and fails `--strict`. args = sys.argv[1:] + if "-h" in args or "--help" in args: + print(__doc__) + return sequential = "--sequential" in args args = [a for a in args if a != "--sequential"] verbose = "--verbose" in args or "-v" in args diff --git a/utama_core/tests/engine/test_tournament_cli_args.py b/utama_core/tests/engine/test_tournament_cli_args.py index 1854991c..df6b2a67 100644 --- a/utama_core/tests/engine/test_tournament_cli_args.py +++ b/utama_core/tests/engine/test_tournament_cli_args.py @@ -1,6 +1,6 @@ """Tests for `round_robin.py`'s hand-rolled `--fuzz-restarts`/`--fuzz-interval` CLI parsing (see `docs/STRATEGY_DEVELOPMENT.md`). -`round_robin.py` has no `--help` and no `argparse` — flags are parsed by +`round_robin.py` has no `argparse` — flags are parsed by scanning `sys.argv` directly inside `main()` — so these tests monkeypatch `sys.argv` and stub out `run_match` (never actually running a match/simulator) to check the flags are parsed and threaded through correctly. @@ -114,3 +114,16 @@ def _fake_run_match(config_a_name, config_b_name, *_args, **_kwargs): tournament.main() assert calls == [("build_tiki_taka_kernel_strategy", "build_low_block_kernel_strategy")] + + +def test_help_prints_usage_and_plays_nothing(monkeypatch, capsys): + # `--help` used to be taken for a config name, so it failed instead of listing the flags. + def _no_match(*_args, **_kwargs): + raise AssertionError("--help must not play a match") + + monkeypatch.setattr(tournament, "run_match", _no_match) + for flag in ("--help", "-h"): + monkeypatch.setattr("sys.argv", ["round_robin.py", flag]) + tournament.main() + out = capsys.readouterr().out + assert "--pair A B" in out and "--reuse" in out