generated from ztimson/template
Added a release bot to create release notes from closed milestones
This commit is contained in:
@@ -15,8 +15,8 @@ jobs:
|
||||
git checkout ${{ github.event.pull_request.head.sha }}
|
||||
git fetch origin ${{ github.event.pull_request.base.ref }}
|
||||
|
||||
- name: Run AI Review
|
||||
run: npx -y -p @ztimson/ai-agents@latest review $GITHUB_WORKSPACE
|
||||
- name: Create review
|
||||
run: npx --no-cache -y -p @ztimson/ai-agents@latest review $GITHUB_WORKSPACE
|
||||
env:
|
||||
AI_HOST: anthropic
|
||||
AI_MODEL: claude-sonnet-4-5
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Release Bot
|
||||
|
||||
on:
|
||||
milestone:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
container: node:22
|
||||
steps:
|
||||
- name: Checkout
|
||||
run: |
|
||||
git clone "$(echo ${{github.server_url}}/${{github.repository}}.git | sed s%://%://${{github.token}}@% )" .
|
||||
git checkout ${{ github.event.repository.default_branch }}
|
||||
|
||||
- name: Create release
|
||||
run: npx --no-cache -y @ztimson/ai-agents@latest release
|
||||
env:
|
||||
AI_HOST: anthropic
|
||||
AI_MODEL: claude-sonnet-4-5
|
||||
AI_TOKEN: ${{ secrets.ANTHROPIC_TOKEN }}
|
||||
GIT_HOST: ${{ github.server_url }}
|
||||
GIT_OWNER: ${{ github.repository_owner }}
|
||||
GIT_REPO: ${{ github.event.repository.name }}
|
||||
GIT_TOKEN: ${{ secrets.ASSISTANT_TOKEN }}
|
||||
MILESTONE: ${{ github.event.milestone.number }}
|
||||
@@ -14,8 +14,8 @@ jobs:
|
||||
git clone "$(echo ${{github.server_url}}/${{github.repository}}.git | sed s%://%://${{github.token}}@% )" .
|
||||
git checkout ${{ github.event.repository.default_branch }}
|
||||
|
||||
- name: Run AI Formatter
|
||||
run: npx -y -p @ztimson/ai-agents@latest refine
|
||||
- name: Refine ticket
|
||||
run: npx --no-cache -y -p @ztimson/ai-agents@latest refine
|
||||
env:
|
||||
AI_HOST: anthropic
|
||||
AI_MODEL: claude-sonnet-4-5
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ztimson/ai-agents",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "AI agents",
|
||||
"keywords": ["ai", "review"],
|
||||
"author": "ztimson",
|
||||
@@ -8,6 +8,7 @@
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"refine": "./src/refine.mjs",
|
||||
"release": "./src/release.mjs",
|
||||
"review": "./src/review.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
import {Ai} from '@ztimson/ai';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
dotenv.config({quiet: true, debug: false});
|
||||
dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
|
||||
|
||||
(async () => {
|
||||
const git = process.env['GIT_HOST'],
|
||||
owner = process.env['GIT_OWNER'],
|
||||
repo = process.env['GIT_REPO'],
|
||||
auth = process.env['GIT_TOKEN'],
|
||||
milestone = process.env['MILESTONE'],
|
||||
host = process.env['AI_HOST'] || 'ollama',
|
||||
model = process.env['AI_MODEL'] || 'llama3',
|
||||
token = process.env['AI_TOKEN'];
|
||||
|
||||
// Get milestone info
|
||||
const milestoneData = await fetch(`${git}/api/v1/repos/${owner}/${repo}/milestones/${milestone}`, {
|
||||
headers: {'Authorization': `token ${auth}`}
|
||||
}).then(resp => resp.ok ? resp.json() : {});
|
||||
|
||||
// Get closed issues
|
||||
const issues = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues?state=closed&milestone=${milestone}`, {
|
||||
headers: {'Authorization': `token ${auth}`}
|
||||
}).then(resp => resp.ok ? resp.json() : []);
|
||||
|
||||
// Get closed PRs
|
||||
const prs = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls?state=closed&milestone=${milestone}`, {
|
||||
headers: {'Authorization': `token ${auth}`}
|
||||
}).then(resp => resp.ok ? resp.json() : []);
|
||||
|
||||
// Get latest tag
|
||||
const latestTag = await $`git describe --tags --abbrev=0`.text();
|
||||
|
||||
// Build context
|
||||
let context = `Milestone: ${milestoneData.title}
|
||||
Description:
|
||||
\`\`\`md
|
||||
${milestoneData.description || ''}
|
||||
\`\`\`
|
||||
|
||||
PRs:
|
||||
${prs.map(pr => `- ${pr.title}\n${pr.body || ''}`).join('\n\n')}
|
||||
|
||||
Issues:
|
||||
${issues.filter(i => !i.pull_request).map(i => `- ${i.title}\n${i.body || ''}`).join('\n\n')}`;
|
||||
|
||||
// Generate release notes
|
||||
let options = {ollama: {model, host}};
|
||||
if(host === 'anthropic') options = {anthropic: {model, token}};
|
||||
else if(host === 'openai') options = {openAi: {model, token}};
|
||||
|
||||
const ai = new Ai({
|
||||
...options,
|
||||
model: [host, model],
|
||||
system: `You are a release notes writer. Format the provided milestone info, PRs, and issues into clean, organized release notes. Use markdown with sections like "Features", "Bug Fixes", "Breaking Changes", etc. Be concise but informative. Include issue/PR numbers in format #123.`
|
||||
});
|
||||
|
||||
const body = (await ai.chat(context)).pop().content;
|
||||
|
||||
// Create release
|
||||
const name = latestTag.trim();
|
||||
await fetch(`${git}/api/v1/repos/${owner}/${repo}/releases`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `token ${auth}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
tag_name: name,
|
||||
body
|
||||
})
|
||||
}).then(resp => resp.ok ? console.log('Release created! 🎉') : console.error('Failed to create release'));
|
||||
|
||||
console.log(`Title: ${name}\nDescription:\n${body}`);
|
||||
})().catch(err => {
|
||||
console.error(`Error: ${err.message || err.toString()}`);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user