Open jonodrew opened 1 year ago
You're using a cdk.Stage
. The examples we have that I found, and what the API reference shows is that the stage class with the addAction
method is a pipelines.StageDeployment
. Please let me know if there are any docs you found that use a cdk.Stage
. Thanks
Thanks for responding. As I wrote in the report, the StageDeployment
object also fails cdk synth
with the error AttributeError: 'StageDeployment' object has no attribute 'add_action'
Can you please provide a snippet for this?
I've expanded the existing snippet. You can also see the code I'm working on, if it's helpful to see the larger context: https://github.com/mentor-matching-online/mentor-match/blob/main/mentor-match-infra/mentor_match_infra/mentor_match_pipeline.py
In that example, neither testing_stage
nor production_stage
will accept a add_action
method
You still aren't creating a StageDeployment
. You're importing Stage
from the core library and trying to directly call add_action
on this Stage. This shouldn't ever work.
stage_deployment = pipeline.add_stage(s) stage_deployment.add_action # fails with
object has no attribute 'add_action'
This should work I think, except I don't think you created the CodePipeline
correctly. You've created a Codepipeline
, which I'm not sure where that comes from, and the CodePipeline
construct requires a synth
prop at the least as well.
Checking source code now
Thanks - you make a good point. My snippet isn't reproducible, sorry. The source code is clearer I hope
Hi, can I hijack this discussion. As I struggle with a more or less similar problem and tried various version and workarounds to add an action to my pipeline without success.
My code is in TypeScript but as far as I can see and also in the linked API documentation there is no method addAction
or in the Python case add_action
(https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_pipelines.StageDeployment.html). Or am I missing something?
The reference code I got as answer for my discussion thread is also not reproducible / working: https://github.com/aws/aws-cdk/discussions/25650
Curious if @peterwoodworth can guide us what we did wrong and how to add correctly an action to a pipeline.
Thanks already for your hard work!
Hey @jonodrew, I took the code in your repository, refactored it a little bit, and didn't run into any errors with the stages. Here's my refactored code:
from aws_cdk import Stack, Environment, Stage
from aws_cdk.pipelines import CodePipeline, ShellStep, CodePipelineSource, ManualApprovalStep
from aws_cdk import aws_lambda as _lambda
from constructs import Construct
class MentorMatchPipeline(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs):
super().__init__(scope, construct_id, **kwargs)
pipeline = CodePipeline(self, "MentorMatchPipeline",
pipeline_name="Pipeline",
cross_account_keys=True,
synth=ShellStep("Synth",
input=CodePipelineSource.git_hub("mentor-matching-online/mentor-match", "main"),
commands=["npm install -g aws-cdk",
"cd mentor-match-infra",
"python -m pip install -r requirements.txt",
"cdk synth"],
primary_output_directory="mentor-match-infra/cdk.out"
)
)
testing_stage = MentorMatchAppStage(self, "testing", env=Environment(account="712310211354", region="eu-west-2"))
pipeline.add_stage(testing_stage)
production_stage = pipeline.add_stage(
MentorMatchAppStage(self, "production", env=Environment(account="712310211354", region="eu-west-2"))
)
production_stage.add_pre(
ManualApprovalStep('approval')
)
class MentorMatchAppStage(Stage):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
service = TestStack(self, "MentorMatchStack")
class TestStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
self.fn = _lambda.Function(
self,
"LambdaFunction",
runtime=_lambda.Runtime.PYTHON_3_9,
code=_lambda.InlineCode("def handler(event, context): print 'hello'"),
handler="index.handler",
)
And here's where I create the stack:
app = cdk.App()
pipeline_stack = MentorMatchPipeline(app, 'MentorMatchPipeline',
env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),
)
This synthesized properly for me, and the stages worked the way they should.
So I wonder if something might be going wrong in your environment? The code you posted looks good to me and also worked for me
Thanks @HannesOberreiter ! I also note in the Python CDK library, the add_action
method has no code under it:
class StageDeployment(
metaclass=jsii.JSIIMeta,
jsii_type="aws-cdk-lib.pipelines.StageDeployment",
):
'''Deployment of a single ``Stage``.
A ``Stage`` consists of one or more ``Stacks``, which will be
deployed in dependency order.
:exampleMetadata: fixture=_generated
Example::
# The code below shows an example of how to instantiate this type.
# The values are placeholders you should change.
import aws_cdk as cdk
from aws_cdk import pipelines
# stack: cdk.Stack
# stage: cdk.Stage
# step: pipelines.Step
stage_deployment = pipelines.StageDeployment.from_stage(stage,
post=[step],
pre=[step],
stack_steps=[pipelines.StackSteps(
stack=stack,
# the properties below are optional
change_set=[step],
post=[step],
pre=[step]
)],
stage_name="stageName"
)
'''
@jsii.member(jsii_name="fromStage")
@builtins.classmethod
def from_stage(
cls,
stage: _Stage_7df8511b,
*,
post: typing.Optional[typing.Sequence["Step"]] = None,
pre: typing.Optional[typing.Sequence["Step"]] = None,
stack_steps: typing.Optional[typing.Sequence[typing.Union[StackSteps, typing.Dict[builtins.str, typing.Any]]]] = None,
stage_name: typing.Optional[builtins.str] = None,
) -> "StageDeployment":
'''Create a new ``StageDeployment`` from a ``Stage``.
Synthesizes the target stage, and deployes the stacks found inside
in dependency order.
:param stage: -
:param post: Additional steps to run after all of the stacks in the stage. Default: - No additional steps
:param pre: Additional steps to run before any of the stacks in the stage. Default: - No additional steps
:param stack_steps: Instructions for additional steps that are run at the stack level. Default: - No additional instructions
:param stage_name: Stage name to use in the pipeline. Default: - Use Stage's construct ID
'''
if __debug__:
type_hints = typing.get_type_hints(_typecheckingstub__a37efd4695086f03c4f48796707d94ae7caf71cecf52f15940e3a454ddce14cf)
check_type(argname="argument stage", value=stage, expected_type=type_hints["stage"])
props = StageDeploymentProps(
post=post, pre=pre, stack_steps=stack_steps, stage_name=stage_name
)
return typing.cast("StageDeployment", jsii.sinvoke(cls, "fromStage", [stage, props]))
# rest of class removed for space
def add_action(self):
pass
@peterwoodworth thank you very much for all your work so far. I've updated my example. As you saw in the code, I don't actually call the add_action
method anywhere because it doesn't work.
You'll note above that I've added the code from the StageDeployment
class. The lack of code under add_action
feels like it might be linked, but I know I might be wrong about that!
You're using a
cdk.Stage
. The examples we have that I found, and what the API reference shows is that the stage class with theaddAction
method is apipelines.StageDeployment
. Please let me know if there are any docs you found that use acdk.Stage
. Thanks
Following up on the documentation question - in the documentation for Step
(https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.pipelines/Step.html#step), users are invited to call add_action
on a variable called stage
. There's no type on that variable, but I think it's fair to assume it should be of type Stage
?
Oh, I think I see where the confusion is now.
codepipeline.Pipeline.addStage()
returns a codepipeline.IStage
which does have this method. pipelines.CodePipeline.addStage()
returns a StageDeployment
- which isn't documented as having addAction()
.
Here's our documentation on how to add an arbitrary action in our pipelines.CodePipeline
. This is the same documentation snippet you just linked, but it's our TypeScript docs which specifies that the Stage
is actually a codepipeline.IStage
, not a pipelines.StageDeployment
Thank you so much! I'm off to try to understand the difference between Pipeline
and CodePipeline
😆
Seems like the way we generate the python docs makes this very easily confusing, so please let us know if you have any ideas on how to make this more clear in the docs
Thank you, was really caught there in a limbo
I think further clarity about when one might use Pipeline
over CodePipeline
, or vice versa, might be helpful. I also don't love that we have aws_cdk.aws_codepipeline.Pipeline
and aws_cdk.pipelines.CodePipeline
😅
Yeah it's not the clearest naming system. We'll see what we can do
Thanks @peterwoodworth . Happy for this to be closed
Describe the bug
I'm trying to follow the documentation here: https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_codepipeline_actions/README.html#manual-approval-action. My aim is to add an action at the end of a testing stage to destroy the resources I don't need any more.
However, when I try to call
add_action
on aStageDeployent
object I get the error'StageDeployment' object has no attribute 'add_action'
. When I try to call it on aStage
object, I get the same error:Stage
object has no attributeadd_action
Expected Behavior
I expect the code to synthesize as written in the docs
Current Behavior
Error as above
Reproduction Steps
Adding this to an existing pipeline will cause the synth to fail with the error
Stage object has no attribute 'add_action'
Possible Solution
No response
Additional Information/Context
No response
CDK CLI Version
2.79.1
Framework Version
2.79.1
Node.js Version
20.1.0
OS
Linux
Language
Python
Language Version
3.9.10
Other information
aws-cdk-lib==2.79.1 jsii==1.81.0
ETA: expanded example