Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add timeout_in_minutes to action block for aws_codepipeline #36316

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading