Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 29 additions & 41 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,62 @@ on:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
issues:
types: [opened, assigned]

jobs:
check-team-membership:
claude:
# Only run if @claude is mentioned in the triggering content
# For issues (opened/assigned), checks the issue body or title
# For comments/reviews, checks the comment/review body
if: contains(github.event.comment.body || github.event.review.body || github.event.issue.body || github.event.issue.title || '', '@claude')
runs-on: ubuntu-latest
outputs:
is-team-member: ${{ steps.check-membership.outputs.is-member }}
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
steps:
- name: Check team membership
id: check-membership
uses: actions/github-script@v8
with:
script: |
try {
// Get username - prioritize sender (the person who triggered the event)
const username = github.event?.sender?.login ||
github.event?.comment?.user?.login;

// Get the user who triggered the event
const username = context.payload.sender?.login;

if (!username) {
console.log('Could not determine username from event payload');
console.log(`Event type: ${github.event_name}`);
console.log(`Event payload keys: ${Object.keys(github.event).join(', ')}`);
return false;
core.setFailed('Could not determine username from event');
return;
}

console.log(`Checking team membership for user: ${username} (triggered by ${github.event_name} event)`);

console.log(`Checking if ${username} is a member of diffplug/spotless`);
const { data } = await github.rest.teams.getMembershipForUserInOrg({
org: 'diffplug',
team_slug: 'spotless',
username: username
});
console.log(`User ${username} membership status: ${data.state}`);
return data.state === 'active';

if (data.state !== 'active') {
core.setFailed(`User ${username} is not an active team member`);
} else {
console.log(`✓ ${username} is an active team member`);
}
} catch (error) {
const username = github.event.sender?.login || github.event.comment?.user?.login || 'unknown user';
console.log(`User ${username} is not a member of the Spotless team or error occurred: ${error.message}`);
return false;
// User is not a team member or API error
core.setFailed(`Access denied: ${error.message}`);
}

claude:
needs: check-team-membership
if: |
needs.check-team-membership.outputs.is-team-member == 'true' &&
(
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
46 changes: 6 additions & 40 deletions gradle/rewrite.gradle
Original file line number Diff line number Diff line change
@@ -1,46 +1,10 @@
apply plugin: 'org.openrewrite.rewrite'

rewrite {
activeRecipe(
'org.openrewrite.gradle.GradleBestPractices',
'org.openrewrite.java.RemoveUnusedImports',
'org.openrewrite.java.format.RemoveTrailingWhitespace',
'org.openrewrite.java.migrate.UpgradeToJava17',
'org.openrewrite.java.recipes.JavaRecipeBestPractices',
'org.openrewrite.java.recipes.RecipeTestingBestPractices',
'org.openrewrite.java.security.JavaSecurityBestPractices',
'org.openrewrite.staticanalysis.EqualsAvoidsNull',
'org.openrewrite.staticanalysis.JavaApiBestPractices',
'org.openrewrite.staticanalysis.LowercasePackage',
'org.openrewrite.staticanalysis.MissingOverrideAnnotation',
'org.openrewrite.staticanalysis.ModifierOrder',
'org.openrewrite.staticanalysis.NoFinalizer',
'org.openrewrite.staticanalysis.NoToStringOnStringType',
'org.openrewrite.staticanalysis.NoValueOfOnStringType',
'org.openrewrite.staticanalysis.RemoveUnusedLocalVariables',
'org.openrewrite.staticanalysis.RemoveUnusedPrivateFields',
'org.openrewrite.staticanalysis.RemoveUnusedPrivateMethods',
'org.openrewrite.staticanalysis.UnnecessaryCloseInTryWithResources',
'org.openrewrite.staticanalysis.UnnecessaryExplicitTypeArguments',
'org.openrewrite.staticanalysis.UnnecessaryParentheses',
'org.openrewrite.staticanalysis.UnnecessaryReturnAsLastStatement',
'tech.picnic.errorprone.refasterrules.BigDecimalRulesRecipes',
'tech.picnic.errorprone.refasterrules.CharSequenceRulesRecipes',
'tech.picnic.errorprone.refasterrules.ClassRulesRecipes',
'tech.picnic.errorprone.refasterrules.CollectionRulesRecipes',
'tech.picnic.errorprone.refasterrules.ComparatorRulesRecipes',
'tech.picnic.errorprone.refasterrules.FileRulesRecipes',
'tech.picnic.errorprone.refasterrules.MicrometerRulesRecipes',
'tech.picnic.errorprone.refasterrules.PatternRulesRecipes',
'tech.picnic.errorprone.refasterrules.PreconditionsRulesRecipes',
'tech.picnic.errorprone.refasterrules.PrimitiveRulesRecipes',
'tech.picnic.errorprone.refasterrules.StreamRulesRecipes',
'tech.picnic.errorprone.refasterrules.TimeRulesRecipes'
//'org.openrewrite.staticanalysis.CodeCleanup', bug
//'org.openrewrite.staticanalysis.CommonStaticAnalysis', bug
//'org.openrewrite.staticanalysis.UnnecessaryThrows', bug
)
activeRecipe('com.diffplug.spotless.openrewrite.SanityCheck')
exclusions.addAll(
'**.dirty.java',
'**FormatterProperties.java',
'**_gradle_node_plugin_example_**',
'**gradle/changelog.gradle',
'**gradle/java-publish.gradle',
Expand All @@ -50,7 +14,9 @@ rewrite {
'**lib/build.gradle',
'**package-info.java',
'**plugin-maven/build.gradle',
'**settings.gradle'
'**settings.gradle',
'**special-tests.gradle',
'**testlib/src/main/resources**'
)
exportDatatables = true
failOnDryRunResults = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2025 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -130,15 +130,15 @@ public boolean errorsDetected() {
synchronized (GroovyLogManager.manager) {
GroovyLogManager.manager.removeLogger(this);
}
return 0 != errors.size();
return !errors.isEmpty();
}

@Override
public String toString() {
StringBuilder string = new StringBuilder();
if (1 < errors.size()) {
string.append("Multiple problems detected during step execution:");
} else if (0 == errors.size()) {
} else if (errors.isEmpty()) {
string.append("Step sucesfully executed.");
}
for (Throwable error : errors) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,23 +164,26 @@ private int category(BodyDeclaration bodyDeclaration) {
return CONSTRUCTORS_INDEX;
}
int flags = method.getModifiers();
if (Modifier.isStatic(flags))
if (Modifier.isStatic(flags)) {
return STATIC_METHODS_INDEX;
else
} else {
return METHOD_INDEX;
}
}
case ASTNode.FIELD_DECLARATION: {
if (JdtFlags.isStatic(bodyDeclaration))
if (JdtFlags.isStatic(bodyDeclaration)) {
return STATIC_FIELDS_INDEX;
else
} else {
return FIELDS_INDEX;
}
}
case ASTNode.INITIALIZER: {
int flags = bodyDeclaration.getModifiers();
if (Modifier.isStatic(flags))
if (Modifier.isStatic(flags)) {
return STATIC_INIT_INDEX;
else
} else {
return INIT_INDEX;
}
}
case ASTNode.TYPE_DECLARATION:
case ASTNode.ENUM_DECLARATION:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024 DiffPlug
* Copyright 2024-2025 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,7 +33,7 @@
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.internal.core.SortElementsOperation;

public class EclipseJdtSortMembers {
public final class EclipseJdtSortMembers {

private static final Pattern PATTERN_DO_NOT_SORT_FIELDS = Pattern.compile("@SortMembers:doNotSortFields\\s*=\\s*(false|true)");
private static final Pattern PATTERN_ENABLED = Pattern.compile("@SortMembers:enabled\\s*=\\s*(false|true)");
Expand Down Expand Up @@ -244,4 +244,6 @@ static SortProperties from(Map<String, String> properties) {
return new SortProperties(enabled, membersOrder, doNotSortFields, sortByVisibility, visibilityOrder);
}
}

private EclipseJdtSortMembers() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,26 @@
/**
* This class is derived and adapted code from the Eclipse JDT project (Derivative Works according to EPL 2.0 license).
*/
class JdtFlags {
final class JdtFlags {

static final int VISIBILITY_CODE_INVALID = -1;

static boolean isStatic(BodyDeclaration bodyDeclaration) {
if (isNestedInterfaceOrAnnotation(bodyDeclaration))
if (isNestedInterfaceOrAnnotation(bodyDeclaration)) {
return true;
}
int nodeType = bodyDeclaration.getNodeType();
if (nodeType != ASTNode.METHOD_DECLARATION
&& nodeType != ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION
&& isInterfaceOrAnnotationMember(bodyDeclaration))
&& isInterfaceOrAnnotationMember(bodyDeclaration)) {
return true;
if (bodyDeclaration instanceof EnumConstantDeclaration)
}
if (bodyDeclaration instanceof EnumConstantDeclaration) {
return true;
if (bodyDeclaration instanceof EnumDeclaration && bodyDeclaration.getParent() instanceof AbstractTypeDeclaration)
}
if (bodyDeclaration instanceof EnumDeclaration && bodyDeclaration.getParent() instanceof AbstractTypeDeclaration) {
return true;
}
return Modifier.isStatic(bodyDeclaration.getModifiers());
}

Expand All @@ -60,8 +64,9 @@ private static boolean isProtected(BodyDeclaration bodyDeclaration) {
}

private static boolean isPublic(BodyDeclaration bodyDeclaration) {
if (isInterfaceOrAnnotationMember(bodyDeclaration))
if (isInterfaceOrAnnotationMember(bodyDeclaration)) {
return true;
}
return Modifier.isPublic(bodyDeclaration.getModifiers());
}

Expand All @@ -80,15 +85,18 @@ private static boolean isNestedInterfaceOrAnnotation(BodyDeclaration bodyDeclara
}

static int getVisibilityCode(BodyDeclaration bodyDeclaration) {
if (isPublic(bodyDeclaration))
if (isPublic(bodyDeclaration)) {
return Modifier.PUBLIC;
else if (isProtected(bodyDeclaration))
} else if (isProtected(bodyDeclaration)) {
return Modifier.PROTECTED;
else if (isPackageVisible(bodyDeclaration))
} else if (isPackageVisible(bodyDeclaration)) {
return Modifier.NONE;
else if (isPrivate(bodyDeclaration))
} else if (isPrivate(bodyDeclaration)) {
return Modifier.PRIVATE;
}
Assert.isTrue(false);
return VISIBILITY_CODE_INVALID;
}

private JdtFlags() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ public EclipseBasedStepBuilder(String formatterName, String formatterStepExt, Pr

/** Returns the FormatterStep (whose state will be calculated lazily). */
public FormatterStep build() {
var roundtrippableState = new EclipseStep(formatterVersion, formatterStepExt, FileSignature.promise(settingsFiles), JarState.promise(() -> {
return JarState.withoutTransitives(dependencies, jarProvisioner);
}));
var roundtrippableState = new EclipseStep(formatterVersion, formatterStepExt, FileSignature.promise(settingsFiles), JarState.promise(() -> JarState.withoutTransitives(dependencies, jarProvisioner)));
return FormatterStep.create(formatterName + formatterStepExt, roundtrippableState,
EclipseStep::state, stateToFormatter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public abstract class EquoBasedStepBuilder {
private File cacheDirectory;

/** Initialize valid default configuration, taking latest version */
public EquoBasedStepBuilder(
protected EquoBasedStepBuilder(
String formatterName,
Provisioner mavenProvisioner,
@Nullable String defaultVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,15 @@ public String endingFor(File file) {

static class RuntimeInit {
/** /etc/gitconfig (system-global), ~/.gitconfig (each might-not exist). */
final FileBasedConfig systemConfig, userConfig;
final FileBasedConfig systemConfig;
final FileBasedConfig userConfig;

/** Repository specific config, can be $GIT_COMMON_DIR/config, project/.git/config or .git/worktrees/<id>/config.worktree if enabled by extension */
final Config repoConfig;

/** Global .gitattributes file pointed at by systemConfig or userConfig, and the file in the repo. */
final @Nullable File globalAttributesFile, repoAttributesFile;
final @Nullable File globalAttributesFile;
final @Nullable File repoAttributesFile;

/** git worktree root, might not exist if we're not in a git repo. */
final @Nullable File workTree;
Expand Down Expand Up @@ -235,7 +237,7 @@ private Runtime atRuntime() {
}

/** https://github.com/git/git/blob/1fe8f2cf461179c41f64efbd1dc0a9fb3b7a0fb1/Documentation/gitattributes.txt */
static class Runtime {
static final class Runtime {
/** .git/info/attributes (and the worktree with that file) */
final List<AttributesRule> infoRules;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public boolean isClean(Project project, ObjectId treeSha, File file) throws IOEx
return isClean(project, treeSha, relativePath);
}

private Map<Repository, DirCache> dirCaches = new HashMap<>();
private final Map<Repository, DirCache> dirCaches = new HashMap<>();

/**
* This is the highest-level method, which all the others serve. Given the sha
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 DiffPlug
* Copyright 2020-2025 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -202,7 +202,7 @@ private static IOException emptyFile(File commonDir) {
return new IOException("Empty 'commondir' file: " + commonDir.getAbsolutePath());
}

@SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
@SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
@Override
public FileRepositoryBuilder readEnvironment(SystemReader sr) {
super.readEnvironment(sr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ protected P2Model model(String version) {
"org.codehaus.groovy.eclipse.core",
"org.eclipse.jdt.groovy.core",
"org.codehaus.groovy"));
model.addFilterAndValidate("no-debug", filter -> {
filter.exclude("org.eclipse.jdt.debug");
});
model.addFilterAndValidate("no-debug", filter -> filter.exclude("org.eclipse.jdt.debug"));
// work around https://github.com/groovy/groovy-eclipse/issues/1617
model.useMavenCentral = false;
return model;
Expand Down
Loading
Loading