Skip to content

Commit

Permalink
Merge pull request #1 from kirpi4ik/v1.1
Browse files Browse the repository at this point in the history
V1.1
  • Loading branch information
kirpi4ik authored Nov 23, 2022
2 parents bd1b120 + 0afc648 commit c2ce604
Show file tree
Hide file tree
Showing 31 changed files with 482 additions and 84 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# 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: [ master ]

env:
QENV: production

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 11

- name: Setup Gradle
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
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
uses: actions/upload-artifact@v3
with:
name: graphql-java-linter
path: build/libs/*.jar
50 changes: 42 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
[![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
### Usage

1. Create yaml configuration file E.g: `linter.yaml`

```yaml
# GraphQL Linter Configuration
level: WARN
failWhenExceedWarningMax: true
registry:
dsl:
uri: src/test/resources/rules/
schema:
# local schema folder
local:
Expand All @@ -38,21 +41,23 @@ 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-cli.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'
}
```

Expand All @@ -63,12 +68,12 @@ dependencies {
<dependency>
<groupId>org.myhab.tools</groupId>
<artifactId>graphql-java-linter</artifactId>
<version>1.0</version>
<version>1.1</version>
<scope>test</scope>
</dependency>
```

junit
#### junit

```java
import graphql.linter.LintRunner;
Expand All @@ -84,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/
```
44 changes: 38 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ plugins {
id 'groovy'
id 'maven-publish'
id 'signing'
id 'java'
}

group 'org.myhab.tools'
version '1.0'
version '1.1'

task cliJar(type: Jar) {
manifest {
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 {
mavenCentral()
Expand All @@ -16,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 {
Expand All @@ -32,7 +42,7 @@ javadoc {
}

artifacts {
archives javadocJar, sourcesJar
archives javadocJar, sourcesJar, cliJar
}
publishing {
publications {
Expand All @@ -42,6 +52,10 @@ publishing {
version = project.version

from project.components.java
artifact cliJar {
classifier "cli"
}

pom {
name = project.name
description = 'GraphQL schema linting tool'
Expand All @@ -65,23 +79,41 @@ publishing {
}
}
}
gpr(MavenPublication) {
artifactId = rootProject.name + "-cli"
artifact cliJar {
classifier "cli"
}
}
}
repositories {
maven {
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
credentials {
username = mavenCentralUsername
password = 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 = project.findProperty("gthUsername") ?: System.getenv("GTH_USERNAME")
password = project.findProperty("gthPassword") ?: System.getenv("GTH_TOKEN")
}
}
}
}
signing {
useGpgCmd()
sign publishing.publications.mavenJava
sign publishing.publications.gpr
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
3 changes: 1 addition & 2 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
rootProject.name = 'graphql-java-linter'

rootProject.name = 'graphql-java-linter'
2 changes: 1 addition & 1 deletion src/main/groovy/graphql/linter/BasicResultHandler.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -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} ")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path> paths = Files.walk((Paths.get(args[0])))) {
try (Stream<Path> paths = Files.walk(Paths.get(yamlConfig.schema['local']['uri']))) {
paths.filter(Files::isRegularFile).map(Files::readString).each {
tdr.merge(schemaParser.parse(it))
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/groovy/graphql/linter/LinterConfiguration.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ class LinterConfiguration {
boolean failWhenExceedWarningMax = false
def schema
def rules = [String: [:]]
private registry = [:]

}
38 changes: 0 additions & 38 deletions src/main/groovy/graphql/linter/RulesRegistry.groovy

This file was deleted.

21 changes: 4 additions & 17 deletions src/main/groovy/graphql/linter/ValidationExecution.groovy
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package graphql.linter

import graphql.linter.exception.RuleValidationError
import graphql.linter.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("_")) {
Expand All @@ -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']) {
Expand All @@ -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']) {
Expand All @@ -69,8 +60,4 @@ class ValidationExecution {
}
}

static RulesRegistry loadRegistry() {
new RulesRegistry()
}

}
2 changes: 0 additions & 2 deletions src/main/groovy/graphql/linter/YamlConfiguration.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit c2ce604

Please sign in to comment.