@devilsdev/rag-pipeline-utils 2.1.4 → 2.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/PROJECT_ROADMAP.md +102 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +8 -0
- package/.github/workflows/auto-release-note.yml +73 -0
- package/.github/workflows/ci.yml +5 -3
- package/.github/workflows/docs-ci.yml +12 -15
- package/.github/workflows/docs-deploy.yml +24 -10
- package/.github/workflows/enforce-release-review.yml +50 -0
- package/.github/workflows/generate-blog-post.yml +44 -0
- package/.github/workflows/post-release-generate-blog.yml +71 -0
- package/.github/workflows/release-sync.yml +50 -0
- package/.github/workflows/roadmap-label-sync.yml +35 -0
- package/.github/workflows/roadmap-labels.yml +67 -0
- package/.github/workflows/roadmap-sync.yml +44 -0
- package/.github/workflows/sync-roadmap.yml +62 -0
- package/.github/workflows/verify-blog-badge.yml +50 -0
- package/CHANGELOG.md +41 -0
- package/README.md +40 -0
- package/__tests__/scripts/ensure-roadmap-labels.test.js +64 -0
- package/docs-site/blog/2025-04-21-release-v2.1.4.md +13 -0
- package/docs-site/blog/2025-04-22-release-v2.1.5.md +13 -0
- package/docs-site/blog/2025-04-24-v2.1.6.md +21 -0
- package/docs-site/package.json +4 -1
- package/package.json +7 -11
- package/scripts/banner-injector.js +82 -69
- package/scripts/close-done-roadmap-issues.js +65 -0
- package/scripts/create-roadmap-issues.js +47 -0
- package/scripts/ensure-roadmap-labels.js +73 -0
- package/scripts/generate-release-note.js +97 -27
- package/scripts/get-previous-tag.js +40 -0
- package/scripts/label-roadmap-issues.js +125 -0
- package/scripts/manual-test-checklist.md +90 -0
- package/scripts/sync-labels.js +71 -0
- package/scripts/sync-roadmap-labels.js +21 -0
- package/scripts/tag-release.js +64 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// scripts/create-roadmap-issues.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Version: 2.0.0
|
|
5
|
+
* Description: Parses PROJECT_ROADMAP.md and syncs GitHub issues
|
|
6
|
+
* Author: Ali Kahwaji
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'fs/promises';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { Octokit } from 'octokit';
|
|
12
|
+
import yaml from 'js-yaml';
|
|
13
|
+
|
|
14
|
+
const roadmapPath = new URL('../.github/PROJECT_ROADMAP.md', import.meta.url);
|
|
15
|
+
|
|
16
|
+
export async function createRoadmapIssues({ token, owner, repo }) {
|
|
17
|
+
const octokit = new Octokit({ auth: token });
|
|
18
|
+
const content = await fs.readFile(roadmapPath, 'utf-8');
|
|
19
|
+
|
|
20
|
+
const blocks = content.split(/^##\s+/gm).slice(1);
|
|
21
|
+
|
|
22
|
+
for (const block of blocks) {
|
|
23
|
+
const [header, ...bodyLines] = block.trim().split('\n');
|
|
24
|
+
const title = header.trim();
|
|
25
|
+
const metadata = {};
|
|
26
|
+
const description = [];
|
|
27
|
+
|
|
28
|
+
for (const line of bodyLines) {
|
|
29
|
+
if (line.includes(':') && line.includes('**')) {
|
|
30
|
+
const [key, val] = line.split(':');
|
|
31
|
+
metadata[key.trim()] = val.replace(/\*\*/g, '').trim();
|
|
32
|
+
} else {
|
|
33
|
+
description.push(line);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const issue = await octokit.rest.issues.create({
|
|
38
|
+
owner,
|
|
39
|
+
repo,
|
|
40
|
+
title,
|
|
41
|
+
body: description.join('\n'),
|
|
42
|
+
labels: [metadata.Priority, metadata.Group].filter(Boolean),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
console.log(`✅ Created: ${issue.data.title}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version: 2.0.1
|
|
3
|
+
* Path: scripts/ensure-roadmap-labels.js
|
|
4
|
+
* Description: Ensures consistent GitHub labels for roadmap tracking and automation.
|
|
5
|
+
* Author: Ali Kahwaji
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Octokit } from 'octokit';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Label definitions for roadmap tracking.
|
|
13
|
+
* Modify this array to add or update roadmap labels.
|
|
14
|
+
* Each object must include: name, color (hex), description.
|
|
15
|
+
*/
|
|
16
|
+
const roadmapLabels = [
|
|
17
|
+
{ name: 'priority: high', color: 'e11d48', description: 'High priority roadmap item' },
|
|
18
|
+
{ name: 'priority: medium', color: 'f59e0b', description: 'Medium priority roadmap item' },
|
|
19
|
+
{ name: 'priority: low', color: '10b981', description: 'Low priority roadmap item' },
|
|
20
|
+
{ name: 'group: docs', color: '6366f1', description: 'Documentation features' },
|
|
21
|
+
{ name: 'group: devx', color: '06b6d4', description: 'Developer experience improvements' },
|
|
22
|
+
{ name: 'group: community', color: 'ec4899', description: 'Community tools & engagement' },
|
|
23
|
+
{ name: 'group: blog', color: 'f97316', description: 'Blog & SEO enhancements' },
|
|
24
|
+
{ name: 'group: infra', color: '64748b', description: 'Infrastructure & deployment features' },
|
|
25
|
+
{ name: 'group: hydra', color: '9333ea', description: 'Hydra runtime & configuration' },
|
|
26
|
+
{ name: 'status: done', color: '10b981', description: 'Issue has been completed' }
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Ensures all roadmap labels are present in the target GitHub repository.
|
|
31
|
+
* Skips label creation if already present.
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} params
|
|
34
|
+
* @param {string} params.token - GitHub access token
|
|
35
|
+
* @param {string} params.owner - Repository owner
|
|
36
|
+
* @param {string} params.repo - Repository name
|
|
37
|
+
*/
|
|
38
|
+
async function ensureRoadmapLabels({ token, owner, repo }) {
|
|
39
|
+
const octokit = new Octokit({ auth: token });
|
|
40
|
+
|
|
41
|
+
const { data: existingLabels } = await octokit.rest.issues.listLabelsForRepo({
|
|
42
|
+
owner,
|
|
43
|
+
repo
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const existingNames = new Set(existingLabels.map((label) => label.name));
|
|
47
|
+
|
|
48
|
+
for (const label of roadmapLabels) {
|
|
49
|
+
if (!existingNames.has(label.name)) {
|
|
50
|
+
await octokit.rest.issues.createLabel({ owner, repo, ...label });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// CLI support
|
|
56
|
+
if (process.argv[1] === new URL(import.meta.url).pathname) {
|
|
57
|
+
const [owner, repo] = process.env.GITHUB_REPOSITORY?.split('/') || [];
|
|
58
|
+
const token = process.env.GITHUB_TOKEN;
|
|
59
|
+
|
|
60
|
+
if (!token || !owner || !repo) {
|
|
61
|
+
console.error('Missing required GITHUB_TOKEN or GITHUB_REPOSITORY');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
ensureRoadmapLabels({ token, owner, repo })
|
|
66
|
+
.then(() => console.log('✅ Roadmap labels ensured'))
|
|
67
|
+
.catch((err) => {
|
|
68
|
+
console.error('Label sync failed:', err);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { ensureRoadmapLabels, roadmapLabels };
|
|
@@ -1,40 +1,110 @@
|
|
|
1
|
-
//
|
|
1
|
+
// scripts/generate-release-note.js
|
|
2
2
|
/**
|
|
3
|
-
* Version:
|
|
4
|
-
* Description:
|
|
3
|
+
* Version: 2.3.0
|
|
4
|
+
* Description: Generate release blog + changelog section, auto-push to Git, fallback to safe defaults
|
|
5
5
|
* Author: Ali Kahwaji
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const [, , newVersionArg, previousVersionArg] = process.argv;
|
|
17
|
+
|
|
18
|
+
if (!newVersionArg) {
|
|
19
|
+
console.error('❌ Usage: node scripts/generate-release-note.js <new-tag> <previous-tag?>');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const newVersion = newVersionArg.startsWith('v') ? newVersionArg : `v${newVersionArg}`;
|
|
24
|
+
|
|
25
|
+
// 🔁 Fallback to previous git tag
|
|
26
|
+
function resolvePreviousTag() {
|
|
27
|
+
try {
|
|
28
|
+
const tags = execSync('git tag --sort=-creatordate', { encoding: 'utf-8' })
|
|
29
|
+
.split('\n')
|
|
30
|
+
.filter(Boolean);
|
|
31
|
+
const idx = tags.indexOf(newVersion);
|
|
32
|
+
return tags[idx + 1] || tags[1] || null;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const prevVersion = previousVersionArg || resolvePreviousTag();
|
|
39
|
+
if (!prevVersion) {
|
|
40
|
+
console.error('❌ Could not resolve previous tag.');
|
|
16
41
|
process.exit(1);
|
|
17
42
|
}
|
|
18
43
|
|
|
19
|
-
|
|
20
|
-
|
|
44
|
+
// 📦 Get commits between versions
|
|
45
|
+
function getCommits(from, to) {
|
|
46
|
+
try {
|
|
47
|
+
return execSync(`git log ${from}..${to} --pretty=format:"- %s"`, { encoding: 'utf-8' });
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error('❌ Failed to fetch commits:', err.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function generateChangelogSection(commits) {
|
|
55
|
+
return `## ${newVersion}\n\n${commits}\n\n---\n`;
|
|
56
|
+
}
|
|
21
57
|
|
|
22
|
-
|
|
58
|
+
function generateBlogMarkdown(version, commits) {
|
|
59
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
60
|
+
const slug = `release-${version}`;
|
|
61
|
+
return `---
|
|
62
|
+
slug: ${slug}
|
|
63
|
+
title: "🚀 Version ${version} Released"
|
|
64
|
+
authors: [ali]
|
|
65
|
+
tags: [release, changelog]
|
|
66
|
+
---
|
|
23
67
|
|
|
24
|
-
|
|
25
|
-
const contributors = execSync(`git shortlog -sne ${previousTag}..HEAD | wc -l`).toString().trim();
|
|
26
|
-
// Count commits
|
|
27
|
-
const commits = execSync(`git rev-list --count ${previousTag}..HEAD`).toString().trim();
|
|
28
|
-
// ISO date
|
|
29
|
-
const date = new Date().toISOString().split('T')[0];
|
|
68
|
+
RAG Pipeline Utils **${version}** is now available on NPM!
|
|
30
69
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
70
|
+
## 🔧 Changes
|
|
71
|
+
|
|
72
|
+
${commits}
|
|
73
|
+
|
|
74
|
+
## 🔗 Resources
|
|
75
|
+
|
|
76
|
+
- GitHub Compare: [${prevVersion}...${version}](https://github.com/DevilsDev/rag-pipeline-utils/compare/${prevVersion}...${version})
|
|
77
|
+
- View full [CHANGELOG on GitHub](https://github.com/DevilsDev/rag-pipeline-utils/blob/main/CHANGELOG.md)
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const commits = getCommits(prevVersion, newVersion);
|
|
82
|
+
const blogContent = generateBlogMarkdown(newVersion, commits);
|
|
83
|
+
const changelogSection = generateChangelogSection(commits);
|
|
84
|
+
|
|
85
|
+
// 📍 Paths
|
|
86
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
87
|
+
const blogPath = path.join(__dirname, `../docs-site/blog/${today}-${newVersion}.md`);
|
|
88
|
+
const changelogPath = path.join(__dirname, '../CHANGELOG.md');
|
|
89
|
+
|
|
90
|
+
// 📝 Write blog + changelog
|
|
91
|
+
fs.writeFileSync(blogPath, blogContent, 'utf-8');
|
|
92
|
+
fs.appendFileSync(changelogPath, `\n${changelogSection}`, 'utf-8');
|
|
93
|
+
|
|
94
|
+
// 🔐 Commit and push
|
|
95
|
+
try {
|
|
96
|
+
execSync('git config user.name "github-actions[bot]"');
|
|
97
|
+
execSync('git config user.email "41898282+github-actions[bot]@users.noreply.github.com"');
|
|
98
|
+
execSync('git add CHANGELOG.md docs-site/blog/*.md');
|
|
99
|
+
execSync(`git commit -m "docs(release): publish changelog and blog for ${newVersion}"`);
|
|
100
|
+
execSync('git push origin main');
|
|
101
|
+
console.log(`✅ Blog + changelog committed for ${newVersion}`);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.warn('⚠️ Git commit skipped (already committed or no changes).');
|
|
104
|
+
}
|
|
38
105
|
|
|
39
|
-
|
|
40
|
-
console.log(
|
|
106
|
+
// 📦 Local preview
|
|
107
|
+
console.log('\n📘 Blog Preview:\n');
|
|
108
|
+
console.log(blogContent);
|
|
109
|
+
console.log('\n📘 Changelog Section:\n');
|
|
110
|
+
console.log(changelogSection);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version: 1.0.0
|
|
3
|
+
* Description: Helper to find the previous Git semver tag before a given tag
|
|
4
|
+
* Usage: node scripts/get-previous-tag.js v2.1.5
|
|
5
|
+
* Output: v2.1.4
|
|
6
|
+
* Author: Ali Kahwaji
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
|
|
11
|
+
const currentTag = process.argv[2];
|
|
12
|
+
|
|
13
|
+
if (!currentTag) {
|
|
14
|
+
console.error('❌ Usage: node get-previous-tag.js <current-tag>');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
// Ensure full tag history
|
|
20
|
+
execSync('git fetch --tags --unshallow 2>/dev/null || git fetch --tags', { stdio: 'inherit' });
|
|
21
|
+
|
|
22
|
+
// List all tags sorted by version (most recent last), remove current tag
|
|
23
|
+
const tags = execSync('git tag --sort=version:refname', { encoding: 'utf-8' })
|
|
24
|
+
.split('\n')
|
|
25
|
+
.map(tag => tag.trim())
|
|
26
|
+
.filter(Boolean);
|
|
27
|
+
|
|
28
|
+
const idx = tags.indexOf(currentTag);
|
|
29
|
+
|
|
30
|
+
if (idx <= 0) {
|
|
31
|
+
console.error('⚠️ Could not find previous tag before', currentTag);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const previousTag = tags[idx - 1];
|
|
36
|
+
console.log(previousTag);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error('❌ Failed to resolve previous tag:', err.message);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version: 2.0.0
|
|
3
|
+
* Description: Auto-label roadmap issues and clean up outdated items
|
|
4
|
+
* Author: Ali Kahwaji
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Octokit } from 'octokit';
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
import 'dotenv/config';
|
|
10
|
+
|
|
11
|
+
const repo = process.env.GITHUB_REPO;
|
|
12
|
+
const token = process.env.GITHUB_TOKEN;
|
|
13
|
+
const ROADMAP_FILE = '.github/PROJECT_ROADMAP.md';
|
|
14
|
+
const CLOSE_STALE = true;
|
|
15
|
+
|
|
16
|
+
if (!repo || !token) {
|
|
17
|
+
console.error('Missing GITHUB_REPO or GITHUB_TOKEN env vars');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const [owner, repoName] = repo.split('/');
|
|
22
|
+
const octokit = new Octokit({ auth: token });
|
|
23
|
+
|
|
24
|
+
const PRIORITY_LABELS = {
|
|
25
|
+
High: 'priority: high',
|
|
26
|
+
Medium: 'priority: medium',
|
|
27
|
+
Low: 'priority: low',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const GROUP_LABELS = {
|
|
31
|
+
'Documentation': 'group: docs',
|
|
32
|
+
'Developer Experience': 'group: devx',
|
|
33
|
+
'Community': 'group: community',
|
|
34
|
+
'Blog & SEO': 'group: blog',
|
|
35
|
+
'Infrastructure': 'group: infra',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function parseRoadmapMarkdown(content) {
|
|
39
|
+
const lines = content.split('\n').filter(l => l.includes('|'));
|
|
40
|
+
const titles = new Set();
|
|
41
|
+
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
const parts = line.split('|').map(p => p.trim());
|
|
44
|
+
if (parts.length < 4 || parts[0] === 'Phase') continue;
|
|
45
|
+
const title = parts[3];
|
|
46
|
+
titles.add(title);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return titles;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function run() {
|
|
53
|
+
const roadmapRaw = await fs.readFile(ROADMAP_FILE, 'utf8');
|
|
54
|
+
const roadmapTitles = parseRoadmapMarkdown(roadmapRaw);
|
|
55
|
+
|
|
56
|
+
const issues = await octokit.paginate(octokit.rest.issues.listForRepo, {
|
|
57
|
+
owner,
|
|
58
|
+
repo: repoName,
|
|
59
|
+
state: 'open',
|
|
60
|
+
per_page: 100,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
for (const issue of issues) {
|
|
64
|
+
if (issue.pull_request) continue;
|
|
65
|
+
|
|
66
|
+
const title = issue.title.trim();
|
|
67
|
+
const body = issue.body || '';
|
|
68
|
+
const labels = new Set(issue.labels.map(l => typeof l === 'string' ? l : l.name));
|
|
69
|
+
|
|
70
|
+
const priority = Object.keys(PRIORITY_LABELS).find(p => body.includes(`Priority: ${p}`));
|
|
71
|
+
const group = Object.keys(GROUP_LABELS).find(g => body.includes(`Group: ${g}`));
|
|
72
|
+
|
|
73
|
+
const expectedLabels = [
|
|
74
|
+
...(priority ? [PRIORITY_LABELS[priority]] : []),
|
|
75
|
+
...(group ? [GROUP_LABELS[group]] : [])
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const currentRoadmap = roadmapTitles.has(title);
|
|
79
|
+
|
|
80
|
+
// Update Labels
|
|
81
|
+
const labelsToAdd = expectedLabels.filter(label => !labels.has(label));
|
|
82
|
+
const labelsToRemove = [...labels].filter(label =>
|
|
83
|
+
Object.values(PRIORITY_LABELS).includes(label) ||
|
|
84
|
+
Object.values(GROUP_LABELS).includes(label)
|
|
85
|
+
).filter(label => !expectedLabels.includes(label));
|
|
86
|
+
|
|
87
|
+
if (labelsToAdd.length > 0 || labelsToRemove.length > 0) {
|
|
88
|
+
console.log(`🔁 Updating labels for issue #${issue.number}: ${title}`);
|
|
89
|
+
if (labelsToAdd.length) {
|
|
90
|
+
await octokit.rest.issues.addLabels({
|
|
91
|
+
owner,
|
|
92
|
+
repo: repoName,
|
|
93
|
+
issue_number: issue.number,
|
|
94
|
+
labels: labelsToAdd,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (labelsToRemove.length) {
|
|
98
|
+
for (const label of labelsToRemove) {
|
|
99
|
+
await octokit.rest.issues.removeLabel({
|
|
100
|
+
owner,
|
|
101
|
+
repo: repoName,
|
|
102
|
+
issue_number: issue.number,
|
|
103
|
+
name: label,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Optionally Close stale issues
|
|
110
|
+
if (CLOSE_STALE && !currentRoadmap) {
|
|
111
|
+
console.log(`🧹 Closing stale issue #${issue.number} (${title}) – not in roadmap`);
|
|
112
|
+
await octokit.rest.issues.update({
|
|
113
|
+
owner,
|
|
114
|
+
repo: repoName,
|
|
115
|
+
issue_number: issue.number,
|
|
116
|
+
state: 'closed',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
run().catch(err => {
|
|
123
|
+
console.error('❌ Label script failed:', err);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# ✅ Manual Test Checklist for RAG Pipeline Utils
|
|
2
|
+
|
|
3
|
+
This document outlines manual test points for validating roadmap automation, documentation builds, CI/CD, blog sync, and changelog generation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 🔄 Roadmap Sync + Label Automation
|
|
8
|
+
|
|
9
|
+
| ✅ Task | Command or Trigger | Notes |
|
|
10
|
+
|--------|--------------------|-------|
|
|
11
|
+
| Sync `PROJECT_ROADMAP.md` to GitHub Issues | `git push` or `workflow_dispatch` for `sync-roadmap.yml` | Issues, assignees, labels should match |
|
|
12
|
+
| Auto-create missing roadmap labels | `sync-roadmap.yml` step: `ensure-roadmap-labels.js` | Should not error even if labels exist |
|
|
13
|
+
| Label updates reflect correct color & description | Rerun roadmap sync | Existing labels should be updated |
|
|
14
|
+
| Roadmap issue closed on ✅ Done status | Modify `PROJECT_ROADMAP.md` status and sync | Corresponding issue should be auto-closed |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 2. 🧭 CLI + Manual Utilities
|
|
19
|
+
|
|
20
|
+
| ✅ Task | Command | Notes |
|
|
21
|
+
|--------|---------|-------|
|
|
22
|
+
| Create roadmap issues manually | `node scripts/create-roadmap-issues.js` | Creates GitHub Issues |
|
|
23
|
+
| Ensure labels via CLI | `node scripts/ensure-roadmap-labels.js` | Must succeed with idempotency |
|
|
24
|
+
| Generate changelog and preview | `npm run release:tag` | Prompt for tag + generate CHANGELOG |
|
|
25
|
+
| Preview auto-generated blog post | Preview `.md` file in `/docs-site/blog` before push |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 3. 📚 Docs + Deployment
|
|
30
|
+
|
|
31
|
+
| ✅ Task | Command | Notes |
|
|
32
|
+
|--------|---------|-------|
|
|
33
|
+
| Build Docusaurus | `npm run docs:build` | No broken links, light/dark theme OK |
|
|
34
|
+
| Deploy to GitHub Pages | `npm run docs:deploy` | Check rendered site at `/rag-pipeline-utils` |
|
|
35
|
+
| Verify CHANGELOG link works | Test `/blog` page post link to `CHANGELOG.md` |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 4. 🧪 CI/CD Validation
|
|
40
|
+
|
|
41
|
+
| ✅ Task | Check | Notes |
|
|
42
|
+
|--------|-------|-------|
|
|
43
|
+
| CI Lint + Test runs | ✅ `ci.yml` | Lint passes, all Jest tests green |
|
|
44
|
+
| Docs CI runs correctly | ✅ `docs-ci.yml` | No script missing error, build valid |
|
|
45
|
+
| Docs auto-deploys on push | ✅ `docs-deploy.yml` | Publishes to GitHub Pages |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 5. 🏷 GitHub Releases
|
|
50
|
+
|
|
51
|
+
| ✅ Task | Trigger | Notes |
|
|
52
|
+
|--------|---------|-------|
|
|
53
|
+
| Generate blog post on release | Publish GitHub tag | `publish-release-blog.yml` should commit new `.md` |
|
|
54
|
+
| Auto-fill blog content | From `CHANGELOG.md` and compare link | Author + commit stats populated |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 6. 🛡 Release Gatekeeping & Metadata
|
|
59
|
+
|
|
60
|
+
| ✅ Task | Outcome | Notes |
|
|
61
|
+
|--------|---------|-------|
|
|
62
|
+
| Badge renders in README | `![Release Review Passed]` | Should point to last workflow run |
|
|
63
|
+
| Protected branch config for PRs | Status check on `release:review` | Prevents push without passing review |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 7. 🧾 Filesystem and Cleanup
|
|
68
|
+
|
|
69
|
+
| ✅ Task | Notes |
|
|
70
|
+
|--------|-------|
|
|
71
|
+
| `src/stories/` removed | No Storybook assets in GH Pages |
|
|
72
|
+
| `postcss.config.cjs` & `tailwind.config.js` removed | Confirm no broken styling or build errors |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 🔁 Optional Manual Commands
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Sync roadmap manually
|
|
80
|
+
node scripts/create-roadmap-issues.js
|
|
81
|
+
|
|
82
|
+
# Ensure roadmap labels
|
|
83
|
+
node scripts/ensure-roadmap-labels.js
|
|
84
|
+
|
|
85
|
+
# Trigger changelog + blog post flow
|
|
86
|
+
npm run release:tag
|
|
87
|
+
|
|
88
|
+
# Build and deploy docs
|
|
89
|
+
npm run docs:build && npm run docs:deploy
|
|
90
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version: 1.1.0
|
|
3
|
+
* Description: Syncs GitHub labels based on roadmap-labels.yml; updates existing, creates missing.
|
|
4
|
+
* Author: Ali Kahwaji
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { Octokit } from '@octokit/rest';
|
|
11
|
+
|
|
12
|
+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
|
|
13
|
+
const REPO = process.env.GITHUB_REPOSITORY;
|
|
14
|
+
|
|
15
|
+
if (!GITHUB_TOKEN || !REPO) {
|
|
16
|
+
console.error('❌ GITHUB_TOKEN or GITHUB_REPOSITORY not defined in environment.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const [owner, repo] = REPO.split('/');
|
|
21
|
+
const octokit = new Octokit({ auth: GITHUB_TOKEN });
|
|
22
|
+
|
|
23
|
+
const LABELS_FILE = path.join('.github', 'roadmap-labels.yml');
|
|
24
|
+
|
|
25
|
+
function loadLabelsFromYAML(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
const file = fs.readFileSync(filePath, 'utf8');
|
|
28
|
+
return yaml.load(file);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
console.error('❌ Failed to load roadmap-labels.yml:', err);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function syncLabels() {
|
|
36
|
+
const labels = loadLabelsFromYAML(LABELS_FILE);
|
|
37
|
+
const existingLabels = await octokit.paginate(octokit.rest.issues.listLabelsForRepo, {
|
|
38
|
+
owner,
|
|
39
|
+
repo,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
for (const label of labels) {
|
|
43
|
+
const existing = existingLabels.find(l => l.name === label.name);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
if (existing) {
|
|
47
|
+
console.log(`🔁 Updating label: ${label.name}`);
|
|
48
|
+
await octokit.rest.issues.updateLabel({
|
|
49
|
+
owner,
|
|
50
|
+
repo,
|
|
51
|
+
name: label.name,
|
|
52
|
+
color: label.color,
|
|
53
|
+
description: label.description,
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
console.log(`➕ Creating label: ${label.name}`);
|
|
57
|
+
await octokit.rest.issues.createLabel({
|
|
58
|
+
owner,
|
|
59
|
+
repo,
|
|
60
|
+
name: label.name,
|
|
61
|
+
color: label.color,
|
|
62
|
+
description: label.description,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
console.error(`❌ Failed to process label: ${label.name}`, err.message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
syncLabels();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// scripts/sync-roadmap-labels.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Version: 1.1.0
|
|
5
|
+
* Description: Sync roadmap labels and issues
|
|
6
|
+
* Author: Ali Kahwaji
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ensureRoadmapLabels } from './ensure-roadmap-labels.js';
|
|
10
|
+
import { createRoadmapIssues } from './create-roadmap-issues.js';
|
|
11
|
+
|
|
12
|
+
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
|
|
13
|
+
const token = process.env.GITHUB_TOKEN;
|
|
14
|
+
|
|
15
|
+
if (!token) {
|
|
16
|
+
console.error('❌ Missing GITHUB_TOKEN');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
await ensureRoadmapLabels({ token, owner, repo });
|
|
21
|
+
await createRoadmapIssues({ token, owner, repo });
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version: 2.0.0
|
|
3
|
+
* Description: Tags release, updates changelog, optionally opens blog preview
|
|
4
|
+
* Author: Ali Kahwaji
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import readline from 'readline';
|
|
11
|
+
|
|
12
|
+
const VERSION = process.argv[2];
|
|
13
|
+
const PREVIEW = process.argv.includes('--preview');
|
|
14
|
+
|
|
15
|
+
if (!VERSION) {
|
|
16
|
+
console.error('❌ Usage: node release-tag.js <version> [--preview]');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const tag = `v${VERSION}`;
|
|
21
|
+
const blogPath = path.join('docs-site', 'blog');
|
|
22
|
+
|
|
23
|
+
// Step 1: Run changelog injection
|
|
24
|
+
execSync(`node scripts/generate-release-note.js ${VERSION}`, { stdio: 'inherit' });
|
|
25
|
+
|
|
26
|
+
// Step 2: Find generated blog file
|
|
27
|
+
const date = new Date().toISOString().split('T')[0];
|
|
28
|
+
const file = path.join(blogPath, `${date}-release-${tag}.md`);
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(file)) {
|
|
31
|
+
console.error(`❌ Blog post not generated: ${file}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Step 3: Preview if enabled
|
|
36
|
+
if (PREVIEW) {
|
|
37
|
+
const editor = process.env.EDITOR || 'code'; // fallback to VS Code
|
|
38
|
+
try {
|
|
39
|
+
execSync(`${editor} ${file}`, { stdio: 'inherit' });
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.warn('⚠️ Failed to open in editor. Please review manually:', file);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
45
|
+
rl.question(`✅ Ready to commit and push ${tag}? (y/n): `, (answer) => {
|
|
46
|
+
rl.close();
|
|
47
|
+
if (answer.toLowerCase() !== 'y') {
|
|
48
|
+
console.log('❌ Aborted. No tag pushed.');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
finalizeRelease();
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
finalizeRelease();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Final tagging + push
|
|
58
|
+
function finalizeRelease() {
|
|
59
|
+
execSync(`git add CHANGELOG.md ${file}`);
|
|
60
|
+
execSync(`git commit -m "release: v${VERSION}"`);
|
|
61
|
+
execSync(`git tag ${tag}`);
|
|
62
|
+
execSync('git push && git push --tags');
|
|
63
|
+
console.log(`🎉 Release ${tag} published and blog post staged!`);
|
|
64
|
+
}
|