Relocate templatingTask into executeTemplate

Signed-off-by: Min Kim <minkimcello@gmail.com>
This commit is contained in:
Min Kim
2024-12-19 17:22:50 -05:00
parent 51d79d5666
commit 664e76da46
6 changed files with 126 additions and 153 deletions
-3
View File
@@ -87,9 +87,6 @@ export default async () => {
try {
await executePluginPackageTemplate(
{
private: options.private,
defaultVersion: options.baseVersion,
license: options.license,
isMonoRepo: await isMonoRepo(),
createTemporaryDirectory,
markAsModified() {
@@ -22,17 +22,18 @@ import {
mockPaths,
} from './testUtils';
import { CreateContext } from './types';
import { executePluginPackageTemplate } from './executeTemplate';
import {
executePluginPackageTemplate,
templatingTask,
} from './executeTemplate';
import { createMockDirectory } from '@backstage/backend-test-utils';
const mockDir = createMockDirectory();
mockPaths({
ownDir: mockDir.resolve('own'),
targetRoot: mockDir.resolve('root'),
});
describe('executePluginPackageTemplate', () => {
const mockDir = createMockDirectory();
mockPaths({
ownDir: mockDir.resolve('own'),
targetRoot: mockDir.resolve('root'),
});
afterEach(() => {
jest.resetAllMocks();
});
@@ -82,7 +83,7 @@ some-package@^1.1.0:
},
} as CreateContext,
{
templateName: 'test-template',
templateDir: 'test-template',
targetDir: mockDir.resolve('target'),
values: {
id: 'testing',
@@ -122,3 +123,47 @@ some-package@^1.1.0:
).resolves.toBe('Hello {{id}}!');
});
});
describe('templatingTask', () => {
const mockDir = createMockDirectory();
it('should template a directory with mix of regular files and templates', async () => {
// Testing template directory
const tmplDir = 'test-tmpl';
// Temporary dest dir to write the template to
const destDir = 'test-dest';
// Files content
const testFileContent = 'testing';
const testVersionFileContent =
"version: {{pluginVersion}} {{versionQuery 'mock-pkg'}}";
mockDir.setContent({
[tmplDir]: {
sub: {
'version.txt.hbs': testVersionFileContent,
},
'test.txt': testFileContent,
},
[destDir]: {},
});
await templatingTask(
mockDir.resolve(tmplDir),
mockDir.resolve(destDir),
{
pluginVersion: '0.0.0',
},
() => '^0.1.2',
true,
);
await expect(
fs.readFile(mockDir.resolve(destDir, 'test.txt'), 'utf8'),
).resolves.toBe(testFileContent);
await expect(
fs.readFile(mockDir.resolve(destDir, 'sub/version.txt'), 'utf8'),
).resolves.toBe('version: 0.0.0 ^0.1.2');
});
});
+72 -4
View File
@@ -16,9 +16,17 @@
import fs from 'fs-extra';
import chalk from 'chalk';
import { resolve as resolvePath, relative as relativePath } from 'path';
import handlebars from 'handlebars';
import recursive from 'recursive-readdir';
import {
basename,
dirname,
resolve as resolvePath,
relative as relativePath,
} from 'path';
import { paths } from '../paths';
import { Task, templatingTask } from '../tasks';
import { Task } from '../tasks';
import { Lockfile } from '../versioning';
import { createPackageVersionProvider } from '../version';
import { CreateContext } from './types';
@@ -31,7 +39,7 @@ export async function executePluginPackageTemplate(
values: Record<string, unknown>;
},
) {
const { targetDir, templateDir } = options;
const { targetDir, templateDir, values } = options;
let lockfile: Lockfile | undefined;
try {
@@ -60,7 +68,7 @@ export async function executePluginPackageTemplate(
await templatingTask(
templateDir,
tempDir,
options.values,
values,
createPackageVersionProvider(lockfile),
ctx.isMonoRepo,
);
@@ -83,3 +91,63 @@ export async function executePluginPackageTemplate(
ctx.markAsModified();
}
export async function templatingTask(
templateDir: string,
destinationDir: string,
context: any,
versionProvider: (name: string, versionHint?: string) => string,
isMonoRepo: boolean,
) {
const files = await recursive(templateDir).catch(error => {
throw new Error(`Failed to read template directory: ${error.message}`);
});
for (const file of files) {
const destinationFile = file.replace(templateDir, destinationDir);
await fs.ensureDir(dirname(destinationFile));
if (file.endsWith('.hbs')) {
await Task.forItem('templating', basename(file), async () => {
const destination = destinationFile.replace(/\.hbs$/, '');
const template = await fs.readFile(file);
const compiled = handlebars.compile(template.toString(), {
strict: true,
});
const contents = compiled(
{ name: basename(destination), ...context },
{
helpers: {
versionQuery(name: string, versionHint: string | unknown) {
return versionProvider(
name,
typeof versionHint === 'string' ? versionHint : undefined,
);
},
},
},
);
await fs.writeFile(destination, contents).catch(error => {
throw new Error(
`Failed to create file: ${destination}: ${error.message}`,
);
});
});
} else {
if (isMonoRepo && file.match('tsconfig.json')) {
continue;
}
await Task.forItem('copying', basename(file), async () => {
await fs.copyFile(file, destinationFile).catch(error => {
const destination = destinationFile;
throw new Error(
`Failed to copy file to ${destination} : ${error.message}`,
);
});
});
}
}
}
-10
View File
@@ -17,18 +17,8 @@
import { Answers, DistinctQuestion } from 'inquirer';
export interface CreateContext {
/** The package scope to use for new packages */
scope?: string;
/** The NPM registry to use for new packages */
npmRegistry?: string;
/** Whether new packages should be marked as private */
private: boolean;
/** Whether we are creating something in a monorepo or not */
isMonoRepo: boolean;
/** The default version to use for new packages */
defaultVersion: string;
/** License to use for new packages */
license: string;
/** Creates a temporary directory. This will always be deleted after creation is done. */
createTemporaryDirectory(name: string): Promise<string>;
-63
View File
@@ -1,63 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fs from 'fs-extra';
import { templatingTask } from './tasks';
import { createMockDirectory } from '@backstage/backend-test-utils';
describe('templatingTask', () => {
const mockDir = createMockDirectory();
it('should template a directory with mix of regular files and templates', async () => {
// Testing template directory
const tmplDir = 'test-tmpl';
// Temporary dest dir to write the template to
const destDir = 'test-dest';
// Files content
const testFileContent = 'testing';
const testVersionFileContent =
"version: {{pluginVersion}} {{versionQuery 'mock-pkg'}}";
mockDir.setContent({
[tmplDir]: {
sub: {
'version.txt.hbs': testVersionFileContent,
},
'test.txt': testFileContent,
},
[destDir]: {},
});
await templatingTask(
mockDir.resolve(tmplDir),
mockDir.resolve(destDir),
{
pluginVersion: '0.0.0',
},
() => '^0.1.2',
true,
);
await expect(
fs.readFile(mockDir.resolve(destDir, 'test.txt'), 'utf8'),
).resolves.toBe(testFileContent);
await expect(
fs.readFile(mockDir.resolve(destDir, 'sub/version.txt'), 'utf8'),
).resolves.toBe('version: 0.0.0 ^0.1.2');
});
});
-64
View File
@@ -15,12 +15,8 @@
*/
import chalk from 'chalk';
import fs from 'fs-extra';
import handlebars from 'handlebars';
import ora from 'ora';
import { promisify } from 'util';
import { basename, dirname } from 'path';
import recursive from 'recursive-readdir';
import { exec as execCb } from 'child_process';
import { assertError } from '@backstage/errors';
@@ -95,63 +91,3 @@ export class Task {
}
}
}
export async function templatingTask(
templateDir: string,
destinationDir: string,
context: any,
versionProvider: (name: string, versionHint?: string) => string,
isMonoRepo: boolean,
) {
const files = await recursive(templateDir).catch(error => {
throw new Error(`Failed to read template directory: ${error.message}`);
});
for (const file of files) {
const destinationFile = file.replace(templateDir, destinationDir);
await fs.ensureDir(dirname(destinationFile));
if (file.endsWith('.hbs')) {
await Task.forItem('templating', basename(file), async () => {
const destination = destinationFile.replace(/\.hbs$/, '');
const template = await fs.readFile(file);
const compiled = handlebars.compile(template.toString(), {
strict: true,
});
const contents = compiled(
{ name: basename(destination), ...context },
{
helpers: {
versionQuery(name: string, versionHint: string | unknown) {
return versionProvider(
name,
typeof versionHint === 'string' ? versionHint : undefined,
);
},
},
},
);
await fs.writeFile(destination, contents).catch(error => {
throw new Error(
`Failed to create file: ${destination}: ${error.message}`,
);
});
});
} else {
if (isMonoRepo && file.match('tsconfig.json')) {
continue;
}
await Task.forItem('copying', basename(file), async () => {
await fs.copyFile(file, destinationFile).catch(error => {
const destination = destinationFile;
throw new Error(
`Failed to copy file to ${destination} : ${error.message}`,
);
});
});
}
}
}