Cleaning up scripts

This commit is contained in:
Justin Dalrymple 2026-01-17 18:17:12 -05:00
parent a84072bffc
commit feb277341f
5 changed files with 131 additions and 198 deletions

View File

@ -469,17 +469,7 @@ jobs:
command: |
export PR_NUMBER=$(echo $CIRCLE_PULL_REQUEST | sed 's/.*\/pull\///')
if [[ -n "$PR_NUMBER" ]]; then
# Check if PR has release:canary label
if node scripts/check-release-label.mjs $PR_NUMBER; then
echo "Proceeding with canary release"
yarn release:canary
else
echo "Skipping canary release"
fi
else
echo "No PR found - skipping canary release"
fi
yarn release:canary
release-production:
executor: node-executor

View File

@ -1,39 +0,0 @@
#!/usr/bin/env node
/**
* Check if PR has release:canary label
* Usage:
* node scripts/check-release-label.mjs <PR_NUMBER>
* node scripts/check-release-label.mjs # Uses environment variables
* Exit code: 0 if label found, 1 if not found
*/
import { fetchPRData } from './github-api.mjs';
const prNumber = process.argv[2] || process.env.CIRCLE_PR_NUMBER || process.env.PR_NUMBER;
if (!prNumber) {
console.error('No PR number provided');
process.exit(1);
}
async function checkReleaseLabel() {
try {
const prData = await fetchPRData(prNumber);
const labels = prData.labels.map(label => label.name);
console.log(`PR #${prNumber} labels: ${labels.join(', ')}`);
if (labels.includes('release:canary')) {
console.log('✅ Found release:canary label');
process.exit(0);
} else {
console.log('❌ No release:canary label found');
process.exit(1);
}
} catch (error) {
console.error('Error checking label:', error.message);
process.exit(1);
}
}
checkReleaseLabel();

View File

@ -1,106 +0,0 @@
#!/usr/bin/env node
import { writeFileSync, existsSync, mkdirSync } from 'fs';
import { execSync } from 'child_process';
import { fetchPRData } from './github-api.mjs';
const labelToChangeType = {
breaking: 'major',
'type:feature': 'minor',
'type:bug': 'minor',
'type:hot fix': 'minor',
'type:technical debt': 'patch',
'type:security': 'patch',
'type:dependencies': 'patch',
'type:types': 'patch',
'type:testing': null,
'type:documentation': null,
};
function getPackageNames() {
try {
// Get all workspace packages using yarn
const output = execSync('yarn workspaces list --json', { encoding: 'utf8' });
const workspaces = output
.trim()
.split('\n')
.map((line) => JSON.parse(line));
// Filter out the root workspace and get package names
const packageNames = workspaces
.filter((ws) => ws.location !== '.' && ws.name) // Skip root workspace
.map((ws) => ws.name);
return packageNames;
} catch (error) {
console.warn('Could not get workspace packages:', error.message);
return [];
}
}
function generateChangesetYaml(packageNames, changeType) {
if (packageNames.length === 0) return '';
return packageNames.map((name) => `"${name}": ${changeType}`).join('\n');
}
async function generateChangesetFromPR() {
const prNumber = process.env.PR_NUMBER;
if (!prNumber) {
console.log('No PR number found in environment, skipping changeset generation');
return;
}
try {
// Fetch PR data from GitHub API
const prData = await fetchPRData(prNumber);
// Get labels
const labels = prData.labels.map((label) => label.name);
console.log(`Found PR labels: ${labels.join(', ')}`);
// Find change type
const changeType = labels
.map((label) => labelToChangeType[label])
.filter(Boolean)
.sort(
(a, b) => ['major', 'minor', 'patch'].indexOf(a) - ['major', 'minor', 'patch'].indexOf(b),
)[0];
if (!changeType) {
console.log('No labels found that trigger a release, skipping changeset generation');
// TODO: Default to patch update instead
return;
}
console.log(`Determined change type: ${changeType}`);
// Get package names using yarn workspaces
const packageNames = getPackageNames();
if (packageNames.length === 0) {
console.warn('No packages found in yarn workspaces');
return;
}
console.log(`Found packages: ${packageNames.join(', ')}`);
// Create changeset
if (!existsSync('.changeset')) mkdirSync('.changeset');
const changesetContent = `---
${generateChangesetYaml(packageNames, changeType)}
---
${prData.title}`;
const filename = `.changeset/pr-${prNumber}-${Date.now()}.md`;
writeFileSync(filename, changesetContent);
console.log(`Generated changeset: ${filename}`);
} catch (error) {
console.error('Error generating changeset:', error.message);
}
}
generateChangesetFromPR();

View File

@ -1,33 +0,0 @@
/**
* Shared GitHub API utilities
*/
/**
* Fetch PR data from GitHub API
* @param {string} prNumber - The PR number
* @returns {Promise<Object>} PR data from GitHub API
*/
export async function fetchPRData(prNumber) {
const repoUrl = process.env.CIRCLE_REPOSITORY_URL || 'https://github.com/jdalrymple/gitbeaker';
// Extract owner/repo from URL
const match = repoUrl.match(/github\.com[/:]([\w-]+)\/([\w-]+)/);
if (!match) {
throw new Error(`Could not parse repository URL: ${repoUrl}`);
}
const [, owner, repo] = match;
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}`, {
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'gitbeaker-api-client'
}
});
if (!response.ok) {
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}
return response.json();
}

View File

@ -4,13 +4,28 @@
*/
import { execSync } from 'child_process';
import { writeFileSync, existsSync, mkdirSync } from 'fs';
import { fetchPRData } from './github-api.mjs';
const isCanary = process.argv[2] === 'canary';
const releaseType = isCanary ? 'canary' : 'production';
const labelToChangeType = {
breaking: 'major',
'type:feature': 'minor',
'type:bug': 'minor',
'type:hot fix': 'minor',
'type:technical debt': 'patch',
'type:security': 'patch',
'type:dependencies': 'patch',
'type:types': 'patch',
'type:testing': null,
'type:documentation': null,
};
function logStep(message) {
const emoji = isCanary ? '🐤' : '🚀';
console.log(`${emoji} ${message}`);
logStep(`${emoji} ${message}`);
}
function execCommand(command, description) {
@ -25,6 +40,99 @@ function execCommand(command, description) {
}
}
function getPackageNames() {
try {
const output = execCommand('yarn workspaces list --json', { encoding: 'utf8' });
const workspaces = output
.trim()
.split('\n')
.map((line) => JSON.parse(line));
return workspaces.filter((ws) => ws.location !== '.' && ws.name).map((ws) => ws.name);
} catch (error) {
console.warn('Could not get workspace packages:', error.message);
return [];
}
}
function generateChangesetYaml(packageNames, changeType) {
if (packageNames.length === 0) return '';
return packageNames.map((name) => `"${name}": ${changeType}`).join('\n');
}
async function generateChangesetFromPR(prNumber, labels, prTitle) {
if (!prNumber) {
logStep('No PR number provided, skipping changeset generation');
return null;
}
logStep(`Generating changeset for PR #${prNumber} with labels: ${labels.join(', ')}`);
// Find change type
const changeType = labels
.map((label) => labelToChangeType[label])
.filter(Boolean)
.sort(
(a, b) => ['major', 'minor', 'patch'].indexOf(a) - ['major', 'minor', 'patch'].indexOf(b),
)[0];
if (!changeType) {
logStep('No labels found that trigger a release, skipping changeset generation');
return null;
}
logStep(`Determined change type: ${changeType}`);
// Get package names using yarn workspaces
const packageNames = getPackageNames();
if (packageNames.length === 0) {
console.warn('No packages found in yarn workspaces');
return null;
}
logStep(`Found packages: ${packageNames.join(', ')}`);
// Create changeset
if (!execCommand('.changeset')) mkdirSync('.changeset');
const changesetContent = `---
${generateChangesetYaml(packageNames, changeType)}
---
${prTitle}`;
const filename = `.changeset/pr-${prNumber}-${Date.now()}.md`;
writeFileSync(filename, changesetContent);
logStep(`Generated changeset: ${filename}`);
return filename;
}
async function fetchPRData(prNumber) {
const repoUrl = process.env.CIRCLE_REPOSITORY_URL || 'https://github.com/jdalrymple/gitbeaker';
// Extract owner/repo from URL
const match = repoUrl.match(/github\.com[/:]([\w-]+)\/([\w-]+)/);
if (!match) {
throw new Error(`Could not parse repository URL: ${repoUrl}`);
}
const [, owner, repo] = match;
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}`, {
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
Accept: 'application/vnd.github.v3+json',
'User-Agent': 'gitbeaker-api-client',
},
});
if (!response.ok) {
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}
return response.json();
}
async function release() {
logStep(`Starting ${releaseType} release`);
@ -37,18 +145,31 @@ async function release() {
return;
}
if (
!execCommand(
'node scripts/generate-changesets-from-labels.mjs',
'Generating changeset from PR labels',
)
) {
// Get PR data
const prData = await fetchPRData(prNumber);
const labels = prData.labels.map((label) => label.name);
if (isCanary && !labels.includes('release:canary')) {
logStep('No canary label present - skipping canary release');
return;
}
// Generate changesets (direct function call, no subprocess)
logStep('Generating changeset from PR labels');
try {
const changesetFile = await generateChangesetFromPR(prNumber, labels, prData.title);
if (!changesetFile) {
logStep(`No changeset generated - skipping ${releaseType} release`);
return;
}
} catch (error) {
console.error(`❌ Failed to generate changeset: ${error.message}`);
process.exit(1);
}
// Check if there are any changesets to process
try {
execSync('yarn changeset version', { stdio: 'pipe' });
execCommand('yarn changeset version', { stdio: 'pipe' });
} catch (error) {
// changeset status exits with non-zero when no changesets found
logStep(`No changesets found - skipping ${releaseType} release`);
@ -82,7 +203,7 @@ async function release() {
// Commit and push (production only)
if (!isCanary) {
const hasChanges = execSync('git status --porcelain', { encoding: 'utf8' }).trim();
const hasChanges = execCommand('git status --porcelain', { encoding: 'utf8' }).trim();
if (hasChanges) {
if (!execCommand('git add .', 'Staging changes')) process.exit(1);
if (