- {releasesWithTags.unmappableTags.length > 0 && (
+ {releaseStats.unmappableTags.length > 0 && (
- Failed to map{' '}
- {releasesWithTags.unmappableTags.length} tags to
- releases
+ Failed to map {releaseStats.unmappableTags.length}{' '}
+ tags to releases
)}
- {releasesWithTags.unmatchedTags.length > 0 && (
+ {releaseStats.unmatchedTags.length > 0 && (
+
+ Failed to match {releaseStats.unmatchedTags.length}{' '}
+ tags to {project.versioningStrategy}
+
+ )}
+
+ {releaseStats.unmatchedReleases.length > 0 && (
Failed to match{' '}
- {releasesWithTags.unmatchedTags.length} tags to{' '}
+ {releaseStats.unmatchedReleases.length} releases to{' '}
{project.versioningStrategy}
)}
- {releasesWithTags.unmatched.length > 0 && (
-
- Failed to match {releasesWithTags.unmatched.length}{' '}
- releases to {project.versioningStrategy}
-
- )}
See full output in the console
);
diff --git a/plugins/github-release-manager/src/features/Stats/contexts/ReleaseStatsContext.tsx b/plugins/github-release-manager/src/features/Stats/contexts/ReleaseStatsContext.tsx
new file mode 100644
index 0000000000..be0d68e2e5
--- /dev/null
+++ b/plugins/github-release-manager/src/features/Stats/contexts/ReleaseStatsContext.tsx
@@ -0,0 +1,64 @@
+/*
+ * 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 { createContext, useContext } from 'react';
+
+import { GitHubReleaseManagerError } from '../../../errors/GitHubReleaseManagerError';
+
+export interface ReleaseStats {
+ unmappableTags: string[];
+ unmatchedTags: string[];
+ unmatchedReleases: string[];
+ releases: {
+ [baseVersion: string]: {
+ baseVersion: string;
+ createdAt: string | null;
+ htmlUrl: string;
+
+ /**
+ * Ordered from new to old
+ */
+ candidates: {
+ tagName: string;
+ sha: string;
+ }[];
+
+ /**
+ * Ordered from new to old
+ */
+ versions: {
+ tagName: string;
+ sha: string;
+ }[];
+ };
+ };
+}
+
+export const ReleaseStatsContext = createContext<
+ { releaseStats: ReleaseStats } | undefined
+>(undefined);
+
+export const useReleaseStatsContext = () => {
+ const { releaseStats } = useContext(ReleaseStatsContext) ?? {};
+
+ if (!releaseStats) {
+ throw new GitHubReleaseManagerError('releaseStats not found');
+ }
+
+ return {
+ releaseStats,
+ };
+};
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.test.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.test.tsx
new file mode 100644
index 0000000000..b4b1a1df4c
--- /dev/null
+++ b/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.test.tsx
@@ -0,0 +1,43 @@
+/*
+ * 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 { getDecimalNumber } from './getDecimalNumber';
+
+describe('getDecimalNumber', () => {
+ it('should handle NaN', () => {
+ const result = getDecimalNumber(NaN);
+
+ expect(result).toEqual(0);
+ });
+
+ it('should only handle decimals', () => {
+ const result = getDecimalNumber(1);
+
+ expect(result).toEqual(1);
+ });
+
+ it('should get decimal number with default decimals = 2', () => {
+ const result = getDecimalNumber(1 / 3);
+
+ expect(result).toMatchInlineSnapshot(`0.33`);
+ });
+
+ it('should get decimal number for decimals = 1', () => {
+ const result = getDecimalNumber(1 / 3, 1);
+
+ expect(result).toMatchInlineSnapshot(`0.3`);
+ });
+});
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.tsx
index 590d95a757..ab4a83fa79 100644
--- a/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.tsx
+++ b/plugins/github-release-manager/src/features/Stats/helpers/getDecimalNumber.tsx
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-export function getDecimalNumber(n: number) {
+export function getDecimalNumber(n: number, decimals = 2) {
if (isNaN(n)) {
return 0;
}
if (n.toString().includes('.')) {
- return n.toFixed(2);
+ return parseFloat(n.toFixed(decimals));
}
return n;
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx
new file mode 100644
index 0000000000..5bea396d5c
--- /dev/null
+++ b/plugins/github-release-manager/src/features/Stats/helpers/getMappedReleases.test.tsx
@@ -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 { getMappedReleases } from './getMappedReleases';
+import { mockSemverProject } from '../../../test-helpers/test-helpers';
+
+describe('getMappedReleases', () => {
+ it('should get mapped releases', () => {
+ const createRelease = (tagName: string) => ({
+ createdAt: '2021-01-01T10:11:12Z',
+ htmlUrl: 'html_url',
+ id: 1,
+ name: 'name',
+ tagName,
+ });
+
+ const result = getMappedReleases({
+ project: mockSemverProject,
+ allReleases: [createRelease('rc-1.0.0'), createRelease('rc-1.1.0')],
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "mappedReleases": Object {
+ "releases": Object {
+ "1.0": Object {
+ "baseVersion": "1.0",
+ "candidates": Array [
+ Object {
+ "sha": "",
+ "tagName": "rc-1.0.0",
+ },
+ ],
+ "createdAt": "2021-01-01T10:11:12Z",
+ "htmlUrl": "html_url",
+ "versions": Array [],
+ },
+ "1.1": Object {
+ "baseVersion": "1.1",
+ "candidates": Array [
+ Object {
+ "sha": "",
+ "tagName": "rc-1.1.0",
+ },
+ ],
+ "createdAt": "2021-01-01T10:11:12Z",
+ "htmlUrl": "html_url",
+ "versions": Array [],
+ },
+ },
+ "unmappableTags": Array [],
+ "unmatchedReleases": Array [],
+ "unmatchedTags": Array [],
+ },
+ }
+ `);
+ });
+});
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/mapReleases.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getMappedReleases.tsx
similarity index 68%
rename from plugins/github-release-manager/src/features/Stats/helpers/mapReleases.tsx
rename to plugins/github-release-manager/src/features/Stats/helpers/getMappedReleases.tsx
index d1103d5e71..55382100ac 100644
--- a/plugins/github-release-manager/src/features/Stats/helpers/mapReleases.tsx
+++ b/plugins/github-release-manager/src/features/Stats/helpers/getMappedReleases.tsx
@@ -17,6 +17,7 @@
import { calverRegexp } from '../../../helpers/tagParts/getCalverTagParts';
import { GetAllReleasesResult } from '../../../api/PluginApiClient';
import { Project } from '../../../contexts/ProjectContext';
+import { ReleaseStats } from '../contexts/ReleaseStatsContext';
import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
export function getMappedReleases({
@@ -28,61 +29,47 @@ export function getMappedReleases({
}) {
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,
- ) => {
+ (acc: ReleaseStats, release) => {
const match =
project.versioningStrategy === 'semver'
? release.tagName.match(semverRegexp)
: release.tagName.match(calverRegexp);
if (!match) {
- acc.unmatched.push(release.tagName);
+ acc.unmatchedReleases.push(release.tagName);
return acc;
}
- const prefix = match[1];
+ const prefix = match[1] as 'rc' | 'version';
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,
+ const releaseEntry = {
+ tagName: release.tagName,
+ sha: '',
};
+
+ acc.releases[baseVersion] = {
+ baseVersion,
+ createdAt: release.createdAt,
+ htmlUrl: release.htmlUrl,
+ candidates: prefix === 'rc' ? [releaseEntry] : [],
+ versions: prefix === 'version' ? [releaseEntry] : [],
+ };
+
return acc;
}
return acc;
},
{
- unmatched: [],
releases: {},
+ unmappableTags: [],
+ unmatchedReleases: [],
+ unmatchedTags: [],
},
),
};
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx
new file mode 100644
index 0000000000..3b59cc4c46
--- /dev/null
+++ b/plugins/github-release-manager/src/features/Stats/helpers/getReleaseStats.test.tsx
@@ -0,0 +1,124 @@
+/*
+ * 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 { getReleaseStats } from './getReleaseStats';
+import { mockSemverProject } from '../../../test-helpers/test-helpers';
+
+describe('getReleaseStats', () => {
+ it('should get releases with tags', () => {
+ const result = getReleaseStats({
+ project: mockSemverProject,
+ mappedReleases: {
+ releases: {
+ '1.0': {
+ baseVersion: '1.0',
+ createdAt: '2021-01-01T10:11:12Z',
+ htmlUrl: 'html_url',
+ candidates: [
+ {
+ tagName: 'rc-1.0.0',
+ sha: '',
+ },
+ ],
+ versions: [],
+ },
+ '1.1': {
+ baseVersion: '1.1',
+ createdAt: '2021-01-01T10:11:12Z',
+ htmlUrl: 'html_url',
+ candidates: [
+ {
+ tagName: 'rc-1.1.0',
+ sha: '',
+ },
+ ],
+ versions: [],
+ },
+ },
+ unmappableTags: [],
+ unmatchedReleases: [],
+ unmatchedTags: [],
+ },
+ allTags: [
+ { sha: 'sha', tagName: 'rc-1.0.0' },
+ { sha: 'sha', tagName: 'rc-1.0.1' },
+ { sha: 'sha', tagName: 'rc-1.0.2' },
+ { sha: 'sha', tagName: 'version-1.0.2' },
+ { sha: 'sha', tagName: 'rc-1.1.1' },
+
+ { sha: 'unmatchable', tagName: 'rc-1/2/3' },
+ { sha: 'unmappable', tagName: 'rc-123.123.123' },
+ ],
+ });
+
+ expect(result).toMatchInlineSnapshot(`
+ Object {
+ "releaseStats": Object {
+ "releases": Object {
+ "1.0": Object {
+ "baseVersion": "1.0",
+ "candidates": Array [
+ Object {
+ "sha": "sha",
+ "tagName": "rc-1.0.0",
+ },
+ Object {
+ "sha": "sha",
+ "tagName": "rc-1.0.1",
+ },
+ Object {
+ "sha": "sha",
+ "tagName": "rc-1.0.2",
+ },
+ ],
+ "createdAt": "2021-01-01T10:11:12Z",
+ "htmlUrl": "html_url",
+ "versions": Array [
+ Object {
+ "sha": "sha",
+ "tagName": "version-1.0.2",
+ },
+ ],
+ },
+ "1.1": Object {
+ "baseVersion": "1.1",
+ "candidates": Array [
+ Object {
+ "sha": "",
+ "tagName": "rc-1.1.0",
+ },
+ Object {
+ "sha": "sha",
+ "tagName": "rc-1.1.1",
+ },
+ ],
+ "createdAt": "2021-01-01T10:11:12Z",
+ "htmlUrl": "html_url",
+ "versions": Array [],
+ },
+ },
+ "unmappableTags": Array [
+ "rc-123.123.123",
+ ],
+ "unmatchedReleases": Array [],
+ "unmatchedTags": Array [
+ "rc-1/2/3",
+ ],
+ },
+ }
+ `);
+ });
+});
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/getReleaseStats.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getReleaseStats.tsx
new file mode 100644
index 0000000000..9b77cc1223
--- /dev/null
+++ b/plugins/github-release-manager/src/features/Stats/helpers/getReleaseStats.tsx
@@ -0,0 +1,81 @@
+/*
+ * 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 { Project } from '../../../contexts/ProjectContext';
+import { ReleaseStats } from '../contexts/ReleaseStatsContext';
+import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
+
+export function getReleaseStats({
+ allTags,
+ project,
+ mappedReleases,
+}: {
+ allTags: GetAllTagsResult;
+ project: Project;
+ mappedReleases: ReleaseStats;
+}) {
+ const releaseStats = allTags.reduce(
+ (acc: ReleaseStats, 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] as 'rc' | 'version';
+ const baseVersion =
+ project.versioningStrategy === 'semver'
+ ? `${match[2]}.${match[3]}` // major.minor
+ : match[2]; // yyyy.MM.dd
+
+ const release = acc.releases[baseVersion];
+
+ if (!release) {
+ acc.unmappableTags.push(tag.tagName);
+ return acc;
+ }
+
+ const dest = release[prefix === 'rc' ? 'candidates' : 'versions'];
+ const releaseToEnrich = dest.find(
+ ({ tagName }) => tagName === tag.tagName,
+ );
+
+ if (releaseToEnrich) {
+ releaseToEnrich.sha = tag.sha;
+ } else {
+ dest.push({
+ tagName: tag.tagName,
+ sha: tag.sha,
+ });
+ }
+
+ return acc;
+ },
+ {
+ ...mappedReleases,
+ },
+ );
+
+ return {
+ releaseStats,
+ };
+}
diff --git a/plugins/github-release-manager/src/features/Stats/helpers/getReleasesWithTags.tsx b/plugins/github-release-manager/src/features/Stats/helpers/getReleasesWithTags.tsx
deleted file mode 100644
index 1c41f78288..0000000000
--- a/plugins/github-release-manager/src/features/Stats/helpers/getReleasesWithTags.tsx
+++ /dev/null
@@ -1,101 +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 './mapReleases';
-import { Project } from '../../../contexts/ProjectContext';
-import { semverRegexp } from '../../../helpers/tagParts/getSemverTagParts';
-
-export function getReleasesWithTags({
- allTags,
- project,
- mappedReleases,
-}: {
- allTags: GetAllTagsResult;
- project: Project;
- mappedReleases: ReturnType