Skip to content

Commit 3e5a8d9

Browse files
feat(codecov): Add output coverage file step 1 (#92044)
Closes https://linear.app/getsentry/issue/CCMRG-427/step-1-outputting-coverage-file-in-ci Adds step 1 of TA onboarding Preview: https://sentry-2ag4w6q3q.sentry.dev/codecov/tests/new
1 parent de8eab6 commit 3e5a8d9

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

static/app/views/codecov/tests/onboarding.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import styled from '@emotion/styled';
55
import RadioGroup from 'sentry/components/forms/controls/radioGroup';
66
import {t} from 'sentry/locale';
77
import {space} from 'sentry/styles/space';
8+
import {OutputCoverageFile} from 'sentry/views/codecov/tests/onboardingSteps/outputCoverageFile';
9+
import TestPreOnboardingPage from 'sentry/views/codecov/tests/preOnboarding';
810

911
type SetupOption = 'githubAction' | 'cli';
1012

@@ -22,6 +24,7 @@ export default function TestsOnboardingPage() {
2224
return (
2325
<LayoutGap>
2426
<p>Test Analytics Onboarding</p>
27+
<TestPreOnboardingPage />
2528
<OnboardingContainer>
2629
<IntroContainer>
2730
<GetStartedHeader>{t('Get Started with Test Analytics')}</GetStartedHeader>
@@ -41,6 +44,9 @@ export default function TestsOnboardingPage() {
4144
['cli', t("Use Sentry Prevent's CLI to upload testing reports")],
4245
]}
4346
/>
47+
<StepsContainer>
48+
<OutputCoverageFile step="1" />
49+
</StepsContainer>
4450
</OnboardingContainer>
4551
</LayoutGap>
4652
);
@@ -78,3 +84,7 @@ const SelectOptionHeader = styled('h5')`
7884
color: ${p => p.theme.tokens.content.primary};
7985
margin-top: ${space(3)};
8086
`;
87+
88+
const StepsContainer = styled('div')`
89+
padding: ${space(3)} ${space(4)};
90+
`;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import styled from '@emotion/styled';
2+
3+
import {space} from 'sentry/styles/space';
4+
5+
const Container = styled('div')`
6+
display: flex;
7+
flex-direction: column;
8+
gap: ${space(1)};
9+
border: 1px solid ${p => p.theme.border};
10+
border-radius: ${p => p.theme.borderRadius};
11+
padding: ${space(2)} ${space(3)};
12+
`;
13+
14+
const Header = styled('h3')`
15+
font-size: ${p => p.theme.fontSizeExtraLarge};
16+
color: ${p => p.theme.gray300};
17+
margin-bottom: 0;
18+
`;
19+
20+
const Content = styled('div')`
21+
/* flex-grow: 1; */
22+
`;
23+
24+
export const OnboardingStep = {
25+
Container,
26+
Header,
27+
Content,
28+
};
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import {Fragment, useState} from 'react';
2+
import {Link} from 'react-router-dom';
3+
import styled from '@emotion/styled';
4+
5+
import {CodeSnippet} from 'sentry/components/codeSnippet';
6+
import {Select} from 'sentry/components/core/select';
7+
import {t, tct} from 'sentry/locale';
8+
import {space} from 'sentry/styles/space';
9+
import {OnboardingStep} from 'sentry/views/codecov/tests/onboardingSteps/onboardingStep';
10+
11+
interface OutputCoverageFileProps {
12+
step: string;
13+
}
14+
15+
type Frameworks = 'jest' | 'vitest' | 'pytest' | 'phpunit';
16+
17+
const INSTALL_REQUIREMENTS_SNIPPETS: Record<Frameworks, string> = {
18+
jest: `pytest --cov --junitxml=junit.xml -o junit_family=legacy`,
19+
vitest: `vitest --reporter=junit --outputFile=test-report.junit.xml`,
20+
pytest: `npm i --save-dev jest-junit`,
21+
phpunit: `./vendor/bin/phpunit --log-junit junit.xml`,
22+
};
23+
24+
const GENERATE_FILE_SNIPPETS: Record<Frameworks, string> = {
25+
jest: '',
26+
vitest: '',
27+
pytest: `JEST_JUNIT_CLASSNAME="{filepath}" jest --reporters=jest-junit`,
28+
phpunit: '',
29+
};
30+
31+
export function OutputCoverageFile({step}: OutputCoverageFileProps) {
32+
const headerText = tct('Step [step]: Output a JUnit XML file in your CI', {
33+
step,
34+
});
35+
const [selectedFramework, setSelectedFramework] = useState<Frameworks>('jest');
36+
37+
return (
38+
<OnboardingStep.Container>
39+
<OnboardingStep.Header>{headerText}</OnboardingStep.Header>
40+
<OnboardingStep.Content>
41+
<p>
42+
{tct(
43+
"Select your language below to generate your testing reports. If your language isn't listed, visit [supported] for your testing framework. Currently, Sentry supports JUnit XML format only.",
44+
{
45+
supported: (
46+
// TODO: the new version of this link is still TBD
47+
<Link to="https://docs.codecov.com/docs/test-analytics#:~:text=Only%20JUnit%20XML%20test%20result%20files%20are%20supported%20at%20the%20moment">
48+
{t('supported languages')}
49+
</Link>
50+
),
51+
}
52+
)}
53+
</p>
54+
<StyledSelectControl
55+
size="md"
56+
options={[
57+
{label: 'Jest', value: 'jest'},
58+
{label: 'Vitest', value: 'vitest'},
59+
{label: 'Pytest', value: 'pytest'},
60+
{label: 'PHPunit', value: 'phpunit'},
61+
]}
62+
value={selectedFramework}
63+
onChange={(option: {value: Frameworks}) => setSelectedFramework(option.value)}
64+
/>
65+
<StyledInstruction>
66+
{t('Install requirements in your terminal:')}
67+
</StyledInstruction>
68+
<CodeSnippet dark language="bash">
69+
{INSTALL_REQUIREMENTS_SNIPPETS[selectedFramework]}
70+
</CodeSnippet>
71+
{selectedFramework === 'pytest' ? (
72+
<Fragment>
73+
<StyledInstruction>
74+
{t('Generate a JUnit XML file that contains the results of your test run.')}
75+
</StyledInstruction>
76+
<CodeSnippet dark language="bash">
77+
{GENERATE_FILE_SNIPPETS.pytest}
78+
</CodeSnippet>
79+
</Fragment>
80+
) : null}
81+
</OnboardingStep.Content>
82+
</OnboardingStep.Container>
83+
);
84+
}
85+
86+
const StyledSelectControl = styled(Select)`
87+
width: 110px;
88+
margin-bottom: ${space(1.5)};
89+
`;
90+
91+
const StyledInstruction = styled('p')`
92+
margin: ${space(1.5)} 0;
93+
`;

static/app/views/codecov/tests/tests.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import PageFiltersContainer from 'sentry/components/organizations/pageFilters/co
88
import {space} from 'sentry/styles/space';
99
import {decodeSorts} from 'sentry/utils/queryString';
1010
import {useLocation} from 'sentry/utils/useLocation';
11+
import TestsOnboardingPage from 'sentry/views/codecov/tests/onboarding';
1112
import {DEFAULT_SORT} from 'sentry/views/codecov/tests/settings';
1213
import {Summaries} from 'sentry/views/codecov/tests/summaries/summaries';
1314
import type {ValidSort} from 'sentry/views/codecov/tests/testAnalyticsTable/testAnalyticsTable';
@@ -81,6 +82,7 @@ export default function TestsPage() {
8182
{/* TODO: Conditionally show these if the branch we're in is the main branch */}
8283
<Summaries />
8384
<TestAnalyticsTable response={fakeApiResponse} sort={sorts[0]} />
85+
<TestsOnboardingPage />
8486
</LayoutGap>
8587
);
8688
}

0 commit comments

Comments
 (0)