Files
towercontrol/scripts/auto-version.ts
2025-11-21 11:12:11 +01:00

186 lines
5.1 KiB
TypeScript

import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
interface Version {
major: number;
minor: number;
patch: number;
}
function parseVersion(version: string): Version {
const [major, minor, patch] = version.split('.').map(Number);
return { major, minor, patch };
}
function formatVersion(v: Version): string {
return `${v.major}.${v.minor}.${v.patch}`;
}
function getLastVersionTag(): string | null {
try {
const tag = execSync('git describe --tags --abbrev=0', {
encoding: 'utf-8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
return tag;
} catch {
return null;
}
}
function getCommitsSinceTag(tag: string | null): string[] {
try {
const range = tag ? `${tag}..HEAD` : 'HEAD';
const commits = execSync(`git log ${range} --pretty=format:"%s"`, {
encoding: 'utf-8',
stdio: ['ignore', 'pipe', 'ignore'],
})
.trim()
.split('\n')
.filter(Boolean);
return commits;
} catch {
return [];
}
}
function determineVersionBump(commits: string[]): 'major' | 'minor' | 'patch' {
let hasBreaking = false;
let hasFeature = false;
let hasPatch = false;
for (const commit of commits) {
const lowerCommit = commit.toLowerCase();
// Breaking changes (major bump)
if (
lowerCommit.includes('breaking change') ||
lowerCommit.includes('breaking:') ||
lowerCommit.match(/^[a-z]+!:/) || // feat!:, refactor!:, etc.
lowerCommit.includes('!')
) {
hasBreaking = true;
}
// Features (minor bump)
if (lowerCommit.startsWith('feat:')) {
hasFeature = true;
}
// Patch bumps: fixes, performance improvements, security fixes, refactorings
if (
lowerCommit.startsWith('fix:') ||
lowerCommit.startsWith('perf:') ||
lowerCommit.startsWith('security:') ||
lowerCommit.startsWith('patch:') ||
lowerCommit.startsWith('refactor:')
) {
hasPatch = true;
}
}
if (hasBreaking) return 'major';
if (hasFeature) return 'minor';
if (hasPatch) return 'patch';
// Par défaut, patch si on a des commits mais aucun type spécifique
return commits.length > 0 ? 'patch' : 'patch';
}
function incrementVersion(
current: Version,
type: 'major' | 'minor' | 'patch'
): Version {
switch (type) {
case 'major':
return { major: current.major + 1, minor: 0, patch: 0 };
case 'minor':
return { major: current.major, minor: current.minor + 1, patch: 0 };
case 'patch':
return {
major: current.major,
minor: current.minor,
patch: current.patch + 1,
};
}
}
function main() {
const silent = process.argv.includes('--silent');
const hookMode = process.argv.includes('--hook');
try {
const packagePath = join(process.cwd(), 'package.json');
const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
const currentVersion = parseVersion(packageJson.version);
const lastTag = getLastVersionTag();
const commits = getCommitsSinceTag(lastTag);
if (commits.length === 0) {
if (!silent) {
console.log('✅ Aucun nouveau commit depuis la dernière version');
console.log(`Version actuelle: ${packageJson.version}`);
}
return;
}
const bumpType = determineVersionBump(commits);
const newVersion = incrementVersion(currentVersion, bumpType);
const newVersionString = formatVersion(newVersion);
// Si la version n'a pas changé, ne rien faire
if (newVersionString === packageJson.version) {
return;
}
if (!silent) {
console.log(`📊 Analyse des commits depuis ${lastTag || 'le début'}:`);
console.log(` - ${commits.length} commit(s) trouvé(s)`);
console.log(` - Type de bump détecté: ${bumpType}`);
console.log(` - Version actuelle: ${packageJson.version}`);
console.log(` - Nouvelle version: ${newVersionString}`);
// Afficher les commits pertinents
console.log('\n📝 Commits analysés:');
commits.slice(0, 10).forEach((commit) => {
console.log(` - ${commit}`);
});
if (commits.length > 10) {
console.log(` ... et ${commits.length - 10} autre(s) commit(s)`);
}
}
// Mettre à jour package.json
packageJson.version = newVersionString;
writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
if (!silent) {
console.log(`\n✅ Version mise à jour dans package.json`);
console.log(
`\n💡 Prochaines étapes:` +
`\n 1. git add package.json` +
`\n 2. git commit -m "chore: bump version to ${newVersionString}"` +
`\n 3. git tag v${newVersionString}`
);
} else if (hookMode) {
// En mode hook, ajouter package.json au staging
try {
execSync('git add package.json', { stdio: 'ignore' });
} catch {
// Ignorer les erreurs en mode hook
}
}
} catch (error) {
if (!silent) {
console.error('❌ Erreur lors de la mise à jour de version:', error);
}
if (!hookMode) {
process.exit(1);
}
}
}
main();