Skip to content

Commit 40d3078

Browse files
authored
feat(cpa): initialize git repo on project creation (#6342)
1 parent 662334a commit 40d3078

File tree

7 files changed

+71
-8
lines changed

7 files changed

+71
-8
lines changed

packages/create-payload-app/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"@types/esprima": "^4.0.6",
5656
"@types/fs-extra": "^9.0.12",
5757
"@types/jest": "^27.0.3",
58-
"@types/node": "20.12.5"
58+
"@types/node": "20.12.5",
59+
"temp-dir": "2.0.0"
5960
}
6061
}

packages/create-payload-app/src/lib/create-project.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,22 @@ import fse from 'fs-extra'
22
import path from 'path'
33
import type { CliArgs, DbType, ProjectTemplate } from '../types.js'
44
import { createProject } from './create-project.js'
5-
import { fileURLToPath } from 'node:url'
65
import { dbReplacements } from './packages.js'
76
import { getValidTemplates } from './templates.js'
87
import globby from 'globby'
98

10-
const filename = fileURLToPath(import.meta.url)
11-
const dirname = path.dirname(filename)
9+
import tempDirectory from 'temp-dir'
1210

13-
const projectDir = path.resolve(dirname, './tmp')
1411
describe('createProject', () => {
12+
let projectDir: string
1513
beforeAll(() => {
1614
console.log = jest.fn()
1715
})
1816

1917
beforeEach(() => {
20-
if (fse.existsSync(projectDir)) {
21-
fse.rmdirSync(projectDir, { recursive: true })
22-
}
18+
projectDir = `${tempDirectory}/${Math.random().toString(36).substring(7)}`
2319
})
20+
2421
afterEach(() => {
2522
if (fse.existsSync(projectDir)) {
2623
fse.rmSync(projectDir, { recursive: true })
@@ -100,6 +97,9 @@ describe('createProject', () => {
10097
const packageJsonPath = path.resolve(projectDir, 'package.json')
10198
const packageJson = fse.readJsonSync(packageJsonPath)
10299

100+
// Verify git was initialized
101+
expect(fse.existsSync(path.resolve(projectDir, '.git'))).toBe(true)
102+
103103
// Should only have one db adapter
104104
expect(
105105
Object.keys(packageJson.dependencies).filter((n) => n.startsWith('@payloadcms/db-')),

packages/create-payload-app/src/lib/create-project.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import path from 'path'
88

99
import type { CliArgs, DbDetails, PackageManager, ProjectTemplate } from '../types.js'
1010

11+
import { tryInitRepoAndCommit } from '../utils/git.js'
1112
import { debug, error, warning } from '../utils/log.js'
1213
import { configurePayloadConfig } from './configure-payload-config.js'
1314

@@ -108,6 +109,10 @@ export async function createProject(args: {
108109
} else {
109110
spinner.stop('Dependency installation skipped')
110111
}
112+
113+
if (!cliArgs['--no-git']) {
114+
tryInitRepoAndCommit({ cwd: projectDir })
115+
}
111116
}
112117

113118
export async function updatePackageJSON(args: {

packages/create-payload-app/src/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ export class Main {
5353
'--use-pnpm': Boolean,
5454
'--use-yarn': Boolean,
5555

56+
// Other
57+
'--no-git': Boolean,
58+
5659
// Flags
5760
'--beta': Boolean,
5861
'--debug': Boolean,

packages/create-payload-app/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface Args extends arg.Spec {
1212
'--local-template': StringConstructor
1313
'--name': StringConstructor
1414
'--no-deps': BooleanConstructor
15+
'--no-git': BooleanConstructor
1516
'--secret': StringConstructor
1617
'--template': StringConstructor
1718
'--template-branch': StringConstructor
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { ExecSyncOptions } from 'child_process'
2+
3+
import { execSync } from 'child_process'
4+
5+
import { warning } from './log.js'
6+
7+
export function tryInitRepoAndCommit(args: { cwd: string }): void {
8+
const execOpts: ExecSyncOptions = { cwd: args.cwd, stdio: 'ignore' }
9+
try {
10+
// Check if git is available
11+
execSync('git -v', execOpts)
12+
13+
// Do nothing if already in a git repo
14+
if (isGitRepo(execOpts)) {
15+
return
16+
}
17+
18+
// Initialize
19+
execSync('git init', execOpts)
20+
if (!ensureHasDefaultBranch(execOpts)) {
21+
execSync('git checkout -b main', execOpts)
22+
}
23+
24+
// Add and commit files
25+
execSync('git add -A', execOpts)
26+
execSync('git commit -m "feat: initial commit"', execOpts)
27+
} catch (_) {
28+
warning('Failed to initialize git repository.')
29+
}
30+
}
31+
32+
function isGitRepo(opts: ExecSyncOptions): boolean {
33+
try {
34+
execSync('git rev-parse --is-inside-work-tree', opts)
35+
return true
36+
} catch (_) {
37+
// Ignore errors
38+
}
39+
return false
40+
}
41+
42+
function ensureHasDefaultBranch(opts: ExecSyncOptions): boolean {
43+
try {
44+
execSync(`git config init.defaultBranch`, opts)
45+
return true
46+
} catch (_) {
47+
// Ignore errros
48+
}
49+
return false
50+
}

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)