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(aws-codepipeline): Jenkins build and test Actions #1216

Merged
merged 1 commit into from
Jan 7, 2019

Conversation

skinny85
Copy link
Contributor

As Jenkins Actions require registering a custom Action, I've also added a skeleton of that functionality, right now not exported from the aws-codepipeline module.

The weird part is that I had to define CustomActionRegistrationProps in the aws-codepipeline-api module (as they should be usable from Action classes, that have access to _registerCustomAction(CustomActionRegistrationProps)), but at the same time I had to put CustomActionRegistration in aws-codepipeline (as it uses the CodePipeline L1 in its implementation). It works fine, it's just that we always put the construction props next to their classes - but I don't see a different way forward in this particular case.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

@skinny85 skinny85 requested a review from eladb November 19, 2018 23:50
@skinny85 skinny85 force-pushed the feature/jenkins-actions branch from a8a73ce to 72fa5d9 Compare November 19, 2018 23:53
@rix0rrr
Copy link
Contributor

rix0rrr commented Nov 20, 2018

The weird part is that I had to define CustomActionRegistrationProps in the aws-codepipeline-api module (as they should be usable from Action classes, that have access to _registerCustomAction(CustomActionRegistrationProps)), but at the same time I had to put CustomActionRegistration in aws-codepipeline (as it uses the CodePipeline L1 in its implementation).

Seems to me there should actually be two interface declarations, that only accidentally have the same properties but are actually different objects.

One is:

  • CustomActionRegistration + CustomActionRegistrationProps, the custom action registration construct.
  • RegisterCustomActionOptions, the arguments to the _registerCustomAction function.

The implementor of _registerCustomAction turns a RegisterCustomActionOptions -> CustomActionRegistrationProps (which in TypeScript is fortunately very easy, because they happen to be structurally compatible).

This also makes it possible to have different arguments/defaults in the two, which might be relevant at some point.

As an aside, I've taken to this convention:

  • XxxProps -> Arguments for creating a construct, a "thing", a noun.
  • XxxOptions -> Arguments for performing an operation (a verb), additional keyword arguments to a method.

The XxxOptions name is generally used in other JavaScript libraries where they allow customization parameters and they call them "options".

But this naming convention has not been ratified by anyone :)

@skinny85 skinny85 force-pushed the feature/jenkins-actions branch from 72fa5d9 to 9676e1a Compare November 27, 2018 23:58
@skinny85
Copy link
Contributor Author

In the newest revision, I've completely changed the approach. I've elevated JenkinsProvider to a top-level Construct, and then referenced it in the Jenkins Actions.

I'm curious what you think of this approach @rix0rrr.

Copy link
Contributor

@rix0rrr rix0rrr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you're now making the registration explicit huh?

I like it! I think the API could be simplified a little further, but I like the approach!

packages/@aws-cdk/aws-codepipeline/README.md Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/lib/jenkins-provider.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/lib/jenkins-provider.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/lib/jenkins-provider.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/lib/jenkins-provider.ts Outdated Show resolved Hide resolved
@skinny85 skinny85 force-pushed the feature/jenkins-actions branch from 9676e1a to 69ce735 Compare December 19, 2018 01:28
@skinny85 skinny85 requested review from RomainMuller and a team as code owners December 19, 2018 01:28
@skinny85
Copy link
Contributor Author

@rix0rrr I've changed the API according to your suggestions. Let me know if this is what you had in mind!

@skinny85 skinny85 force-pushed the feature/jenkins-actions branch from 69ce735 to d9ae019 Compare December 19, 2018 19:20
@skinny85
Copy link
Contributor Author

Rebased on top of the new master to get the builds going again (master was broken before).

@rix0rrr still waiting for your comments here!

packages/@aws-cdk/aws-codepipeline/lib/jenkins-actions.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-codepipeline/lib/jenkins-provider.ts Outdated Show resolved Hide resolved
}).makeImportValue().toString(),
version: new cdk.Output(this, 'JenkinsProviderVersion', {
value: this.version,
}).makeImportValue().toString(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can export forBuild and forTest here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could, but I'm not sure it makes much sense. For example, then export would be affected whether addToPipeline / addToPipelineAsTest was called before, which I'm not sure is the correct behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm trying to enable is the following 2 scenario's:

  1. Define JenkinsProvider in the same stack as where it's used. Automatically works with a minimal amount of fuss.
  2. Define JenkinsProvider in stack A. Enable "forBuild" upon construction (because it won't be done automatically). Export it and import it in the stack B. The imported one cannot be used for tests (it will throw an error because it knows it wasn't "set up" that way), but it can be used for builds.

The case that in a two-stack scenario "forBuild" may be implicitly switched on if you happen to use a build action in stack A is maybe not fantastic, but also doesn't hurt anything (imo), especially with runtime validation in stack B (because if you remove that code, the runtime error will prevent a broken template from from being synthesized).

The fact that in scenario (2) the imported provider in stack B automatically knows what actual providers have been registered on the real provider in stack A only makes it better. Without this automatic piggy-backing of configuration information you would still have had to manually switch on the correct registrations in stack A, and in stack B you would also have to either assume it was configured correctly with no way of checking, or you would have to pass this additional information on import.

Copy link
Contributor

@rix0rrr rix0rrr Jan 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're concerned about ordering, fair enough. Not something we can avoid, really, in the paradigm that we've chosen. I'd hate to lose ergonomics because of it, and also not a blocker since you can always trigger the behavior you want with constructor arguments if the ordering happens to not work out in your favor.

packages/@aws-cdk/aws-codepipeline/lib/jenkins-provider.ts Outdated Show resolved Hide resolved
*/
version?: string;

forBuild?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you like this better than a Build/Test/Both enum?

Also, docstrings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you like this better than a Build/Test/Both enum?

I do, but I won't insist if you really like the enum approach more :).

Also, docstrings.

Yep, done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to have had the argument, and confirmation that you prefer this.

}

public _includeBuildVariant(): void {
// do nothing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make the forBuild and forTest arguments to the imported props, we can do a sanity check and throw a useful error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't that make using the imported provider more irritating? I assume that forBuild and forTest will be false by default, so if you do:

const provider = codepipeline.JenkinsProvider.import(this, 'Provider', {
  providerName: 'Provider',
  serverUrl: 'http://my-jenkins.com:8080',
});

provider.addToPipeline(/* ... */);

and you would get an exception saying forBuild should be true when doing the import.

Not sure it's worth it...?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your concern. My thoughts were that it would be used with the export()/import() combination instead of a manual import, in which case you wouldn't need to pass the additional argument yourself.

You seem to be optimizing for cross-app, while I'm optimizing for in-app, cross-stack. Is that fair to say?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I'm optimizing for it, just pointing out a potential usability issue with that use case :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I'm looking at it, by deciding whether or not to add that parameter to the ImportProps, we're optimizing for usability of one of the two cases. We just have to decide which one we care more about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer the current approach, for 2 reasons:

a) the link between specifying the forBuild: true parameter to import before calling provider.addToPipeline(...) seems very unintuitive to me. I understand we can have a nice error message, but still, I don't love this approach.
b) I can't see a good use case for creating the provider in one Stack, but adding it to the Pipeline in another. Even if someone tried to do it, it wouldn't actually work! The imported Provider would throw an exception saying it wasn't marked for build. Of course, you could pass forBuild: true when creating it in the original Stack, but again, I don't find that intuitive.

Personally, if you feel strongly about having this validation, then I would rather go back to having separate Providers for build & test. I don't think forcing passing forBuild/forTest: true, and in a call before you get the actual exception, is a great API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alrighty then. That was the last point of discussion, right? So ship it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So ship it?

If you don't have any other comments, then yep :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already approved on my part so go ahead

@skinny85 skinny85 force-pushed the feature/jenkins-actions branch 2 times, most recently from 75e3551 to 08b97e4 Compare January 7, 2019 20:16
@skinny85
Copy link
Contributor Author

skinny85 commented Jan 7, 2019

Rebased to resolve conflict.

@skinny85 skinny85 force-pushed the feature/jenkins-actions branch from 08b97e4 to b95008a Compare January 7, 2019 21:31
@skinny85
Copy link
Contributor Author

skinny85 commented Jan 7, 2019

New revision due to upstream changes (parent -> scope, aws-linter warnings).

@skinny85 skinny85 merged commit 471e8eb into aws:master Jan 7, 2019
@skinny85 skinny85 deleted the feature/jenkins-actions branch January 7, 2019 23:19
@NGL321 NGL321 added the contribution/core This is a PR that came from AWS. label Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants