156 lines
5.6 KiB
TypeScript
156 lines
5.6 KiB
TypeScript
import { BaseFormatter } from '../classes.baseformatter.js';
|
|
import type { IPlannedChange } from '../interfaces.format.js';
|
|
import * as plugins from '../mod.plugins.js';
|
|
import * as paths from '../../paths.js';
|
|
import { logger, logVerbose } from '../../gitzone.logging.js';
|
|
|
|
export class TemplatesFormatter extends BaseFormatter {
|
|
get name(): string {
|
|
return 'templates';
|
|
}
|
|
|
|
async analyze(): Promise<IPlannedChange[]> {
|
|
const changes: IPlannedChange[] = [];
|
|
const project = this.project;
|
|
const projectType = project.gitzoneConfig?.data?.projectType;
|
|
|
|
// VSCode template - for all projects
|
|
const vscodeChanges = await this.analyzeTemplate('vscode', [
|
|
{ templatePath: '.vscode/settings.json', destPath: '.vscode/settings.json' },
|
|
{ templatePath: '.vscode/launch.json', destPath: '.vscode/launch.json' },
|
|
]);
|
|
changes.push(...vscodeChanges);
|
|
|
|
// CI and other templates based on projectType
|
|
switch (projectType) {
|
|
case 'npm':
|
|
case 'wcc':
|
|
const accessLevel = project.gitzoneConfig?.data?.npmciOptions?.npmAccessLevel;
|
|
const ciTemplate = accessLevel === 'public' ? 'ci_default' : 'ci_default_private';
|
|
const ciChanges = await this.analyzeTemplate(ciTemplate, [
|
|
{ templatePath: '.gitea/workflows/default_nottags.yaml', destPath: '.gitea/workflows/default_nottags.yaml' },
|
|
{ templatePath: '.gitea/workflows/default_tags.yaml', destPath: '.gitea/workflows/default_tags.yaml' },
|
|
]);
|
|
changes.push(...ciChanges);
|
|
break;
|
|
|
|
case 'service':
|
|
case 'website':
|
|
const dockerCiChanges = await this.analyzeTemplate('ci_docker', [
|
|
{ templatePath: '.gitea/workflows/docker_nottags.yaml', destPath: '.gitea/workflows/docker_nottags.yaml' },
|
|
{ templatePath: '.gitea/workflows/docker_tags.yaml', destPath: '.gitea/workflows/docker_tags.yaml' },
|
|
]);
|
|
changes.push(...dockerCiChanges);
|
|
|
|
const dockerfileChanges = await this.analyzeTemplate('dockerfile_service', [
|
|
{ templatePath: 'Dockerfile', destPath: 'Dockerfile' },
|
|
{ templatePath: 'dockerignore', destPath: '.dockerignore' },
|
|
]);
|
|
changes.push(...dockerfileChanges);
|
|
|
|
const cliChanges = await this.analyzeTemplate('cli', [
|
|
{ templatePath: 'cli.js', destPath: 'cli.js' },
|
|
{ templatePath: 'cli.ts.js', destPath: 'cli.ts.js' },
|
|
]);
|
|
changes.push(...cliChanges);
|
|
break;
|
|
}
|
|
|
|
// Update templates based on projectType
|
|
if (projectType === 'website') {
|
|
const websiteChanges = await this.analyzeTemplate('website_update', [
|
|
{ templatePath: 'html/index.html', destPath: 'html/index.html' },
|
|
]);
|
|
changes.push(...websiteChanges);
|
|
} else if (projectType === 'service') {
|
|
const serviceChanges = await this.analyzeTemplate('service_update', []);
|
|
changes.push(...serviceChanges);
|
|
} else if (projectType === 'wcc') {
|
|
const wccChanges = await this.analyzeTemplate('wcc_update', [
|
|
{ templatePath: 'html/index.html', destPath: 'html/index.html' },
|
|
{ templatePath: 'html/index.ts', destPath: 'html/index.ts' },
|
|
]);
|
|
changes.push(...wccChanges);
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
private async analyzeTemplate(
|
|
templateName: string,
|
|
files: Array<{ templatePath: string; destPath: string }>,
|
|
): Promise<IPlannedChange[]> {
|
|
const changes: IPlannedChange[] = [];
|
|
const templateDir = plugins.path.join(paths.templatesDir, templateName);
|
|
|
|
// Check if template exists
|
|
const templateExists = await plugins.smartfs.directory(templateDir).exists();
|
|
if (!templateExists) {
|
|
logVerbose(`Template ${templateName} not found`);
|
|
return changes;
|
|
}
|
|
|
|
for (const file of files) {
|
|
const templateFilePath = plugins.path.join(templateDir, file.templatePath);
|
|
const destFilePath = file.destPath;
|
|
|
|
// Check if template file exists
|
|
const fileExists = await plugins.smartfs.file(templateFilePath).exists();
|
|
if (!fileExists) {
|
|
logVerbose(`Template file ${templateFilePath} not found`);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
// Read template content
|
|
const templateContent = (await plugins.smartfs
|
|
.file(templateFilePath)
|
|
.encoding('utf8')
|
|
.read()) as string;
|
|
|
|
// Check if destination file exists
|
|
const destExists = await plugins.smartfs.file(destFilePath).exists();
|
|
let currentContent = '';
|
|
if (destExists) {
|
|
currentContent = (await plugins.smartfs
|
|
.file(destFilePath)
|
|
.encoding('utf8')
|
|
.read()) as string;
|
|
}
|
|
|
|
// Only add change if content differs
|
|
if (templateContent !== currentContent) {
|
|
changes.push({
|
|
type: destExists ? 'modify' : 'create',
|
|
path: destFilePath,
|
|
module: this.name,
|
|
description: `Apply template ${templateName}/${file.templatePath}`,
|
|
content: templateContent,
|
|
});
|
|
}
|
|
} catch (error) {
|
|
logVerbose(`Failed to read template ${templateFilePath}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
async applyChange(change: IPlannedChange): Promise<void> {
|
|
if (!change.content) return;
|
|
|
|
// Ensure destination directory exists
|
|
const destDir = plugins.path.dirname(change.path);
|
|
if (destDir && destDir !== '.') {
|
|
await plugins.smartfs.directory(destDir).recursive().create();
|
|
}
|
|
|
|
if (change.type === 'create') {
|
|
await this.createFile(change.path, change.content);
|
|
} else {
|
|
await this.modifyFile(change.path, change.content);
|
|
}
|
|
logger.log('info', `Applied template to ${change.path}`);
|
|
}
|
|
}
|