chore: prepare 0.0.3 release notes (#37)
This commit is contained in:
parent
23fb595755
commit
abe0bf3c13
@ -26,6 +26,7 @@ Rules:
|
|||||||
After reviewing the generated notes:
|
After reviewing the generated notes:
|
||||||
|
|
||||||
- confirm the `package.json` version matches the intended release tag when one is provided
|
- confirm the `package.json` version matches the intended release tag when one is provided
|
||||||
|
- sanity-check that the notes only cover changes since the previous release
|
||||||
- tighten wording only when it improves clarity
|
- tighten wording only when it improves clarity
|
||||||
- preserve the existing section structure unless there is a strong reason to merge sections
|
- preserve the existing section structure unless there is a strong reason to merge sections
|
||||||
- suggest saving the finalized notes to `release-notes/v<version>.md` when a version is known
|
- suggest saving the finalized notes to `release-notes/v<version>.md` when a version is known
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
],
|
],
|
||||||
"project": ["**/*.{js,mjs,ts,tsx}", "!src/routeTree.gen.ts", "!web/**"],
|
"project": ["**/*.{js,mjs,ts,tsx}", "!src/routeTree.gen.ts", "!web/**"],
|
||||||
"ignore": ["drizzle-prod.config.ts"],
|
"ignore": ["drizzle-prod.config.ts"],
|
||||||
|
"ignoreBinaries": ["tsx"],
|
||||||
// Disable Drizzle plugin - it tries to load drizzle.config.ts which imports cloudflare:workers
|
// Disable Drizzle plugin - it tries to load drizzle.config.ts which imports cloudflare:workers
|
||||||
"drizzle": false,
|
"drizzle": false,
|
||||||
"ignoreDependencies": [
|
"ignoreDependencies": [
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"name": "open-seo",
|
"name": "open-seo",
|
||||||
"private": true,
|
"private": true,
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "AUTH_MODE=local_noauth vite dev",
|
"dev": "AUTH_MODE=local_noauth vite dev",
|
||||||
|
|||||||
14
release-notes/v0.0.3.md
Normal file
14
release-notes/v0.0.3.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
## Added
|
||||||
|
|
||||||
|
- Added the Backlinks page.
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Renamed from OpenRank back to OpenSEO.
|
||||||
|
- Fixed website styling issues.
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
- Clarified how to update self-hosted Docker instances.
|
||||||
|
|
||||||
|
Full Changelog: https://github.com/bensenescu/open-seo/compare/v0.0.2...HEAD
|
||||||
@ -3,10 +3,10 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
import { execFileSync } from "node:child_process";
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { parseArgs } from "node:util";
|
import { parseArgs } from "node:util";
|
||||||
import { writeFileSync } from "node:fs";
|
|
||||||
|
|
||||||
const argv = process.argv.slice(2);
|
const argv = process.argv.slice(2);
|
||||||
const normalizedArgv = argv[0] === "--" ? argv.slice(1) : argv;
|
const normalizedArgv = argv[0] === "--" ? argv.slice(1) : argv;
|
||||||
@ -54,6 +54,107 @@ function getLatestSemverTag() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @typedef {{ major: number, minor: number, patch: number }} Semver */
|
||||||
|
/** @typedef {{ tag: string, version: Semver, source: "tag" | "release-notes" }} VersionCandidate */
|
||||||
|
|
||||||
|
/** @param {string} value */
|
||||||
|
function parseSemver(value) {
|
||||||
|
const match = value.match(/^v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9A-Za-z.-]+)?$/);
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
major: Number(match[1]),
|
||||||
|
minor: Number(match[2]),
|
||||||
|
patch: Number(match[3]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {Semver} left @param {Semver} right */
|
||||||
|
function compareSemver(left, right) {
|
||||||
|
if (left.major !== right.major) return left.major - right.major;
|
||||||
|
if (left.minor !== right.minor) return left.minor - right.minor;
|
||||||
|
return left.patch - right.patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {unknown} value @returns {value is Record<string, unknown>} */
|
||||||
|
function isRecord(value) {
|
||||||
|
return Boolean(value) && typeof value === "object";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPackageVersion() {
|
||||||
|
/** @type {unknown} */
|
||||||
|
const packageJson = JSON.parse(readFileSync("package.json", "utf8"));
|
||||||
|
if (!isRecord(packageJson)) return null;
|
||||||
|
const version = packageJson.version;
|
||||||
|
return typeof version === "string" ? version : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReleaseNoteVersions() {
|
||||||
|
try {
|
||||||
|
return readdirSync("release-notes").flatMap((name) => {
|
||||||
|
const version = name.match(
|
||||||
|
/^v(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\.md$/,
|
||||||
|
)?.[1];
|
||||||
|
return version ? [version] : [];
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {string[]} versionValues @param {VersionCandidate["source"]} source */
|
||||||
|
function collectVersionCandidates(versionValues, source) {
|
||||||
|
return versionValues.flatMap((value) => {
|
||||||
|
const version = parseSemver(value);
|
||||||
|
if (!version) return [];
|
||||||
|
return [{ tag: source === "tag" ? value : `v${value}`, version, source }];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultFromTag() {
|
||||||
|
/** @type {string | null} */
|
||||||
|
const currentVersion = getPackageVersion();
|
||||||
|
const parsedCurrentVersion = currentVersion
|
||||||
|
? parseSemver(currentVersion)
|
||||||
|
: null;
|
||||||
|
if (!parsedCurrentVersion) return getLatestSemverTag();
|
||||||
|
|
||||||
|
const tagCandidates = collectVersionCandidates(
|
||||||
|
git(["tag", "--sort=-version:refname"])
|
||||||
|
.split("\n")
|
||||||
|
.map((tag) => tag.trim())
|
||||||
|
.filter(Boolean),
|
||||||
|
"tag",
|
||||||
|
);
|
||||||
|
|
||||||
|
const releaseNoteCandidates = collectVersionCandidates(
|
||||||
|
getReleaseNoteVersions(),
|
||||||
|
"release-notes",
|
||||||
|
);
|
||||||
|
|
||||||
|
const candidates = [...tagCandidates, ...releaseNoteCandidates]
|
||||||
|
.filter((entry) => compareSemver(entry.version, parsedCurrentVersion) < 0)
|
||||||
|
.reduce((sorted, entry) => {
|
||||||
|
const insertAt = sorted.findIndex(
|
||||||
|
(candidate) => compareSemver(entry.version, candidate.version) > 0,
|
||||||
|
);
|
||||||
|
if (insertAt === -1) {
|
||||||
|
sorted.push(entry);
|
||||||
|
} else {
|
||||||
|
sorted.splice(insertAt, 0, entry);
|
||||||
|
}
|
||||||
|
return sorted;
|
||||||
|
}, /** @type {VersionCandidate[]} */ ([]));
|
||||||
|
|
||||||
|
const bestVersion = candidates[0]?.tag;
|
||||||
|
if (!bestVersion) return getLatestSemverTag();
|
||||||
|
|
||||||
|
const matchingTag = tagCandidates.find((entry) => entry.tag === bestVersion);
|
||||||
|
if (matchingTag) return matchingTag.tag;
|
||||||
|
|
||||||
|
return getLatestSemverTag();
|
||||||
|
}
|
||||||
|
|
||||||
function getOriginRepo() {
|
function getOriginRepo() {
|
||||||
const remote = git(["remote", "get-url", "origin"]);
|
const remote = git(["remote", "get-url", "origin"]);
|
||||||
const match = remote.match(/github\.com[:/]([^/]+\/[^/.]+)(?:\.git)?$/);
|
const match = remote.match(/github\.com[:/]([^/]+\/[^/.]+)(?:\.git)?$/);
|
||||||
@ -164,7 +265,7 @@ function buildNotes({ from, to, repo }) {
|
|||||||
return lines.join("\n").trim();
|
return lines.join("\n").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const from = values.from ?? getLatestSemverTag();
|
const from = values.from ?? getDefaultFromTag();
|
||||||
const to = values.to;
|
const to = values.to;
|
||||||
const repo = values.repo ?? getOriginRepo();
|
const repo = values.repo ?? getOriginRepo();
|
||||||
const notes = buildNotes({ from, to, repo });
|
const notes = buildNotes({ from, to, repo });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user