chore: map release notes to their respective file names on GH (#8790)

* chore: map release notes to their respective file names on GH
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: create mapping json file automatically
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: add release notes and image to mapping
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: change json file structure
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: remove release notes mapping in renderer
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: create separate json file for each release
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: remove truncate from parser
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: remove generated files
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: add tests
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: configure tests for website
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: refactor notes code
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: remove unused import
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: fix tests
Signed-off-by: Sonia Sandler <ssandler@redhat.com>

* chore: change automatic line change in package.json
Signed-off-by: Sonia Sandler <ssandler@redhat.com>
This commit is contained in:
SoniaSandler 2024-09-12 09:22:31 -04:00 committed by GitHub
parent e815a220da
commit 7155f934d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 217 additions and 1 deletions

View file

@ -947,6 +947,9 @@ importers:
'@docusaurus/tsconfig':
specifier: ^3.5.2
version: 3.5.2
'@docusaurus/types':
specifier: ^3.5.2
version: 3.5.2(react-dom@18.3.1(react@18.2.0))(react@18.2.0)
autoprefixer:
specifier: ^10.4.20
version: 10.4.20(postcss@8.4.45)
@ -971,6 +974,9 @@ importers:
typescript:
specifier: ^5.5.4
version: 5.5.4
vitest:
specifier: ^2.0.5
version: 2.0.5(@types/node@20.16.5)(jsdom@25.0.0)(terser@5.31.6)
website-argos:
devDependencies:

View file

@ -1,6 +1,7 @@
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion
import { resolve } from 'node:path';
import { createNotesFiles } from './release-notes-parser';
import Storybook from './storybook';
const lightCodeTheme = require('prism-react-renderer').themes.github;
@ -24,6 +25,9 @@ const config = {
trailingSlash: false,
markdown: {
mermaid: true,
parseFrontMatter: async params => {
return createNotesFiles(params);
},
},
themes: ['@docusaurus/theme-mermaid'],
plugins: [

View file

@ -44,6 +44,7 @@
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.5.2",
"@docusaurus/tsconfig": "^3.5.2",
"@docusaurus/types": "^3.5.2",
"autoprefixer": "^10.4.20",
"markdownlint": "^0.35.0",
"markdownlint-cli2": "^0.14.0",
@ -51,7 +52,8 @@
"tailwindcss": "^3.4.11",
"typedoc": "^0.26.7",
"typedoc-plugin-markdown": "^4.2.7",
"typescript": "^5.5.4"
"typescript": "^5.5.4",
"vitest": "^2.0.5"
},
"browserslist": {
"production": [

View file

@ -0,0 +1,93 @@
/**********************************************************************
* Copyright (C) 2024 Red Hat, Inc.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/
import { beforeEach, expect, test, vi } from 'vitest';
import { createNotesFiles } from './release-notes-parser';
const mocks = vi.hoisted(() => ({
existsSyncMock: vi.fn(),
mkdirMock: vi.fn(),
readFileMock: vi.fn(),
writeFileMock: vi.fn(),
}));
vi.mock('node:fs', () => {
return {
default: {
existsSync: mocks.existsSyncMock,
promises: {
mkdir: mocks.mkdirMock,
readFile: mocks.readFileMock,
writeFile: mocks.writeFileMock,
},
},
};
});
const notesInfo =
'--- title: test1\nslug: podman-desktop-release-test1\nimage: /img/blog/podman-desktop-release-test1/test1.png\n---';
const notesText = 'import a\ntest1 release title!\n![test1-release](img1)\nello world\n';
const notesPoints =
'- **line1**:line1 info\n- **line2**:line2 info\n- **line3**:line3 info\n- **line4**:line4 info\n- **line5**:line5 info\n';
const jsonResult = {
image: 'https://podman-desktop.io/img/blog/podman-desktop-release-test1/test1.png',
blog: 'https://podman-desktop.io/blog/podman-desktop-release-test1',
title: 'test1 release title!',
summary: '- **line1**:line1 info\n- **line2**:line2 info\n- **line3**:line3 info\n- **line4**:line4 info',
};
const defaultParseFrontMatterMock = vi.fn();
const defaultParseFrontMatterResultMock = {
frontMatter: {
title: 'Release notes 1.0',
},
content: '',
};
const params = {
filePath: 'file/test1file',
fileContent: notesInfo + notesText + notesPoints,
defaultParseFrontMatter: defaultParseFrontMatterMock,
};
beforeEach(() => {
vi.resetAllMocks();
mocks.readFileMock.mockReturnValue(notesInfo + notesText + notesPoints);
mocks.existsSyncMock.mockReturnValue(true);
defaultParseFrontMatterMock.mockResolvedValue(defaultParseFrontMatterResultMock);
});
test('create release-notes directory when it does not exist', async () => {
mocks.existsSyncMock.mockReturnValue(false);
await createNotesFiles(params);
expect(mocks.mkdirMock).toHaveBeenCalled();
});
test('Do not create release-nnotes directory when it exists', async () => {
await createNotesFiles(params);
expect(mocks.mkdirMock).not.toHaveBeenCalled();
});
test('parse provided release notes as expected', async () => {
await createNotesFiles(params);
expect(mocks.writeFileMock).toBeCalledWith('./static/release-notes/1.0.json', JSON.stringify(jsonResult));
});

View file

@ -0,0 +1,80 @@
/**********************************************************************
* Copyright (C) 2024 Red Hat, Inc.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/
import fs from 'node:fs';
import type {
DefaultParseFrontMatter,
ParseFrontMatterParams,
ParseFrontMatterResult,
} from '@docusaurus/types/src/config';
export async function createNotesFiles(
params: ParseFrontMatterParams & {
defaultParseFrontMatter: DefaultParseFrontMatter;
},
): Promise<ParseFrontMatterResult> {
const result = await params.defaultParseFrontMatter(params);
// eslint-disable-next-line sonarjs/slow-regex
const versionRegex = /\d+\.\d+/;
if (
result.frontMatter.title &&
/[Rr]elease/.exec(String(result.frontMatter.title)) &&
versionRegex.exec(String(result.frontMatter.title))
) {
const versionMatch = versionRegex.exec(String(result.frontMatter.title)) ?? [];
const version = versionMatch ? versionMatch[0] : '';
if (version) {
const folderName = './static/release-notes';
const fileContent = await fs.promises.readFile(params.filePath, { encoding: 'utf-8' });
const resultText = fileContent.split('---', 3);
// get release image url
const imagePath = /image: (.+)\n/.exec(resultText[1]);
const imageName = imagePath ? imagePath[1] : '';
const imageUrl = imageName ? `https://podman-desktop.io${imageName}` : '';
const pageName = /slug: (.+)\n/.exec(resultText[1]);
const blogName = pageName ? pageName[1] : `podman-desktop-release-${version}`;
const blogUrl = `https://podman-desktop.io/blog/${blogName}`;
// get summary part of release notes
const text = resultText[2]
.replace(/!\[.+\)\n/, '') // remove image link
.replace(/\[Click here to download it\]\(.+\)!/, '') //remove download new version
.replace(/\n(\n)+/g, '\n') // change all multi-newlines chars to one newline char
.split('\n');
const summary = text.filter(line => line.includes('- **')); // all summary bullet points start with "- **"
const summaryText = summary.slice(0, 4).join('\n'); // limit the number of bullet points to 4
const titleText = text.filter(line => !line.includes('import') && line)[0];
const jsonInput = { image: imageUrl, blog: blogUrl, title: titleText, summary: summaryText };
if (!fs.existsSync(folderName)) {
try {
await fs.promises.mkdir(folderName);
} catch (error) {
// directory already exists
}
}
await fs.promises.writeFile(`${folderName}/${version}.json`, JSON.stringify(jsonInput));
}
}
return result;
}

31
website/vitest.config.js Normal file
View file

@ -0,0 +1,31 @@
/**********************************************************************
* Copyright (C) 2023 Red Hat, Inc.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/
import { coverageConfig, testConfig } from '../vitest-shared-extensions.config';
const PACKAGE_ROOT = __dirname;
const PACKAGE_NAME = 'website';
const config = {
test: {
...testConfig(),
...coverageConfig(PACKAGE_ROOT, PACKAGE_NAME),
},
};
export default config;