From 084b4a2695363b49f7ad6ce08223d7d49393e672 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:08:29 +0200 Subject: [PATCH 01/22] Fix CLI usage via fat jar --- README.md | 2 +- build.gradle | 13 ++++++++++++- settings.gradle | 3 +-- .../{Executor.groovy => CLIRunner.groovy} | 6 +++--- src/test/resources/linter.yaml | 18 ++++++++++++++++++ 5 files changed, 35 insertions(+), 7 deletions(-) rename src/main/groovy/graphql/linter/{Executor.groovy => CLIRunner.groovy} (85%) create mode 100644 src/test/resources/linter.yaml diff --git a/README.md b/README.md index 4a1ed1d..be1747f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Version](https://badge.fury.io/gh/kirpi4ik%2Fgraphql-java-linter.svg)](https://badge.fury.io/gh/kirpi4ik%2Fgraphql-java-linter) [![GitHub Release](https://img.shields.io/github/v/release/kirpi4ik/graphql-java-linter?include_prereleases)]() [![Maven Central](https://img.shields.io/maven-central/v/org.myhab.tools/graphql-java-linter)]() -[![Nexus snapshot](https://img.shields.io/nexus/s/org.myhab.tools/graphql-java-linter?server=https%3A%2F%2Fs01.oss.sonatype.org%2F)]() +[![Nexus snapshot](https://img.shields.io/nexus/s/org.myhab.tools/graphql-java-linter?server=https%3A%2F%2Fs01.oss.sonatype.org%2F)](https://s01.oss.sonatype.org/content/repositories/snapshots/org/myhab/tools/graphql-java-linter/) ### Usage command line diff --git a/build.gradle b/build.gradle index 5fd1850..da68b15 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,21 @@ plugins { id 'groovy' id 'maven-publish' id 'signing' + id 'java' } group 'org.myhab.tools' -version '1.0' +version '1.1-SNAPSHOT' + +jar { + manifest { + attributes "Main-Class": 'graphql.linter.CLIRunner' + } + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} repositories { mavenCentral() diff --git a/settings.gradle b/settings.gradle index 69360e1..2f0c08e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1 @@ -rootProject.name = 'graphql-java-linter' - +rootProject.name = 'graphql-java-linter' \ No newline at end of file diff --git a/src/main/groovy/graphql/linter/Executor.groovy b/src/main/groovy/graphql/linter/CLIRunner.groovy similarity index 85% rename from src/main/groovy/graphql/linter/Executor.groovy rename to src/main/groovy/graphql/linter/CLIRunner.groovy index b437e80..4954738 100644 --- a/src/main/groovy/graphql/linter/Executor.groovy +++ b/src/main/groovy/graphql/linter/CLIRunner.groovy @@ -11,15 +11,15 @@ import java.nio.file.Path import java.nio.file.Paths import java.util.stream.Stream -class Executor { +class CLIRunner { static void main(String[] args) { assert args.size() > 0 - def yamlConfig = new YamlConfiguration(args.size() > 1 ? args[1] : null).config + def yamlConfig = new YamlConfiguration(args[0]).config SchemaParser schemaParser = new SchemaParser(); SchemaGenerator schemaGenerator = new SchemaGenerator(); TypeDefinitionRegistry tdr = new TypeDefinitionRegistry(); - try (Stream paths = Files.walk((Paths.get(args[0])))) { + try (Stream paths = Files.walk((Paths.get(yamlConfig.schema['local']['uri'])))) { paths.filter(Files::isRegularFile).map(Files::readString).each { tdr.merge(schemaParser.parse(it)) } diff --git a/src/test/resources/linter.yaml b/src/test/resources/linter.yaml new file mode 100644 index 0000000..f866736 --- /dev/null +++ b/src/test/resources/linter.yaml @@ -0,0 +1,18 @@ +level: WARN +failWhenExceedWarningMax: true + +schema: + local: + uri: src/test/resources/schema/ + extensions: + - "graphql" + - "graphqls" +rules: + field_name_first_lowercase: + level: WARN + disable: false + failWhenExceed: 2 + defined_types_are_used: + level: WARN + disable: false + failWhenExceed: 10 \ No newline at end of file From 66cb8409b7f32740001635525b19efc73a3c6410 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:19:13 +0200 Subject: [PATCH 02/22] test github action --- .github/workflows/gradle.yml | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/gradle.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..6917821 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,46 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Build project + +on: + push: + branches: [ v1.1 ] + +env: + QENV: production + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + with: + version: latest + - name: Builder instance name + run: echo ${{ steps.buildx.outputs.name }} + - name: Available platforms + run: echo ${{ steps.buildx.outputs.platforms }} + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: 11 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Cache Gradle packages + uses: actions/cache@v2.1.4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: graphql-java-linter + path: build/libs/*.jar From c092bdabc8f8e6c812cc09315b7f8e97c7628492 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:24:40 +0200 Subject: [PATCH 03/22] test github action --- .github/workflows/gradle.yml | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 6917821..3980033 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -16,29 +16,20 @@ jobs: runs-on: ubuntu-latest steps: - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: - version: latest - - name: Builder instance name - run: echo ${{ steps.buildx.outputs.name }} - - name: Available platforms - run: echo ${{ steps.buildx.outputs.platforms }} - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - distribution: 'zulu' + distribution: temurin java-version: 11 - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Cache Gradle packages - uses: actions/cache@v2.1.4 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: ${{ runner.os }}-gradle + gradle-version: 7.3.3 + + - name: Execute Gradle build + run: ./gradlew build + - name: Upload artifacts uses: actions/upload-artifact@v3 with: From aff606a7d8b1ea603e3bd8317f5b7dfbc9a35762 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:25:51 +0200 Subject: [PATCH 04/22] test github action --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 3980033..3d67cd0 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -28,7 +28,7 @@ jobs: gradle-version: 7.3.3 - name: Execute Gradle build - run: ./gradlew build + run: ./gradlew build - name: Upload artifacts uses: actions/upload-artifact@v3 From d8a5c0ca943290d073a260f0e39c18ebb20d35b1 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:28:13 +0200 Subject: [PATCH 05/22] test github action --- .github/workflows/gradle.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 3d67cd0..e686706 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -26,9 +26,16 @@ jobs: uses: gradle/gradle-build-action@v2 with: gradle-version: 7.3.3 - + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Cache Gradle packages + uses: actions/cache@v2.1.4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle - name: Execute Gradle build - run: ./gradlew build + run: ./gradlew clean build - name: Upload artifacts uses: actions/upload-artifact@v3 From f5902f21417df10b05356a0cfaeff47f73eb38a3 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:30:44 +0200 Subject: [PATCH 06/22] test github action --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index e686706..e68c186 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -35,7 +35,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - name: Execute Gradle build - run: ./gradlew clean build + run: ./gradlew clean build -x sign - name: Upload artifacts uses: actions/upload-artifact@v3 From ea1295a0646091c8b955bfa8d3195e2084b6260e Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 17:54:54 +0200 Subject: [PATCH 07/22] test github action --- README.md | 15 ++++++++------- build.gradle | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index be1747f..98cf005 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Maven Central](https://img.shields.io/maven-central/v/org.myhab.tools/graphql-java-linter)]() [![Nexus snapshot](https://img.shields.io/nexus/s/org.myhab.tools/graphql-java-linter?server=https%3A%2F%2Fs01.oss.sonatype.org%2F)](https://s01.oss.sonatype.org/content/repositories/snapshots/org/myhab/tools/graphql-java-linter/) -### Usage command line +### Usage 1. Create yaml configuration file E.g: `linter.yaml` @@ -38,21 +38,22 @@ rules: failWhenExceed: 10 ``` -2. Run from command line E.g: +### Command line +#### Run from command line: ```bash -java -jar graphql-java-linter-1.0.jar linter.yaml +java -jar graphql-java-linter-1.1.jar linter.yaml ``` ### In CI/CD flow via unit tests -1. Add dependency +#### Add dependency `build.gradle` ```groovy dependencies { - test 'org.myhab.tools:graphql-java-linter:1.0' + test 'org.myhab.tools:graphql-java-linter:1.1' } ``` @@ -63,12 +64,12 @@ dependencies { org.myhab.tools graphql-java-linter - 1.0 + 1.1 test ``` -junit +#### junit ```java import graphql.linter.LintRunner; diff --git a/build.gradle b/build.gradle index da68b15..43ee1d3 100644 --- a/build.gradle +++ b/build.gradle @@ -83,8 +83,8 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = mavenCentralUsername - password = mavenCentralPassword + username = !System.env.MVN_CENTRAL_USERNAME?:mavenCentralUsername + password = !System.env.MVN_CENTRAL_PASSWD?:mavenCentralPassword } } } From c29f1eea5fd2839f287c4024508c6d1b0dd7ad91 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:06:29 +0200 Subject: [PATCH 08/22] publish artifact --- .github/workflows/gradle.yml | 2 +- build.gradle | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index e68c186..2298434 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -35,7 +35,7 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - name: Execute Gradle build - run: ./gradlew clean build -x sign + run: ./gradlew clean build :publishGprPublicationToGitHubPackagesRepository - name: Upload artifacts uses: actions/upload-artifact@v3 diff --git a/build.gradle b/build.gradle index 43ee1d3..ac38d5e 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,9 @@ artifacts { } publishing { publications { + gpr(MavenPublication) { + from(components.java) + } mavenJava(MavenPublication) { groupId = project.group artifactId = rootProject.name @@ -87,6 +90,14 @@ publishing { password = !System.env.MVN_CENTRAL_PASSWD?:mavenCentralPassword } } + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/kirpi4ik/graphql-java-linter") + credentials { + username = System.getenv("GTH_USERNAME")?:gthUsername + password = System.getenv("GTH_TOKEN")?:gthPassword + } + } } } signing { From 72f7714c166e96bd9c439be79ec49c684e31f51c Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:08:17 +0200 Subject: [PATCH 09/22] publish artifact --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index ac38d5e..95a5d58 100644 --- a/build.gradle +++ b/build.gradle @@ -86,16 +86,16 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = !System.env.MVN_CENTRAL_USERNAME?:mavenCentralUsername - password = !System.env.MVN_CENTRAL_PASSWD?:mavenCentralPassword + username = !System.env.MVN_CENTRAL_USERNAME ?: mavenCentralUsername + password = !System.env.MVN_CENTRAL_PASSWD ?: mavenCentralPassword } } maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/kirpi4ik/graphql-java-linter") credentials { - username = System.getenv("GTH_USERNAME")?:gthUsername - password = System.getenv("GTH_TOKEN")?:gthPassword + username = !System.env.GTH_USERNAME ?: gthUsername + password = !System.env.GTH_TOKEN ?: gthPassword } } } From 6ef4299fb515ccde8db6219c1eadd559454f7788 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:31:34 +0200 Subject: [PATCH 10/22] publish artifact --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 95a5d58..27bd717 100644 --- a/build.gradle +++ b/build.gradle @@ -86,16 +86,16 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = !System.env.MVN_CENTRAL_USERNAME ?: mavenCentralUsername - password = !System.env.MVN_CENTRAL_PASSWD ?: mavenCentralPassword + username = mavenCentralUsername ?: System.getenv("MVN_CENTRAL_USERNAME") + password = mavenCentralPassword ?: System.getenv("MVN_CENTRAL_PASSWD") } } maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/kirpi4ik/graphql-java-linter") credentials { - username = !System.env.GTH_USERNAME ?: gthUsername - password = !System.env.GTH_TOKEN ?: gthPassword + username = gthUsername ?: System.getenv("GTH_USERNAME") + password = gthPassword ?: System.getenv("GTH_TOKEN") } } } From 65638fc4534a630c1fd297184325bcbc28cb90da Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:33:44 +0200 Subject: [PATCH 11/22] publish artifact --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 27bd717..e593e2a 100644 --- a/build.gradle +++ b/build.gradle @@ -86,8 +86,8 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = mavenCentralUsername ?: System.getenv("MVN_CENTRAL_USERNAME") - password = mavenCentralPassword ?: System.getenv("MVN_CENTRAL_PASSWD") + username = mavenCentralUsername ?: System.env.MVN_CENTRAL_USERNAME + password = mavenCentralPassword ?: System.env.MVN_CENTRAL_PASSWD } } maven { From 05097ad0aa76f8f837664bf0e776ced9ec9789c1 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:36:20 +0200 Subject: [PATCH 12/22] publish artifact --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index e593e2a..3a067ad 100644 --- a/build.gradle +++ b/build.gradle @@ -86,16 +86,16 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = mavenCentralUsername ?: System.env.MVN_CENTRAL_USERNAME - password = mavenCentralPassword ?: System.env.MVN_CENTRAL_PASSWD + username = System.env.MVN_CENTRAL_USERNAME ?: mavenCentralUsername + password = System.env.MVN_CENTRAL_PASSWD ?: mavenCentralPassword } } maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/kirpi4ik/graphql-java-linter") credentials { - username = gthUsername ?: System.getenv("GTH_USERNAME") - password = gthPassword ?: System.getenv("GTH_TOKEN") + username = System.env.GTH_USERNAME ?: gthUsername + password = System.env.GTH_TOKEN ?: gthPassword } } } From b373b9b6231b04230e6cc925ecff989f271e2505 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:41:48 +0200 Subject: [PATCH 13/22] publish artifact --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 3a067ad..bfe2d39 100644 --- a/build.gradle +++ b/build.gradle @@ -86,16 +86,16 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = System.env.MVN_CENTRAL_USERNAME ?: mavenCentralUsername - password = System.env.MVN_CENTRAL_PASSWD ?: mavenCentralPassword + username = System.env.MVN_CENTRAL_USERNAME ?: project.findProperty("mavenCentralUsername") + password = System.env.MVN_CENTRAL_PASSWD ?: project.findProperty("mavenCentralPassword") } } maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/kirpi4ik/graphql-java-linter") credentials { - username = System.env.GTH_USERNAME ?: gthUsername - password = System.env.GTH_TOKEN ?: gthPassword + username = System.env.GTH_USERNAME ?: project.findProperty("gthUsername") + password = System.env.GTH_TOKEN ?: project.findProperty("gthPassword") } } } From 902653ab00bb2b76c2e9b7a0410fca18dfcba74c Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:46:14 +0200 Subject: [PATCH 14/22] publish artifact --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index bfe2d39..dae81c4 100644 --- a/build.gradle +++ b/build.gradle @@ -86,16 +86,16 @@ publishing { def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { - username = System.env.MVN_CENTRAL_USERNAME ?: project.findProperty("mavenCentralUsername") - password = System.env.MVN_CENTRAL_PASSWD ?: project.findProperty("mavenCentralPassword") + username = project.findProperty("mavenCentralUsername") ?: System.getenv("MVN_CENTRAL_USERNAME") + password = project.findProperty("mavenCentralPassword") ?: System.getenv("MVN_CENTRAL_PASSWD") } } maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/kirpi4ik/graphql-java-linter") credentials { - username = System.env.GTH_USERNAME ?: project.findProperty("gthUsername") - password = System.env.GTH_TOKEN ?: project.findProperty("gthPassword") + username = project.findProperty("gthUsername") ?: System.getenv("GTH_USERNAME") + password = project.findProperty("gthPassword") ?: System.getenv("GTH_TOKEN") } } } From a9fd1996952148b1aa5796352870781bf3af44d2 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:52:58 +0200 Subject: [PATCH 15/22] publish artifact --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index dae81c4..30e3568 100644 --- a/build.gradle +++ b/build.gradle @@ -47,9 +47,6 @@ artifacts { } publishing { publications { - gpr(MavenPublication) { - from(components.java) - } mavenJava(MavenPublication) { groupId = project.group artifactId = rootProject.name @@ -79,6 +76,9 @@ publishing { } } } + gpr(MavenPublication) { + from(components.java) + } } repositories { maven { From aba7dd25564dd23ef5954534f826f21ef8208a3b Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 19:55:14 +0200 Subject: [PATCH 16/22] debug action --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 30e3568..a1f2058 100644 --- a/build.gradle +++ b/build.gradle @@ -85,6 +85,7 @@ publishing { def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + println "XXX: "+project.findProperty("mavenCentralUsername") ?: System.getenv("MVN_CENTRAL_USERNAME") credentials { username = project.findProperty("mavenCentralUsername") ?: System.getenv("MVN_CENTRAL_USERNAME") password = project.findProperty("mavenCentralPassword") ?: System.getenv("MVN_CENTRAL_PASSWD") From 260f1d592189a3a7bac5c43f8111d2bac539a633 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 20:01:37 +0200 Subject: [PATCH 17/22] debug action --- .github/workflows/gradle.yml | 5 +++++ build.gradle | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 2298434..49dc981 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -35,6 +35,11 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - name: Execute Gradle build + env: + MVN_CENTRAL_USERNAME: ${{ secrets.MVN_CENTRAL_USERNAME }} + MVN_CENTRAL_PASSWD: ${{ secrets.MVN_CENTRAL_PASSWD }} + GTH_USERNAME: ${{ secrets.GTH_USERNAME }} + GTH_TOKEN: ${{ secrets.GTH_TOKEN }} run: ./gradlew clean build :publishGprPublicationToGitHubPackagesRepository - name: Upload artifacts diff --git a/build.gradle b/build.gradle index a1f2058..30e3568 100644 --- a/build.gradle +++ b/build.gradle @@ -85,7 +85,6 @@ publishing { def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - println "XXX: "+project.findProperty("mavenCentralUsername") ?: System.getenv("MVN_CENTRAL_USERNAME") credentials { username = project.findProperty("mavenCentralUsername") ?: System.getenv("MVN_CENTRAL_USERNAME") password = project.findProperty("mavenCentralPassword") ?: System.getenv("MVN_CENTRAL_PASSWD") From 761c2a4e4ab617658707b90a46cce1341bcea307 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Tue, 22 Nov 2022 20:36:53 +0200 Subject: [PATCH 18/22] update cli publish --- .github/workflows/gradle.yml | 2 +- build.gradle | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 49dc981..23d8365 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -5,7 +5,7 @@ name: Build project on: push: - branches: [ v1.1 ] + branches: [ master ] env: QENV: production diff --git a/build.gradle b/build.gradle index 30e3568..b731606 100644 --- a/build.gradle +++ b/build.gradle @@ -8,14 +8,14 @@ plugins { group 'org.myhab.tools' version '1.1-SNAPSHOT' -jar { +task cliJar(type: Jar) { manifest { - attributes "Main-Class": 'graphql.linter.CLIRunner' - } - - from { - configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + attributes 'Main-Class': 'graphql.linter.CLIRunner' } + archiveBaseName = "${project.name}-cli" + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } + with jar } repositories { @@ -43,7 +43,7 @@ javadoc { } artifacts { - archives javadocJar, sourcesJar + archives javadocJar, sourcesJar, cliJar } publishing { publications { @@ -53,6 +53,10 @@ publishing { version = project.version from project.components.java + artifact cliJar{ + classifier "cli" + } + pom { name = project.name description = 'GraphQL schema linting tool' From 1ce28916aae01ef10b90055e3c2ae6d4ee95260c Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Wed, 23 Nov 2022 12:59:27 +0200 Subject: [PATCH 19/22] Add support for external DSL rules Add spock for testing --- build.gradle | 6 +- .../graphql/linter/BasicResultHandler.groovy | 2 +- .../groovy/graphql/linter/CLIRunner.groovy | 2 +- .../graphql/linter/LinterConfiguration.groovy | 2 + .../graphql/linter/ValidationExecution.groovy | 21 ++----- .../graphql/linter/YamlConfiguration.groovy | 2 - .../graphql/linter/rules/LintRule.groovy | 5 +- .../graphql/linter/rules/RuleDSL.groovy | 23 +++++++ .../graphql/linter/rules/RuleType.groovy | 6 ++ .../linter/rules/registry/Registry.groovy | 9 +++ .../linter/rules/registry/RuleContext.groovy | 4 ++ .../rules/registry/RulesRegistry.groovy | 28 +++++++++ .../registry/RulesRegistryDynamic.groovy | 61 +++++++++++++++++++ .../registry/RulesRegistryStatic.groovy} | 18 +++--- .../linter/rules/registry/ServiceUtils.groovy | 5 ++ .../graphql/linter/CLIRunnerTest.groovy | 12 ++++ .../registry/RulesRegistryDynamicSpec.groovy | 17 ++++++ src/test/resources/linter.yaml | 4 +- .../resources/rules/test_field_rule.groovy | 5 ++ 19 files changed, 197 insertions(+), 35 deletions(-) create mode 100644 src/main/groovy/graphql/linter/rules/RuleDSL.groovy create mode 100644 src/main/groovy/graphql/linter/rules/RuleType.groovy create mode 100644 src/main/groovy/graphql/linter/rules/registry/Registry.groovy create mode 100644 src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy create mode 100644 src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy create mode 100644 src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy rename src/main/groovy/graphql/linter/{RulesRegistry.groovy => rules/registry/RulesRegistryStatic.groovy} (57%) create mode 100644 src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy create mode 100644 src/test/groovy/graphql/linter/CLIRunnerTest.groovy create mode 100644 src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy create mode 100644 src/test/resources/rules/test_field_rule.groovy diff --git a/build.gradle b/build.gradle index b731606..5a8f6f0 100644 --- a/build.gradle +++ b/build.gradle @@ -27,8 +27,7 @@ dependencies { implementation 'com.graphql-java:graphql-java:19.2' implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.yaml:snakeyaml:1.33' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0' } java { @@ -110,4 +109,7 @@ signing { } test { useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } } \ No newline at end of file diff --git a/src/main/groovy/graphql/linter/BasicResultHandler.groovy b/src/main/groovy/graphql/linter/BasicResultHandler.groovy index c92652b..36eb0fa 100644 --- a/src/main/groovy/graphql/linter/BasicResultHandler.groovy +++ b/src/main/groovy/graphql/linter/BasicResultHandler.groovy @@ -20,7 +20,7 @@ class BasicResultHandler implements ResultHandler{ printf "# [ %-30s ] [ %-3d failures][%-6d runs] [%-4.3f sec/rule] #%n", ruleName, ruleWarn.size(), context.execution[ruleName]['count'], context.execution[ruleName]['time'] ruleWarn.each { error -> printf("# + %-100s #%n", error.message) } - def failWhenExceed = executionEnvironment.config['rules'][ruleName]['failWhenExceed'] + def failWhenExceed = executionEnvironment.config['rules'][ruleName as String]?['failWhenExceed'] if (executionEnvironment.config['failWhenExceedWarningMax'] && (failWhenExceed && ruleWarn.size() > failWhenExceed)) { throw new RuleValidationError("[${ruleName}] Exceeded number of failures. ${ruleWarn.size()} > ${failWhenExceed} ") } diff --git a/src/main/groovy/graphql/linter/CLIRunner.groovy b/src/main/groovy/graphql/linter/CLIRunner.groovy index 4954738..9a06ef0 100644 --- a/src/main/groovy/graphql/linter/CLIRunner.groovy +++ b/src/main/groovy/graphql/linter/CLIRunner.groovy @@ -19,7 +19,7 @@ class CLIRunner { SchemaParser schemaParser = new SchemaParser(); SchemaGenerator schemaGenerator = new SchemaGenerator(); TypeDefinitionRegistry tdr = new TypeDefinitionRegistry(); - try (Stream paths = Files.walk((Paths.get(yamlConfig.schema['local']['uri'])))) { + try (Stream paths = Files.walk(Paths.get(yamlConfig.schema['local']['uri']))) { paths.filter(Files::isRegularFile).map(Files::readString).each { tdr.merge(schemaParser.parse(it)) } diff --git a/src/main/groovy/graphql/linter/LinterConfiguration.groovy b/src/main/groovy/graphql/linter/LinterConfiguration.groovy index 9245ebc..6aa1bbb 100644 --- a/src/main/groovy/graphql/linter/LinterConfiguration.groovy +++ b/src/main/groovy/graphql/linter/LinterConfiguration.groovy @@ -5,4 +5,6 @@ class LinterConfiguration { boolean failWhenExceedWarningMax = false def schema def rules = [String: [:]] + private registry = [:] + } diff --git a/src/main/groovy/graphql/linter/ValidationExecution.groovy b/src/main/groovy/graphql/linter/ValidationExecution.groovy index 8d5da11..0d7d993 100644 --- a/src/main/groovy/graphql/linter/ValidationExecution.groovy +++ b/src/main/groovy/graphql/linter/ValidationExecution.groovy @@ -1,19 +1,16 @@ package graphql.linter -import graphql.linter.exception.RuleValidationError +import graphql.linter.rules.registry.RulesRegistry import graphql.schema.* import groovy.time.TimeCategory class ValidationExecution { RulesRegistry rulesRegistry - ValidationExecution() { - this.rulesRegistry = loadRegistry() - } - ExecutionContext validate(ExecutionEnvironment executionEnvironment, ResultHandler resultHandler) { assert executionEnvironment.config != null assert executionEnvironment.schema != null + rulesRegistry = new RulesRegistry(executionEnvironment.config) ExecutionContext context = new ExecutionContext() executionEnvironment.schema.typeMap.entrySet().each { if (!it.key.startsWith("_")) { @@ -31,13 +28,8 @@ class ValidationExecution { return context } - static def handleResult(executionEnvironment, context) { - - } - def validateType(ExecutionEnvironment executionEnvironment, ExecutionContext context, GraphQLNamedType graphQLNamedType) { - rulesRegistry.getTypeRuleSet().each { - def rule = it.getDeclaredConstructor().newInstance() + rulesRegistry.getTypeRuleSet().each { rule -> rule.setContext(context) rule.setExecutionEnvironment(executionEnvironment) if (!executionEnvironment.config['rules'][rule.name()] ?['disable']) { @@ -52,9 +44,8 @@ class ValidationExecution { def validateFields(ExecutionEnvironment executionEnvironment, ExecutionContext context, type) { type.fields.each { field -> - rulesRegistry.getFieldRuleSet().each { + rulesRegistry.getFieldRuleSet().each { rule -> if (field instanceof GraphQLFieldDefinition) { - def rule = it.getDeclaredConstructor().newInstance() rule.setContext(context) rule.setExecutionEnvironment(executionEnvironment) if (!executionEnvironment.config['rules'][rule.name()] ?['disable']) { @@ -69,8 +60,4 @@ class ValidationExecution { } } - static RulesRegistry loadRegistry() { - new RulesRegistry() - } - } diff --git a/src/main/groovy/graphql/linter/YamlConfiguration.groovy b/src/main/groovy/graphql/linter/YamlConfiguration.groovy index 258e7a7..6f63156 100644 --- a/src/main/groovy/graphql/linter/YamlConfiguration.groovy +++ b/src/main/groovy/graphql/linter/YamlConfiguration.groovy @@ -8,8 +8,6 @@ import java.nio.file.Paths class YamlConfiguration { private static def yaml = new Yaml(); private LinterConfiguration config - private schema = [:] - YamlConfiguration(yamlURI) { if (yamlURI) { diff --git a/src/main/groovy/graphql/linter/rules/LintRule.groovy b/src/main/groovy/graphql/linter/rules/LintRule.groovy index bb8f1a8..06de33e 100644 --- a/src/main/groovy/graphql/linter/rules/LintRule.groovy +++ b/src/main/groovy/graphql/linter/rules/LintRule.groovy @@ -8,9 +8,10 @@ import graphql.schema.GraphQLNamedSchemaElement abstract class LintRule { protected ExecutionContext context protected ExecutionEnvironment executionEnvironment + protected name LintRule() { - + name = this.getClass().getSimpleName().replaceAll(/([A-Z]+)([A-Z][a-z])/, "\$1_\$2").replaceAll(/([a-z])([A-Z])/, "\$1_\$2").toLowerCase() } LintRule(ExecutionContext context) { @@ -20,7 +21,7 @@ abstract class LintRule { def abstract validate(GraphQLNamedSchemaElement parent, GraphQLNamedSchemaElement node) String name() { - return this.getClass().getSimpleName().replaceAll(/([A-Z]+)([A-Z][a-z])/, "\$1_\$2").replaceAll(/([a-z])([A-Z])/, "\$1_\$2").toLowerCase() + return name } void setContext(ExecutionContext context) { diff --git a/src/main/groovy/graphql/linter/rules/RuleDSL.groovy b/src/main/groovy/graphql/linter/rules/RuleDSL.groovy new file mode 100644 index 0000000..172f00b --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/RuleDSL.groovy @@ -0,0 +1,23 @@ +package graphql.linter.rules + +import graphql.schema.GraphQLNamedSchemaElement + +class RuleDSL extends LintRule { + + private RuleType[] types + private Closure validateClosure + + public void rule(Collection types, Closure validateClosure) { + this.validateClosure = validateClosure + this.types = types.collect { + it as RuleType + } + } + + @Override + def validate(GraphQLNamedSchemaElement parent, GraphQLNamedSchemaElement node) { + validateClosure.setProperty("node", node) + validateClosure.setProperty("parent", parent) + validateClosure.run() + } +} diff --git a/src/main/groovy/graphql/linter/rules/RuleType.groovy b/src/main/groovy/graphql/linter/rules/RuleType.groovy new file mode 100644 index 0000000..37b8173 --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/RuleType.groovy @@ -0,0 +1,6 @@ +package graphql.linter.rules + +enum RuleType { + FIELD, + TYPE +} \ No newline at end of file diff --git a/src/main/groovy/graphql/linter/rules/registry/Registry.groovy b/src/main/groovy/graphql/linter/rules/registry/Registry.groovy new file mode 100644 index 0000000..6026d62 --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/registry/Registry.groovy @@ -0,0 +1,9 @@ +package graphql.linter.rules.registry + +import graphql.linter.rules.LintRule + +interface Registry { + Set getFieldRuleSet() + + Set getTypeRuleSet() +} \ No newline at end of file diff --git a/src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy b/src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy new file mode 100644 index 0000000..e57e1b3 --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy @@ -0,0 +1,4 @@ +package graphql.linter.rules.registry + +class RuleContext { +} diff --git a/src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy b/src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy new file mode 100644 index 0000000..43b41bd --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy @@ -0,0 +1,28 @@ +package graphql.linter.rules.registry + +import graphql.linter.LinterConfiguration +import graphql.linter.rules.LintRule + +class RulesRegistry implements Registry { + private Set fieldRules = new HashSet<>() + private Set typeRules = new HashSet<>() + + RulesRegistry(LinterConfiguration config) { + def registryDynamic = new RulesRegistryDynamic(config) + fieldRules.addAll registryDynamic.fieldRuleSet + typeRules.addAll registryDynamic.typeRuleSet + def registryStatic = new RulesRegistryStatic() + fieldRules.addAll registryStatic.fieldRuleSet + typeRules.addAll registryStatic.typeRuleSet + } + + @Override + Set getFieldRuleSet() { + return fieldRules + } + + @Override + Set getTypeRuleSet() { + return typeRules + } +} diff --git a/src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy b/src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy new file mode 100644 index 0000000..2b5fe9c --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy @@ -0,0 +1,61 @@ +package graphql.linter.rules.registry + +import graphql.linter.LinterConfiguration +import graphql.linter.rules.LintRule +import graphql.linter.rules.RuleDSL +import graphql.linter.rules.RuleType +import org.codehaus.groovy.control.CompilerConfiguration +import org.codehaus.groovy.control.customizers.ImportCustomizer + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.stream.Stream + +class RulesRegistryDynamic implements Registry { + private LinterConfiguration config + private Set fieldRules = new HashSet<>() + private Set typeRules = new HashSet<>() + + RulesRegistryDynamic(LinterConfiguration config) { + this.config = config + + def classloader = this.class.getClassLoader(); + def compilerConfiguration = new CompilerConfiguration(); + compilerConfiguration.setScriptBaseClass(DelegatingScript.class.getName()); + + def ic = new ImportCustomizer(); + ic.addImports(ServiceUtils.class.getName()); + compilerConfiguration.addCompilationCustomizers(ic); + + Binding binding = new Binding(); + binding.setVariable("context", new RuleContext()); + for (def prop : properties.entrySet()) { + binding.setVariable(prop.getKey() as String, prop.getValue()); + } + + def gs = new GroovyShell(classloader, binding, compilerConfiguration); + try (Stream paths = Files.walk(Paths.get(config.registry['dsl']['uri']))) { + paths.filter(Files::isRegularFile).map(p -> new MapEntry((p.getFileName()), Files.readString(p))).each { scriptFile -> + DelegatingScript ruleScript = (DelegatingScript) gs.parse(scriptFile.value as String) + ruleScript.setDelegate(new RuleDSL(name: (scriptFile.key as String).replaceAll("(? getFieldRuleSet() { + return fieldRules + } + + @Override + Set getTypeRuleSet() { + return typeRules + } +} diff --git a/src/main/groovy/graphql/linter/RulesRegistry.groovy b/src/main/groovy/graphql/linter/rules/registry/RulesRegistryStatic.groovy similarity index 57% rename from src/main/groovy/graphql/linter/RulesRegistry.groovy rename to src/main/groovy/graphql/linter/rules/registry/RulesRegistryStatic.groovy index f2f0add..38d7eb1 100644 --- a/src/main/groovy/graphql/linter/RulesRegistry.groovy +++ b/src/main/groovy/graphql/linter/rules/registry/RulesRegistryStatic.groovy @@ -1,4 +1,4 @@ -package graphql.linter +package graphql.linter.rules.registry import graphql.linter.rules.DefinedTypesAreUsed import graphql.linter.rules.FieldNameFirstLowercase @@ -6,11 +6,11 @@ import graphql.linter.rules.LintRule import graphql.linter.rules.types.FieldRule import graphql.linter.rules.types.TypeRule -class RulesRegistry { - private Set> fieldRules = new HashSet<>() - private Set> typeRules = new HashSet<>() +class RulesRegistryStatic implements Registry { + private Set fieldRules = new HashSet<>() + private Set typeRules = new HashSet<>() - RulesRegistry() { + RulesRegistryStatic() { register(FieldNameFirstLowercase.class) register(DefinedTypesAreUsed.class) } @@ -19,20 +19,20 @@ class RulesRegistry { rule.getAnnotations().each { typeAnnotation -> switch (typeAnnotation.annotationType()) { case FieldRule.class: - fieldRules.add(rule as Class) + fieldRules.add((rule as Class).getDeclaredConstructor().newInstance()) break; case TypeRule.class: - typeRules.add(rule as Class) + typeRules.add((rule as Class).getDeclaredConstructor().newInstance()) break; } } } - Set> getFieldRuleSet() { + Set getFieldRuleSet() { fieldRules } - Set> getTypeRuleSet() { + Set getTypeRuleSet() { typeRules } } diff --git a/src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy b/src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy new file mode 100644 index 0000000..bfc7da0 --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy @@ -0,0 +1,5 @@ +package graphql.linter.rules.registry + +class ServiceUtils { + +} \ No newline at end of file diff --git a/src/test/groovy/graphql/linter/CLIRunnerTest.groovy b/src/test/groovy/graphql/linter/CLIRunnerTest.groovy new file mode 100644 index 0000000..97b9051 --- /dev/null +++ b/src/test/groovy/graphql/linter/CLIRunnerTest.groovy @@ -0,0 +1,12 @@ +package graphql.linter + +import spock.lang.Specification + +import java.nio.file.Paths + +class CLIRunnerTest extends Specification { + def "Main"() { + expect: + CLIRunner.main(["src/test/resources/linter.yaml"] as String[]) + } +} diff --git a/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy b/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy new file mode 100644 index 0000000..976430c --- /dev/null +++ b/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy @@ -0,0 +1,17 @@ +package graphql.linter.rules.registry + +import graphql.linter.YamlConfiguration +import spock.lang.* + +import java.nio.file.Paths + + +class RulesRegistryDynamicSpec extends Specification { + def "Load dynamic DSL rules"() { + when: + RulesRegistryDynamic registryDynamic = new RulesRegistryDynamic(new YamlConfiguration(Paths.get("src", "test", "resources", "linter.yaml").toUri()).config) + then: + registryDynamic.fieldRuleSet.size() == 1 + registryDynamic.typeRuleSet.size() == 1 + } +} diff --git a/src/test/resources/linter.yaml b/src/test/resources/linter.yaml index f866736..52676c0 100644 --- a/src/test/resources/linter.yaml +++ b/src/test/resources/linter.yaml @@ -1,6 +1,8 @@ level: WARN failWhenExceedWarningMax: true - +registry: + dsl: + uri: src/test/resources/rules/ schema: local: uri: src/test/resources/schema/ diff --git a/src/test/resources/rules/test_field_rule.groovy b/src/test/resources/rules/test_field_rule.groovy new file mode 100644 index 0000000..5e091b5 --- /dev/null +++ b/src/test/resources/rules/test_field_rule.groovy @@ -0,0 +1,5 @@ +rule(["FIELD", "TYPE"]) { + if (node.name ==~ /^[a-z].*/) { + fail(parent, node, "The fieldname `${parent.name}.${node.name}` starts with uppercase.") + } +} \ No newline at end of file From 12c019265d2974a7eba6aae5562d1c1dc8c0e6fe Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Wed, 23 Nov 2022 15:42:59 +0200 Subject: [PATCH 20/22] Add rules : - ArgumentsHasDescriptions - DeprecationHasReason - EnumValueAllCaps --- build.gradle | 8 +++- .../graphql/linter/ValidationExecution.groovy | 2 +- .../{rules => }/registry/Registry.groovy | 2 +- .../linter/{rules => registry}/RuleDSL.groovy | 4 +- .../graphql/linter/registry/RuleUtils.groovy | 5 +++ .../{rules => }/registry/RulesRegistry.groovy | 2 +- .../registry/RulesRegistryDynamic.groovy | 15 +++---- .../registry/RulesRegistryStatic.groovy | 13 ++++--- .../types/FieldRule.groovy | 2 +- .../{rules => registry/types}/RuleType.groovy | 2 +- .../{rules => registry}/types/TypeRule.groovy | 2 +- .../rules/ArgumentsHasDescriptions.groovy | 22 +++++++++++ .../linter/rules/DefinedTypesAreUsed.groovy | 3 +- .../linter/rules/DeprecationHasReason.groovy | 39 +++++++++++++++++++ .../linter/rules/EnumValueAllCaps.groovy | 17 ++++++++ .../rules/FieldNameFirstLowercase.groovy | 3 +- .../linter/rules/registry/RuleContext.groovy | 4 -- .../linter/rules/registry/ServiceUtils.groovy | 5 --- .../registry/RulesRegistryDynamicSpec.groovy | 3 +- .../rules/test_arguments_has_descriptions | 10 +++++ src/test/resources/schema/file1.graphqls | 16 +++++++- 21 files changed, 144 insertions(+), 35 deletions(-) rename src/main/groovy/graphql/linter/{rules => }/registry/Registry.groovy (77%) rename src/main/groovy/graphql/linter/{rules => registry}/RuleDSL.groovy (83%) create mode 100644 src/main/groovy/graphql/linter/registry/RuleUtils.groovy rename src/main/groovy/graphql/linter/{rules => }/registry/RulesRegistry.groovy (95%) rename src/main/groovy/graphql/linter/{rules => }/registry/RulesRegistryDynamic.groovy (84%) rename src/main/groovy/graphql/linter/{rules => }/registry/RulesRegistryStatic.groovy (76%) rename src/main/groovy/graphql/linter/{rules => registry}/types/FieldRule.groovy (77%) rename src/main/groovy/graphql/linter/{rules => registry/types}/RuleType.groovy (50%) rename src/main/groovy/graphql/linter/{rules => registry}/types/TypeRule.groovy (80%) create mode 100644 src/main/groovy/graphql/linter/rules/ArgumentsHasDescriptions.groovy create mode 100644 src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy create mode 100644 src/main/groovy/graphql/linter/rules/EnumValueAllCaps.groovy delete mode 100644 src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy delete mode 100644 src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy create mode 100644 src/test/resources/rules/test_arguments_has_descriptions diff --git a/build.gradle b/build.gradle index 5a8f6f0..b66f435 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ publishing { version = project.version from project.components.java - artifact cliJar{ + artifact cliJar { classifier "cli" } @@ -80,7 +80,10 @@ publishing { } } gpr(MavenPublication) { - from(components.java) + artifactId = rootProject.name + "-cli" + artifact cliJar { + classifier "cli" + } } } repositories { @@ -106,6 +109,7 @@ publishing { signing { useGpgCmd() sign publishing.publications.mavenJava + sign publishing.publications.gpr } test { useJUnitPlatform() diff --git a/src/main/groovy/graphql/linter/ValidationExecution.groovy b/src/main/groovy/graphql/linter/ValidationExecution.groovy index 0d7d993..c59bb8e 100644 --- a/src/main/groovy/graphql/linter/ValidationExecution.groovy +++ b/src/main/groovy/graphql/linter/ValidationExecution.groovy @@ -1,6 +1,6 @@ package graphql.linter -import graphql.linter.rules.registry.RulesRegistry +import graphql.linter.registry.RulesRegistry import graphql.schema.* import groovy.time.TimeCategory diff --git a/src/main/groovy/graphql/linter/rules/registry/Registry.groovy b/src/main/groovy/graphql/linter/registry/Registry.groovy similarity index 77% rename from src/main/groovy/graphql/linter/rules/registry/Registry.groovy rename to src/main/groovy/graphql/linter/registry/Registry.groovy index 6026d62..c5ae9b1 100644 --- a/src/main/groovy/graphql/linter/rules/registry/Registry.groovy +++ b/src/main/groovy/graphql/linter/registry/Registry.groovy @@ -1,4 +1,4 @@ -package graphql.linter.rules.registry +package graphql.linter.registry import graphql.linter.rules.LintRule diff --git a/src/main/groovy/graphql/linter/rules/RuleDSL.groovy b/src/main/groovy/graphql/linter/registry/RuleDSL.groovy similarity index 83% rename from src/main/groovy/graphql/linter/rules/RuleDSL.groovy rename to src/main/groovy/graphql/linter/registry/RuleDSL.groovy index 172f00b..1f4af55 100644 --- a/src/main/groovy/graphql/linter/rules/RuleDSL.groovy +++ b/src/main/groovy/graphql/linter/registry/RuleDSL.groovy @@ -1,5 +1,7 @@ -package graphql.linter.rules +package graphql.linter.registry +import graphql.linter.registry.types.RuleType +import graphql.linter.rules.LintRule import graphql.schema.GraphQLNamedSchemaElement class RuleDSL extends LintRule { diff --git a/src/main/groovy/graphql/linter/registry/RuleUtils.groovy b/src/main/groovy/graphql/linter/registry/RuleUtils.groovy new file mode 100644 index 0000000..aaa6971 --- /dev/null +++ b/src/main/groovy/graphql/linter/registry/RuleUtils.groovy @@ -0,0 +1,5 @@ +package graphql.linter.registry + +class RuleUtils { + +} \ No newline at end of file diff --git a/src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy b/src/main/groovy/graphql/linter/registry/RulesRegistry.groovy similarity index 95% rename from src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy rename to src/main/groovy/graphql/linter/registry/RulesRegistry.groovy index 43b41bd..9fdcbb4 100644 --- a/src/main/groovy/graphql/linter/rules/registry/RulesRegistry.groovy +++ b/src/main/groovy/graphql/linter/registry/RulesRegistry.groovy @@ -1,4 +1,4 @@ -package graphql.linter.rules.registry +package graphql.linter.registry import graphql.linter.LinterConfiguration import graphql.linter.rules.LintRule diff --git a/src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy b/src/main/groovy/graphql/linter/registry/RulesRegistryDynamic.groovy similarity index 84% rename from src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy rename to src/main/groovy/graphql/linter/registry/RulesRegistryDynamic.groovy index 2b5fe9c..a9aa93c 100644 --- a/src/main/groovy/graphql/linter/rules/registry/RulesRegistryDynamic.groovy +++ b/src/main/groovy/graphql/linter/registry/RulesRegistryDynamic.groovy @@ -1,9 +1,8 @@ -package graphql.linter.rules.registry +package graphql.linter.registry import graphql.linter.LinterConfiguration +import graphql.linter.registry.types.RuleType import graphql.linter.rules.LintRule -import graphql.linter.rules.RuleDSL -import graphql.linter.rules.RuleType import org.codehaus.groovy.control.CompilerConfiguration import org.codehaus.groovy.control.customizers.ImportCustomizer @@ -25,11 +24,12 @@ class RulesRegistryDynamic implements Registry { compilerConfiguration.setScriptBaseClass(DelegatingScript.class.getName()); def ic = new ImportCustomizer(); - ic.addImports(ServiceUtils.class.getName()); + ic.addImports(RuleUtils.class.getName()); + ic.addStarImports("graphql.schema") compilerConfiguration.addCompilationCustomizers(ic); Binding binding = new Binding(); - binding.setVariable("context", new RuleContext()); + binding.setVariable("ruleUtils", new RuleUtils()); for (def prop : properties.entrySet()) { binding.setVariable(prop.getKey() as String, prop.getValue()); } @@ -38,11 +38,12 @@ class RulesRegistryDynamic implements Registry { try (Stream paths = Files.walk(Paths.get(config.registry['dsl']['uri']))) { paths.filter(Files::isRegularFile).map(p -> new MapEntry((p.getFileName()), Files.readString(p))).each { scriptFile -> DelegatingScript ruleScript = (DelegatingScript) gs.parse(scriptFile.value as String) - ruleScript.setDelegate(new RuleDSL(name: (scriptFile.key as String).replaceAll("(? fieldRules = new HashSet<>() @@ -13,6 +11,9 @@ class RulesRegistryStatic implements Registry { RulesRegistryStatic() { register(FieldNameFirstLowercase.class) register(DefinedTypesAreUsed.class) + register(ArgumentsHasDescriptions.class) + register(DeprecationHasReason.class) + register(EnumValueAllCaps.class) } def register(Class rule) { diff --git a/src/main/groovy/graphql/linter/rules/types/FieldRule.groovy b/src/main/groovy/graphql/linter/registry/types/FieldRule.groovy similarity index 77% rename from src/main/groovy/graphql/linter/rules/types/FieldRule.groovy rename to src/main/groovy/graphql/linter/registry/types/FieldRule.groovy index 75117c2..c840943 100644 --- a/src/main/groovy/graphql/linter/rules/types/FieldRule.groovy +++ b/src/main/groovy/graphql/linter/registry/types/FieldRule.groovy @@ -1,4 +1,4 @@ -package graphql.linter.rules.types +package graphql.linter.registry.types import java.lang.annotation.* diff --git a/src/main/groovy/graphql/linter/rules/RuleType.groovy b/src/main/groovy/graphql/linter/registry/types/RuleType.groovy similarity index 50% rename from src/main/groovy/graphql/linter/rules/RuleType.groovy rename to src/main/groovy/graphql/linter/registry/types/RuleType.groovy index 37b8173..b3c08c3 100644 --- a/src/main/groovy/graphql/linter/rules/RuleType.groovy +++ b/src/main/groovy/graphql/linter/registry/types/RuleType.groovy @@ -1,4 +1,4 @@ -package graphql.linter.rules +package graphql.linter.registry.types enum RuleType { FIELD, diff --git a/src/main/groovy/graphql/linter/rules/types/TypeRule.groovy b/src/main/groovy/graphql/linter/registry/types/TypeRule.groovy similarity index 80% rename from src/main/groovy/graphql/linter/rules/types/TypeRule.groovy rename to src/main/groovy/graphql/linter/registry/types/TypeRule.groovy index 698ea55..de76776 100644 --- a/src/main/groovy/graphql/linter/rules/types/TypeRule.groovy +++ b/src/main/groovy/graphql/linter/registry/types/TypeRule.groovy @@ -1,4 +1,4 @@ -package graphql.linter.rules.types +package graphql.linter.registry.types import java.lang.annotation.* diff --git a/src/main/groovy/graphql/linter/rules/ArgumentsHasDescriptions.groovy b/src/main/groovy/graphql/linter/rules/ArgumentsHasDescriptions.groovy new file mode 100644 index 0000000..a690233 --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/ArgumentsHasDescriptions.groovy @@ -0,0 +1,22 @@ +package graphql.linter.rules + + +import graphql.linter.registry.types.FieldRule +import graphql.schema.GraphQLArgument +import graphql.schema.GraphQLNamedSchemaElement + +@FieldRule +class ArgumentsHasDescriptions extends LintRule { + + @Override + def validate(GraphQLNamedSchemaElement parent, GraphQLNamedSchemaElement node) { + node.children.each { schemaElement -> + if (schemaElement instanceof GraphQLArgument) { + if (schemaElement.description == null) { + fail(parent, node, "Argument `${parent.name}.${node.name}(${schemaElement.name})` missing description.") + } + } + + } + } +} diff --git a/src/main/groovy/graphql/linter/rules/DefinedTypesAreUsed.groovy b/src/main/groovy/graphql/linter/rules/DefinedTypesAreUsed.groovy index 33271ca..d6c5280 100644 --- a/src/main/groovy/graphql/linter/rules/DefinedTypesAreUsed.groovy +++ b/src/main/groovy/graphql/linter/rules/DefinedTypesAreUsed.groovy @@ -1,6 +1,7 @@ package graphql.linter.rules -import graphql.linter.rules.types.TypeRule + +import graphql.linter.registry.types.TypeRule import graphql.schema.GraphQLInputObjectType import graphql.schema.GraphQLNamedSchemaElement import graphql.schema.GraphQLObjectType diff --git a/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy b/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy new file mode 100644 index 0000000..16b1cc4 --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy @@ -0,0 +1,39 @@ +package graphql.linter.rules + + +import graphql.linter.registry.types.FieldRule +import graphql.linter.registry.types.TypeRule +import graphql.schema.GraphQLArgument +import graphql.schema.GraphQLDirective +import graphql.schema.GraphQLNamedSchemaElement + +@FieldRule +class DeprecationHasReason extends LintRule { + + + public static final String defaultReasonMsg = "No longer supported" + + @Override + def validate(GraphQLNamedSchemaElement parent, GraphQLNamedSchemaElement node) { + node.children.each { schemaElement -> + if (schemaElement instanceof GraphQLDirective) { + if (schemaElement.name == "deprecated" && !hasReason(schemaElement)) { + fail(parent, node, "Directive for `${parent.name}.${node.name}` missing deprecation reason.") + } + } + if (schemaElement instanceof GraphQLArgument) { + schemaElement.children.each { directive -> + if (directive instanceof GraphQLDirective) { + if (directive.name == "deprecated" && !hasReason(directive)) { + fail(parent, node, "Directive for `${parent.name}.${node.name}(${schemaElement.name})` missing deprecation reason.") + } + } + } + } + } + } + + def hasReason(directive) { + return directive.arguments.find { it.name == "reason" && it.value.value.value != defaultReasonMsg } != null + } +} diff --git a/src/main/groovy/graphql/linter/rules/EnumValueAllCaps.groovy b/src/main/groovy/graphql/linter/rules/EnumValueAllCaps.groovy new file mode 100644 index 0000000..b20540a --- /dev/null +++ b/src/main/groovy/graphql/linter/rules/EnumValueAllCaps.groovy @@ -0,0 +1,17 @@ +package graphql.linter.rules + + +import graphql.linter.registry.types.TypeRule +import graphql.schema.GraphQLEnumType +import graphql.schema.GraphQLNamedSchemaElement + +@TypeRule +class EnumValueAllCaps extends LintRule { + + @Override + def validate(GraphQLNamedSchemaElement parent, GraphQLNamedSchemaElement node) { + if (node instanceof GraphQLEnumType && node.children.find({ it.name ==~ /[a-z]*/ })) { + fail(parent, node, "Enum value `${node.name}` contains lowercase") + } + } +} diff --git a/src/main/groovy/graphql/linter/rules/FieldNameFirstLowercase.groovy b/src/main/groovy/graphql/linter/rules/FieldNameFirstLowercase.groovy index 7132f83..1098537 100644 --- a/src/main/groovy/graphql/linter/rules/FieldNameFirstLowercase.groovy +++ b/src/main/groovy/graphql/linter/rules/FieldNameFirstLowercase.groovy @@ -1,6 +1,7 @@ package graphql.linter.rules -import graphql.linter.rules.types.FieldRule + +import graphql.linter.registry.types.FieldRule import graphql.schema.GraphQLNamedSchemaElement @FieldRule diff --git a/src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy b/src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy deleted file mode 100644 index e57e1b3..0000000 --- a/src/main/groovy/graphql/linter/rules/registry/RuleContext.groovy +++ /dev/null @@ -1,4 +0,0 @@ -package graphql.linter.rules.registry - -class RuleContext { -} diff --git a/src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy b/src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy deleted file mode 100644 index bfc7da0..0000000 --- a/src/main/groovy/graphql/linter/rules/registry/ServiceUtils.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package graphql.linter.rules.registry - -class ServiceUtils { - -} \ No newline at end of file diff --git a/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy b/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy index 976430c..9aed0fc 100644 --- a/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy +++ b/src/test/groovy/graphql/linter/rules/registry/RulesRegistryDynamicSpec.groovy @@ -1,6 +1,7 @@ package graphql.linter.rules.registry import graphql.linter.YamlConfiguration +import graphql.linter.registry.RulesRegistryDynamic import spock.lang.* import java.nio.file.Paths @@ -11,7 +12,7 @@ class RulesRegistryDynamicSpec extends Specification { when: RulesRegistryDynamic registryDynamic = new RulesRegistryDynamic(new YamlConfiguration(Paths.get("src", "test", "resources", "linter.yaml").toUri()).config) then: - registryDynamic.fieldRuleSet.size() == 1 + registryDynamic.fieldRuleSet.size() == 2 registryDynamic.typeRuleSet.size() == 1 } } diff --git a/src/test/resources/rules/test_arguments_has_descriptions b/src/test/resources/rules/test_arguments_has_descriptions new file mode 100644 index 0000000..9b1545b --- /dev/null +++ b/src/test/resources/rules/test_arguments_has_descriptions @@ -0,0 +1,10 @@ +rule(["FIELD"]) { + node.children.each { schemaElement -> + if (schemaElement instanceof GraphQLArgument) { + if (schemaElement.description == null) { + fail(parent, node, "Argument `${parent.name}.${node.name}(${schemaElement.name})` missing description.") + } + } + + } +} \ No newline at end of file diff --git a/src/test/resources/schema/file1.graphqls b/src/test/resources/schema/file1.graphqls index 4cac2df..6f92959 100644 --- a/src/test/resources/schema/file1.graphqls +++ b/src/test/resources/schema/file1.graphqls @@ -1,10 +1,19 @@ +directive @customDirective( + context: [String!] +) on FIELD_DEFINITION | OBJECT | INTERFACE + type Query{ is : String someType: SomeUsedType } type SomeUsedType { - aField:String + aField:String @customDirective +} +type DeprecatedType{ + id: String! + derepcatedField(deprecatedArgument:String @deprecated):String @deprecated + derepcatedField2(deprecatedArgument2:String @deprecated(reason: "deprecated")):String @deprecated(reason: "deprecated") } type UnusedTypeOne{ someField: String @@ -38,3 +47,8 @@ enum SomeEnum { ABBA } +enum EnumWithLowerCase { + BBaa + aBB + aaa +} \ No newline at end of file From ee4589d7033d3a8bd953fc59de76dc06147b67e1 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Wed, 23 Nov 2022 15:53:44 +0200 Subject: [PATCH 21/22] Update java doc Set release version --- README.md | 35 ++++++++++++++++++- build.gradle | 2 +- .../linter/rules/DeprecationHasReason.groovy | 2 -- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 98cf005..90b6e94 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ # GraphQL Linter Configuration level: WARN failWhenExceedWarningMax: true +registry: + dsl: + uri: src/test/resources/rules/ schema: # local schema folder local: @@ -39,10 +42,11 @@ rules: ``` ### Command line + #### Run from command line: ```bash -java -jar graphql-java-linter-1.1.jar linter.yaml +java -jar graphql-java-linter-1.1-cli.jar linter.yaml ``` ### In CI/CD flow via unit tests @@ -85,3 +89,32 @@ public class GraphQLLinterTest { } } ``` + +### DSL support + +Besides +linter's [rules](https://github.com/kirpi4ik/graphql-java-linter/tree/master/src/main/groovy/graphql/linter/rules) which +are embedded, you can define own set of rules using custom groovy DSL + +`arguments_has_descriptions` + +```groovy +rule(["FIELD"]) { + node.children.each { schemaElement -> + if (schemaElement instanceof GraphQLArgument) { + if (schemaElement.description == null) { + fail(parent, node, "Argument `${parent.name}.${node.name}(${schemaElement.name})` missing description.") + } + } + + } +} +``` + +In configuration file you will have to specify folder location which contains the dsl rules + +```yaml +registry: + dsl: + uri: src/test/resources/rules/ +``` diff --git a/build.gradle b/build.gradle index b66f435..a529ad4 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'org.myhab.tools' -version '1.1-SNAPSHOT' +version '1.1' task cliJar(type: Jar) { manifest { diff --git a/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy b/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy index 16b1cc4..aa52540 100644 --- a/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy +++ b/src/main/groovy/graphql/linter/rules/DeprecationHasReason.groovy @@ -1,8 +1,6 @@ package graphql.linter.rules - import graphql.linter.registry.types.FieldRule -import graphql.linter.registry.types.TypeRule import graphql.schema.GraphQLArgument import graphql.schema.GraphQLDirective import graphql.schema.GraphQLNamedSchemaElement From 0afc648b649dde28ffc8465962cb3c3ecf58e517 Mon Sep 17 00:00:00 2001 From: kirpi4ik Date: Wed, 23 Nov 2022 16:01:42 +0200 Subject: [PATCH 22/22] fix lift warning --- src/main/groovy/graphql/linter/registry/RuleUtils.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/groovy/graphql/linter/registry/RuleUtils.groovy b/src/main/groovy/graphql/linter/registry/RuleUtils.groovy index aaa6971..2879ea7 100644 --- a/src/main/groovy/graphql/linter/registry/RuleUtils.groovy +++ b/src/main/groovy/graphql/linter/registry/RuleUtils.groovy @@ -2,4 +2,7 @@ package graphql.linter.registry class RuleUtils { + public static debug(msg) { + println(msg) + } } \ No newline at end of file