Skip to content

Commit

Permalink
Merge pull request hashicorp#36316 from acwwat/f-aws_codepipeline-add…
Browse files Browse the repository at this point in the history
…_timeout_in_minutes_arg

feat: Add timeout_in_minutes to action block for aws_codepipeline
  • Loading branch information
ewbankkit authored Jul 17, 2024
2 parents 734cccc + 30bc570 commit c3b9b48
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 11 deletions.
7 changes: 7 additions & 0 deletions .changelog/36316.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_codepipeline: Add `timeout_in_minutes` argument to the `action` configuration block
```

```release-note:bug
resource/aws_codepipeline: Mark `trigger` as Computed
```
20 changes: 17 additions & 3 deletions internal/service/codepipeline/codepipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ func resourcePipeline() *schema.Resource {
Computed: true,
ValidateFunc: validation.IntBetween(1, 999),
},
"timeout_in_minutes": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(5, 86400),
},
names.AttrVersion: {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -225,6 +230,7 @@ func resourcePipeline() *schema.Resource {
"trigger": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 50,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -658,7 +664,7 @@ func expandPipelineDeclaration(d *schema.ResourceData) (*types.PipelineDeclarati
case 1:
for region, v := range artifactStores {
if region != "" {
return nil, errors.New("region cannot be set for a single-region CodePipeline")
return nil, errors.New("region cannot be set for a single-region CodePipeline Pipeline")
}
v := v
apiObject.ArtifactStore = &v
Expand All @@ -667,11 +673,11 @@ func expandPipelineDeclaration(d *schema.ResourceData) (*types.PipelineDeclarati
default:
for region := range artifactStores {
if region == "" {
return nil, errors.New("region must be set for a cross-region CodePipeline")
return nil, errors.New("region must be set for a cross-region CodePipeline Pipeline")
}
}
if n != v.(*schema.Set).Len() {
return nil, errors.New("only one Artifact Store can be defined per region for a cross-region CodePipeline")
return nil, errors.New("only one Artifact Store can be defined per region for a cross-region CodePipeline Pipeline")
}
apiObject.ArtifactStores = artifactStores
}
Expand Down Expand Up @@ -877,6 +883,10 @@ func expandActionDeclaration(tfMap map[string]interface{}) *types.ActionDeclarat
apiObject.RunOrder = aws.Int32(int32(v))
}

if v, ok := tfMap["timeout_in_minutes"].(int); ok && v != 0 {
apiObject.TimeoutInMinutes = aws.Int32(int32(v))
}

if v, ok := tfMap[names.AttrVersion].(string); ok && v != "" {
apiObject.ActionTypeId.Version = aws.String(v)
}
Expand Down Expand Up @@ -1357,6 +1367,10 @@ func flattenActionDeclaration(d *schema.ResourceData, i, j int, apiObject types.
tfMap["run_order"] = aws.ToInt32(v)
}

if v := apiObject.TimeoutInMinutes; v != nil {
tfMap["timeout_in_minutes"] = aws.ToInt32(v)
}

return tfMap
}

Expand Down
234 changes: 226 additions & 8 deletions internal/service/codepipeline/codepipeline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ func TestAccCodePipeline_pipelinetype(t *testing.T) {
CheckDestroy: testAccCheckPipelineDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccCodePipelineConfig_pipelinetype(rName),
Config: testAccCodePipelineConfig_pipelinetype(rName, "V1"),
Check: resource.ComposeTestCheckFunc(
testAccCheckPipelineExists(ctx, resourceName, &p),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.codepipeline_role", names.AttrARN),
Expand Down Expand Up @@ -908,7 +908,7 @@ func TestAccCodePipeline_pipelinetype(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "variable.1.name", "test_var2"),
resource.TestCheckResourceAttr(resourceName, "variable.1.description", "This is test pipeline variable 2."),
resource.TestCheckResourceAttr(resourceName, "variable.1.default_value", acctest.CtValue2),
resource.TestCheckResourceAttr(resourceName, "trigger.0.git_configuration.#", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, "trigger.0.git_configuration.#", acctest.Ct1),
),
},
{
Expand All @@ -921,14 +921,14 @@ func TestAccCodePipeline_pipelinetype(t *testing.T) {
},
},
{
Config: testAccCodePipelineConfig_pipelinetype(rName),
Config: testAccCodePipelineConfig_pipelinetype(rName, "V2"),
Check: resource.ComposeTestCheckFunc(
testAccCheckPipelineExists(ctx, resourceName, &p),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.codepipeline_role", names.AttrARN),
acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "codepipeline", regexache.MustCompile(fmt.Sprintf("test-pipeline-%s", rName))),
resource.TestCheckResourceAttr(resourceName, "artifact_store.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "execution_mode", string(types.ExecutionModeSuperseded)),
resource.TestCheckResourceAttr(resourceName, "pipeline_type", string(types.PipelineTypeV1)),
resource.TestCheckResourceAttr(resourceName, "pipeline_type", string(types.PipelineTypeV2)),
resource.TestCheckResourceAttr(resourceName, "stage.#", acctest.Ct2),
resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"),
resource.TestCheckResourceAttr(resourceName, "stage.0.action.#", acctest.Ct1),
Expand Down Expand Up @@ -962,7 +962,74 @@ func TestAccCodePipeline_pipelinetype(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.role_arn", ""),
resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.run_order", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.region", ""),
resource.TestCheckResourceAttr(resourceName, "trigger.0.git_configuration.#", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, "trigger.0.git_configuration.#", acctest.Ct1),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccCodePipeline_manualApprovalTimeoutInMinutes(t *testing.T) {
ctx := acctest.Context(t)
var p types.PipelineDeclaration
rName := sdkacctest.RandString(10)
resourceName := "aws_codepipeline.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.CodePipelineServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckPipelineDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccCodePipelineConfig_manualApprovalTimeoutInMinutes(rName, 5),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckPipelineExists(ctx, resourceName, &p),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.codepipeline_role", names.AttrARN),
acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "codepipeline", regexache.MustCompile(fmt.Sprintf("test-pipeline-%s", rName))),
resource.TestCheckResourceAttr(resourceName, "artifact_store.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.#", acctest.Ct3),
resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"),
resource.TestCheckResourceAttr(resourceName, "stage.0.action.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.timeout_in_minutes", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Approval"),
resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.timeout_in_minutes", "5"),
resource.TestCheckResourceAttr(resourceName, "stage.2.name", "Build"),
resource.TestCheckResourceAttr(resourceName, "stage.2.action.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.2.action.0.timeout_in_minutes", acctest.Ct0),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccCodePipelineConfig_manualApprovalNoTimeoutInMinutes(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckPipelineExists(ctx, resourceName, &p),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.codepipeline_role", names.AttrARN),
acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "codepipeline", regexache.MustCompile(fmt.Sprintf("test-pipeline-%s", rName))),
resource.TestCheckResourceAttr(resourceName, "artifact_store.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.#", acctest.Ct3),
resource.TestCheckResourceAttr(resourceName, "stage.0.name", "Source"),
resource.TestCheckResourceAttr(resourceName, "stage.0.action.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.0.action.0.timeout_in_minutes", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, "stage.1.name", "Approval"),
resource.TestCheckResourceAttr(resourceName, "stage.1.action.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.1.action.0.timeout_in_minutes", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, "stage.2.name", "Build"),
resource.TestCheckResourceAttr(resourceName, "stage.2.action.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "stage.2.action.0.timeout_in_minutes", acctest.Ct0),
),
},
{
Expand Down Expand Up @@ -1291,7 +1358,7 @@ resource "aws_codestarconnections_connection" "test" {
`, rName))
}

func testAccCodePipelineConfig_pipelinetype(rName string) string { // nosemgrep:ci.codepipeline-in-func-name
func testAccCodePipelineConfig_pipelinetype(rName, pipelineType string) string { // nosemgrep:ci.codepipeline-in-func-name
return acctest.ConfigCompose(
testAccS3DefaultBucket(rName),
testAccServiceIAMRole(rName),
Expand Down Expand Up @@ -1346,14 +1413,14 @@ resource "aws_codepipeline" "test" {
}
}
pipeline_type = "V1"
pipeline_type = %[2]q
}
resource "aws_codestarconnections_connection" "test" {
name = %[1]q
provider_type = "GitHub"
}
`, rName))
`, rName, pipelineType))
}

func testAccCodePipelineConfig_pipelinetypeUpdated1(rName string) string { // nosemgrep:ci.codepipeline-in-func-name
Expand Down Expand Up @@ -2449,3 +2516,154 @@ resource "aws_codepipeline" "test" {
}
`, rName))
}

func testAccCodePipelineConfig_manualApprovalTimeoutInMinutes(rName string, timeoutInMinutes int) string { // nosemgrep:ci.codepipeline-in-func-name
return acctest.ConfigCompose(
testAccS3DefaultBucket(rName),
testAccServiceIAMRole(rName),
fmt.Sprintf(`
resource "aws_codepipeline" "test" {
name = "test-pipeline-%[1]s"
role_arn = aws_iam_role.codepipeline_role.arn
artifact_store {
location = aws_s3_bucket.test.bucket
type = "S3"
encryption_key {
id = "1234"
type = "KMS"
}
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["test"]
configuration = {
ConnectionArn = aws_codestarconnections_connection.test.arn
FullRepositoryId = "lifesum-terraform/test"
BranchName = "main"
}
}
}
stage {
name = "Approval"
action {
name = "Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = "1"
timeout_in_minutes = %[2]d
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["test"]
version = "1"
configuration = {
ProjectName = "test"
}
}
}
}
resource "aws_codestarconnections_connection" "test" {
name = %[1]q
provider_type = "GitHub"
}
`, rName, timeoutInMinutes))
}

func testAccCodePipelineConfig_manualApprovalNoTimeoutInMinutes(rName string) string { // nosemgrep:ci.codepipeline-in-func-name
return acctest.ConfigCompose(
testAccS3DefaultBucket(rName),
testAccServiceIAMRole(rName),
fmt.Sprintf(`
resource "aws_codepipeline" "test" {
name = "test-pipeline-%[1]s"
role_arn = aws_iam_role.codepipeline_role.arn
artifact_store {
location = aws_s3_bucket.test.bucket
type = "S3"
encryption_key {
id = "1234"
type = "KMS"
}
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["test"]
configuration = {
ConnectionArn = aws_codestarconnections_connection.test.arn
FullRepositoryId = "lifesum-terraform/test"
BranchName = "main"
}
}
}
stage {
name = "Approval"
action {
name = "Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = "1"
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["test"]
version = "1"
configuration = {
ProjectName = "test"
}
}
}
}
resource "aws_codestarconnections_connection" "test" {
name = %[1]q
provider_type = "GitHub"
}
`, rName))
}
1 change: 1 addition & 0 deletions website/docs/cdktf/python/r/codepipeline.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ An `action` block supports the following arguments:
* `run_order` - (Optional) The order in which actions are run.
* `region` - (Optional) The region in which to run the action.
* `namespace` - (Optional) The namespace all output variables will be accessed from.
* `timeout_in_minutes` - (Optional) A timeout duration in minutes that can be applied against the action type's default timeout value specified in [Quotas for AWS CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/limits.html). This argument is available only to the manual approval action type.

~> **Note:** The input artifact of an action must exactly match the output artifact declared in a preceding action, but the input artifact does not have to be the next action in strict sequence from the action that provided the output artifact. Actions in parallel can declare different output artifacts, which are in turn consumed by different following actions.

Expand Down

0 comments on commit c3b9b48

Please sign in to comment.