使用AWS CDK Pipeline构建栈时遇.git/HEAD不存在错误
问题描述
使用aws-cdk-lib/pipelines通过AWS Code Pipeline构建CDK CloudFormation栈,本地执行cdk ls正常,也能成功部署流水线,但在CodeBuild阶段执行npx cdk synth时出现错误。
错误信息
[Container] 2022/12/30 09:18:36 Running command npx cdk synth Error: .git/HEAD does not exist at gitHeadPath (/codebuild/output/src224694107/src/backend/node_modules/git-branch/index.js:36:11) at branch (/codebuild/output/src224694107/src/backend/node_modules/git-branch/index.js:14:28) at /codebuild/output/src224694107/src/backend/src/context/getContext.ts:11:41 at new Promise (<anonymous>) at Object.exports.getContext (/codebuild/output/src224694107/src/backend/src/context/getContext.ts:9:12) at createStack (/codebuild/output/src224694107/src/backend/bin/template.ts:9:25) at Object.<anonymous> (/codebuild/output/src224694107/src/backend/bin/template.ts:18:1) at Module._compile (internal/modules/cjs/loader.js:1085:14) at Module.m._compile (/codebuild/output/src224694107/src/backend/node_modules/ts-node/src/index.ts:1618:23) at Module._extensions..js (internal/modules/cjs/loader.js:1114:10) (node:179) UnhandledPromiseRejectionWarning: undefined (Use `node --trace-warnings ...` to show where the warning was created) (node:179) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2) (node:179) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
相关代码
CDK流水线代码
this.codePipeline = new CodePipeline(this, `${environment}-pipeline-${appName}`, { pipelineName: `${environment}-pipeline-${appName}`, selfMutation: true, crossAccountKeys: false, role: this.codePipelineRole, synth: new ShellStep("Deployment", { input: CodePipelineSource.codeCommit(this.codeRepository, environment), installCommands: ["npm uninstall -g aws-cdk", "npm i -g npm@latest", "npm install -g aws-cdk"], commands: ["cd backend", "npm ci", "npm run build", "npx cdk synth"], primaryOutputDirectory: "backend/cdk.out", }), });
getContext函数
export const getContext = (app: App): Promise<CDKContext> => { return new Promise(async (resolve, reject) => { try { const currentBranch = await gitBranch(); const environment = app.node.tryGetContext("environments").find((e: any) => e.branchName === currentBranch); const globals = app.node.tryGetContext("globals"); return resolve({...globals, ...environment}); } catch (error) { console.error("error", error); return reject(); } }) }
Package.json依赖
"dependencies": { "@aws-cdk/aws-appsync-alpha": "^2.55.1-alpha.0", "aws-cdk-lib": "^2.58.0", "aws-sdk": "^2.1278.0", "constructs": "^10.1.204", "git-branch": "^2.0.1", "source-map-support": "^0.5.21" }
问题原因
本地环境是完整的Git仓库,包含.git目录,因此git-branch库可以正常读取.git/HEAD获取分支名。但AWS CodeBuild默认拉取代码时,不会包含完整的.git目录(仅获取代码文件),导致git-branch库找不到.git/HEAD文件,抛出错误。
解决方案
方案1:让CodeBuild拉取完整Git仓库
修改CodePipelineSource.codeCommit的配置,添加codeBuildCloneOutput: true参数,让CodeBuild获取完整的Git仓库(包含.git目录):
this.codePipeline = new CodePipeline(this, `${environment}-pipeline-${appName}`, { pipelineName: `${environment}-pipeline-${appName}`, selfMutation: true, crossAccountKeys: false, role: this.codePipelineRole, synth: new ShellStep("Deployment", { input: CodePipelineSource.codeCommit(this.codeRepository, environment, { codeBuildCloneOutput: true // 启用完整Git仓库克隆 }), installCommands: ["npm uninstall -g aws-cdk", "npm i -g npm@latest", "npm install -g aws-cdk"], commands: ["cd backend", "npm ci", "npm run build", "npx cdk synth"], primaryOutputDirectory: "backend/cdk.out", }), });
方案2:移除对git-branch库的依赖
既然流水线已经明确指定了分支(environment参数),可以直接将该分支名传递给getContext函数,无需通过Git仓库获取:
- 修改
getContext函数,改为接收分支参数:
export const getContext = (app: App, branch: string): CDKContext => { const environmentConfig = app.node.tryGetContext("environments").find((e: any) => e.branchName === branch); const globals = app.node.tryGetContext("globals"); return {...globals, ...environmentConfig}; }
- 在
bin/template.ts中直接传入流水线使用的分支名:
// 假设environment变量在当前作用域可访问 const context = getContext(app, environment); createStack(app, context);
此方案还可以移除package.json中的git-branch依赖,减少不必要的依赖项。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

