Hide live tie metadata and stream CI logs

This commit is contained in:
Daniel Schädler 2026-04-15 14:35:00 +02:00
parent 3e2400616b
commit 24d4c0a253
3 changed files with 51 additions and 40 deletions

View File

@ -282,6 +282,11 @@ class GroupStageService
compared_group_score = sorted_group_scores[comparison_index]
comparison_reason = group_score.comparison_reason_against(compared_group_score)
if comparison_reason[:tied] && !group_ready_for_decider_check
decisions[group_score_cache_key(group_score)] = nil
next
end
decisions[group_score_cache_key(group_score)] = {
resolved_by: comparison_reason[:resolved_by].to_s,
compared_with_team_id: compared_group_score.team.id,

View File

@ -300,7 +300,7 @@ RSpec.describe GroupStageService do
)
end
it 'does not request a decider while regular matches in the group are still unfinished' do
it 'does not expose unresolved tie metadata while regular matches in the group are still unfinished' do
tournament.update!(playoff_teams_amount: 1, instant_finalists_amount: 1, intermediate_round_participants_amount: 0)
create(:group_match, group: group, state: :in_progress).tap do |match|
@ -315,23 +315,11 @@ RSpec.describe GroupStageService do
GroupStageService.send(:recalculate_position_of_group_scores!, [score_a, score_b, score_c, score_d]).each(&:save!)
expect(GroupStageService.ranking_decision_for(score_a)).to include(
resolved_by: 'tie',
direct_comparison_result: 'draw',
hidden_points_result: 'not_played',
tied: true,
needs_decider_match: false
)
expect(GroupStageService.ranking_decision_for(score_b)).to include(
resolved_by: 'tie',
direct_comparison_result: 'draw',
hidden_points_result: 'not_played',
tied: true,
needs_decider_match: false
)
expect(GroupStageService.ranking_decision_for(score_a)).to be_nil
expect(GroupStageService.ranking_decision_for(score_b)).to be_nil
end
it 'marks unresolved ties outside the advancing cutoff without requesting a decider' do
it 'does not expose unresolved tie metadata outside the advancing cutoff before the group is finished' do
tournament.update!(playoff_teams_amount: 2, instant_finalists_amount: 2, intermediate_round_participants_amount: 0)
score_a = create(:group_score, group: group, team: team_a, group_points: 9, scored_points: 5, received_points: 1, position: 1)
@ -342,18 +330,8 @@ RSpec.describe GroupStageService do
GroupStageService.send(:recalculate_position_of_group_scores!, [score_a, score_b, score_c, score_d]).each(&:save!)
expect([score_a.position, score_b.position, score_c.position, score_d.position]).to eq([1, 2, 3, 3])
expect(GroupStageService.ranking_decision_for(score_c)).to include(
resolved_by: 'tie',
hidden_points_result: 'not_played',
tied: true,
needs_decider_match: false
)
expect(GroupStageService.ranking_decision_for(score_d)).to include(
resolved_by: 'tie',
hidden_points_result: 'not_played',
tied: true,
needs_decider_match: false
)
expect(GroupStageService.ranking_decision_for(score_c)).to be_nil
expect(GroupStageService.ranking_decision_for(score_d)).to be_nil
end
it 'uses the decider hidden points to resolve a cutoff tie' do

View File

@ -131,6 +131,31 @@ def _run_subprocess(command, env=None, capture_output=False, check=True):
return completed
def _stream_subprocess(command, env=None, check=True):
process = subprocess.Popen(
command,
env=env,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
bufsize=1,
)
output_chunks = []
assert process.stdout is not None
for line in process.stdout:
print(line, end="")
output_chunks.append(line)
process.wait()
output = "".join(output_chunks)
if check and process.returncode != 0:
raise subprocess.CalledProcessError(process.returncode, command, output=output, stderr=None)
return subprocess.CompletedProcess(command, process.returncode, stdout=output, stderr="")
def _compose_env(
host_port=SERVER_PORT,
app_image=PRODUCTION_TAG,
@ -164,6 +189,15 @@ def _format_command(command):
return " ".join(shlex.quote(part) for part in command)
def _rspec_command(*paths):
command = ["bundle", "exec", "rspec", *paths]
if os.environ.get("CI"):
command.extend(["--format", "documentation", "--no-color"])
else:
command.extend(["--format", "progress", "--tty"])
return command
def _compose_run(compose_args, env, capture_output=False, check=True):
command = _docker_compose_cmd() + compose_args
return _run_subprocess(command, env=env, capture_output=capture_output, check=check)
@ -283,13 +317,9 @@ def _run_blackbox_rspec(base_url, email, password, username, alt_email=E2E_ALT_E
TURNIERE_E2E_ALT_PASSWORD=alt_password,
TURNIERE_E2E_ALT_USERNAME=alt_username,
)
command = ["bundle", "exec", "rspec", "spec/e2e/http", "--format", "documentation"]
command = _rspec_command("spec/e2e/http")
print(_format_command(command))
result = _run_subprocess(command, env=env, capture_output=True, check=False)
if result.stdout:
print(result.stdout.rstrip())
if result.stderr:
print(result.stderr.rstrip())
result = _stream_subprocess(command, env=env, check=False)
report = _parse_rspec_report(f"{result.stdout}\n{result.stderr}")
_print_header("Blackbox report")
@ -419,7 +449,7 @@ def start_test_local(
@task
def test(c):
"""Run the normal RSpec suite."""
c.run(_bundle_exec("rspec", "--format", "progress", "--tty"), pty=True)
_stream_subprocess(_rspec_command(), env=_env())
@task(name="test-shard")
@ -451,11 +481,9 @@ def test_shard(c, node_index=1, node_total=8, dry_run=False):
if not files:
return
c.run(
_bundle_exec("rspec", "--format", "progress", "--tty") +
" --require ./spec/rails_helper " +
" ".join(shlex.quote(path) for path in files),
pty=True,
_stream_subprocess(
_rspec_command("--require", "./spec/rails_helper", *files),
env=_env(),
)