Stats: Create individual component for Row children

Stats: Improve names for helpers

Signed-off-by: Erik Engervall <erik.engervall@gmail.com>
This commit is contained in:
Erik Engervall
2021-04-23 14:39:22 +02:00
parent 10c9547245
commit e3c318ded1
12 changed files with 577 additions and 432 deletions
@@ -29,14 +29,14 @@ import {
} from '@material-ui/core';
import { CenteredCircularProgress } from '../../components/CenteredCircularProgress';
import { getMappedReleases } from './helpers/getMappedReleases';
import { getMappedReleases } from './helpers/mapReleases';
import { getReleasesWithTags } from './helpers/getReleasesWithTags';
import { getSummary } from './helpers/getSummary';
import { getTags } from './helpers/getTags';
import { Row } from './Row';
import { Row } from './Row/Row';
import { Summary } from './Summary';
import { useGetStats } from './hooks/useGetStats';
import { useProjectContext } from '../../contexts/ProjectContext';
import { Warn } from './Warn';
import { Summary } from './Summary';
const useStyles = makeStyles({
table: {
@@ -64,20 +64,24 @@ export function DialogBody() {
}
const { allReleases, allTags } = stats.value;
const mappedReleases = getMappedReleases({ allReleases, project });
const tags = getTags({ allTags, project, mappedReleases });
const summary = getSummary({ mappedReleases });
const { mappedReleases } = getMappedReleases({ allReleases, project });
const { releasesWithTags } = getReleasesWithTags({
mappedReleases,
allTags,
project,
});
const summary = getSummary({ releasesWithTags });
const shouldWarn =
tags.unmappable.length > 0 ||
tags.unmatched.length > 0 ||
mappedReleases.unmatched.length > 0;
releasesWithTags.unmappableTags.length > 0 ||
releasesWithTags.unmatchedTags.length > 0 ||
releasesWithTags.unmatched.length > 0;
if (shouldWarn) {
// eslint-disable-next-line no-console
console.log("⚠️ Here's a summary of unmapped/unmatched tags/releases", {
unmappableTags: tags.unmappable,
unmatchableTags: tags.unmatched,
unmatchableReleases: mappedReleases.unmatched,
unmappableTags: releasesWithTags.unmappableTags,
unmatchedTags: releasesWithTags.unmatchedTags,
unmatchedReleases: releasesWithTags.unmatched,
});
}
@@ -98,13 +102,13 @@ export function DialogBody() {
</TableHead>
<TableBody>
{Object.entries(mappedReleases.releases).map(
([baseVersion, mappedRelease], index) => {
{Object.entries(releasesWithTags.releases).map(
([baseVersion, releaseWithTags], index) => {
return (
<Row
key={`row-${index}`}
baseVersion={baseVersion}
mappedRelease={mappedRelease}
releaseWithTags={releaseWithTags}
/>
);
},
@@ -115,7 +119,7 @@ export function DialogBody() {
<Box marginTop={2}>
{shouldWarn && (
<Warn tags={tags} mappedReleases={mappedReleases} project={project} />
<Warn releasesWithTags={releasesWithTags} project={project} />
)}
</Box>
</>
@@ -1,229 +0,0 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState } from 'react';
import { DateTime, DurationObject } from 'luxon';
import {
Box,
Collapse,
IconButton,
Link,
makeStyles,
TableCell,
TableRow,
Typography,
} from '@material-ui/core';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
import { getMappedReleases } from './helpers/getMappedReleases';
import { useGetCommit } from './hooks/useGetCommit';
import { CenteredCircularProgress } from '../../components/CenteredCircularProgress';
const useRowStyles = makeStyles({
root: {
'& > *': {
borderBottom: 'unset',
},
},
});
interface RowProps {
baseVersion: string;
mappedRelease: ReturnType<typeof getMappedReleases>['releases']['0'];
}
export function Row({ baseVersion, mappedRelease }: RowProps) {
const [open, setOpen] = useState(false);
const classes = useRowStyles();
return (
<React.Fragment>
<TableRow className={classes.root}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell component="th" scope="row">
<Link href={mappedRelease.htmlUrl} target="_blank">
{baseVersion}
{mappedRelease.versions.length === 0 ? ' (prerelease)' : ''}
</Link>
</TableCell>
<TableCell>
{mappedRelease.createdAt
? DateTime.fromISO(mappedRelease.createdAt)
.setLocale('sv-SE')
.toFormat('yyyy-MM-dd')
: '-'}
</TableCell>
<TableCell>{mappedRelease.candidates.length}</TableCell>
<TableCell>{Math.max(0, mappedRelease.versions.length - 1)}</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<CollapsedEl mappedRelease={mappedRelease} />
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
function CollapsedEl({
mappedRelease,
}: {
mappedRelease: ReturnType<typeof getMappedReleases>['releases']['0'];
}) {
const reversedCandidates = [...mappedRelease.candidates].reverse();
const { commit: releaseCut } = useGetCommit({
ref: reversedCandidates[0]?.sha,
});
const { commit: releaseComplete } = useGetCommit({
ref: mappedRelease.versions[0]?.sha,
});
console.log('*** releaseCut > ', releaseCut.value); // eslint-disable-line no-console
console.log('*** releaseComplete > ', releaseComplete.value); // eslint-disable-line no-console
let diff = { days: -1 } as DurationObject;
if (releaseCut.value?.createdAt && releaseComplete.value?.createdAt) {
diff = DateTime.fromISO(releaseComplete.value.createdAt)
.diff(DateTime.fromISO(releaseCut.value.createdAt), ['days', 'hours'])
.toObject();
}
return (
<Box
margin={1}
style={{
display: 'flex',
alignItems: 'stretch',
paddingLeft: '20%',
paddingRight: '20%',
}}
>
<Box
style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
{mappedRelease.versions.length > 0 && (
<Box margin={1} style={{ position: 'relative' }}>
{mappedRelease.versions.map(version => (
<React.Fragment key={version.tagName}>
<Typography variant="body1">{version.tagName}</Typography>
</React.Fragment>
))}
</Box>
)}
{mappedRelease.versions.length > 0 && (
<Box
margin={1}
style={{
position: 'relative',
transform: 'rotate(-45deg)',
fontSize: 30,
}}
>
{' 🚀 '}
</Box>
)}
<Box margin={1} style={{ position: 'relative' }}>
{mappedRelease.candidates.map(candidate => (
<React.Fragment key={candidate.tagName}>
<Typography variant="body1">{candidate.tagName}</Typography>
</React.Fragment>
))}
</Box>
</Box>
<Box
style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
{releaseComplete.loading ? (
<CenteredCircularProgress />
) : (
<>
<Box
style={{
flex: 1,
display: 'flex',
alignItems: 'flex-end',
}}
>
Release completed{' '}
{releaseComplete.value?.createdAt &&
DateTime.fromISO(releaseComplete.value.createdAt)
.setLocale('sv-SE')
.toFormat('yyyy-MM-dd')}
</Box>
<Box
style={{
flex: 1,
display: 'flex',
alignItems: 'center',
}}
>
<Typography variant="h4">
Release time: {diff.days} days
</Typography>
</Box>
<Box
style={{
flex: 1,
display: 'flex',
alignItems: 'flex-start',
}}
>
RC created{' '}
{releaseCut.value?.createdAt &&
DateTime.fromISO(releaseCut.value.createdAt)
.setLocale('sv-SE')
.toFormat('yyyy-MM-dd')}
</Box>
</>
)}
</Box>
</Box>
);
}
@@ -0,0 +1,96 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState } from 'react';
import { DateTime } from 'luxon';
import {
Collapse,
IconButton,
Link,
makeStyles,
TableCell,
TableRow,
} from '@material-ui/core';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
import { getReleasesWithTags } from '../helpers/getReleasesWithTags';
import { RowCollapsed } from './RowCollapsed/RowCollapsed';
const useRowStyles = makeStyles({
root: {
'& > *': {
borderBottom: 'unset',
},
},
});
interface RowProps {
baseVersion: string;
releaseWithTags: ReturnType<
typeof getReleasesWithTags
>['releasesWithTags']['releases']['0'];
}
export function Row({ baseVersion, releaseWithTags }: RowProps) {
const [open, setOpen] = useState(false);
const classes = useRowStyles();
return (
<React.Fragment>
<TableRow className={classes.root}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell component="th" scope="row">
<Link href={releaseWithTags.htmlUrl} target="_blank">
{baseVersion}
{releaseWithTags.versions.length === 0 ? ' (prerelease)' : ''}
</Link>
</TableCell>
<TableCell>
{releaseWithTags.createdAt
? DateTime.fromISO(releaseWithTags.createdAt)
.setLocale('sv-SE')
.toFormat('yyyy-MM-dd')
: '-'}
</TableCell>
<TableCell>{releaseWithTags.candidates.length}</TableCell>
<TableCell>
{Math.max(0, releaseWithTags.versions.length - 1)}
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<RowCollapsed releaseWithTags={releaseWithTags} />
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
@@ -0,0 +1,71 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box, Typography } from '@material-ui/core';
import { getReleasesWithTags } from '../../helpers/getReleasesWithTags';
export function ReleaseTagList({
releaseWithTags,
}: {
releaseWithTags: ReturnType<
typeof getReleasesWithTags
>['releasesWithTags']['releases']['0'];
}) {
return (
<Box
style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
{releaseWithTags.versions.length > 0 && (
<Box style={{ position: 'relative' }}>
{releaseWithTags.versions.map(version => (
<Typography variant="body1" key={version.tagName}>
{version.tagName}
</Typography>
))}
</Box>
)}
{releaseWithTags.versions.length > 0 && (
<Box
margin={1}
style={{
position: 'relative',
transform: 'rotate(-45deg)',
fontSize: 30,
}}
>
{' 🚀 '}
</Box>
)}
<Box style={{ position: 'relative' }}>
{releaseWithTags.candidates.map(candidate => (
<Typography variant="body1" key={candidate.tagName}>
{candidate.tagName}
</Typography>
))}
</Box>
</Box>
);
}
@@ -0,0 +1,139 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box, Typography } from '@material-ui/core';
import { DateTime } from 'luxon';
import { CenteredCircularProgress } from '../../../../components/CenteredCircularProgress';
import { getReleasesWithTags } from '../../helpers/getReleasesWithTags';
import { useGetCommit } from '../../hooks/useGetCommit';
import { Alert } from '@material-ui/lab';
interface ReleaseTimeProps {
releaseWithTags: ReturnType<
typeof getReleasesWithTags
>['releasesWithTags']['releases']['0'];
}
export function ReleaseTime({ releaseWithTags }: ReleaseTimeProps) {
const reversedCandidates = [...releaseWithTags.candidates].reverse();
const firstCandidateSha = reversedCandidates[0]?.sha;
const { commit: releaseCut } = useGetCommit({ ref: firstCandidateSha });
const mostRecentVersionSha = releaseWithTags.versions[0]?.sha;
const { commit: releaseComplete } = useGetCommit({
ref: mostRecentVersionSha,
});
if (releaseCut.loading || releaseComplete.loading) {
return (
<Wrapper>
<CenteredCircularProgress />
</Wrapper>
);
}
if (releaseCut.error) {
return (
<Alert severity="error">
Failed to fetch the first Release Candidate commit (
{releaseCut.error.message})
</Alert>
);
}
if (releaseComplete.error) {
return (
<Alert severity="error">
Failed to fetch the final Release Version Commit (
{releaseComplete.error.message})
</Alert>
);
}
const diff =
releaseCut.value?.createdAt && releaseComplete.value?.createdAt
? DateTime.fromISO(releaseComplete.value.createdAt)
.diff(DateTime.fromISO(releaseCut.value.createdAt), ['days', 'hours'])
.toObject()
: { days: -1 };
return (
<Wrapper>
<Box
style={{
flex: 1,
display: 'flex',
alignItems: 'flex-start',
}}
>
<Typography variant="body1">
Release completed{' '}
{releaseComplete.value?.createdAt &&
DateTime.fromISO(releaseComplete.value.createdAt)
.setLocale('sv-SE')
.toFormat('yyyy-MM-dd')}
</Typography>
</Box>
<Box
style={{
flex: 1,
display: 'flex',
alignItems: 'center',
}}
>
<Typography variant="h5" color="secondary">
Release time: {diff.days} days
</Typography>
</Box>
<Box
style={{
flex: 1,
display: 'flex',
alignItems: 'flex-end',
}}
>
<Typography variant="body1">
Release Candidate created{' '}
{releaseCut.value?.createdAt &&
DateTime.fromISO(releaseCut.value.createdAt)
.setLocale('sv-SE')
.toFormat('yyyy-MM-dd')}
</Typography>
</Box>
</Wrapper>
);
}
function Wrapper({ children }: { children: React.ReactNode }) {
return (
<Box
style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
{children}
</Box>
);
}
@@ -0,0 +1,45 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box } from '@material-ui/core';
import { getReleasesWithTags } from '../../helpers/getReleasesWithTags';
import { ReleaseTime } from './ReleaseTime';
import { ReleaseTagList } from './ReleaseTagList';
interface RowCollapsedProps {
releaseWithTags: ReturnType<
typeof getReleasesWithTags
>['releasesWithTags']['releases']['0'];
}
export function RowCollapsed({ releaseWithTags }: RowCollapsedProps) {
return (
<Box
margin={1}
style={{
display: 'flex',
alignItems: 'stretch',
paddingLeft: '10%',
paddingRight: '10%',
}}
>
<ReleaseTagList releaseWithTags={releaseWithTags} />
<ReleaseTime releaseWithTags={releaseWithTags} />
</Box>
);
}
@@ -17,36 +17,36 @@
import React from 'react';
import { Alert } from '@material-ui/lab';
import { getMappedReleases } from './helpers/getMappedReleases';
import { getTags } from './helpers/getTags';
import { getReleasesWithTags } from './helpers/getReleasesWithTags';
import { Project } from '../../contexts/ProjectContext';
interface WarnProps {
tags: ReturnType<typeof getTags>;
mappedReleases: ReturnType<typeof getMappedReleases>;
releasesWithTags: ReturnType<typeof getReleasesWithTags>['releasesWithTags'];
project: Project;
}
export const Warn = ({ tags, mappedReleases, project }: WarnProps) => {
export const Warn = ({ releasesWithTags, project }: WarnProps) => {
return (
<Alert severity="warning" style={{ marginBottom: 10 }}>
{tags.unmappable.length > 0 && (
{releasesWithTags.unmappableTags.length > 0 && (
<div>
Failed to map <strong>{tags.unmappable.length}</strong> tags to
Failed to map{' '}
<strong>{releasesWithTags.unmappableTags.length}</strong> tags to
releases
</div>
)}
{tags.unmatched.length > 0 && (
{releasesWithTags.unmatchedTags.length > 0 && (
<div>
Failed to match <strong>{tags.unmatched.length}</strong> tags to{' '}
Failed to match{' '}
<strong>{releasesWithTags.unmatchedTags.length}</strong> tags to{' '}
{project.versioningStrategy}
</div>
)}
{mappedReleases.unmatched.length > 0 && (
{releasesWithTags.unmatched.length > 0 && (
<div>
Failed to match <strong>{mappedReleases.unmatched.length}</strong>{' '}
Failed to match <strong>{releasesWithTags.unmatched.length}</strong>{' '}
releases to {project.versioningStrategy}
</div>
)}
@@ -1,82 +0,0 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { calverRegexp } from '../../../helpers/tagParts/getCalverTagParts';
import { GetAllReleasesResult } from '../../../api/PluginApiClient';
import { Project } from '../../../contexts/ProjectContext';
import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
export function getMappedReleases({
allReleases,
project,
}: {
allReleases: GetAllReleasesResult;
project: Project;
}) {
return allReleases.reduce(
(
acc: {
unmatched: string[];
releases: {
[baseVersion: string]: {
createdAt: string | null;
candidates: {
tagName: string;
sha: string;
}[];
versions: {
tagName: string;
sha: string;
}[];
htmlUrl: string;
};
};
},
release,
) => {
const match =
project.versioningStrategy === 'semver'
? release.tagName.match(semverRegexp)
: release.tagName.match(calverRegexp);
if (!match) {
acc.unmatched.push(release.tagName);
return acc;
}
const prefix = match[1];
const baseVersion =
project.versioningStrategy === 'semver'
? `${match[2]}.${match[3]}`
: match[2];
if (!acc.releases[baseVersion]) {
acc.releases[baseVersion] = {
createdAt: release.createdAt,
candidates:
prefix === 'rc' ? [{ tagName: release.tagName, sha: '' }] : [],
versions:
prefix === 'version' ? [{ tagName: release.tagName, sha: '' }] : [],
htmlUrl: release.htmlUrl,
};
return acc;
}
return acc;
},
{ unmatched: [], releases: {} },
);
}
@@ -0,0 +1,101 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { calverRegexp } from '../../../helpers/tagParts/getCalverTagParts';
import { GetAllTagsResult } from '../../../api/PluginApiClient';
import { getMappedReleases } from './mapReleases';
import { Project } from '../../../contexts/ProjectContext';
import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
export function getReleasesWithTags({
allTags,
project,
mappedReleases,
}: {
allTags: GetAllTagsResult;
project: Project;
mappedReleases: ReturnType<typeof getMappedReleases>['mappedReleases'];
}) {
return {
releasesWithTags: allTags.reduce(
(
acc: ReturnType<typeof getMappedReleases>['mappedReleases'] & {
unmatchedTags: string[];
unmappableTags: string[];
},
tag,
) => {
const match =
project.versioningStrategy === 'semver'
? tag.tagName.match(semverRegexp)
: tag.tagName.match(calverRegexp);
if (!match) {
acc.unmatchedTags.push(tag.tagName);
return acc;
}
const prefix = match[1];
const baseVersion =
project.versioningStrategy === 'semver'
? `${match[2]}.${match[3]}`
: match[2];
if (!acc.releases[baseVersion]) {
acc.unmappableTags.push(tag.tagName);
return acc;
}
if (prefix === 'rc') {
const existingEntry = acc.releases[baseVersion].candidates.find(
({ tagName }) => tagName === tag.tagName,
);
if (existingEntry) {
existingEntry.sha = tag.sha;
} else {
acc.releases[baseVersion].candidates.push({
tagName: tag.tagName,
sha: tag.sha,
});
}
}
if (prefix === 'version') {
const existingEntry = acc.releases[baseVersion].versions.find(
({ tagName }) => tagName === tag.tagName,
);
if (existingEntry) {
existingEntry.sha = tag.sha;
} else {
acc.releases[baseVersion].versions.push({
tagName: tag.tagName,
sha: tag.sha,
});
}
}
return acc;
},
{
...mappedReleases,
unmatchedTags: [],
unmappableTags: [],
},
),
};
}
@@ -14,14 +14,14 @@
* limitations under the License.
*/
import { getMappedReleases } from './getMappedReleases';
import { getReleasesWithTags } from './getReleasesWithTags';
export function getSummary({
mappedReleases,
releasesWithTags,
}: {
mappedReleases: ReturnType<typeof getMappedReleases>;
releasesWithTags: ReturnType<typeof getReleasesWithTags>['releasesWithTags'];
}) {
return Object.entries(mappedReleases.releases).reduce(
return Object.entries(releasesWithTags.releases).reduce(
(
acc: {
totalReleases: number;
@@ -1,89 +0,0 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { calverRegexp } from '../../../helpers/tagParts/getCalverTagParts';
import { GetAllTagsResult } from '../../../api/PluginApiClient';
import { getMappedReleases } from './getMappedReleases';
import { Project } from '../../../contexts/ProjectContext';
import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
export function getTags({
allTags,
project,
mappedReleases,
}: {
allTags: GetAllTagsResult;
project: Project;
mappedReleases: ReturnType<typeof getMappedReleases>;
}) {
return allTags.reduce(
(acc: { unmatched: string[]; unmappable: string[] }, tag) => {
const match =
project.versioningStrategy === 'semver'
? tag.tagName.match(semverRegexp)
: tag.tagName.match(calverRegexp);
if (!match) {
acc.unmatched.push(tag.tagName);
return acc;
}
const prefix = match[1];
const baseVersion =
project.versioningStrategy === 'semver'
? `${match[2]}.${match[3]}`
: match[2];
if (!mappedReleases.releases[baseVersion]) {
acc.unmappable.push(tag.tagName);
return acc;
}
if (prefix === 'rc') {
const existingEntry = mappedReleases.releases[
baseVersion
].candidates.find(({ tagName }) => tagName === tag.tagName);
if (existingEntry) {
existingEntry.sha = tag.sha;
} else {
mappedReleases.releases[baseVersion].candidates.push({
tagName: tag.tagName,
sha: tag.sha,
});
}
}
if (prefix === 'version') {
const existingEntry = mappedReleases.releases[
baseVersion
].versions.find(({ tagName }) => tagName === tag.tagName);
if (existingEntry) {
existingEntry.sha = tag.sha;
} else {
mappedReleases.releases[baseVersion].versions.push({
tagName: tag.tagName,
sha: tag.sha,
});
}
}
return acc;
},
{ unmatched: [], unmappable: [] },
);
}
@@ -0,0 +1,89 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { calverRegexp } from '../../../helpers/tagParts/getCalverTagParts';
import { GetAllReleasesResult } from '../../../api/PluginApiClient';
import { Project } from '../../../contexts/ProjectContext';
import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
export function getMappedReleases({
allReleases,
project,
}: {
allReleases: GetAllReleasesResult;
project: Project;
}) {
return {
mappedReleases: allReleases.reduce(
(
acc: {
unmatched: string[];
releases: {
[baseVersion: string]: {
createdAt: string | null;
candidates: {
tagName: string;
sha: string;
}[];
versions: {
tagName: string;
sha: string;
}[];
htmlUrl: string;
};
};
},
release,
) => {
const match =
project.versioningStrategy === 'semver'
? release.tagName.match(semverRegexp)
: release.tagName.match(calverRegexp);
if (!match) {
acc.unmatched.push(release.tagName);
return acc;
}
const prefix = match[1];
const baseVersion =
project.versioningStrategy === 'semver'
? `${match[2]}.${match[3]}`
: match[2];
if (!acc.releases[baseVersion]) {
acc.releases[baseVersion] = {
createdAt: release.createdAt,
candidates:
prefix === 'rc' ? [{ tagName: release.tagName, sha: '' }] : [],
versions:
prefix === 'version'
? [{ tagName: release.tagName, sha: '' }]
: [],
htmlUrl: release.htmlUrl,
};
return acc;
}
return acc;
},
{
unmatched: [],
releases: {},
},
),
};
}