Skip to content

Commit

Permalink
feat: Created recipe to add property comment (#4723)
Browse files Browse the repository at this point in the history
* feat: Created recipe to add property comment

Refs: #4722

* feat: Improved return value

Refs: #4722

* feat: Added option to comment out property

Refs: #4722

* Minor polish

* Move commenting to visitEntry

* Use ListUtils.flatMap to prevent new allocation

---------

Co-authored-by: Andrei Shakirin <[email protected]>
Co-authored-by: Tim te Beek <[email protected]>
  • Loading branch information
3 people authored Nov 27, 2024
1 parent 6bb23d4 commit 860631f
Show file tree
Hide file tree
Showing 2 changed files with 301 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.properties;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.*;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.marker.Markers;
import org.openrewrite.properties.search.FindProperties;
import org.openrewrite.properties.tree.Properties;

import java.util.Arrays;
import java.util.function.Function;

import static org.openrewrite.Tree.randomId;

@Value
@EqualsAndHashCode(callSuper = false)
public class AddPropertyComment extends Recipe {

@Option(displayName = "Property key",
description = "The name of the property to add comment.",
example = "management.metrics.binders")
String propertyKey;

@Option(example = "comment", displayName = "Comment",
description = "The comment to be added.")
String comment;

@Option(example = "true", displayName = "Comment out property",
description = "If true, property will be commented out.",
required = false)
@Nullable
Boolean commentOutProperty;

@Override
public String getDisplayName() {
return "Add comment before property key";
}

@Override
public String getDescription() {
return "Add a new comment before a property key if not already present, optionally commenting out the property.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
PropertiesVisitor<ExecutionContext> propertiesVisitor = new PropertiesVisitor<ExecutionContext>() {
@Override
public Properties visitFile(Properties.File file, ExecutionContext ctx) {
Properties.File p = file.withContent(ListUtils.flatMap(file.getContent(), new Function<Properties.Content, Object>() {
Properties.@Nullable Content previousContent = null;

@Override
public Object apply(Properties.Content c) {
if (c instanceof Properties.Entry &&
((Properties.Entry) c).getKey().equals(propertyKey) &&
!isCommentAlreadyPresent(previousContent, comment)) {
Properties.Comment commentContent = new Properties.Comment(
randomId(),
previousContent == null ? "" : "\n",
Markers.EMPTY,
Properties.Comment.Delimiter.HASH_TAG,
" " + comment.trim());
previousContent = c;
return Arrays.asList(commentContent, c.getPrefix().contains("\n") ?
c : c.withPrefix("\n" + c.getPrefix()));
}
previousContent = c;
return c;
}
}
));
return super.visitFile(p, ctx);
}

@Override
public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) {
if (Boolean.TRUE.equals(commentOutProperty) && entry.getKey().equals(propertyKey)) {
return new Properties.Comment(
randomId(),
entry.getPrefix(),
entry.getMarkers(),
Properties.Comment.Delimiter.HASH_TAG,
" " + entry.printTrimmed(getCursor()));
}
return super.visitEntry(entry, ctx);
}
};
return Preconditions.check(new FindProperties(propertyKey, false).getVisitor(), propertiesVisitor);
}

private boolean isCommentAlreadyPresent(Properties.@Nullable Content previousContent, String comment) {
return previousContent instanceof Properties.Comment &&
((Properties.Comment) previousContent).getMessage().contains(comment.trim());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.properties;

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.properties.Assertions.properties;

class AddPropertyCommentTest implements RewriteTest {

@DocumentExample
@Test
void shouldAddCommentToFirstProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
false
)),
properties(
"""
management.metrics.enable.process.files=true
yyy=true
""",
"""
# myComment
management.metrics.enable.process.files=true
yyy=true
"""
)
);
}

@Test
void shouldAddCommentToMiddleProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
false
)),
properties(
"""
xxx=true
management.metrics.enable.process.files=true
yyy=true
""",
"""
xxx=true
# myComment
management.metrics.enable.process.files=true
yyy=true
"""
)
);
}

@Test
void shouldAcceptExistingComment() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
false
)),
properties(
"""
# myComment
management.metrics.enable.process.files=true
"""
)
);
}

@Test
void shouldSkipNotExistingProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"xxx",
"myComment",
false
)),
properties(
"""
yyy=true
"""
)
);
}

@Test
void shouldCommentOutFirstProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
true
)),
properties(
"""
management.metrics.enable.process.files=true
yyy=true
""",
"""
# myComment
# management.metrics.enable.process.files=true
yyy=true
"""
)
);
}

@Test
void shouldCommentOutMiddleProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
true
)),
properties(
"""
xxx=true
management.metrics.enable.process.files=true
yyy=true
""",
"""
xxx=true
# myComment
# management.metrics.enable.process.files=true
yyy=true
"""
)
);
}

@Test
void shouldAcceptExistingCommentAndCommentOutProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
true
)),
properties(
"""
# myComment
management.metrics.enable.process.files=true
""",
"""
# myComment
# management.metrics.enable.process.files=true
"""
)
);
}

@Test
void shouldASkipCommentOutProperty() {
rewriteRun(
spec -> spec.recipe(new AddPropertyComment(
"management.metrics.enable.process.files",
"myComment",
true
)),
properties(
"""
# myComment
# management.metrics.enable.process.files=true
"""
)
);
}
}

0 comments on commit 860631f

Please sign in to comment.