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
[JENKINS-38153] Adding synthetic stage marker. #13
Conversation
Also adding synthetic stages for pre-build stuff.
This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation. |
Also cc @svanoort |
Agree with adding a new action -- however I think this is where we should do a trivial JENKINS-26522 implementation. Give me a minute I'm going to hack together something for you :) "Synthetic" would be one of the annotations for us, just one of many, used here. Need a bit of time in order to be able to give you a full review. |
@abayer and @vivek I like the basic ideal but think a JENKINS-26522 implemetation around arbitrary annotations like this is better and more flexible: jenkinsci/workflow-api-plugin#12 <-- POC concept In that case, we'd use a tag "SYNTHETIC" on the action. |
@svanoort Well, that's part of it, but we did need more metadata than just the tag - we're also recording the execution context (currently the only options are pre-build/post-build, but I have a feeling we'll add more to that in the future). |
Yeah you're just annotating which synthetic stage type it is. That's a SYNTHETIC tag and/or SYNTHETIC_PRE/SYNTHETIC_POST. Are there additional requirements/plans that have not been disclosed yet that you'd like to disclose now? |
Awwww, I have to translate everything to string tags? I'm back in AWS-land! =) |
@abayer Okay, but implementation-nitpicking aside: don't tell me you don't want JENKINS-26522... ;) Or that you will get to be the trailblazer use case to justify it, with pipeline model definitions. |
Yes, I do want that. =) |
Conflicts: src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy
Seems hackish. Better to define a simple |
@abayer If we pull in the TagsAction here I think will be ready for merge? |
@svanoort Yeah, I can redo this with |
Now properly downstream of jenkinsci/workflow-api-plugin#12 |
Conflicts: src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/Utils.groovy src/test/java/org/jenkinsci/plugins/pipeline/modeldefinition/BasicModelDefTest.java
FYI, current failure on ci.jenkins.io PR build is due to SNAPSHOT check staleness. |
|
||
package org.jenkinsci.plugins.pipeline.modeldefinition.actions; | ||
|
||
public enum SyntheticContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐛 I think you meant to remove this, since we don't need the whole Context/ContextAction bit after adding the TagsAction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, I meant to leave it - I want an enum of possible values for the SYNTHETIC_STAGE_TAG.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
..but have now gotten rid of it. yay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay!
* | ||
* @author Andrew Bayer | ||
*/ | ||
public class SyntheticStageMarkerAction extends InvisibleAction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐛 Not needed now that we can use TagsAction as our marker (and indeed a broader-use marker).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, forgot to delete that.
* @param context | ||
*/ | ||
@Whitelisted | ||
static void markSyntheticStage(String stageName, SyntheticContext context) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐛 Better to use static final strings for the markers, i.e. "PRE" and "POST" or similar. Creating an enum just for two values is kind of silly, and if we're just getting string values for 'em we might as well use that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigh. Ok. =)
assertNull(scanner.findFirstMatch(heads, null, syntheticStagePredicate(SyntheticStageNames.dockerPull(), SyntheticContext.PRE))); | ||
} | ||
|
||
private Predicate<FlowNode> syntheticStagePredicate(final String stageName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to expose this as part of the public API for Blue Ocean to use with the search/filter workflow APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm betting y'all can write something better. =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You give people too much credit ;)
@svanoort Ok, switched to |
if (currentNode.getAction(TagsAction.class) == null) { | ||
currentNode.actions.add(new TagsAction()) | ||
} | ||
currentNode.getAction(TagsAction.class).addTag(SYNTHETIC_STAGE_TAG, context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a hack. Better to have a block-scoped Step
which adds this Action
using the supported APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to limit the visibility/exposure of a Step
? i.e., can I create one that only can be used in this plugin? If not, then hacks are really the only way I can see to get what we need - a Step
that shows up in the snippet generator, etc that does this would be...flawed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isAdvanced
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I have to disagree with @jglick about the block-scoped step -- it doesn't feel like synthetic stages are truly a different animal than a normal stage. We're just attaching some additional helper information to that stage. Actions are exactly the right thing to use here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I strangely enough agree with @svanoort =)
script.stage(SyntheticStage.dockerPull()) { | ||
Utils.markSyntheticStage(SyntheticStage.dockerPull(), SyntheticStage.SYNTHETIC_PRE) | ||
script.getProperty("docker").image(agent.docker).pull() | ||
} | ||
script.getProperty("docker").image(agent.docker).inside { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW more directly written as
script.docker.image…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So at least at some point in the past, that very much didn't work. Dunno if it would now, I'll give it a try.
ci.jenkins.io is still...questionable at times. Right now it's barfing due to git |
} | ||
|
||
private Predicate<FlowNode> syntheticStagePredicate(final String stageName, | ||
final SyntheticContext context) { | ||
final String context) { | ||
return new Predicate<FlowNode>() { | ||
@Override | ||
public boolean apply(FlowNode input) { | ||
return input.getDisplayName().equals(stageName) && | ||
input.getAction(TagsAction.class) != null && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐛 Upon further examination (sorry). Fetching the action 3x is undesirable for performance (sigh). Normally pessimization wouldn't be a bug but I happen to know this one can be fairly costly.
Also worth checking for 'input instanceof StepNode && ((StepNode)input).getDescriptor == WhateverTheStageDescriptorIs' -- faster than string equals since it is a direct memory location compare.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait. Nevermind, that's test-only. It would be a bug if it were a public API.
Going to blame that one on still being jetlagged post-JenkinsWorld.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I'm specifically trying to compare the displayName
to make sure it's the right stage
. I did try using StageStartNode
, I think it was, whatever you suggested earlier, and it...did not work. At all. So I went back to this. =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Display name can be the typeDisplayName if there isn't a LabelAction though, so it's not a safe check to be using in general (since you can get false positives). Again, okay in the walled garden of tests, but I wouldn't want to see it elsewhere.
In general, prefer type checks and then a LabelAction (or StageAction) check -- you're putting preconditions first that can be tested quickly. Should be safer and a bit faster (since it'll return negative 99% of the time).
In general: the context removal and string changeover look good. I think this one is 🐝 worthy -- though might suggest using your NotNull/CheckForNull annotations some more. |
Closing in favor of #47 |
JENKINS-38153
Also adding synthetic stages for pre-build stuff.
cc @reviewbybees esp @vivek