diff --git a/src/libs/git.ts b/src/libs/git.ts index 885292d..47aedcf 100644 --- a/src/libs/git.ts +++ b/src/libs/git.ts @@ -15,5 +15,5 @@ export function initGitRepository(repoPath: string) { } export function stageFiles(repoPath: string, files: string[]) { - return exec('git', ['add', ...files], { cwd: repoPath, silent: true }) + return exec('git', ['add', ...files.sort()], { cwd: repoPath, silent: true }) } diff --git a/src/libs/pm.ts b/src/libs/pm.ts index 1b39afd..6d653d8 100644 --- a/src/libs/pm.ts +++ b/src/libs/pm.ts @@ -1,3 +1,5 @@ +import os from 'node:os' + import { PACKAGE_MANAGER, PACKAGE_MANAGER_EXECUTE } from '../config' import { exec, type ExecOptions } from './exec' @@ -26,8 +28,15 @@ export function executePackageManagerCommand(appPath: string, args: string[], si return runPackageManager(appPath, args, { execute: true, silent: !!silent }) } +export function getPackageManagerBinary(execute?: RunOptions['execute']) { + const executable = execute ? PACKAGE_MANAGER_EXECUTE : PACKAGE_MANAGER + const extension = os.platform() === 'win32' ? '.cmd' : '' + + return `${executable}${extension}` +} + function runPackageManager(appPath: string, args: string[], options: RunOptions = {}) { - return exec(options.execute ? PACKAGE_MANAGER_EXECUTE : PACKAGE_MANAGER, args, { ...options, cwd: appPath }) + return exec(getPackageManagerBinary(options.execute), args, { ...options, cwd: appPath }) } interface RunOptions extends ExecOptions { diff --git a/src/libs/template.ts b/src/libs/template.ts index ea14a1d..1eb69e6 100644 --- a/src/libs/template.ts +++ b/src/libs/template.ts @@ -37,13 +37,13 @@ let templateVariables: TemplateVariables | undefined export async function getTemplatePaths(ignoreSpecialTemplates = true) { const templatePath = getTemplatesPath() - const allTemplatePaths = await glob(path.join(templatePath, '**/*'), { absolute: true, dot: true, filesOnly: true }) + const allTemplatePaths = await glob('**/*', { cwd: templatePath, absolute: true, dot: true, filesOnly: true }) const templates: Template[] = [] for (const absolutePath of allTemplatePaths) { const template = { - destination: absolutePath.replace(`${templatePath}/`, ''), + destination: absolutePath.replace(`${templatePath}${path.sep}`, ''), source: absolutePath, } @@ -112,7 +112,7 @@ export function compileTemplate(content: string) { function getTemplatesPath() { const dirName = path.dirname(fileURLToPath(import.meta.url)) - return path.join(dirName, dirName.endsWith('src/libs') ? '../..' : '..', 'templates') + return path.join(dirName, dirName.endsWith(path.join('src', 'libs')) ? '../..' : '..', 'templates') } function isValidTemplateVariable(variable: string): variable is keyof TemplateVariables { diff --git a/tests/app.test.ts b/tests/app.test.ts index 9405d15..9fe2edf 100644 --- a/tests/app.test.ts +++ b/tests/app.test.ts @@ -1,4 +1,5 @@ import { spawn } from 'node:child_process' +import path from 'node:path' import type { PackageJson } from 'type-fest' import * as undici from 'undici' @@ -11,7 +12,6 @@ import { NPM_REGISTRY_URL, NPM_RELEASE_STEP, PACKAGE_MANAGER, - PACKAGE_MANAGER_EXECUTE, PKG_INVALID_DEPENDENCIES, PKG_KEYS_ORDER, USER_MAIL, @@ -21,6 +21,7 @@ import { import { UNSUPPORTED_ESLINT_CONFIG_FILENAMES } from '../src/libs/eslint' import { getPkgTsConfig } from '../src/libs/jsdelivr' import { parsePkg } from '../src/libs/pkg' +import { getPackageManagerBinary } from '../src/libs/pm' import type { TemplateVariables } from '../src/libs/template' import { parseTsConfig, PRESERVED_TS_COMPILER_OPTIONS } from '../src/libs/typescript' @@ -302,21 +303,28 @@ describe.each(testScenarios)('$description', ({ appName, options, setup }) => { }) test('should install dependencies', () => { - expectSpawnToHaveBeenNthCalledWith(PACKAGE_MANAGER, ['install']) + expectSpawnToHaveBeenNthCalledWith(getPackageManagerBinary(), ['install']) }) test('should configure Git hooks', () => { - expectSpawnToHaveBeenNthCalledWith(PACKAGE_MANAGER_EXECUTE, ['husky', 'init']) + expectSpawnToHaveBeenNthCalledWith(getPackageManagerBinary(true), ['husky', 'init']) }) test('should run ESLint when updating an existing app', () => { if (!options.isNew) { - expectSpawnToHaveBeenNthCalledWith(PACKAGE_MANAGER, ['exec', 'eslint', '.', '--fix']) + expectSpawnToHaveBeenNthCalledWith(getPackageManagerBinary(), ['exec', 'eslint', '.', '--fix']) } }) test('should prettify the app', () => { - expectSpawnToHaveBeenNthCalledWith(PACKAGE_MANAGER, ['exec', 'prettier', '-w', '--log-level', 'silent', '.']) + expectSpawnToHaveBeenNthCalledWith(getPackageManagerBinary(), [ + 'exec', + 'prettier', + '-w', + '--log-level', + 'silent', + '.', + ]) }) test('should check if the repository exists on GitHub', () => { @@ -357,22 +365,25 @@ describe.each(testScenarios)('$description', ({ appName, options, setup }) => { }) test('should stage new or updated files', () => { - expectSpawnToHaveBeenNthCalledWith('git', [ - 'add', - '.github/workflows/integration.yml', - '.github/workflows/release.yml', - '.gitignore', - '.husky/pre-commit', - '.prettierignore', - '.vscode/extensions.json', - '.vscode/settings.json', - 'LICENSE', - 'README.md', - 'eslint.config.mjs', - 'package.json', - 'tsconfig.json', - 'pnpm-lock.yaml', - ]) + expectSpawnToHaveBeenNthCalledWith( + 'git', + [ + 'add', + '.github/workflows/integration.yml', + '.github/workflows/release.yml', + '.gitignore', + '.husky/pre-commit', + '.prettierignore', + '.vscode/extensions.json', + '.vscode/settings.json', + 'LICENSE', + 'README.md', + 'eslint.config.mjs', + 'package.json', + 'pnpm-lock.yaml', + 'tsconfig.json', + ].map((filePath) => path.normalize(filePath)), + ) }) test('should cache jsdelivr results', () => { diff --git a/tests/utils.ts b/tests/utils.ts index 39a236d..f594fef 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -75,7 +75,7 @@ export function setupTest(testName: string) { } export async function getTestDirPaths(testDir: string) { - const testDirPaths = await glob(path.join(testDir, '**/*'), { absolute: true, dot: true, filesOnly: true }) + const testDirPaths = await glob('**/*', { cwd: testDir, absolute: true, dot: true, filesOnly: true }) return testDirPaths.map((testDirPath) => testDirPath.replace(testDir, '')) }