fix(ci): release notes script (#32827)
(cherry picked from commit f47b02f91d6d55e0b0281609c37e6b1676626115)
This commit is contained in:
@@ -154,8 +154,8 @@ jobs:
|
||||
previous=$(grep -A1 -xF "${TAG}" <<< "${tags}" | tail -1)
|
||||
echo "generating notes from ${previous}"
|
||||
|
||||
mise //:notes --tag "${TAG}" --previous "${previous}" > "${RUNNER_TEMP}/notes.md"
|
||||
cat "${RUNNER_TEMP}/notes.md"
|
||||
mise //:notes --tag "${TAG}" --previous "${previous}"
|
||||
cat misc/release/notes.md
|
||||
|
||||
- name: Create draft release
|
||||
env:
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
--draft \
|
||||
--verify-tag \
|
||||
--prerelease="${PRERELEASE}" \
|
||||
--notes-file "${RUNNER_TEMP}/notes.md" \
|
||||
--notes-file misc/release/notes.md \
|
||||
docker/docker-compose.yml \
|
||||
docker/docker-compose.rootless.yml \
|
||||
docker/example.env \
|
||||
|
||||
@@ -28,3 +28,4 @@ vite.config.js.timestamp-*
|
||||
.devcontainer/.env*
|
||||
*.tsbuildinfo
|
||||
*.tsbuildInfo
|
||||
misc/release/notes.md
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Command, Option } from 'commander';
|
||||
import {
|
||||
FileSystem,
|
||||
GitClient,
|
||||
GitHubClient,
|
||||
type NotesOptions,
|
||||
@@ -63,10 +64,11 @@ export const cli = (argv: string[]) => {
|
||||
.action(async ({ token, ...options }: NotesOptions & { token: string }) => {
|
||||
try {
|
||||
const service = new NotesService(
|
||||
new FileSystem(),
|
||||
new GitClient(),
|
||||
new GitHubClient(token),
|
||||
);
|
||||
process.stdout.write(await service.handleNotes(options));
|
||||
await service.handleNotes(options);
|
||||
} catch (error) {
|
||||
console.error(error instanceof Error ? error.message : error);
|
||||
process.exit(1);
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Public } from 'src/types.js';
|
||||
import { beforeEach, describe, expect, it, type Mocked, vi } from 'vitest';
|
||||
import {
|
||||
type Contributor,
|
||||
type FileSystem,
|
||||
type GitClient,
|
||||
type GitHubClient,
|
||||
NotesService,
|
||||
@@ -37,6 +38,7 @@ const changelog = (...lines: string[]) =>
|
||||
const body = (notes: string) => notes.slice(notes.indexOf("## What's Changed"));
|
||||
|
||||
describe(NotesService.name, () => {
|
||||
let fs: Mocked<Public<FileSystem>>;
|
||||
let git: Mocked<Public<GitClient>>;
|
||||
let github: Mocked<Public<GitHubClient>>;
|
||||
let sut: NotesService;
|
||||
@@ -88,12 +90,16 @@ describe(NotesService.name, () => {
|
||||
github.getFirstTimers.mockResolvedValue(firstTimers);
|
||||
};
|
||||
|
||||
const run = () => sut.handleNotes({ tag: 'v3.3.0', previous: 'v3.2.4' });
|
||||
const run = async () => {
|
||||
await sut.handleNotes({ tag: 'v3.3.0', previous: 'v3.2.4' });
|
||||
return fs.writeFileSync.mock.lastCall?.[1] as string;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
fs = { writeFileSync: vi.fn() };
|
||||
git = { log: vi.fn() };
|
||||
github = { getPullRequests: vi.fn(), getFirstTimers: vi.fn() };
|
||||
sut = new NotesService(git, github);
|
||||
sut = new NotesService(fs, git, github);
|
||||
});
|
||||
|
||||
it('should compare the previous tag with the new tag', async () => {
|
||||
@@ -104,6 +110,18 @@ describe(NotesService.name, () => {
|
||||
expect(git.log).toHaveBeenCalledWith('v3.2.4', 'v3.3.0');
|
||||
});
|
||||
|
||||
it('should write the notes to misc/release/notes.md', async () => {
|
||||
setup([{ number: 1 }]);
|
||||
|
||||
await run();
|
||||
|
||||
expect(fs.writeFileSync).toHaveBeenCalledOnce();
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/\/misc\/release\/notes\.md$/),
|
||||
expect.any(String),
|
||||
);
|
||||
});
|
||||
|
||||
it('should start with the template and end with the full changelog', async () => {
|
||||
setup([{ number: 1 }]);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import type { Public } from 'src/types.js';
|
||||
@@ -15,6 +15,7 @@ const REPO = 'immich-app/immich';
|
||||
const Files = {
|
||||
Config: join(root, '.github/release.yml'),
|
||||
Template: join(root, 'misc/release/notes.tmpl'),
|
||||
Output: join(root, 'misc/release/notes.md'),
|
||||
};
|
||||
|
||||
export type NotesOptions = {
|
||||
@@ -55,6 +56,12 @@ type PullRequestNode = {
|
||||
const PULL_REQUEST_BATCH = 50;
|
||||
const SEARCH_BATCH = 20;
|
||||
|
||||
export class FileSystem {
|
||||
writeFileSync(path: string, data: string) {
|
||||
writeFileSync(path, data);
|
||||
}
|
||||
}
|
||||
|
||||
export class GitClient {
|
||||
log(previous: string, tag: string) {
|
||||
return execFileSync(
|
||||
@@ -189,6 +196,7 @@ export class GitHubClient {
|
||||
|
||||
export class NotesService {
|
||||
constructor(
|
||||
private fs: Public<FileSystem>,
|
||||
private git: Public<GitClient>,
|
||||
private github: Public<GitHubClient>,
|
||||
) {}
|
||||
@@ -198,8 +206,9 @@ export class NotesService {
|
||||
const pulls = await this.getPullRequests(commits);
|
||||
const changes = this.selectChanges(commits, pulls);
|
||||
const firstTimers = await this.getFirstTimers(changes);
|
||||
const notes = this.render({ tag, previous, changes, firstTimers });
|
||||
|
||||
return this.render({ tag, previous, changes, firstTimers });
|
||||
this.fs.writeFileSync(Files.Output, notes);
|
||||
}
|
||||
|
||||
private parseCommits(log: string): Commit[] {
|
||||
|
||||
Reference in New Issue
Block a user