fix(mod_format): render format templates through smartscaf before comparing generated files

This commit is contained in:
2026-03-24 16:56:34 +00:00
parent b55e75d169
commit 142adfd396
6 changed files with 72 additions and 42 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## 2026-03-24 - 2.13.12 - fix(mod_format)
render format templates through smartscaf before comparing generated files
- adds smartscaf-based in-memory template rendering so supplied variables are applied before detecting changes
- supports release.accessLevel as a fallback when selecting public vs private CI templates
- matches rendered output by template or destination path to handle renamed files from template frontmatter
## 2026-03-24 - 2.13.10 - fix(config) ## 2026-03-24 - 2.13.10 - fix(config)
migrate configuration handling from npmextra to smartconfig migrate configuration handling from npmextra to smartconfig

View File

@@ -86,7 +86,7 @@
"@push.rocks/smartopen": "^2.0.0", "@push.rocks/smartopen": "^2.0.0",
"@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartscaf": "^4.0.19", "@push.rocks/smartscaf": "^4.0.21",
"@push.rocks/smartshell": "^3.3.7", "@push.rocks/smartshell": "^3.3.7",
"@push.rocks/smartunique": "^3.0.9", "@push.rocks/smartunique": "^3.0.9",
"@push.rocks/smartupdate": "^2.0.6", "@push.rocks/smartupdate": "^2.0.6",

10
pnpm-lock.yaml generated
View File

@@ -78,8 +78,8 @@ importers:
specifier: ^4.2.3 specifier: ^4.2.3
version: 4.2.3 version: 4.2.3
'@push.rocks/smartscaf': '@push.rocks/smartscaf':
specifier: ^4.0.19 specifier: ^4.0.21
version: 4.0.19 version: 4.0.21
'@push.rocks/smartshell': '@push.rocks/smartshell':
specifier: ^3.3.7 specifier: ^3.3.7
version: 3.3.7 version: 3.3.7
@@ -1216,8 +1216,8 @@ packages:
'@push.rocks/smarts3@5.3.0': '@push.rocks/smarts3@5.3.0':
resolution: {integrity: sha512-6bo55ovCDEylbTxwPFZYDrZrz2babQEUmxHIexmVcP2j+6LYRHDbGYnWoyKdtqniqDFZ04pFkOoZ85hUzU5xCw==} resolution: {integrity: sha512-6bo55ovCDEylbTxwPFZYDrZrz2babQEUmxHIexmVcP2j+6LYRHDbGYnWoyKdtqniqDFZ04pFkOoZ85hUzU5xCw==}
'@push.rocks/smartscaf@4.0.19': '@push.rocks/smartscaf@4.0.21':
resolution: {integrity: sha512-J9z2rWtFhT55kDZfWGpghnwy4aybmJoatzq5icfbZMXohS2KALuj1N17iXZ9L+43F1AwpUeZ/KnokNsh7yHZ5w==} resolution: {integrity: sha512-vt+O/dp/uSTdfK2CtkgMSJenYwfZLMTi9IM9uHfkKd8DaI4UvqiFCO6/smkv08zWQlLBVlUD2UWVd7RM9h1BJg==}
'@push.rocks/smartserve@2.0.1': '@push.rocks/smartserve@2.0.1':
resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==} resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==}
@@ -6224,7 +6224,7 @@ snapshots:
'@push.rocks/smartrust': 1.3.1 '@push.rocks/smartrust': 1.3.1
'@tsclass/tsclass': 9.3.0 '@tsclass/tsclass': 9.3.0
'@push.rocks/smartscaf@4.0.19': '@push.rocks/smartscaf@4.0.21':
dependencies: dependencies:
'@push.rocks/lik': 6.3.1 '@push.rocks/lik': 6.3.1
'@push.rocks/smartfile': 11.2.7 '@push.rocks/smartfile': 11.2.7

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/cli', name: '@git.zone/cli',
version: '2.13.10', version: '2.13.12',
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.' description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
} }

View File

@@ -9,6 +9,32 @@ export class TemplatesFormatter extends BaseFormatter {
return 'templates'; return 'templates';
} }
/**
* Render a template directory through smartscaf and return a map of path → content.
*/
private async renderTemplate(templateName: string): Promise<Map<string, string>> {
const templateDir = plugins.path.join(paths.templatesDir, templateName);
const scafTemplate = new plugins.smartscaf.ScafTemplate(templateDir);
await scafTemplate.readTemplateFromDir();
const gitzoneData = this.project.gitzoneConfig?.data;
if (gitzoneData) {
await scafTemplate.supplyVariables({
module: gitzoneData.module,
projectType: gitzoneData.projectType,
});
}
const renderedFiles = await scafTemplate.renderToMemory();
const fileMap = new Map<string, string>();
for (const file of renderedFiles) {
fileMap.set(file.path, file.contents.toString());
}
return fileMap;
}
async analyze(): Promise<IPlannedChange[]> { async analyze(): Promise<IPlannedChange[]> {
const changes: IPlannedChange[] = []; const changes: IPlannedChange[] = [];
const project = this.project; const project = this.project;
@@ -25,7 +51,8 @@ export class TemplatesFormatter extends BaseFormatter {
switch (projectType) { switch (projectType) {
case 'npm': case 'npm':
case 'wcc': case 'wcc':
const accessLevel = project.gitzoneConfig?.data?.npmciOptions?.npmAccessLevel; const accessLevel = (project.gitzoneConfig?.data as any)?.release?.accessLevel
|| project.gitzoneConfig?.data?.npmciOptions?.npmAccessLevel;
const ciTemplate = accessLevel === 'public' ? 'ci_default' : 'ci_default_private'; const ciTemplate = accessLevel === 'public' ? 'ci_default' : 'ci_default_private';
const ciChanges = await this.analyzeTemplate(ciTemplate, [ const ciChanges = await this.analyzeTemplate(ciTemplate, [
{ templatePath: '.gitea/workflows/default_nottags.yaml', destPath: '.gitea/workflows/default_nottags.yaml' }, { templatePath: '.gitea/workflows/default_nottags.yaml', destPath: '.gitea/workflows/default_nottags.yaml' },
@@ -80,54 +107,48 @@ export class TemplatesFormatter extends BaseFormatter {
const changes: IPlannedChange[] = []; const changes: IPlannedChange[] = [];
const templateDir = plugins.path.join(paths.templatesDir, templateName); const templateDir = plugins.path.join(paths.templatesDir, templateName);
// Check if template exists
const templateExists = await plugins.smartfs.directory(templateDir).exists(); const templateExists = await plugins.smartfs.directory(templateDir).exists();
if (!templateExists) { if (!templateExists) {
logVerbose(`Template ${templateName} not found`); logVerbose(`Template ${templateName} not found`);
return changes; return changes;
} }
for (const file of files) { let renderedFiles: Map<string, string>;
const templateFilePath = plugins.path.join(templateDir, file.templatePath); try {
const destFilePath = file.destPath; renderedFiles = await this.renderTemplate(templateName);
} catch (error) {
logVerbose(`Failed to render template ${templateName}: ${error.message}`);
return changes;
}
// Check if template file exists for (const file of files) {
const fileExists = await plugins.smartfs.file(templateFilePath).exists(); // Look up by templatePath first, then destPath (frontmatter may rename files)
if (!fileExists) { const processedContent = renderedFiles.get(file.templatePath)
logVerbose(`Template file ${templateFilePath} not found`); || renderedFiles.get(file.destPath);
if (!processedContent) {
logVerbose(`Template file ${file.templatePath} not found in rendered output`);
continue; continue;
} }
try { const destExists = await plugins.smartfs.file(file.destPath).exists();
// 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 = ''; let currentContent = '';
if (destExists) { if (destExists) {
currentContent = (await plugins.smartfs currentContent = (await plugins.smartfs
.file(destFilePath) .file(file.destPath)
.encoding('utf8') .encoding('utf8')
.read()) as string; .read()) as string;
} }
// Only add change if content differs if (processedContent !== currentContent) {
if (templateContent !== currentContent) {
changes.push({ changes.push({
type: destExists ? 'modify' : 'create', type: destExists ? 'modify' : 'create',
path: destFilePath, path: file.destPath,
module: this.name, module: this.name,
description: `Apply template ${templateName}/${file.templatePath}`, description: `Apply template ${templateName}/${file.templatePath}`,
content: templateContent, content: processedContent,
}); });
} }
} catch (error) {
logVerbose(`Failed to read template ${templateFilePath}: ${error.message}`);
}
} }
return changes; return changes;

View File

@@ -8,6 +8,7 @@ import * as smartobject from '@push.rocks/smartobject';
import * as smartnpm from '@push.rocks/smartnpm'; import * as smartnpm from '@push.rocks/smartnpm';
import * as smartconfig from '@push.rocks/smartconfig'; import * as smartconfig from '@push.rocks/smartconfig';
import * as smartdiff from '@push.rocks/smartdiff'; import * as smartdiff from '@push.rocks/smartdiff';
import * as smartscaf from '@push.rocks/smartscaf';
export { export {
path, path,
@@ -18,4 +19,5 @@ export {
smartnpm, smartnpm,
smartconfig, smartconfig,
smartdiff, smartdiff,
smartscaf,
}; };