Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions dev/archery/archery/crossbow/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import fnmatch
import functools
import time
from urllib.parse import quote

import click
import requests
Expand Down Expand Up @@ -82,6 +83,14 @@ def task_url(self, task):
# show link to the actual build, some CI providers implement
# the statuses API others implement the checks API, retrieve any.
return build_links[0]
elif task.ci == 'github':
branch = quote(task.branch, safe='')
return f'{self.repo_url}/actions?query=branch:{branch}'
elif task.ci == 'azure':
repo = '/'.join(self.repo_url.rsplit('/', 2)[-2:])
branch = quote(task.branch, safe='')
return (f'https://dev.azure.com/{repo}/_build/latest'
f'?definitionId=1&branchName={branch}')
else:
# show link to the branch if no status build link was found.
return self.branch_url(task.branch)
Expand Down
75 changes: 75 additions & 0 deletions dev/archery/archery/crossbow/tests/test_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,87 @@

import re
import textwrap
from unittest import mock

import pytest

from archery.crossbow.cli import (NightlyEmailReport, TokenExpirationEmailReport)
from archery.crossbow.core import yaml
from archery.crossbow.reports import (ChatReport, CommentReport, Report)


@pytest.mark.parametrize(('ci', 'expected_url'), [
('github', 'https://github.com/apache/crossbow/actions?query=branch:{branch}'),
('azure', 'https://dev.azure.com/apache/crossbow/_build/latest'
'?definitionId=1&branchName={branch}'),
('travis', 'https://github.com/apache/crossbow/tree/{branch}'),
('circle', 'https://github.com/apache/crossbow/tree/{branch}'),
('appveyor', 'https://github.com/apache/crossbow/tree/{branch}'),
('drone', 'https://github.com/apache/crossbow/tree/{branch}'),
])
def test_crossbow_task_url_without_build_link(load_fixture, ci, expected_url):
job = load_fixture('crossbow-job.yaml', decoder=yaml.load)
task = job.tasks['docker-cpp-cmake32']
task.ci = ci
task.status().build_links = []

report = Report(job)
assert report.task_url(task) == expected_url.format(branch=task.branch)


@pytest.mark.parametrize(('ci', 'expected_url'), [
('github', 'https://github.com/apache/crossbow/actions?query=branch:'
'feature%2Ffoo%2Bbar%26baz'),
('azure', 'https://dev.azure.com/apache/crossbow/_build/latest'
'?definitionId=1&branchName=feature%2Ffoo%2Bbar%26baz'),
])
def test_crossbow_task_url_escaped_branch(load_fixture, ci, expected_url):
job = load_fixture('crossbow-job.yaml', decoder=yaml.load)
job.queue._remote_url += '.git'
task = job.tasks['docker-cpp-cmake32']
task.ci = ci
task.branch = 'feature/foo+bar&baz'
task.status().build_links = []

assert Report(job).task_url(task) == expected_url


def test_crossbow_task_url_build_link(load_fixture):
job = load_fixture('crossbow-job.yaml', decoder=yaml.load)
task = job.tasks['docker-cpp-cmake32']
task.ci = 'github'
task.status().build_links = [
'https://github.com/apache/crossbow/actions/runs/1',
'https://github.com/apache/crossbow/actions/runs/2',
]
report = Report(job, wait_for_task=10)

with mock.patch('archery.crossbow.reports.time.sleep') as sleep:
assert report.task_url(task) == task.status().build_links[0]
sleep.assert_not_called()


@pytest.mark.parametrize('build_links', [
[],
['https://github.com/apache/crossbow/actions/runs/1'],
])
def test_crossbow_task_url_after_wait(load_fixture, build_links):
job = load_fixture('crossbow-job.yaml', decoder=yaml.load)
task = job.tasks['docker-cpp-cmake32']
task.ci = 'github'
report = Report(job, wait_for_task=10)
expected_url = (build_links[0] if build_links else
f'https://github.com/apache/crossbow/actions'
f'?query=branch:{task.branch}')

with mock.patch.object(task, 'status', side_effect=[
mock.Mock(build_links=[]), mock.Mock(build_links=build_links)
]) as status, mock.patch('archery.crossbow.reports.time.sleep') as sleep:
assert report.task_url(task) == expected_url
sleep.assert_called_once_with(10)
assert status.call_args_list == [mock.call(), mock.call(force_query=True)]


def test_crossbow_comment_formatter(load_fixture):
msg = load_fixture('crossbow-success-message.md')
job = load_fixture('crossbow-job.yaml', decoder=yaml.load)
Expand Down
Loading