Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f7de045
Feature 372: Pipeline Triggers
StewartW Oct 8, 2021
f89f695
Undoing black linting
StewartW Oct 8, 2021
062d52c
Update user-guide.md
StewartW Oct 22, 2021
f4ac55c
Addressing PR feedback
StewartW Oct 22, 2021
e18c246
Merge branch 'master' into feature/372
StewartW Nov 10, 2021
232cd8f
Adding in documentation and code for completion triggers
StewartW Nov 10, 2021
a0085ac
Update docs/user-guide.md
StewartW Nov 10, 2021
b67e79e
Update docs/user-guide.md
StewartW Nov 10, 2021
ace8aac
Update docs/user-guide.md
StewartW Nov 10, 2021
35c4b02
Update src/lambda_codebase/initial_commit/bootstrap_repository/adf-bu…
StewartW Nov 10, 2021
0b365c5
Update src/lambda_codebase/initial_commit/bootstrap_repository/adf-bu…
StewartW Nov 10, 2021
89a4006
Update src/lambda_codebase/initial_commit/bootstrap_repository/adf-bu…
StewartW Nov 10, 2021
73de4ab
Merge branch 'master' of github.com:awslabs/aws-deployment-framework …
StewartW Nov 10, 2021
4b5eb95
Code Review Comments
StewartW Nov 10, 2021
1232e01
Apply suggestions from code review
StewartW Nov 17, 2021
50306d6
Code Review changes
StewartW Nov 17, 2021
7e9bb7f
Merge branch 'master' of github.com:awslabs/aws-deployment-framework …
StewartW Nov 17, 2021
73f8cc7
Update src/lambda_codebase/initial_commit/bootstrap_repository/adf-bu…
StewartW Nov 17, 2021
a716228
Update src/lambda_codebase/initial_commit/bootstrap_repository/adf-bu…
StewartW Nov 17, 2021
d03717d
Merge branch 'feature/372' of github.com:StewartW/aws-deployment-fram…
StewartW Nov 17, 2021
13bd91d
Added new line on adf_default_pipeline
sbkok Nov 17, 2021
0da37f5
Merge branch 'master' into feature/372
sbkok Nov 17, 2021
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
49 changes: 44 additions & 5 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- [Params](#params)
- [Repositories](#repositories)
- [Completion Triggers](#completion-triggers)
- [Additional Triggers](#additional-triggers)
- [Additional Deployment Maps](#additional-deployment-maps)
- [Removing Pipelines](#removing-pipelines)
- [Deploying via Pipelines](#deploying-via-pipelines)
Expand Down Expand Up @@ -214,7 +215,7 @@ The following are the available pipeline parameters:

### Completion Triggers

Pipelines can also trigger other pipelines upon completion. To do this, use the *completion_trigger* key on the pipeline definition. For example:
Pipelines can also trigger other pipelines upon completion. To do this, use the *on_complete* key on the triggers definition. For example:

```yaml
- name: ami-builder
Expand All @@ -229,9 +230,10 @@ Pipelines can also trigger other pipelines upon completion. To do this, use the
size: medium
params:
schedule: rate(7 days)
completion_trigger: # What should happen when this pipeline completes
pipelines:
- my-web-app-pipeline # Start this pipeline
triggers: # What should trigger this pipeline, and what should be triggered when it completes
on_complete:
pipelines:
- my-web-app-pipeline # Start this pipeline

- name: my-web-app-pipeline
default_providers:
Expand All @@ -247,7 +249,44 @@ Pipelines can also trigger other pipelines upon completion. To do this, use the
name: web-app-testing
```

In the above example, the *ami-builder* pipeline runs every 7 days based on its schedule. When it completes, it executes the *my-web-app-pipeline* pipeline as defined in its *completion_trigger* property.
Completion triggers can also be defined in a short handed fashion. Take the above example for the ami-builder pipeline.
```yaml
- name: ami-builder
# Default providers and parameters are the same as defined above.
# Only difference: instead of using `triggers` it uses the `completion_triggers`
params:
schedule: rate(7 days)
completion_triggers: # What should trigger this pipeline, and what should be triggered when it completes
pipelines:
- my-web-app-pipeline # Start this pipeline

- name: my-web-app-pipeline
# Same configuration as defined above.
```


### Additional Triggers

Pipelines can also be triggered by other events using the *triggered_by* key on the triggers definition. For example, a new version of a package hosted on CodeArtifact being published:

```yaml
- name: ami-builder
default_providers:
source:
provider: codecommit
properties:
account_id: 222222222222
build:
provider: codebuild
role: packer
size: medium
triggers: # What should trigger this pipeline, and what should be triggered when it completes
triggered_by:
code_artifact:
repository: my_test_repository
```

In the above example, the *ami-builder* pipeline is triggered when a new package version is published to the *my_test_repository* repository in CodeArtifact.

### Additional Deployment Maps

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from aws_cdk import (
aws_codepipeline as _codepipeline,
aws_events as _eventbridge,
aws_events_targets as _eventbridge_targets,
core
)

Expand All @@ -22,6 +24,7 @@
ADF_PIPELINE_PREFIX = os.environ.get("ADF_PIPELINE_PREFIX", "")
ADF_DEFAULT_BUILD_TIMEOUT = 20


LOGGER = configure_logger(__name__)


Expand Down Expand Up @@ -419,6 +422,10 @@ class Pipeline(core.Construct):
'SendSlackNotificationLambdaArn'
]

CODEARTIFACT_TRIGGER = "CODEARTIFACT"

_accepted_triggers = {"code_artifact": CODEARTIFACT_TRIGGER}

def __init__(self, scope: core.Construct, id: str, map_params: dict, ssm_params: dict, stages, **kwargs): #pylint: disable=W0622
super().__init__(scope, id, **kwargs)
[_codepipeline_role_arn, _code_build_role_arn, _send_slack_notification_lambda_arn] = Pipeline.import_required_arns() #pylint: disable=W0632
Expand All @@ -443,7 +450,7 @@ def __init__(self, scope: core.Construct, id: str, map_params: dict, ssm_params:
),
"topic_arn": map_params.get('topic_arn'),
"name": map_params['name'],
"completion_trigger": map_params.get('completion_trigger'),
"completion_trigger": map_params.get('triggers', {}).get('on_complete', map_params.get('completion_trigger')),
"schedule": map_params.get('schedule'),
"source": {
"provider": map_params.get('default_providers', {}).get('source', {}).get('provider'),
Expand Down Expand Up @@ -486,3 +493,25 @@ def import_required_arns():
# pylint: disable=no-value-for-parameter
_output.append(core.Fn.import_value(arn))
return _output


def add_pipeline_trigger(self, trigger_type, trigger_config):
if trigger_type not in self._accepted_triggers:
LOGGER.error(f"{trigger_type} is not currently supported. Supported values are: {self._accepted_triggers.keys()}")
raise Exception(f"{trigger_type} is not currently supported as a pipeline trigger")
trigger_type = self._accepted_triggers[trigger_type]

if trigger_type == self.CODEARTIFACT_TRIGGER:
details = {"repositoryName": trigger_config["repository"]}
if trigger_config.get("package"):
details["packageName"] = trigger_config["package"]
_eventbridge.Rule(
self,
f"codeartifact-pipeline-trigger-{trigger_config['repository']}-{trigger_config.get('package', 'all')}",
event_pattern=_eventbridge.EventPattern(
source=["aws.codeartifact"],
detail_type=["CodeArtifact Package Version State Change"],
detail=details,
),
targets=[_eventbridge_targets.CodePipeline(pipeline=_codepipeline.Pipeline.from_pipeline_arn(self, "imported", pipeline_arn=self.cfn.ref))],
)
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ def generate_adf_default_pipeline(scope: core.Stack, stack_input):
if "github" in _source_name:
adf_github.GitHub.create_webhook_when_required(scope, _pipeline.cfn, stack_input["input"])

pipeline_triggers = stack_input["input"].get("triggers", {}).get("triggered_by")
if pipeline_triggers:
for trigger_type, trigger_config in pipeline_triggers.items():
_pipeline.add_pipeline_trigger(trigger_type=trigger_type, trigger_config=trigger_config)

if isinstance(notification_config, dict) and notification_config.get('type', '') == 'chat_bot':
adf_chatbot.PipelineNotifications(scope, "adf_chatbot_notifications", _pipeline.cfn, notification_config)


def generate_source_stage_for_pipeline(_stages, scope, stack_input):
_source_name = stack_input["input"]["default_providers"]["source"][
"provider"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,113 @@ def test_pipeline_creation_outputs_as_expected_when_source_is_codecommit_with_co
assert len(build_stage['Actions']) == 1


def test_pipeline_creation_outputs_with_codeartifact_trigger():
region_name = "eu-central-1"
acount_id = "123456789012"

stack_input = {
"input": {"params": {}, "default_providers": {}, "regions": {}, "triggers": {"triggered_by": {"code_artifact": {"repository": "my_test_repo"} }}},
"ssm_params": {"fake-region": {}},
}

stack_input["input"]["name"] = "test-stack"

stack_input["input"]["default_providers"]["source"] = {
"provider": "codecommit",
"properties": {"account_id": "123456789012"},
}
stack_input["input"]["default_providers"]["build"] = {
"provider": "codebuild",
"properties": {"account_id": "123456789012"},
}

stack_input["ssm_params"][region_name] = {
"modules": "fake-bucket-name",
"kms": f"arn:aws:kms:{region_name}:{acount_id}:key/my-unique-kms-key-id",
}
app = core.App()
PipelineStack(app, stack_input)

cloud_assembly = app.synth()
resources = {k[0:-8]: v for k, v in cloud_assembly.stacks[0].template['Resources'].items()}
trigger = resources['codepipelinecodeartifactpipelinetriggermytestrepoall']
assert trigger["Type"] == "AWS::Events::Rule"
assert trigger["Properties"]["EventPattern"]["detail-type"] == ["CodeArtifact Package Version State Change"]
assert trigger["Properties"]["EventPattern"]["source"] == ["aws.codeartifact"]
assert trigger["Properties"]["EventPattern"]["detail"] == {"repositoryName": "my_test_repo"}


def test_pipeline_creation_outputs_with_codeartifact_trigger_with_package_name():
region_name = "eu-central-1"
acount_id = "123456789012"

stack_input = {
"input": {"params": {}, "default_providers": {}, "regions": {}, "triggers": {"triggered_by": {"code_artifact": {"repository": "my_test_repo", "package": "my_test_package"} }}},
"ssm_params": {"fake-region": {}},
}

stack_input["input"]["name"] = "test-stack"

stack_input["input"]["default_providers"]["source"] = {
"provider": "codecommit",
"properties": {"account_id": "123456789012"},
}
stack_input["input"]["default_providers"]["build"] = {
"provider": "codebuild",
"properties": {"account_id": "123456789012"},
}

stack_input["ssm_params"][region_name] = {
"modules": "fake-bucket-name",
"kms": f"arn:aws:kms:{region_name}:{acount_id}:key/my-unique-kms-key-id",
}
app = core.App()
PipelineStack(app, stack_input)

cloud_assembly = app.synth()
resources = {k[0:-8]: v for k, v in cloud_assembly.stacks[0].template['Resources'].items()}
trigger = resources['codepipelinecodeartifactpipelinetriggermytestrepomytestpackage']
assert trigger["Type"] == "AWS::Events::Rule"
assert trigger["Properties"]["EventPattern"]["detail-type"] == ["CodeArtifact Package Version State Change"]
assert trigger["Properties"]["EventPattern"]["source"] == ["aws.codeartifact"]
assert trigger["Properties"]["EventPattern"]["detail"] == {"repositoryName": "my_test_repo", "packageName": "my_test_package"}


def test_pipeline_creation_outputs_with_invalid_trigger_type():
region_name = "eu-central-1"
acount_id = "123456789012"

stack_input = {
"input": {"params": {}, "default_providers": {}, "regions": {}, "triggers": {"triggered_by": {"infinidash": {"arn": "arn:aws:11111111:us-east-1:infinidash/dash:blahblahblah"} }}},
"ssm_params": {"fake-region": {}},
}

stack_input["input"]["name"] = "test-stack"

stack_input["input"]["default_providers"]["source"] = {
"provider": "codecommit",
"properties": {"account_id": "123456789012"},
}
stack_input["input"]["default_providers"]["build"] = {
"provider": "codebuild",
"properties": {"account_id": "123456789012"},
}

stack_input["ssm_params"][region_name] = {
"modules": "fake-bucket-name",
"kms": f"arn:aws:kms:{region_name}:{acount_id}:key/my-unique-kms-key-id",
}
app = core.App()


with pytest.raises(Exception) as e_info:
PipelineStack(app, stack_input)
cloud_assembly = app.synth()

error_message = str(e_info.value)
assert error_message.find("is not currently supported as a pipeline trigger") >= 0


def test_pipeline_creation_outputs_as_expected_when_notification_endpoint_is_chatbot():
region_name = "eu-central-1"
acount_id = "123456789012"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,14 +316,25 @@
COMPLETION_TRIGGERS_SCHEMA = {
"pipelines": [str]
}
PIPELINE_TRIGGERS_SCHEMA = {
Optional("code_artifact"): {
"repository": str,
Optional("package"): str,
}
}
TRIGGERS_SCHEMA = {
Optional("on_complete"): COMPLETION_TRIGGERS_SCHEMA,
Optional("triggered_by"): [PIPELINE_TRIGGERS_SCHEMA],
}
PIPELINE_SCHEMA = {
"name": And(str, len),
"default_providers": PROVIDER_SCHEMA,
Optional("params"): PARAM_SCHEMA,
Optional("tags"): dict,
Optional("targets"): [Or(str, int, TARGET_SCHEMA, TARGET_LIST_SCHEMA)],
Optional("regions"): REGION_SCHEMA,
Optional("completion_trigger"): COMPLETION_TRIGGERS_SCHEMA
Optional("completion_trigger"): COMPLETION_TRIGGERS_SCHEMA,
Optional("triggers"): TRIGGERS_SCHEMA
}
TOP_LEVEL_SCHEMA = {
"pipelines": [PIPELINE_SCHEMA],
Expand Down