mirror of
https://github.com/mivodev/mivo.git
synced 2026-01-26 05:25:42 +07:00
ci: add ai release notes generator to workflow
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
|
.github
|
||||||
.env
|
.env
|
||||||
node_modules
|
node_modules
|
||||||
deploy_package.tar.gz
|
deploy_package.tar.gz
|
||||||
|
|||||||
97
.github/scripts/generate-release-notes.js
vendored
Normal file
97
.github/scripts/generate-release-notes.js
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
const { GoogleGenerativeAI } = require("@google/generative-ai");
|
||||||
|
const { execSync } = require("child_process");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const API_KEY = process.env.GEMINI_API_KEY;
|
||||||
|
const MODEL_NAME = process.env.GEMINI_MODEL || "gemini-2.5-flash";
|
||||||
|
const VERSION_TAG = process.argv[2]; // e.g., v1.2.0
|
||||||
|
// Fix for Windows: Avoid 2>/dev/null, handle error in try-catch block instead
|
||||||
|
const PREVIOUS_TAG_CMD = `git describe --abbrev=0 --tags ${VERSION_TAG}~1`;
|
||||||
|
|
||||||
|
if (!API_KEY) {
|
||||||
|
console.error("Error: GEMINI_API_KEY is not set.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VERSION_TAG) {
|
||||||
|
console.error("Error: Version tag must be provided as the first argument.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
try {
|
||||||
|
console.log(`Generating release notes for ${VERSION_TAG} using ${MODEL_NAME}...`);
|
||||||
|
|
||||||
|
// 1. Get Previous Tag
|
||||||
|
let previousTag;
|
||||||
|
try {
|
||||||
|
previousTag = execSync(PREVIOUS_TAG_CMD).toString().trim();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("No previous tag found, assuming first release.");
|
||||||
|
previousTag = execSync("git rev-list --max-parents=0 HEAD").toString().trim();
|
||||||
|
}
|
||||||
|
console.log(`Comparing from ${previousTag} to ${VERSION_TAG}`);
|
||||||
|
|
||||||
|
// 2. Get Commit Messages
|
||||||
|
const commits = execSync(`git log ${previousTag}..${VERSION_TAG} --pretty=format:"- %s (%h)" --no-merges`).toString();
|
||||||
|
|
||||||
|
if (!commits) {
|
||||||
|
console.log("No commits found between tags.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Generate Content with Gemini
|
||||||
|
const genAI = new GoogleGenerativeAI(API_KEY);
|
||||||
|
const model = genAI.getGenerativeModel({ model: MODEL_NAME });
|
||||||
|
|
||||||
|
const prompt = `
|
||||||
|
You are a release note generator for a software project named 'Mivo'.
|
||||||
|
|
||||||
|
Here are the commits for the new version ${VERSION_TAG}:
|
||||||
|
${commits}
|
||||||
|
|
||||||
|
Please generate a clean, professional release note in Markdown format.
|
||||||
|
|
||||||
|
Strict Rules:
|
||||||
|
1. **NO EMOJIS**: Do not use any emojis in headers, bullet points, or text.
|
||||||
|
2. **Structure**: Group changes strictly into these headers (if applicable):
|
||||||
|
- ### Features
|
||||||
|
- ### Bug Fixes
|
||||||
|
- ### Improvements
|
||||||
|
- ### Maintenance
|
||||||
|
3. **Format**: Use simple bullet points (-) for each item.
|
||||||
|
4. **Content**: Keep it concise but descriptive. Do not mention 'Merge pull request' commits.
|
||||||
|
5. **Header**: Start with a simple header: "# Release Notes ${VERSION_TAG}"
|
||||||
|
6. **Output**: Output ONLY the markdown content.
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await model.generateContent(prompt);
|
||||||
|
const response = await result.response;
|
||||||
|
const text = response.text();
|
||||||
|
|
||||||
|
// 4. Read Template (Optional) and Merge
|
||||||
|
// For now, we just output the AI text. You can append this to a template if needed.
|
||||||
|
|
||||||
|
// Write to file
|
||||||
|
const outputPath = path.join(process.cwd(), ".github", "release_notes.md");
|
||||||
|
fs.writeFileSync(outputPath, text);
|
||||||
|
|
||||||
|
console.log(`Release notes generated at ${outputPath}`);
|
||||||
|
console.log(text);
|
||||||
|
|
||||||
|
// Export for GitHub Actions
|
||||||
|
const githubOutput = process.env.GITHUB_OUTPUT;
|
||||||
|
if (githubOutput) {
|
||||||
|
// Multiline string for GitHub Output
|
||||||
|
fs.appendFileSync(githubOutput, `RELEASE_NOTES<<EOF\n${text}\nEOF\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to generate release notes:", error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
@@ -32,7 +34,7 @@ jobs:
|
|||||||
# Export source using git archive (respects .gitattributes)
|
# Export source using git archive (respects .gitattributes)
|
||||||
git archive --format=tar HEAD | tar -x -C release_temp
|
git archive --format=tar HEAD | tar -x -C release_temp
|
||||||
|
|
||||||
- name: Install Development Dependencies (for Build)
|
- name: Install Development Dependencies (for Build & AI)
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
- name: Build Localized Assets & Editor Bundle
|
- name: Build Localized Assets & Editor Bundle
|
||||||
@@ -40,6 +42,12 @@ jobs:
|
|||||||
npm run sync:assets
|
npm run sync:assets
|
||||||
npm run build:editor
|
npm run build:editor
|
||||||
|
|
||||||
|
- name: Generate AI Release Notes
|
||||||
|
env:
|
||||||
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
||||||
|
run: |
|
||||||
|
node .github/scripts/generate-release-notes.js ${{ github.ref_name }}
|
||||||
|
|
||||||
- name: Install Production Dependencies
|
- name: Install Production Dependencies
|
||||||
run: |
|
run: |
|
||||||
cd release_temp
|
cd release_temp
|
||||||
@@ -60,8 +68,8 @@ jobs:
|
|||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: mivo-v${{ steps.get_version.outputs.VERSION }}.zip
|
files: mivo-v${{ steps.get_version.outputs.VERSION }}.zip
|
||||||
body_path: .github/release_template.md
|
body_path: .github/release_notes.md
|
||||||
generate_release_notes: true
|
generate_release_notes: false
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
env:
|
env:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,6 +25,7 @@ Thumbs.db
|
|||||||
# Build Scripts & Artifacts
|
# Build Scripts & Artifacts
|
||||||
build_release.ps1
|
build_release.ps1
|
||||||
deploy.ps1
|
deploy.ps1
|
||||||
|
.github/release_notes.md
|
||||||
|
|
||||||
# User Uploads
|
# User Uploads
|
||||||
/public/uploads/*
|
/public/uploads/*
|
||||||
|
|||||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mivo",
|
"name": "mivo",
|
||||||
"version": "1.1.1",
|
"version": "1.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mivo",
|
"name": "mivo",
|
||||||
"version": "1.1.1",
|
"version": "1.2.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lint": "^6.9.2",
|
"@codemirror/lint": "^6.9.2",
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
"@codemirror/lang-html": "^6.4.11",
|
"@codemirror/lang-html": "^6.4.11",
|
||||||
"@codemirror/theme-one-dark": "^6.1.3",
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
"@emmetio/codemirror6-plugin": "^0.4.0",
|
"@emmetio/codemirror6-plugin": "^0.4.0",
|
||||||
|
"@google/generative-ai": "^0.2.0",
|
||||||
"@uiw/codemirror-extensions-color": "^4.25.4",
|
"@uiw/codemirror-extensions-color": "^4.25.4",
|
||||||
"autoprefixer": "^10.4.23",
|
"autoprefixer": "^10.4.23",
|
||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
@@ -696,6 +697,16 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@google/generative-ai": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-gNmMFadfwi7qf/6M9gImgyGJXY1jKQ/de8vGOqgJ0PPYgQ7WwzZDavbKrIuXS2zdqZZaYtxW3EFN6aG9x5wtFw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"esbuild": "^0.27.2",
|
"esbuild": "^0.27.2",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^3.4.17"
|
"tailwindcss": "^3.4.17",
|
||||||
|
"@google/generative-ai": "^0.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user