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

Added recipe for changing Groovy params #4581

Open
wants to merge 22 commits into
base: main
Choose a base branch
from

Conversation

ThomasKianek-Gepardec
Copy link

What's changed?

Added recipe for changing Groovy parameter value in method invocation.

What's your motivation?

To be used in Jenkins files (e.g. to update the JDK version).

Have you considered any alternatives or workarounds?

Preconditions for selecting a given method in Groovy did not work as expected (had to use if-statement instead).

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

Xaeras and others added 9 commits October 15, 2024 11:02
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@sgartner03
Copy link

sgartner03 commented Oct 16, 2024

Hi @timtebeek, I've incorporated the suggested changes from the GH Action. I think this contribution matches your code styling now.

@sgartner03
Copy link

@timtebeek
Copy link
Contributor

hi @ThomasKianek-Gepardec & @sgartner03 ! Do I understand this is a recipe that can change a named parameter value in a Groovy method invocation to a different String value? I feel like we might be more explicit about those limitations in how we name the recipe, as opposed to only have that in the description.

It might also make sense to add some additional tests with methods that have more than one named parameter, only changing the right one, or no named parameters, just to ensure we handle all cases correctly.

@sgartner03
Copy link

Hi @timtebeek, yes exactly that is what this recipe does. Thank you for your, feedback, I'll incorporate it now.

@sgartner03
Copy link

Hi, I've added 3 more tests. This tests:

  • Multiple params
  • Empty Methods
  • Parameters of other type.

As of now, this recipe only supports Strings and GStrings

@sgartner03
Copy link

@timtebeek

Copy link
Contributor

@timtebeek timtebeek left a comment

Choose a reason for hiding this comment

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

hi @sgartner03 ; I was out hiking a few days, hence the delayed response. I've pushed up a small formatting for the tests, and posted a number of questions on the implementation that I think we should address before a merge. A wider context of intended use might help for this otherwise generic recipe. I see now that this is intended to be used for Jenkins projects. Perhaps we can start this as a visitor in rewrite-jenkins first and let it mature from there?

}

private boolean isInTargetMethod() {
return getCursor().firstEnclosingOrThrow(J.MethodInvocation.class).getSimpleName().equals(methodName);
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the intended use case here? Because we'd much rather match using a MethodMatcher as opposed to a String comparision, as this would match any method anywhere of the same name, which is not as type safe as we prefer to be. For Gradle build script type information isn't always available to match reliably, but even then there's established patterns to be a little more sure we're not just matching any method by simple name, hence why I ask here.

}

private char extractQuoting(final G.MapEntry mapEntry) {
return mapEntry.getValue().printTrimmed(getCursor()).charAt(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the only time I've seen printTrimmed used in all of rewrite-groovy; is there no safer alternative? It seems you're looking to skip over anything that's not a J.Literal or GString; perhaps that can be checked here?

Choose a reason for hiding this comment

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

Yeah, you're right. I've removed extractQuoting

Comment on lines 63 to 64
char quote = extractQuoting(mapEntry);
if (quote != '\'' && extractQuoting(mapEntry) != '"') {
Copy link
Contributor

Choose a reason for hiding this comment

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

See below as well for a potential alternative looking at the type of the mapEntry instead, but calling the same method twice with the same argument is a bit suspect.

Suggested change
char quote = extractQuoting(mapEntry);
if (quote != '\'' && extractQuoting(mapEntry) != '"') {
char quote = extractQuoting(mapEntry);
if (quote != '\'' && quote != '"') {

}

private G. MapEntry replaceValue(final G.MapEntry mapEntry, char quote) {
return mapEntry.withValue(new J.Literal(Tree.randomId(), Space.SINGLE_SPACE, Markers.EMPTY, value, String.format("%c%s%c", quote, value, quote), null, JavaType.Primitive.String));
Copy link
Contributor

Choose a reason for hiding this comment

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

Would we not want to retain any original formatting and comments by using withValue and withValueSource instead?

@sgartner03
Copy link

Hey @timtebeek ! Thank you for your extensive feedback. This is really valuable for me - so far I've only developed InHouse-Recipes for one Repo, where I didn't focus on clean code a lot.

Yes, you're right, this is intended for Jenkinsfiles on our end. We thought, it could be used in other Groovy Use-Cases too.

Initially, we thought we could decide between GString / J.String by using instanceof on mapEntry#getValue. However, we did notice that through all our tests, only J.Strings exist. Meaning, ", as well as ' quotes are represented by J.String. But I've removed extractQuoting() and replaced it by filtering through J.Literal#getType and just replacing the old value inside of J.Literal#getValueSource with the new one. This also replaced the constructor-call with just ".with*"-Operations.

However, I'm not that sure about using a MethodMatcher. I have to point out, that my groovy knowledge is close to zero. But how can types even be used in terms of stuff like a Jenkinsfile or other groovy stuff? You've mentioned other established ways to limit the scope, what would these be? And can't limiting the scope be implemented with a precondition on the user's end?

(PS I didn't mean to stress - I just forgot to ping you on the initial message)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
recipe Requested Recipe
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

4 participants