You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AWS CDK实现CodePipeline QA阶段每日定时触发的方案问询

解决方案:定时触发CodePipeline QA阶段

需求回顾

  • 代码合并至master分支时,自动触发CodePipeline的DEV阶段,完成后暂停流程,不自动进入QA阶段。
  • 每日印度标准时间(IST)12点,自动触发QA阶段继续执行。

关键修改点

  1. Pipeline阶段结构调整:在DEV阶段后添加手动审批阶段Pre_QA_Approval,确保DEV完成后流程暂停在此处。
  2. Lambda权限补充:添加codepipeline:GetPipelineState权限,允许Lambda获取Pipeline状态以获取审批token。
  3. Scheduler定时规则修正:IST12点对应UTC时间6:30,修正Cron表达式为cron(30 6 * * ? *)。
  4. 参数硬编码修复:Scheduler输入中的流水线名称改为CDK变量引用,避免硬编码错误。
  5. Lambda逻辑优化:移除事件中的approvalToken参数,Lambda自动从Pipeline状态中获取最新的审批token。

修正后的Lambda函数代码

import { CodePipeline } from "aws-sdk";
import { Handler } from "aws-lambda";

// 初始化CodePipeline客户端
const codePipeline = new CodePipeline();

interface LambdaEvent {
  pipelineName: string;
  stageName: string;
  actionName: string;
}

export const handler: Handler<LambdaEvent> = async (event) => {
  const { pipelineName, stageName, actionName } = event;

  try {
    // 获取流水线状态
    const pipelineState = await codePipeline.getPipelineState({ name: pipelineName }).promise();

    if (!pipelineState.stageStates) {
      throw new Error("未找到流水线的阶段状态");
    }

    // 定位目标阶段
    const targetStage = pipelineState.stageStates.find(stage => stage.stageName === stageName);
    if (!targetStage || !targetStage.actionStates) {
      throw new Error(`未找到阶段 ${stageName} 或该阶段无操作状态`);
    }

    // 定位审批操作
    const approvalAction = targetStage.actionStates.find(actionState => actionState.actionName === actionName);
    if (!approvalAction || !approvalAction.latestExecution || !approvalAction.latestExecution.token) {
      throw new Error(`未找到审批操作 ${actionName} 或该操作无可用审批token`);
    }

    const approvalToken = approvalAction.latestExecution.token;

    // 提交审批通过结果
    const approvalParams = {
      pipelineName,
      stageName,
      actionName,
      result: {
        status: "Approved",
        summary: "Lambda自动审批通过QA阶段"
      },
      token: approvalToken
    };

    console.log("审批参数:", approvalParams);
    const response = await codePipeline.putApprovalResult(approvalParams).promise();
    console.log("审批结果提交成功:", response);

    return { message: "QA阶段审批提交成功" };
  } catch (error) {
    console.error("提交审批结果失败:", error);
    throw error;
  }
};

修正后的CDK栈代码

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { Pipeline, Artifact } from "aws-cdk-lib/aws-codepipeline";
import {
  GitHubSourceAction,
  CodeBuildAction,
  ManualApprovalAction,
} from "aws-cdk-lib/aws-codepipeline-actions";
import { Project, BuildSpec } from "aws-cdk-lib/aws-codebuild";
import {
  Effect,
  Policy,
  PolicyDocument,
  PolicyStatement,
  Role,
  ServicePrincipal,
} from "aws-cdk-lib/aws-iam";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { CfnResource, Duration } from "aws-cdk-lib";

export class CdkPocStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // GitHub仓库配置
    const githubRepoOwner = "owner";
    const githubRepoName = "sample-repo";
    const githubBranch = "master";
    const githubOAuthToken = cdk.SecretValue.secretsManager("token");

    // 创建CodePipeline
    const pipeline = new Pipeline(this, "MyCodePipeline", {
      pipelineName: "MyCodePipeline",
    });

    // 流水线产物定义
    const sourceOutput = new Artifact();
    const devBuildOutput = new Artifact();

    // 源阶段:从GitHub拉取代码
    const sourceAction = new GitHubSourceAction({
      actionName: "GitHub_Source",
      owner: githubRepoOwner,
      repo: githubRepoName,
      oauthToken: githubOAuthToken,
      output: sourceOutput,
      branch: githubBranch,
    });

    pipeline.addStage({
      stageName: "Source",
      actions: [sourceAction],
    });

    // DEV阶段:构建任务
    const devProject = new Project(this, "DevBuildStageProject", {
      buildSpec: BuildSpec.fromObject({
        version: "0.2",
        phases: {
          install: {
            runtimeVersions: {
              nodejs: 18,
            },
            commands: ["npm install"],
          },
        },
        artifacts: {
          files: "**/*",
        },
      }),
    });

    const devAction = new CodeBuildAction({
      actionName: "Dev_Stage_Build",
      project: devProject,
      input: sourceOutput,
      outputs: [devBuildOutput],
    });

    pipeline.addStage({
      stageName: "DEV",
      actions: [devAction],
    });

    // QA前置审批阶段:手动审批节点,DEV完成后暂停在此
    const manualApprovalAction = new ManualApprovalAction({
      actionName: "Approve_QA",
    });

    pipeline.addStage({
      stageName: "Pre_QA_Approval",
      actions: [manualApprovalAction],
    });

    // QA阶段:测试任务,需等待审批通过后执行
    const qaProject = new Project(this, "QaBuildStageProject", {
      buildSpec: BuildSpec.fromObject({
        version: "0.2",
        phases: {
          install: {
            runtimeVersions: {
              nodejs: 18,
            },
            commands: ["npm install"],
          },
        },
        artifacts: {
          files: "**/*",
        },
      }),
    });

    const qaAction = new CodeBuildAction({
      actionName: "QA_Stage_Test",
      project: qaProject,
      input: sourceOutput,
    });

    pipeline.addStage({
      stageName: "QA",
      actions: [qaAction],
    });

    // Lambda执行角色:权限包括日志、CodePipeline操作
    const lambdaRole = new Role(this, "LambdaExecutionRole", {
      assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
    });

    lambdaRole.addManagedPolicy({
      managedPolicyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
    });

    lambdaRole.addToPolicy(
      new PolicyStatement({
        actions: [
          "codepipeline:GetPipelineState",
          "codepipeline:PutApprovalResult"
        ],
        resources: [pipeline.pipelineArn],
        effect: Effect.ALLOW,
      }),
    );

    // 用于自动审批QA阶段的Lambda
    const qaApprovalLambda = new NodejsFunction(this, "QaApprovalLambda", {
      entry: "./lib/lambda/qa-stage-trigger.ts", // 确保路径与实际文件位置一致
      handler: "handler",
      runtime: Runtime.NODEJS_20_X,
      timeout: Duration.seconds(10),
      role: lambdaRole,
      environment: {
        PIPELINE_NAME: pipeline.pipelineName,
      },
    });

    // Scheduler执行角色:允许调用Lambda
    const schedulerRole = new Role(this, "SchedulerExecutionRole", {
      assumedBy: new ServicePrincipal("scheduler.amazonaws.com"),
    });

    schedulerRole.addToPolicy(
      new PolicyStatement({
        actions: ["lambda:InvokeFunction"],
        resources: [qaApprovalLambda.functionArn],
        effect: Effect.ALLOW,
      }),
    );

    // 每日IST12点触发的Scheduler规则(对应UTC 6:30)
    new CfnResource(this, "DailyQaTriggerSchedule", {
      type: "AWS::Scheduler::Schedule",
      properties: {
        Name: "DailyQaTriggerSchedule",
        Description: "每日IST12点自动触发QA阶段",
        FlexibleTimeWindow: { Mode: "OFF" },
        ScheduleExpression: "cron(30 6 * * ? *)", // UTC 6:30 = IST 12:00
        Target: {
          Arn: qaApprovalLambda.functionArn,
          RoleArn: schedulerRole.roleArn,
          Input: JSON.stringify({
            pipelineName: pipeline.pipelineName,
            stageName: "Pre_QA_Approval",
            actionName: "Approve_QA",
          }),
        },
      },
    });
  }
}

内容的提问来源于stack exchange,提问作者Surya Prakash Chaudhary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:22:05