Bug 1618751 - Push Health show trunk parent and commits

This commit is contained in:
Cameron Dawson 2020-02-28 14:24:30 -08:00
Родитель ab28c4ccb4
Коммит bfdd99d9b9
9 изменённых файлов: 439 добавлений и 284 удалений

Просмотреть файл

@ -3,12 +3,12 @@ import datetime
import responses
from treeherder.model.models import Push
from treeherder.push_health.compare import (get_parent,
from treeherder.push_health.compare import (get_commit_history,
get_response_object)
def test_get_response_object(test_push, test_repository):
resp = get_response_object('1234', test_push, test_repository)
resp = get_response_object('1234', [1, 2], 2, test_push, test_repository)
assert resp['parentSha'] == '1234'
assert resp['id'] == 1
assert resp['exactMatch'] is False
@ -16,7 +16,7 @@ def test_get_response_object(test_push, test_repository):
@responses.activate
def test_get_parent(test_push, test_repository):
def test_get_commit_history_automationrelevance(test_push, test_repository):
test_revision = '4c45a777949168d16c03a4cba167678b7ab65f76'
parent_revision = 'abcdef77949168d16c03a4cba167678b7ab65f76'
Push.objects.create(
@ -25,28 +25,101 @@ def test_get_parent(test_push, test_repository):
author='foo@bar.baz',
time=datetime.datetime.now()
)
commits_url = '{}/json-pushes?version=2&full=1&changeset={}'.format(
test_repository.url, test_revision)
commits = {'pushes': {1: {'changesets': [{'parents': [parent_revision]}]}}}
responses.add(responses.GET, commits_url, json=commits, content_type='application/json', status=200)
autorel_commits = {'changesets': [
{
'author': 'Cheech Marin <cheech.marin@gmail.com>', 'backsoutnodes': [],
'desc': 'Bug 1612891 - Suppress parsing easing error in early returns of ConvertKeyframeSequence.\n\nWe add a stack based class and supress the exception of parsing easing\nin the destructor, to avoid hitting the potential assertions.\n\nDifferential Revision: https://phabricator.services.mozilla.com/D64268\nDifferential Diff: PHID-DIFF-c4e7dcfpalwiem7bxsnk',
'node': '3ca259f9cbdea763e64f10e286e58b271d89ab9d',
'parents': [parent_revision],
},
{
'author': 'libmozevent <release-mgmt-analysis@mozilla.com>',
'desc': 'try_task_config for https://phabricator.services.mozilla.com/D64268\nDifferential Diff: PHID-DIFF-c4e7dcfpalwiem7bxsnk',
'node': '18f68eb12ebbd88fe3a4fc3afe7df6529a0153fb',
'parents': ['3ca259f9cbdea763e64f10e286e58b271d89ab9d'],
}
], 'visible': True}
parent = get_parent(test_repository, test_revision, test_push)
assert parent['parentSha'] == parent_revision
assert parent['revision'] == parent_revision
autorel_url = 'https://hg.mozilla.org/{}/json-automationrelevance/{}'.format(
test_repository.name, test_revision)
responses.add(
responses.GET,
autorel_url,
json=autorel_commits,
content_type='application/json',
status=200
)
history = get_commit_history(test_repository, test_revision, test_push)
assert history['parentSha'] == parent_revision
assert history['revision'] == parent_revision
@responses.activate
def test_get_parent_not_found(test_push, test_repository):
def test_get_commit_history_json_pushes(test_push, test_repository):
test_revision = '4c45a777949168d16c03a4cba167678b7ab65f76'
parent_revision = 'abcdef77949168d16c03a4cba167678b7ab65f76'
Push.objects.create(
revision=parent_revision,
repository=test_repository,
author='foo@bar.baz',
time=datetime.datetime.now()
)
autorel_url = 'https://hg.mozilla.org/{}/json-automationrelevance/{}'.format(
test_repository.name, test_revision)
responses.add(
responses.GET,
autorel_url,
json={},
content_type='application/json',
status=500
)
jsonpushes_commits = {
'pushes': {'108872': {'changesets': [
{
'author': 'Hiro Protagonist <hprotagonist@gmail.com>',
'desc': 'Bug 1617666 - Use a separate Debugger to improve performance of eval.',
'node': '4fb5e268cf7440332e917e431f14e8bb6dc41a0d',
'parents': [parent_revision],
}
]}}
}
commits_url = '{}/json-pushes?version=2&full=1&changeset={}'.format(
test_repository.url, test_revision)
responses.add(
responses.GET,
commits_url,
json=jsonpushes_commits,
content_type='application/json',
status=200
)
history = get_commit_history(test_repository, test_revision, test_push)
assert history['parentSha'] == parent_revision
assert history['revision'] == parent_revision
@responses.activate
def test_get_commit_history_not_found(test_push, test_repository):
test_revision = '4c45a777949168d16c03a4cba167678b7ab65f76'
# Does not exist as a Push in the DB.
parent_revision = 'abcdef77949168d16c03a4cba167678b7ab65f76'
commits_url = '{}/json-pushes?version=2&full=1&changeset={}'.format(
test_repository.url, test_revision)
commits = {'pushes': {1: {'changesets': [{'parents': [parent_revision]}]}}}
commits = {'pushes': {1: {'changesets': [
{
'author': 'Boris Chiou <boris.chiou@gmail.com>', 'backsoutnodes': [],
'desc': 'Bug 1612891 - Suppress parsing easing error in early returns of ConvertKeyframeSequence.\n\nWe add a stack based class and supress the exception of parsing easing\nin the destructor, to avoid hitting the potential assertions.\n\nDifferential Revision: https://phabricator.services.mozilla.com/D64268\nDifferential Diff: PHID-DIFF-c4e7dcfpalwiem7bxsnk',
'node': '3ca259f9cbdea763e64f10e286e58b271d89ab9d',
'parents': [parent_revision],
},
]}}}
responses.add(responses.GET, commits_url, json=commits, content_type='application/json', status=200)
parent = get_parent(test_repository, test_revision, test_push)
parent = get_commit_history(test_repository, test_revision, test_push)
assert parent['parentSha'] == parent_revision
assert parent['revision'] is None

Просмотреть файл

@ -3,8 +3,8 @@
"id": 630837,
"result": "fail",
"metrics": {
"parent": {
"name": "Parent",
"commitHistory": {
"name": "Commit History",
"result": "none",
"details": {
"parentSha": "eeb6fd68c0223a72d8714734a34d3e6da69995e1",
@ -35,7 +35,40 @@
"running": 0,
"success": 293,
"testfailed": 5
}
},
"revisions": [
{
"comments": "Bug 1596812 Part 1 - Update our custom nsisui.exe. r=agashlin\n\nSummary:\n\nMinify this file by removing the dialogs we don't need and hide all the\nunnecessary controls in the one we do need, so the stub installer code\ndoesn't have to do that manually (I would have removed those controls\naltogether, but the NSIS compiler errors out if you do that).\n\nDifferential Revision: https://phabricator.services.mozilla.com/D56576\n\n\n\nTest Plan:\n\nReviewers: agashlin\n\nSubscribers:\n\nBug #: 1596812\nDifferential Diff: PHID-DIFF-2cdiggedu3yo3ijopy7k",
"author": "Molly Howell <mhowell@mozilla.com>",
"revision": "298d6ae2f80cad932f8ec605395e7d263c86e734"
},
{
"comments": "Bug 1596812 Part 2 - NSIS WebBrowser plugin. r=agashlin\n\nSummary:\n\nThis is all the code and build files for an NSIS plugin that enables\nrendering a web page as the content of an NSIS dialog.\n\nDocumentation and the compiled binary are in later commits in this series.\n\nDifferential Revision: https://phabricator.services.mozilla.com/D56577\n\nDepends on D56576\n\nTest Plan:\n\nReviewers: agashlin\n\nSubscribers:\n\nBug #: 1596812\nDifferential Diff: PHID-DIFF-qxemgpfgytrfewwdnp3c",
"author": "Molly Howell <mhowell@mozilla.com>",
"revision": "c639aa34f1249c0b280ad71b7a131c8a8bd40a28"
},
{
"comments": "Bug 1596812 Part 3 - Compiled binary for the WebBrowser plugin. r=agashlin\n\nSummary:\n\nDifferential Revision: https://phabricator.services.mozilla.com/D56579\n\nDepends on D56577\n\nTest Plan:\n\nReviewers: agashlin\n\nSubscribers:\n\nBug #: 1596812\nDifferential Diff: PHID-DIFF-thzbkzegigfe45ytmmq3",
"author": "Molly Howell <mhowell@mozilla.com>",
"revision": "9ee489147076c8776003ff47bbf7ba4122afda44"
},
{
"comments": "Bug 1596812 Part 4 - Add the WebBrowser plugin to the installer build files. r=agashlin\n\nSummary:\n\nDifferential Revision: https://phabricator.services.mozilla.com/D56580\n\nDepends on D56579\n\nTest Plan:\n\nReviewers: agashlin\n\nSubscribers:\n\nBug #: 1596812\nDifferential Diff: PHID-DIFF-fczkua6yvptm5a7nhwdj",
"author": "Molly Howell <mhowell@mozilla.com>",
"revision": "8dff5e5e9e4fa080e93fa358e42fd2422d1e2d60"
},
{
"comments": "Bug 1596812 Part 5 - Add the web content files and include them in the installer build. r=agashlin\n\nSummary:\n\nDifferential Revision: https://phabricator.services.mozilla.com/D56581\n\nDepends on D56580\n\nTest Plan:\n\nReviewers: agashlin\n\nSubscribers:\n\nBug #: 1596812\nDifferential Diff: PHID-DIFF-klktifjsu4dzhdvk5464",
"author": "Molly Howell <mhowell@mozilla.com>",
"revision": "d00d10fe888660fe536a6e6e3f2a243c0a70431c"
},
{
"comments": "try_task_config for https://phabricator.services.mozilla.com/D56581\nDifferential Diff: PHID-DIFF-klktifjsu4dzhdvk5464",
"author": "libmozevent <release-mgmt-analysis@mozilla.com>",
"revision": "62489dedc9c4af40387b91993fa70b0e643b6b71"
}
],
"revisionCount": 6
}
},
"linting": { "name": "Linting", "result": "pass", "details": [] },

Просмотреть файл

@ -0,0 +1,85 @@
import React from 'react';
import fetchMock from 'fetch-mock';
import { render, cleanup, waitForElement } from '@testing-library/react';
import CommitHistory from '../../../ui/push-health/CommitHistory';
import pushHealth from '../mock/push_health';
beforeEach(() => {
fetchMock.get(
'/api/project/autoland/push/health_summary/?revision=eeb6fd68c0223a72d8714734a34d3e6da69995e1',
{ needInvestigation: 87, unsupported: 8 },
);
});
afterEach(() => {
cleanup();
fetchMock.reset();
});
describe('CommitHistory', () => {
const testCommitHistory = history => <CommitHistory history={history} />;
test('should show a parent commit and health icon for that parent', async () => {
const { details: commitHistory } = pushHealth.metrics.commitHistory;
const { getByText, queryByTestId } = render(
testCommitHistory(commitHistory),
);
expect(
getByText('eeb6fd68c0223a72d8714734a34d3e6da69995e1'),
).toBeInTheDocument();
expect(
queryByTestId('health-status-eeb6fd68c0223a72d8714734a34d3e6da69995e1'),
).not.toBeInTheDocument();
expect(
await waitForElement(() => getByText('87 items')),
).toBeInTheDocument();
});
test('should show warning if not exact commit match', async () => {
const { details: commitHistory } = pushHealth.metrics.commitHistory;
commitHistory.id = 123;
commitHistory.parentSha = '00000827c820f34b3b595f887f57b4c847316fcc';
commitHistory.exactMatch = false;
const { getByText } = render(testCommitHistory(commitHistory));
expect(
getByText(
'Warning: Could not find an exact match parent Push in Treeherder.',
),
).toBeInTheDocument();
expect(getByText('Closest match:')).toBeInTheDocument();
expect(
getByText('eeb6fd68c0223a72d8714734a34d3e6da69995e1'),
).toBeInTheDocument();
expect(
getByText('00000827c820f34b3b595f887f57b4c847316fcc'),
).toBeInTheDocument();
expect(
await waitForElement(() => getByText('87 items')),
).toBeInTheDocument();
});
test('should not have parent PushHealthStatus if no push id', async () => {
const { details: commitHistory } = pushHealth.metrics.commitHistory;
commitHistory.id = null;
commitHistory.parentSha = '00000827c820f34b3b595f887f57b4c847316fcc';
commitHistory.exactMatch = false;
const { getByText, queryByTestId } = render(
testCommitHistory(commitHistory),
);
expect(
await waitForElement(() =>
getByText(
'Warning: Could not find an exact match parent Push in Treeherder.',
),
),
).toBeInTheDocument();
expect(
queryByTestId('health-status-eeb6fd68c0223a72d8714734a34d3e6da69995e1'),
).not.toBeInTheDocument();
});
});

Просмотреть файл

@ -1,114 +0,0 @@
import React from 'react';
import fetchMock from 'fetch-mock';
import { render, cleanup, waitForElement } from '@testing-library/react';
import ParentPush from '../../../ui/push-health/ParentPush';
beforeEach(() => {
fetchMock.get(
'/api/project/mozilla-central/push/health_summary/?revision=76ee1827c820f34b3b595f887f57b4c847316fcc',
{ needInvestigation: 87, unsupported: 8 },
);
});
afterEach(() => {
cleanup();
fetchMock.reset();
});
const getParent = (
id = 636452,
parentSha = '76ee1827c820f34b3b595f887f57b4c847316fcc',
exactMatch = true,
) => {
return {
parentSha,
exactMatch,
revision: '76ee1827c820f34b3b595f887f57b4c847316fcc',
repository: {
id: 1,
repository_group: {
name: 'development',
description:
'Collection of repositories where code initially lands in the development process',
},
name: 'mozilla-central',
dvcs_type: 'hg',
url: 'https://hg.mozilla.org/mozilla-central',
branch: null,
codebase: 'gecko',
description: '',
active_status: 'active',
performance_alerts_enabled: false,
expire_performance_data: false,
is_try_repo: false,
tc_root_url: 'https://firefox-ci-tc.services.mozilla.com',
},
id,
jobCounts: {
completed: 8117,
pending: 236,
running: 117,
success: 8025,
retry: 40,
testfailed: 52,
},
};
};
describe('PushParent', () => {
const testPushParent = parent => <ParentPush parent={parent} />;
test('should show a parent commit and health icon for that parent', async () => {
const parent = getParent();
const { getByText, queryByTestId } = render(testPushParent(parent));
expect(
getByText('76ee1827c820f34b3b595f887f57b4c847316fcc'),
).toBeInTheDocument();
expect(
queryByTestId('health-status-76ee1827c820f34b3b595f887f57b4c847316fcc'),
).not.toBeInTheDocument();
expect(
await waitForElement(() => getByText('87 items')),
).toBeInTheDocument();
});
test('should show warning if not exact commit match', async () => {
const parent = getParent(
123,
'00000827c820f34b3b595f887f57b4c847316fcc',
false,
);
const { getByText } = render(testPushParent(parent));
expect(
getByText('Warning: Could not find an exact match parent Push.'),
).toBeInTheDocument();
expect(getByText('Closest match:')).toBeInTheDocument();
expect(
getByText('76ee1827c820f34b3b595f887f57b4c847316fcc'),
).toBeInTheDocument();
expect(
getByText('00000827c820f34b3b595f887f57b4c847316fcc'),
).toBeInTheDocument();
expect(
await waitForElement(() => getByText('87 items')),
).toBeInTheDocument();
});
test('should not have parent PushHealthStatus if no push id', async () => {
const parent = getParent(
null,
'00000827c820f34b3b595f887f57b4c847316fcc',
false,
);
const { getByText, queryByTestId } = render(testPushParent(parent));
expect(
await waitForElement(() =>
getByText('Warning: Could not find an exact match parent Push.'),
),
).toBeInTheDocument();
expect(
queryByTestId('health-status-76ee1827c820f34b3b595f887f57b4c847316fcc'),
).not.toBeInTheDocument();
});
});

Просмотреть файл

@ -8,7 +8,7 @@ from treeherder.webapp.api.serializers import RepositorySerializer
logger = logging.getLogger(__name__)
def get_response_object(parent_sha, push, repository):
def get_response_object(parent_sha, revisions, revision_count, push, repository):
resp = {
'parentSha': parent_sha,
'exactMatch': False,
@ -16,6 +16,8 @@ def get_response_object(parent_sha, push, repository):
'repository': RepositorySerializer(repository).data,
'id': None,
'jobCounts': None,
'revisions': revisions,
'revisionCount': revision_count,
}
if push:
resp.update({
@ -27,49 +29,75 @@ def get_response_object(parent_sha, push, repository):
return resp
def get_parent(repository, revision, push):
def commit_to_revision(commit):
return {
'comments': commit['desc'],
'author': commit['author'],
'revision': commit['node'],
}
def get_commits(repository, revision):
# This gets the list of revisions for the push. Treeherder only holds the the last 20 per push, so we may
# not have the oldest one.
commits_url = '{}/json-pushes?version=2&full=1&changeset={}'.format(repository.url, revision)
try:
parent_resp = list(fetch_json(commits_url)["pushes"].values())[0]
eldest_commit = parent_resp['changesets'][0]
parent_sha = eldest_commit['parents'][0]
parent_pushes = Push.objects.filter(revision=parent_sha)
len_parents = len(parent_pushes)
logger.error('len parents {}'.format(len_parents))
autorel_resp = fetch_json(
'https://hg.mozilla.org/{}/json-automationrelevance/{}'.format(
repository.name, revision))
if len_parents == 1:
parent_push = parent_pushes[0]
return get_response_object(parent_sha, parent_push, parent_push.repository)
return list(autorel_resp["changesets"])
except Exception:
# fallback to using json-pushes
elif len_parents > 1:
mc_pushes = parent_pushes.filter(repository__name='mozilla-central')
if len(mc_pushes):
logger.error('mc_pushes {}'.format(mc_pushes))
# we have more than one parent push on mozilla-central. Just pick the
# first one. No way to know which one is more correct.
mc_push = mc_pushes[0]
return get_response_object(parent_sha, mc_push, mc_push.repository)
try:
json_pushes_resp = fetch_json(
'{}/json-pushes?version=2&full=1&changeset={}'.format(
repository.url, revision))
changesets = list(json_pushes_resp["pushes"].values())[0]['changesets']
changesets.reverse()
# we have more than one push that matches, but not one in m-c,
# so let's see what we have.
for parent in parent_pushes:
logger.error('parent with repo {}'.format(parent.repository.name))
return changesets
except Exception as json_push_ex:
raise json_push_ex
# This parent doesn't have its own push, so look for it in the commits table
# If there are multiple, we don't have a way to know which is the "right" one,
# so pick the first. If the only one is a commit for the push in question, then
# skip it.
commits = Commit.objects.filter(revision=revision)
for commit in commits:
if commit.push.revision != revision:
return get_response_object(parent_sha, commit.push, commit.push.repository)
# We can't find any mention of this commit, so return what we have. Hope
# for the best that it's in the same repository as the push in question.
return get_response_object(parent_sha, None, repository)
def get_commit_history(repository, revision, push):
commits = get_commits(repository, revision) or []
revisions = [commit_to_revision(commit) for commit in commits]
revision_count = push.commits.count()
parent_sha = commits[0]['parents'][0]
parent_pushes = Push.objects.filter(revision=parent_sha)
len_parents = len(parent_pushes)
except Exception as e:
logger.exception(e)
if len_parents == 1:
parent_push = parent_pushes[0]
return get_response_object(
parent_sha, revisions, revision_count, parent_push, parent_push.repository
)
elif len_parents > 1:
mc_pushes = parent_pushes.filter(repository__name='mozilla-central')
if len(mc_pushes):
# we have more than one parent push on mozilla-central. Just pick the
# first one. No way to know which one is more correct.
mc_push = mc_pushes[0]
return get_response_object(
parent_sha, revisions, revision_count, mc_push, mc_push.repository
)
# This parent doesn't have its own push, so look for it in the commits table
# If there are multiple, we don't have a way to know which is the "right" one,
# so pick the first. If the only one is a commit for the push in question, then
# skip it.
commits = Commit.objects.filter(revision=revision)
for commit in commits:
if commit.push.revision != revision:
return get_response_object(
parent_sha, commits, revision_count, commit.push, commit.push.repository
)
# We can't find any mention of this commit, so return what we have. Hope
# for the best that it's in the same repository as the push in question.
return get_response_object(
parent_sha, revisions, revision_count, None, repository
)

Просмотреть файл

@ -14,7 +14,7 @@ from treeherder.model.models import (Job,
Push,
Repository)
from treeherder.push_health.builds import get_build_failures
from treeherder.push_health.compare import get_parent
from treeherder.push_health.compare import get_commit_history
from treeherder.push_health.linting import get_lint_failures
from treeherder.push_health.performance import get_perf_failures
from treeherder.push_health.tests import get_test_failures
@ -252,7 +252,8 @@ class PushViewSet(viewsets.ViewSet):
# Parent link only supported for Hg at this time.
# Bug https://bugzilla.mozilla.org/show_bug.cgi?id=1612645
parent_details = None if repository.dvcs_type == 'git' else get_parent(repository, revision, push)
commit_history_details = None if repository.dvcs_type == 'git' \
else get_commit_history(repository, revision, push)
build_failures = get_build_failures(push)
build_result = 'fail' if len(build_failures) else 'pass'
@ -275,10 +276,10 @@ class PushViewSet(viewsets.ViewSet):
'id': push.id,
'result': push_result,
'metrics': {
'parent': {
'name': 'Parent Push',
'commitHistory': {
'name': 'Commit History',
'result': 'none',
'details': parent_details,
'details': commit_history_details,
},
'linting': {
'name': 'Linting',

Просмотреть файл

@ -0,0 +1,113 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Alert } from 'reactstrap';
import PushHealthStatus from '../shared/PushHealthStatus';
import { RevisionList } from '../shared/RevisionList';
import { getJobsUrl } from '../helpers/url';
import RepositoryModel from '../models/repository';
import Clipboard from '../shared/Clipboard';
class CommitHistory extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
clipboardVisible: false,
};
}
showClipboard = show => {
this.setState({ clipboardVisible: show });
};
render() {
const {
history: {
repository,
revision,
jobCounts,
exactMatch,
parentSha,
id,
revisions,
revisionCount,
},
} = this.props;
const { clipboardVisible } = this.state;
const repoModel = new RepositoryModel(repository);
return (
<React.Fragment>
<h5>Parent Push</h5>
{!exactMatch && (
<div className="ml-4">
<div
className="mb-2 ml-3"
onMouseEnter={() => this.showClipboard(true)}
onMouseLeave={() => this.showClipboard(false)}
>
<Clipboard
description="full hash"
text={parentSha}
visible={clipboardVisible}
/>
<a
href={repoModel.getRevisionHref(parentSha)}
target="_blank"
rel="noopener noreferrer"
>
{parentSha}
</a>
</div>
<Alert color="warning" className="m-3 font-italics">
Warning: Could not find an exact match parent Push in Treeherder.
</Alert>
{id && <div>Closest match: </div>}
</div>
)}
{id && (
<div className="ml-5">
<a
href={`${getJobsUrl({ revision, repo: repository.name })}`}
className="mx-3"
target="_blank"
rel="noopener noreferrer"
title="Open this push in Treeherder"
>
{revision}
</a>
<PushHealthStatus
revision={revision}
repoName={repository.name}
jobCounts={jobCounts}
/>
</div>
)}
<h5 className="mt-4">Commit revisions</h5>
<RevisionList
revision={revision}
revisions={revisions.slice(0, 20)}
revisionCount={revisionCount}
repo={repoModel}
/>
</React.Fragment>
);
}
}
CommitHistory.propTypes = {
history: PropTypes.shape({
repository: PropTypes.object.isRequired,
revision: PropTypes.string.isRequired,
revisionCount: PropTypes.number.isRequired,
job_counts: PropTypes.shape({
completed: PropTypes.number.isRequired,
pending: PropTypes.number.isRequired,
running: PropTypes.number.isRequired,
}),
id: PropTypes.number,
}).isRequired,
};
export default CommitHistory;

Просмотреть файл

@ -30,7 +30,7 @@ import Metric from './Metric';
import Navigation from './Navigation';
import TestMetric from './TestMetric';
import JobListMetric from './JobListMetric';
import ParentPush from './ParentPush';
import CommitHistory from './CommitHistory';
export default class Health extends React.PureComponent {
constructor(props) {
@ -47,7 +47,7 @@ export default class Health extends React.PureComponent {
failureMessage: null,
notifications: [],
progressExpanded: true,
parentPushExpanded: false,
commitHistoryExpanded: false,
lintingExpanded: false,
buildsExpanded: false,
testsExpanded: false,
@ -159,14 +159,14 @@ export default class Health extends React.PureComponent {
notifications,
status,
progressExpanded,
parentPushExpanded,
commitHistoryExpanded,
lintingExpanded,
buildsExpanded,
testsExpanded,
performanceExpanded,
searchStr,
} = this.state;
const { tests, parent, linting, builds, performance } = metrics;
const { tests, commitHistory, linting, builds, performance } = metrics;
const { currentRepo } = this.props;
const percentComplete = status ? getPercentComplete(status) : 0;
const progress = {
@ -190,40 +190,45 @@ export default class Health extends React.PureComponent {
{!!tests && (
<Nav className="metric-buttons mb-2 pt-2 pl-3 justify-content-between w-100">
<span>
{[progress, linting, builds, tests, performance, parent].map(
metric => (
<span key={metric.name}>
{!!metric.details && (
<Button
size="sm"
className="mr-2"
color={resultColorMap[metric.result]}
title={`Click to toggle ${
metric.name
}: ${metric.result.toUpperCase()}`}
onClick={() => this.setExpanded(metric.name, true)}
key={metric.name}
>
{metric.name}
{['pass', 'fail', 'indeterminate'].includes(
metric.result,
) ? (
<FontAwesomeIcon
className="ml-1"
icon={
metric.result === 'pass'
? faCheckCircle
: faExclamationTriangle
}
/>
) : (
<span className="ml-1">{metric.value}</span>
)}
</Button>
)}
</span>
),
)}
{[
progress,
linting,
builds,
tests,
performance,
commitHistory,
].map(metric => (
<span key={metric.name}>
{!!metric.details && (
<Button
size="sm"
className="mr-2"
color={resultColorMap[metric.result]}
title={`Click to toggle ${
metric.name
}: ${metric.result.toUpperCase()}`}
onClick={() => this.setExpanded(metric.name, true)}
key={metric.name}
>
{metric.name}
{['pass', 'fail', 'indeterminate'].includes(
metric.result,
) ? (
<FontAwesomeIcon
className="ml-1"
icon={
metric.result === 'pass'
? faCheckCircle
: faExclamationTriangle
}
/>
) : (
<span className="ml-1">{metric.value}</span>
)}
</Button>
)}
</span>
))}
</span>
<span className="mr-2">
<InputFilter
@ -295,15 +300,15 @@ export default class Health extends React.PureComponent {
setExpanded={this.setExpanded}
/>
</Row>
{parent.details && (
{commitHistory.details && (
<Row className="w-100">
<Metric
name="Parent Push"
name="Commit History"
result=""
expanded={parentPushExpanded}
expanded={commitHistoryExpanded}
setExpanded={this.setExpanded}
>
<ParentPush parent={parent.details} />
<CommitHistory history={commitHistory.details} />
</Metric>
</Row>
)}

Просмотреть файл

@ -1,69 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Alert } from 'reactstrap';
import PushHealthStatus from '../shared/PushHealthStatus';
import { getJobsUrl } from '../helpers/url';
import RepositoryModel from '../models/repository';
const ParentPush = props => {
const {
parent: { repository, revision, jobCounts, exactMatch, parentSha, id },
} = props;
const repoModel = new RepositoryModel(repository);
return (
<React.Fragment>
{!exactMatch && (
<React.Fragment>
<div className="mb-2">
<a
href={repoModel.getRevisionHref(parentSha)}
target="_blank"
rel="noopener noreferrer"
>
{parentSha}
</a>
</div>
<Alert color="warning" className="m-3 font-italics">
Warning: Could not find an exact match parent Push.
</Alert>
{id && <div>Closest match: </div>}
</React.Fragment>
)}
{id && (
<React.Fragment>
<a
href={`${getJobsUrl({ revision, repo: repository.name })}`}
className="mx-1"
target="_blank"
rel="noopener noreferrer"
title="Open this push in Treeherder"
>
{revision}
</a>
<PushHealthStatus
revision={revision}
repoName={repository.name}
jobCounts={jobCounts}
/>
</React.Fragment>
)}
</React.Fragment>
);
};
ParentPush.propTypes = {
parent: PropTypes.shape({
repository: PropTypes.object.isRequired,
revision: PropTypes.string.isRequired,
job_counts: PropTypes.shape({
completed: PropTypes.number.isRequired,
pending: PropTypes.number.isRequired,
running: PropTypes.number.isRequired,
}),
id: PropTypes.number,
}).isRequired,
};
export default ParentPush;