Skip to content

Commit 296906e

Browse files
authored
Update version CI/CD (#14)
* Update navbar * yeee * ok * update (thx coderabiit) * ok
1 parent 02a5ba3 commit 296906e

File tree

7 files changed

+745
-16
lines changed

7 files changed

+745
-16
lines changed
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#!/usr/bin/env node
2+
3+
import { execSync } from "child_process";
4+
import fs from "fs";
5+
6+
function getCommitsSinceLastTag() {
7+
try {
8+
// Get the last tag
9+
const lastTag = execSync("git describe --tags --abbrev=0 2>/dev/null", {
10+
encoding: "utf8",
11+
}).trim();
12+
13+
// Get commits since last tag
14+
const commits = execSync(`git log ${lastTag}..HEAD --pretty=format:"%s"`, {
15+
encoding: "utf8",
16+
}).trim();
17+
18+
return commits ? commits.split("\n") : [];
19+
} catch (error) {
20+
// If no tags exist, get all commits from the beginning
21+
try {
22+
const commits = execSync('git log --pretty=format:"%s"', {
23+
encoding: "utf8",
24+
}).trim();
25+
26+
return commits ? commits.split("\n") : [];
27+
} catch (e) {
28+
return [];
29+
}
30+
}
31+
}
32+
33+
function categorizeCommits(commits) {
34+
const categories = {
35+
features: [],
36+
fixes: [],
37+
improvements: [],
38+
chores: [],
39+
breaking: [],
40+
other: []
41+
};
42+
43+
commits.forEach(commit => {
44+
// Skip auto-increment commits
45+
if (commit.includes("🤖 Auto-increment version")) {
46+
return;
47+
}
48+
49+
const lowerCommit = commit.toLowerCase();
50+
51+
if (lowerCommit.includes("breaking") || lowerCommit.includes("breaking change")) {
52+
categories.breaking.push(commit);
53+
} else if (lowerCommit.startsWith("feat:") || lowerCommit.startsWith("feature:") || lowerCommit.includes("add ")) {
54+
categories.features.push(commit);
55+
} else if (lowerCommit.startsWith("fix:") || lowerCommit.startsWith("bug:") || lowerCommit.includes("fix ")) {
56+
categories.fixes.push(commit);
57+
} else if (lowerCommit.startsWith("improve:") || lowerCommit.startsWith("enhancement:") || lowerCommit.includes("improve ")) {
58+
categories.improvements.push(commit);
59+
} else if (lowerCommit.startsWith("chore:") || lowerCommit.startsWith("ci:") || lowerCommit.startsWith("docs:")) {
60+
categories.chores.push(commit);
61+
} else {
62+
categories.other.push(commit);
63+
}
64+
});
65+
66+
return categories;
67+
}
68+
69+
function generateReleaseNotes(version, categories) {
70+
let notes = `# Release ${version}\n\n`;
71+
72+
// Add date
73+
const date = new Date().toISOString().split('T')[0];
74+
notes += `**Release Date:** ${date}\n\n`;
75+
76+
// Breaking changes (if any)
77+
if (categories.breaking.length > 0) {
78+
notes += "## ⚠️ Breaking Changes\n\n";
79+
categories.breaking.forEach(commit => {
80+
notes += `- ${commit}\n`;
81+
});
82+
notes += "\n";
83+
}
84+
85+
// Features
86+
if (categories.features.length > 0) {
87+
notes += "## ✨ New Features\n\n";
88+
categories.features.forEach(commit => {
89+
notes += `- ${commit}\n`;
90+
});
91+
notes += "\n";
92+
}
93+
94+
// Bug fixes
95+
if (categories.fixes.length > 0) {
96+
notes += "## 🐛 Bug Fixes\n\n";
97+
categories.fixes.forEach(commit => {
98+
notes += `- ${commit}\n`;
99+
});
100+
notes += "\n";
101+
}
102+
103+
// Improvements
104+
if (categories.improvements.length > 0) {
105+
notes += "## 🚀 Improvements\n\n";
106+
categories.improvements.forEach(commit => {
107+
notes += `- ${commit}\n`;
108+
});
109+
notes += "\n";
110+
}
111+
112+
// Other changes
113+
if (categories.other.length > 0) {
114+
notes += "## 📝 Other Changes\n\n";
115+
categories.other.forEach(commit => {
116+
notes += `- ${commit}\n`;
117+
});
118+
notes += "\n";
119+
}
120+
121+
// Chores (optional, usually less important)
122+
if (categories.chores.length > 0) {
123+
notes += "## 🔧 Maintenance\n\n";
124+
categories.chores.forEach(commit => {
125+
notes += `- ${commit}\n`;
126+
});
127+
notes += "\n";
128+
}
129+
130+
// Add footer
131+
notes += "---\n\n";
132+
notes += `**Full Changelog:** https://github.com/${process.env.GITHUB_REPOSITORY}/compare/...${version}\n\n`;
133+
134+
return notes.trim();
135+
}
136+
137+
function main() {
138+
const version = process.argv[2];
139+
140+
if (!version) {
141+
console.error("Usage: node generate-release-notes.js <version>");
142+
process.exit(1);
143+
}
144+
145+
console.log(`Generating release notes for version ${version}...`);
146+
147+
const commits = getCommitsSinceLastTag();
148+
console.log(`Found ${commits.length} commits since last release`);
149+
150+
const categories = categorizeCommits(commits);
151+
const releaseNotes = generateReleaseNotes(version, categories);
152+
153+
// Output for GitHub Actions
154+
if (process.env.GITHUB_OUTPUT) {
155+
// Escape newlines for GitHub Actions
156+
const escapedNotes = releaseNotes.replace(/\n/g, '%0A').replace(/\r/g, '%0D');
157+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `release_notes=${escapedNotes}\n`);
158+
159+
// Also write to a file for easier debugging
160+
fs.writeFileSync('release-notes.md', releaseNotes);
161+
console.log("Release notes written to release-notes.md");
162+
} else {
163+
// For local testing
164+
console.log("\n" + "=".repeat(50));
165+
console.log("RELEASE NOTES:");
166+
console.log("=".repeat(50));
167+
console.log(releaseNotes);
168+
}
169+
}
170+
171+
// Run if this script is executed directly
172+
if (import.meta.url === `file://${process.argv[1]}`) {
173+
main();
174+
}
175+
176+
export { generateReleaseNotes, categorizeCommits, getCommitsSinceLastTag };

.github/scripts/increment-version.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ function incrementVersion(version) {
5252
return `${version}.1`;
5353
}
5454

55+
function isStableRelease(version) {
56+
// Check if version is a stable release (not alpha, beta, canary, etc.)
57+
// Include common typos and variations
58+
const prereleasePattern =
59+
/-(alpha|beta|canary|canery|rc|dev|pre|snapshot|nightly|test)/i;
60+
return !prereleasePattern.test(version);
61+
}
62+
5563
function updateProjectData() {
5664
try {
5765
// Read the current file
@@ -68,6 +76,9 @@ function updateProjectData() {
6876
const currentVersion = match[1];
6977
const newVersion = incrementVersion(currentVersion);
7078

79+
// Check if this is a stable release
80+
const isStable = isStableRelease(newVersion);
81+
7182
// Replace the version in the content
7283
const newContent = content.replace(
7384
versionPattern,
@@ -78,6 +89,7 @@ function updateProjectData() {
7889
fs.writeFileSync(PROJECT_DATA_PATH, newContent, "utf8");
7990

8091
console.log(`Version updated from ${currentVersion} to ${newVersion}`);
92+
console.log(`Stable release: ${isStable}`);
8193

8294
// Output for GitHub Actions (using modern format)
8395
if (process.env.GITHUB_OUTPUT) {
@@ -86,10 +98,12 @@ function updateProjectData() {
8698
`current=${currentVersion}\n`,
8799
);
88100
fs.appendFileSync(process.env.GITHUB_OUTPUT, `new=${newVersion}\n`);
101+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `is_stable=${isStable}\n`);
89102
} else {
90103
// Fallback for local testing
91104
console.log(`current=${currentVersion}`);
92105
console.log(`new=${newVersion}`);
106+
console.log(`is_stable=${isStable}`);
93107
}
94108
} catch (error) {
95109
console.error("Error updating version:", error.message);
@@ -102,4 +116,4 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
102116
updateProjectData();
103117
}
104118

105-
export { incrementVersion, updateProjectData };
119+
export { incrementVersion, updateProjectData, isStableRelease };

0 commit comments

Comments
 (0)