-
Notifications
You must be signed in to change notification settings - Fork 1
chore: add JetBrains auto-approval compliance linter #139
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
Merged
+379
β1
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
name: JetBrains Auto-Approval Compliance | ||
|
||
on: | ||
push: | ||
branches: [ main, develop ] | ||
pull_request: | ||
branches: [ main, develop ] | ||
|
||
jobs: | ||
compliance-check: | ||
runs-on: ubuntu-latest | ||
name: JetBrains Compliance Linting | ||
|
||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up JDK 21 | ||
uses: actions/setup-java@v4 | ||
with: | ||
java-version: '21' | ||
distribution: 'temurin' | ||
|
||
- name: Cache Gradle packages | ||
uses: actions/cache@v4 | ||
with: | ||
path: | | ||
~/.gradle/caches | ||
~/.gradle/wrapper | ||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
restore-keys: | | ||
${{ runner.os }}-gradle- | ||
|
||
- name: Make gradlew executable | ||
run: chmod +x ./gradlew | ||
|
||
- name: Run JetBrains Compliance Checks | ||
run: | | ||
echo "Running JetBrains auto-approval compliance checks with detekt..." | ||
./gradlew detekt | ||
|
||
- name: Upload detekt reports | ||
uses: actions/upload-artifact@v4 | ||
if: always() | ||
with: | ||
name: detekt-reports | ||
path: | | ||
build/reports/detekt/ | ||
retention-days: 30 | ||
|
||
- name: Comment PR with compliance status | ||
if: github.event_name == 'pull_request' && failure() | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
github.rest.issues.createComment({ | ||
issue_number: context.issue.number, | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
body: 'β οΈ **JetBrains Auto-Approval Compliance Check Failed**\n\n' + | ||
'This PR contains code that violates JetBrains auto-approval requirements:\n\n' + | ||
'- β Do **not** use forbidden Kotlin experimental APIs\n' + | ||
'- β Do **not** add lambdas, handlers, or class handles to Java runtime hooks\n' + | ||
'- β Do **not** create threads manually (use coroutines or ensure cleanup in `CoderRemoteProvider#close()`)\n' + | ||
'- β Do **not** bundle libraries already provided by Toolbox\n' + | ||
'- β Do **not** perform ill-intentioned actions\n\n' + | ||
'Please check the workflow logs for detailed violations and fix them before merging.' | ||
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# JetBrains Auto-Approval Compliance | ||
|
||
This document describes the linting setup to ensure compliance with JetBrains auto-approval requirements for Toolbox plugins. | ||
|
||
## Overview | ||
|
||
JetBrains has enabled auto-approval for this plugin, which requires following specific guidelines to maintain the approval status. This repository includes automated checks to ensure compliance. | ||
|
||
## Requirements | ||
|
||
Based on communication with JetBrains team, the following requirements must be met: | ||
|
||
### β Allowed | ||
- **Coroutines**: Use `coroutineScope.launch` for concurrent operations | ||
- **Library-managed threads**: Libraries like OkHttp with their own thread pools are acceptable | ||
- **Some experimental coroutines APIs**: `kotlinx.coroutines.selects.select` and `kotlinx.coroutines.selects.onTimeout` are acceptable | ||
- **Proper cleanup**: Ensure resources are released in `CoderRemoteProvider#close()` method | ||
|
||
### β Forbidden | ||
- **Kotlin experimental APIs**: Core Kotlin experimental APIs (not coroutines-specific ones) | ||
- **Java runtime hooks**: No lambdas, handlers, or class handles to Java runtime hooks | ||
- **Manual thread creation**: Avoid `Thread()`, `Executors.new*()`, `ThreadPoolExecutor`, etc. | ||
- **Bundled libraries**: Don't bundle libraries already provided by Toolbox | ||
- **Ill-intentioned actions**: No malicious or harmful code | ||
|
||
## Linting Setup | ||
|
||
### JetBrains Compliance with Detekt | ||
|
||
The primary compliance checking is done using Detekt with custom configuration in `detekt.yml`: | ||
|
||
```bash | ||
./gradlew detekt | ||
``` | ||
|
||
This configuration includes JetBrains-specific rules that check for: | ||
- **ForbiddenAnnotation**: Detects forbidden experimental API usage | ||
- **ForbiddenMethodCall**: Detects Java runtime hooks and manual thread creation | ||
- **ForbiddenImport**: Detects potentially bundled libraries | ||
- **Standard code quality rules**: Complexity, naming, performance, etc. | ||
|
||
|
||
|
||
## CI/CD Integration | ||
|
||
The GitHub Actions workflow `.github/workflows/jetbrains-compliance.yml` runs compliance checks on every PR and push. | ||
|
||
## Running Locally | ||
|
||
```bash | ||
# Run JetBrains compliance and code quality check | ||
./gradlew detekt | ||
|
||
# View HTML report | ||
open build/reports/detekt/detekt.html | ||
``` | ||
|
||
|
||
|
||
## Understanding Results | ||
|
||
### Compliance Check Results | ||
|
||
- **β No critical violations**: Code complies with JetBrains requirements | ||
- **β Critical violations**: Must be fixed before auto-approval | ||
- **β οΈ Warnings**: Should be reviewed but may be acceptable | ||
|
||
### Common Warnings | ||
|
||
1. **Manual thread creation**: If you see warnings about thread creation: | ||
- Prefer coroutines: `coroutineScope.launch { ... }` | ||
- If using libraries with threads, ensure cleanup in `close()` | ||
|
||
2. **Library imports**: If you see warnings about library imports: | ||
- Verify the library isn't bundled in the final plugin | ||
- Check that Toolbox doesn't already provide the library | ||
|
||
3. **GlobalScope usage**: If you see warnings about `GlobalScope`: | ||
- Use the coroutine scope provided by Toolbox instead | ||
|
||
## Resources | ||
|
||
- [JetBrains Toolbox Plugin Development](https://plugins.jetbrains.com/docs/toolbox/) | ||
- [Detekt Documentation](https://detekt.dev/) | ||
- [Kotlin Coroutines Guide](https://kotlinlang.org/docs/coroutines-guide.html) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
# Detekt configuration for JetBrains Toolbox Plugin Auto-Approval Compliance | ||
# Based on clarified requirements from JetBrains team | ||
|
||
build: | ||
maxIssues: 1000 # Allow many issues for code quality reporting | ||
excludeCorrectable: false | ||
|
||
config: | ||
validation: true | ||
warningsAsErrors: false # Don't treat warnings as errors | ||
checkExhaustiveness: false | ||
|
||
# CRITICAL: JetBrains Compliance Rules using detekt built-in rules | ||
style: | ||
active: true | ||
|
||
# JetBrains Auto-Approval Compliance: Forbidden experimental annotations | ||
ForbiddenAnnotation: | ||
active: true | ||
annotations: | ||
- reason: 'Forbidden for JetBrains auto-approval: Core Kotlin experimental APIs are not allowed' | ||
value: 'kotlin.ExperimentalStdlibApi' | ||
- reason: 'Forbidden for JetBrains auto-approval: Core Kotlin experimental APIs are not allowed' | ||
value: 'kotlin.ExperimentalUnsignedTypes' | ||
- reason: 'Forbidden for JetBrains auto-approval: Core Kotlin experimental APIs are not allowed' | ||
value: 'kotlin.contracts.ExperimentalContracts' | ||
- reason: 'Forbidden for JetBrains auto-approval: Core Kotlin experimental APIs are not allowed' | ||
value: 'kotlin.experimental.ExperimentalTypeInference' | ||
- reason: 'Forbidden for JetBrains auto-approval: Internal coroutines APIs should be avoided' | ||
value: 'kotlinx.coroutines.InternalCoroutinesApi' | ||
- reason: 'Forbidden for JetBrains auto-approval: Experimental time APIs are not allowed' | ||
value: 'kotlin.time.ExperimentalTime' | ||
# Note: ExperimentalCoroutinesApi, DelicateCoroutinesApi, FlowPreview are acceptable | ||
# based on JetBrains feedback about select/onTimeout being OK | ||
|
||
# JetBrains Auto-Approval Compliance: Forbidden method calls | ||
ForbiddenMethodCall: | ||
active: true | ||
methods: | ||
# Java runtime hooks - forbidden | ||
- reason: 'Forbidden for JetBrains auto-approval: Java runtime hooks are not allowed' | ||
value: 'java.lang.Runtime.addShutdownHook' | ||
- reason: 'Forbidden for JetBrains auto-approval: Java runtime hooks are not allowed' | ||
value: 'java.lang.System.setSecurityManager' | ||
- reason: 'Forbidden for JetBrains auto-approval: Java runtime hooks are not allowed' | ||
value: 'java.lang.Thread.setUncaughtExceptionHandler' | ||
- reason: 'Forbidden for JetBrains auto-approval: Java runtime hooks are not allowed' | ||
value: 'java.lang.Thread.setDefaultUncaughtExceptionHandler' | ||
# Manual thread creation - warnings (allowed with proper cleanup) | ||
- reason: 'Warning for JetBrains auto-approval: Manual thread creation detected. Consider using coroutineScope.launch or ensure proper cleanup in CoderRemoteProvider#close()' | ||
value: 'java.lang.Thread.<init>' | ||
- reason: 'Warning for JetBrains auto-approval: Manual thread creation detected. Consider using coroutineScope.launch or ensure proper cleanup in CoderRemoteProvider#close()' | ||
value: 'java.util.concurrent.Executors.newFixedThreadPool' | ||
- reason: 'Warning for JetBrains auto-approval: Manual thread creation detected. Consider using coroutineScope.launch or ensure proper cleanup in CoderRemoteProvider#close()' | ||
value: 'java.util.concurrent.Executors.newCachedThreadPool' | ||
- reason: 'Warning for JetBrains auto-approval: Manual thread creation detected. Consider using coroutineScope.launch or ensure proper cleanup in CoderRemoteProvider#close()' | ||
value: 'java.util.concurrent.Executors.newSingleThreadExecutor' | ||
- reason: 'Warning for JetBrains auto-approval: Manual thread creation detected. Consider using coroutineScope.launch or ensure proper cleanup in CoderRemoteProvider#close()' | ||
value: 'java.util.concurrent.CompletableFuture.runAsync' | ||
- reason: 'Warning for JetBrains auto-approval: Manual thread creation detected. Consider using coroutineScope.launch or ensure proper cleanup in CoderRemoteProvider#close()' | ||
value: 'java.util.concurrent.CompletableFuture.supplyAsync' | ||
|
||
# JetBrains Auto-Approval Compliance: Forbidden imports | ||
ForbiddenImport: | ||
active: true | ||
imports: | ||
# Potentially bundled libraries - warnings | ||
- reason: 'Warning for JetBrains auto-approval: Ensure slf4j is not bundled - it is provided by Toolbox' | ||
value: 'org.slf4j.*' | ||
- reason: 'Warning for JetBrains auto-approval: Ensure annotations library is not bundled - it is provided by Toolbox' | ||
value: 'org.jetbrains.annotations.*' | ||
# Runtime hook classes - forbidden | ||
- reason: 'Forbidden for JetBrains auto-approval: Runtime hook classes are not allowed' | ||
value: 'java.lang.Runtime' | ||
- reason: 'Forbidden for JetBrains auto-approval: Security manager modifications are not allowed' | ||
value: 'java.security.SecurityManager' | ||
|
||
# Other important style rules | ||
MagicNumber: | ||
active: true | ||
ignoreNumbers: | ||
- '-1' | ||
- '0' | ||
- '1' | ||
- '2' | ||
ignoreHashCodeFunction: true | ||
ignorePropertyDeclaration: false | ||
ignoreLocalVariableDeclaration: false | ||
ignoreConstantDeclaration: true | ||
ignoreCompanionObjectPropertyDeclaration: true | ||
ignoreAnnotation: false | ||
ignoreNamedArgument: true | ||
ignoreEnums: false | ||
ignoreRanges: false | ||
ignoreExtensionFunctions: true | ||
|
||
MaxLineLength: | ||
active: true | ||
maxLineLength: 120 | ||
excludePackageStatements: true | ||
excludeImportStatements: true | ||
excludeCommentStatements: false | ||
|
||
NewLineAtEndOfFile: | ||
active: true | ||
|
||
WildcardImport: | ||
active: true | ||
|
||
# Essential built-in rules for basic code quality | ||
complexity: | ||
active: true | ||
CyclomaticComplexMethod: | ||
active: true | ||
threshold: 15 | ||
LongMethod: | ||
active: true | ||
threshold: 60 | ||
LongParameterList: | ||
active: true | ||
functionThreshold: 6 | ||
constructorThreshold: 7 | ||
NestedBlockDepth: | ||
active: true | ||
threshold: 4 | ||
|
||
coroutines: | ||
active: true | ||
GlobalCoroutineUsage: | ||
active: true | ||
RedundantSuspendModifier: | ||
active: true | ||
SleepInsteadOfDelay: | ||
active: true | ||
|
||
exceptions: | ||
active: true | ||
ExceptionRaisedInUnexpectedLocation: | ||
active: true | ||
ObjectExtendsThrowable: | ||
active: true | ||
PrintStackTrace: | ||
active: true | ||
ReturnFromFinally: | ||
active: true | ||
SwallowedException: | ||
active: true | ||
ThrowingExceptionFromFinally: | ||
active: true | ||
ThrowingExceptionsWithoutMessageOrCause: | ||
active: true | ||
TooGenericExceptionCaught: | ||
active: true | ||
TooGenericExceptionThrown: | ||
active: true | ||
|
||
naming: | ||
active: true | ||
ClassNaming: | ||
active: true | ||
classPattern: '[A-Z][a-zA-Z0-9]*' | ||
FunctionNaming: | ||
active: true | ||
functionPattern: '[a-z][a-zA-Z0-9]*' | ||
PackageNaming: | ||
active: true | ||
packagePattern: '[a-z]+(\.?[a-z][A-Za-z0-9]*)*' | ||
VariableNaming: | ||
active: true | ||
variablePattern: '[a-z][A-Za-z0-9]*' | ||
|
||
performance: | ||
active: true | ||
ArrayPrimitive: | ||
active: true | ||
ForEachOnRange: | ||
active: true | ||
SpreadOperator: | ||
active: true | ||
UnnecessaryTemporaryInstantiation: | ||
active: true | ||
|
||
potential-bugs: | ||
active: true | ||
EqualsAlwaysReturnsTrueOrFalse: | ||
active: true | ||
EqualsWithHashCodeExist: | ||
active: true | ||
ExplicitGarbageCollectionCall: | ||
active: true | ||
HasPlatformType: | ||
active: true | ||
InvalidRange: | ||
active: true | ||
UnreachableCatchBlock: | ||
active: true | ||
UnreachableCode: | ||
active: true | ||
UnsafeCallOnNullableType: | ||
active: true | ||
UnsafeCast: | ||
active: true | ||
WrongEqualsTypeParameter: | ||
active: true |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Minor: we can do a static import here.