fix: Include .gitignore in node-cli generated projects (#30068)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garrit Franke 2026-05-12 18:48:20 +02:00 committed by GitHub
parent 93fc4f3f79
commit 0626ed2d6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 0 deletions

View File

@ -3,6 +3,7 @@ import handlebars from 'handlebars';
import * as fs from 'node:fs/promises';
import {
copyDefaultTemplateFilesToDestination,
copyTemplateFilesToDestination,
templateStaticFiles,
createTemplate,
@ -53,6 +54,29 @@ describe('Templates > core', () => {
});
});
describe('copyDefaultTemplateFilesToDestination', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('copies the shared default template and restores renamed dotfiles', async () => {
mockCopyFolder.mockResolvedValue();
mockFs.rename.mockResolvedValue();
await copyDefaultTemplateFilesToDestination(baseData);
expect(mockCopyFolder).toHaveBeenCalledWith(
expect.objectContaining({
destination: '/dest',
ignore: ['dist', 'node_modules'],
}),
);
// npm strips `.gitignore` from published packages, so it's shipped as `gitignore`
// and renamed back at scaffold time.
expect(mockFs.rename).toHaveBeenCalledWith('/dest/gitignore', '/dest/.gitignore');
});
});
describe('templateStaticFiles', () => {
beforeEach(() => {
vi.clearAllMocks();
@ -96,6 +120,7 @@ describe('Templates > core', () => {
mockFs.readFile.mockResolvedValue('');
mockHandlebars.compile.mockReturnValue(() => '');
mockFs.writeFile.mockResolvedValue();
mockFs.rename.mockResolvedValue();
const wrapped = createTemplate(template);
await wrapped.run(baseData);

View File

@ -41,12 +41,25 @@ export async function copyTemplateFilesToDestination<Config extends object>(
});
}
// npm strips certain dotfiles (e.g. `.gitignore`) from published packages, so the
// template ships them under alternative names and we restore the originals after
// copying to the destination. Add more entries here as needed.
const RENAMED_DEFAULT_TEMPLATE_FILES: Record<string, string> = {
gitignore: '.gitignore',
};
export async function copyDefaultTemplateFilesToDestination(data: TemplateData) {
await copyFolder({
source: path.resolve(__dirname, 'templates/shared/default'),
destination: data.destinationPath,
ignore: ['dist', 'node_modules'],
});
await Promise.all(
Object.entries(RENAMED_DEFAULT_TEMPLATE_FILES).map(
async ([from, to]) =>
await fs.rename(path.join(data.destinationPath, from), path.join(data.destinationPath, to)),
),
);
}
export async function templateStaticFiles(data: TemplateData) {