mirror of
https://github.com/Heretek-AI/heretek-openclaw.git
synced 2026-07-01 12:23:18 -04:00
chore: Add migration setup script
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Post-Migration Repository Setup Script
|
||||
*
|
||||
* Sets up CI/CD workflows, CODEOWNERS, README, and CONTRIBUTING
|
||||
* for all 6 extracted repositories.
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const REPO_CONFIGS = {
|
||||
'heretek-openclaw-core': {
|
||||
readmeTemplate: 'README-core.md',
|
||||
hasTests: true,
|
||||
hasTypescript: false,
|
||||
publishType: 'docker'
|
||||
},
|
||||
'heretek-openclaw-cli': {
|
||||
readmeTemplate: 'README-cli.md',
|
||||
hasTests: true,
|
||||
hasTypescript: false,
|
||||
publishType: 'npm'
|
||||
},
|
||||
'heretek-openclaw-dashboard': {
|
||||
readmeTemplate: 'README-dashboard.md',
|
||||
hasTests: true,
|
||||
hasTypescript: true,
|
||||
publishType: 'none'
|
||||
},
|
||||
'heretek-openclaw-plugins': {
|
||||
readmeTemplate: 'README-plugins.md',
|
||||
hasTests: true,
|
||||
hasTypescript: false,
|
||||
publishType: 'npm'
|
||||
},
|
||||
'heretek-openclaw-deploy': {
|
||||
readmeTemplate: 'README-deploy.md',
|
||||
hasTests: false,
|
||||
hasTypescript: false,
|
||||
publishType: 'none'
|
||||
},
|
||||
'heretek-openclaw-docs': {
|
||||
readmeTemplate: 'README-docs.md',
|
||||
hasTests: true,
|
||||
hasTypescript: true,
|
||||
publishType: 'none'
|
||||
}
|
||||
};
|
||||
|
||||
const TEMPLATES_DIR = path.join(__dirname, 'templates');
|
||||
const BASE_DIR = path.join(__dirname, '..', '..');
|
||||
|
||||
/**
|
||||
* Read template file
|
||||
*/
|
||||
function readTemplate(filename) {
|
||||
const filepath = path.join(TEMPLATES_DIR, filename);
|
||||
return fs.readFileSync(filepath, 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize CI workflow for a specific repository
|
||||
*/
|
||||
function customizeCIWorkflow(repoName, config) {
|
||||
let workflow = readTemplate('workflow-ci.yml');
|
||||
|
||||
// Customize based on repo
|
||||
if (!config.hasTests) {
|
||||
// Remove test job for repos without tests
|
||||
workflow = workflow.replace(/ test:\n[\s\S]*? needs: \[lint, typecheck, test\]/g, ' build:');
|
||||
workflow = workflow.replace(/needs: \[lint, typecheck, test\]/g, 'needs: [lint, typecheck]');
|
||||
}
|
||||
|
||||
if (!config.hasTypescript) {
|
||||
// Remove typecheck job for non-TS repos
|
||||
workflow = workflow.replace(/ typecheck:\n[\s\S]*? test:/g, ' test:');
|
||||
workflow = workflow.replace(/needs: \[lint, typecheck\]/g, 'needs: [lint]');
|
||||
}
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize CODEOWNERS for a specific repository
|
||||
*/
|
||||
function customizeCODEOWNERS(repoName) {
|
||||
let codeowners = readTemplate('CODEOWNERS');
|
||||
|
||||
// Customize based on repo
|
||||
const repoSpecific = repoName.replace('heretek-openclaw-', '');
|
||||
codeowners = codeowners.replace(/@heretek\/core-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/agent-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/research-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/safety-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/skill-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/memory-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/plugin-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/qa-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/docs-team/g, `@heretek/${repoSpecific}-team`);
|
||||
codeowners = codeowners.replace(/@heretek\/devops-team/g, `@heretek/${repoSpecific}-team`);
|
||||
|
||||
return codeowners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a single repository
|
||||
*/
|
||||
function setupRepository(repoName, config) {
|
||||
const repoPath = path.join(BASE_DIR, repoName);
|
||||
const workflowsPath = path.join(repoPath, '.github', 'workflows');
|
||||
|
||||
console.log(`\n🔧 Setting up ${repoName}...`);
|
||||
|
||||
// Ensure .github/workflows directory exists
|
||||
if (!fs.existsSync(workflowsPath)) {
|
||||
fs.mkdirSync(workflowsPath, { recursive: true });
|
||||
console.log(` ✅ Created .github/workflows directory`);
|
||||
}
|
||||
|
||||
// Write CI workflow
|
||||
const ciWorkflow = customizeCIWorkflow(repoName, config);
|
||||
fs.writeFileSync(path.join(workflowsPath, 'ci.yml'), ciWorkflow);
|
||||
console.log(` ✅ Created .github/workflows/ci.yml`);
|
||||
|
||||
// Write Release workflow
|
||||
const releaseWorkflow = readTemplate('workflow-release.yml');
|
||||
fs.writeFileSync(path.join(workflowsPath, 'release.yml'), releaseWorkflow);
|
||||
console.log(` ✅ Created .github/workflows/release.yml`);
|
||||
|
||||
// Write CODEOWNERS
|
||||
const codeowners = customizeCODEOWNERS(repoName);
|
||||
fs.writeFileSync(path.join(repoPath, 'CODEOWNERS'), codeowners);
|
||||
console.log(` ✅ Created CODEOWNERS`);
|
||||
|
||||
// Write README
|
||||
const readme = readTemplate(config.readmeTemplate);
|
||||
fs.writeFileSync(path.join(repoPath, 'README.md'), readme);
|
||||
console.log(` ✅ Created README.md`);
|
||||
|
||||
// Write CONTRIBUTING
|
||||
const contributing = readTemplate('CONTRIBUTING.md');
|
||||
const customizedContributing = contributing.replace(/heretek-openclaw-<repo>/g, repoName);
|
||||
fs.writeFileSync(path.join(repoPath, 'CONTRIBUTING.md'), customizedContributing);
|
||||
console.log(` ✅ Created CONTRIBUTING.md`);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit and push changes for a repository
|
||||
*/
|
||||
function commitAndPush(repoName) {
|
||||
const repoPath = path.join(BASE_DIR, repoName);
|
||||
|
||||
console.log(`\n📦 Committing changes in ${repoName}...`);
|
||||
|
||||
try {
|
||||
execSync('git add -A', { cwd: repoPath, stdio: 'pipe' });
|
||||
|
||||
const status = execSync('git status --porcelain', { cwd: repoPath, encoding: 'utf-8' });
|
||||
|
||||
if (status.trim()) {
|
||||
execSync('git commit -m "chore: Add CI/CD workflows, CODEOWNERS, and documentation templates"', {
|
||||
cwd: repoPath,
|
||||
stdio: 'pipe'
|
||||
});
|
||||
console.log(` ✅ Committed changes`);
|
||||
|
||||
console.log(` 📤 Pushing to GitHub...`);
|
||||
execSync('git push', { cwd: repoPath, stdio: 'pipe' });
|
||||
console.log(` ✅ Pushed to GitHub`);
|
||||
} else {
|
||||
console.log(` ⚠️ No changes to commit`);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(` ❌ Error: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
async function main() {
|
||||
console.log('🚀 Post-Migration Repository Setup\n');
|
||||
console.log('This script will set up CI/CD workflows, CODEOWNERS, README, and CONTRIBUTING.md');
|
||||
console.log('for all 6 extracted repositories.\n');
|
||||
|
||||
const results = {};
|
||||
|
||||
// Set up each repository
|
||||
for (const [repoName, config] of Object.entries(REPO_CONFIGS)) {
|
||||
const setupSuccess = setupRepository(repoName, config);
|
||||
results[repoName] = { setup: setupSuccess, push: false };
|
||||
}
|
||||
|
||||
console.log('\n\n📤 Pushing changes to GitHub...\n');
|
||||
|
||||
// Commit and push each repository
|
||||
for (const repoName of Object.keys(REPO_CONFIGS)) {
|
||||
const pushSuccess = commitAndPush(repoName);
|
||||
results[repoName].push = pushSuccess;
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log('\n\n✅ Setup Complete!\n');
|
||||
console.log('Summary:');
|
||||
console.log('--------');
|
||||
|
||||
let allSuccess = true;
|
||||
for (const [repoName, result] of Object.entries(results)) {
|
||||
const setupIcon = result.setup ? '✅' : '❌';
|
||||
const pushIcon = result.push ? '✅' : '❌';
|
||||
const status = result.setup && result.push ? '✅' : '⚠️';
|
||||
|
||||
if (!result.setup || !result.push) {
|
||||
allSuccess = false;
|
||||
}
|
||||
|
||||
console.log(`${status} ${repoName}: Setup ${setupIcon} Push ${pushIcon}`);
|
||||
}
|
||||
|
||||
if (allSuccess) {
|
||||
console.log('\n🎉 All repositories set up successfully!');
|
||||
} else {
|
||||
console.log('\n⚠️ Some repositories had issues. Please check the output above.');
|
||||
}
|
||||
}
|
||||
|
||||
// Run
|
||||
main().catch(console.error);
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
/**
|
||||
* Heretek OpenClaw Monorepo Split Script
|
||||
*
|
||||
*
|
||||
* Extracts specified paths from the monorepo into dedicated repositories.
|
||||
* Uses git-filter-repo for efficient history preservation.
|
||||
*
|
||||
*
|
||||
* Usage: node scripts/migration/split-repos.js <repo-name>
|
||||
*
|
||||
*
|
||||
* Available repositories:
|
||||
* - heretek-openclaw-core
|
||||
* - heretek-openclaw-cli
|
||||
@@ -17,9 +17,9 @@
|
||||
* - heretek-openclaw-docs
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
import { execSync } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// Repository configuration
|
||||
const REPOS = {
|
||||
@@ -306,6 +306,7 @@ function splitRepo(repoName, config) {
|
||||
console.log(` Paths: ${config.paths.length} entries`);
|
||||
|
||||
const repoDir = path.join(process.cwd(), repoName);
|
||||
const sourceRepoDir = process.cwd(); // Use current directory as source
|
||||
|
||||
// Check if git-filter-repo is installed
|
||||
try {
|
||||
@@ -317,22 +318,19 @@ function splitRepo(repoName, config) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Clone the monorepo
|
||||
console.log(' Cloning monorepo...');
|
||||
// Clone from local repository
|
||||
console.log(' Cloning from local monorepo...');
|
||||
if (fs.existsSync(repoDir)) {
|
||||
console.log(' ⚠️ Directory already exists, removing...');
|
||||
fs.rmSync(repoDir, { recursive: true, force: true });
|
||||
}
|
||||
exec(`git clone --depth 1 git@github.com:heretek/heretek-openclaw.git ${repoName}`, { stdio: 'pipe' });
|
||||
exec(`git clone file://${sourceRepoDir} ${repoName}`, { stdio: 'pipe' });
|
||||
|
||||
// Change to repo directory
|
||||
const originalDir = process.cwd();
|
||||
process.chdir(repoDir);
|
||||
|
||||
try {
|
||||
// Initialize git for filter-repo (fresh clone might not have full history)
|
||||
exec('git fetch --unshallow 2>/dev/null || true', { stdio: 'pipe' });
|
||||
|
||||
// Filter to only include specified paths
|
||||
const pathsArg = config.paths.map(p => `--path ${p}`).join(' ');
|
||||
console.log(' Filtering repository...');
|
||||
@@ -344,16 +342,14 @@ function splitRepo(repoName, config) {
|
||||
config.postProcess(repoDir);
|
||||
}
|
||||
|
||||
// Update remote URL
|
||||
console.log(' Updating remote...');
|
||||
exec(`git remote set-url origin git@github.com:heretek/${repoName}.git`);
|
||||
// Add remote URL for new GitHub repository
|
||||
console.log(' Adding remote...');
|
||||
exec(`git remote add origin git@github.com:Heretek-AI/${repoName}.git`);
|
||||
|
||||
// Push to new repository
|
||||
console.log(' Pushing to new repository...');
|
||||
exec('git push -u origin main --force');
|
||||
|
||||
console.log(`✅ ${repoName} split complete!`);
|
||||
console.log(` Repository: https://github.com/heretek/${repoName}`);
|
||||
console.log(`✅ ${repoName} extracted to ${repoDir}`);
|
||||
console.log(` Next steps:`);
|
||||
console.log(` 1. cd ${repoDir}`);
|
||||
console.log(` 2. git push -u origin main --force`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error splitting ${repoName}: ${error.message}`);
|
||||
|
||||
Reference in New Issue
Block a user