Skip to content

Commit

Permalink
Add autodetect federation directives in gradle plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Lovakov authored and jmartisk committed Oct 11, 2024
1 parent 45497d6 commit 5fe6673
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.smallrye.graphql.gradle.tasks;

import io.smallrye.graphql.api.federation.Authenticated;
import io.smallrye.graphql.api.federation.ComposeDirective;
import io.smallrye.graphql.api.federation.Extends;
import io.smallrye.graphql.api.federation.External;
import io.smallrye.graphql.api.federation.Inaccessible;
import io.smallrye.graphql.api.federation.InterfaceObject;
import io.smallrye.graphql.api.federation.Key;
import io.smallrye.graphql.api.federation.Override;
import io.smallrye.graphql.api.federation.Provides;
import io.smallrye.graphql.api.federation.Requires;
import io.smallrye.graphql.api.federation.Shareable;
import io.smallrye.graphql.api.federation.Tag;
import io.smallrye.graphql.api.federation.link.Link;
import io.smallrye.graphql.api.federation.policy.Policy;
import io.smallrye.graphql.api.federation.requiresscopes.RequiresScopes;
import org.jboss.jandex.DotName;

import java.util.ArrayList;
import java.util.List;

public final class FederationDotNames {
public static final List<DotName> FEDERATION_DIRECTIVES_NAMES;

static {
FEDERATION_DIRECTIVES_NAMES = new ArrayList<>();
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Authenticated.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(ComposeDirective.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Extends.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(External.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Inaccessible.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(InterfaceObject.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Key.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Override.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Provides.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Requires.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Shareable.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Tag.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Link.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(Policy.class));
FEDERATION_DIRECTIVES_NAMES.add(DotName.createSimple(RequiresScopes.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Repeatable;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
Expand All @@ -13,6 +14,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -36,11 +38,37 @@
import org.jboss.jandex.Result;

import graphql.schema.GraphQLSchema;
import io.smallrye.graphql.api.Deprecated;
import io.smallrye.graphql.api.Entry;
import io.smallrye.graphql.api.OneOf;
import io.smallrye.graphql.api.federation.Authenticated;
import io.smallrye.graphql.api.federation.ComposeDirective;
import io.smallrye.graphql.api.federation.Extends;
import io.smallrye.graphql.api.federation.External;
import io.smallrye.graphql.api.federation.FieldSet;
import io.smallrye.graphql.api.federation.Inaccessible;
import io.smallrye.graphql.api.federation.InterfaceObject;
import io.smallrye.graphql.api.federation.Key;
import io.smallrye.graphql.api.federation.Override;
import io.smallrye.graphql.api.federation.Provides;
import io.smallrye.graphql.api.federation.Requires;
import io.smallrye.graphql.api.federation.Shareable;
import io.smallrye.graphql.api.federation.Tag;
import io.smallrye.graphql.api.federation.link.Import;
import io.smallrye.graphql.api.federation.link.Link;
import io.smallrye.graphql.api.federation.link.Purpose;
import io.smallrye.graphql.api.federation.policy.Policy;
import io.smallrye.graphql.api.federation.policy.PolicyGroup;
import io.smallrye.graphql.api.federation.policy.PolicyItem;
import io.smallrye.graphql.api.federation.requiresscopes.RequiresScopes;
import io.smallrye.graphql.api.federation.requiresscopes.ScopeGroup;
import io.smallrye.graphql.api.federation.requiresscopes.ScopeItem;
import io.smallrye.graphql.bootstrap.Bootstrap;
import io.smallrye.graphql.execution.SchemaPrinter;
import io.smallrye.graphql.schema.SchemaBuilder;
import io.smallrye.graphql.schema.model.Schema;
import io.smallrye.graphql.spi.config.Config;

import static io.smallrye.graphql.gradle.tasks.FederationDotNames.FEDERATION_DIRECTIVES_NAMES;

/**
* Generate schema task.
Expand Down Expand Up @@ -178,10 +206,17 @@ public static GradleConfig getConfig() {

@TaskAction
public void generateSchema() throws Exception {
this.config = new GradleConfig(includeScalars, includeDirectives, includeSchemaDefinition, includeIntrospectionTypes);
config = new GradleConfig(includeScalars, includeDirectives, includeSchemaDefinition, includeIntrospectionTypes);
ClassLoader classLoader = getClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
IndexView index = createIndex();

if (hasFederationDirectives(index)) {
config.setFederationEnabled(true);
System.setProperty("smallrye.graphql.federation.enabled", "true");
index = CompositeIndex.create(index, createFederationApiIndex());
}

String schema = generateSchema(index);
if (schema != null) {
write(schema);
Expand All @@ -190,6 +225,13 @@ public void generateSchema() throws Exception {
}
}

private static boolean hasFederationDirectives(IndexView index) {
return index.getKnownClasses().stream()
.anyMatch(classInfo -> FEDERATION_DIRECTIVES_NAMES.stream()
.anyMatch(classInfo::hasAnnotation)
);
}

private IndexView createIndex() {
IndexView moduleIndex;
try {
Expand Down Expand Up @@ -227,6 +269,45 @@ private IndexView createIndex() {
}
}

private IndexView createFederationApiIndex() throws IOException {
Indexer indexer = new Indexer();
indexer.indexClass(Map.class);
indexer.indexClass(Entry.class);
indexer.indexClass(Repeatable.class);

indexer.indexClass(Deprecated.class);
indexer.indexClass(OneOf.class);

// directives from the API module
indexer.indexClass(Authenticated.class);
indexer.indexClass(ComposeDirective.class);
indexer.indexClass(Extends.class);
indexer.indexClass(External.class);
indexer.indexClass(FieldSet.class);
indexer.indexClass(Inaccessible.class);
indexer.indexClass(InterfaceObject.class);
indexer.indexClass(Key.class);
indexer.indexClass(Override.class);
indexer.indexClass(Provides.class);
indexer.indexClass(Requires.class);
indexer.indexClass(Shareable.class);
indexer.indexClass(Tag.class);

indexer.indexClass(Link.class);
indexer.indexClass(Import.class);
indexer.indexClass(Purpose.class);

indexer.indexClass(Policy.class);
indexer.indexClass(PolicyGroup.class);
indexer.indexClass(PolicyItem.class);

indexer.indexClass(RequiresScopes.class);
indexer.indexClass(ScopeGroup.class);
indexer.indexClass(ScopeItem.class);

return indexer.complete();
}

// index the classes of this Gradle module
private Index indexModuleClasses() throws IOException {
Indexer indexer = new Indexer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ public class GradleConfig {

private final boolean includeIntrospectionTypes;

public GradleConfig(boolean includeScalars, boolean includeDirectives, boolean includeSchemaDefinition, boolean includeIntrospectionTypes) {
private boolean federationEnabled;

public GradleConfig(boolean includeScalars, boolean includeDirectives, boolean includeSchemaDefinition,
boolean includeIntrospectionTypes) {
this.includeScalars = includeScalars;
this.includeDirectives = includeDirectives;
this.includeSchemaDefinition = includeSchemaDefinition;
Expand All @@ -32,4 +35,12 @@ public boolean isIncludeSchemaDefinition() {
public boolean isIncludeIntrospectionTypes() {
return includeIntrospectionTypes;
}

public void setFederationEnabled(boolean federationEnabled) {
this.federationEnabled = federationEnabled;
}

public boolean isFederationEnabled() {
return federationEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class GradleConfigFacade implements Config {

private boolean includeIntrospectionTypes;

private boolean federationEnabled;

// Constructor used by the ServiceLoader mechanism. When this is called, we assume that GenerateSchemaTask
// has already produced a config based on the environment, and we just make a copy of it
public GradleConfigFacade() {
Expand All @@ -20,17 +22,19 @@ public GradleConfigFacade() {
this.includeDirectives = instance.isIncludeDirectives();
this.includeSchemaDefinition = instance.isIncludeSchemaDefinition();
this.includeIntrospectionTypes = instance.isIncludeIntrospectionTypes();

this.federationEnabled = instance.isFederationEnabled();
}

public GradleConfigFacade(boolean includeScalarsInSchema,
boolean includeDirectivesInSchema,
boolean includeSchemaDefinitionInSchema,
boolean includeIntrospectionTypesInSchema) {
boolean includeIntrospectionTypesInSchema,
boolean federationEnabled) {
this.includeScalars = includeScalarsInSchema;
this.includeDirectives = includeDirectivesInSchema;
this.includeSchemaDefinition = includeSchemaDefinitionInSchema;
this.includeIntrospectionTypes = includeIntrospectionTypesInSchema;
this.federationEnabled = federationEnabled;
}

@Override
Expand All @@ -57,4 +61,9 @@ public boolean isIncludeSchemaDefinitionInSchema() {
public boolean isIncludeIntrospectionTypesInSchema() {
return includeIntrospectionTypes;
}

@Override
public boolean isFederationEnabled() {
return federationEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.gradle.testkit.runner.BuildResult;
Expand All @@ -30,8 +29,13 @@ public void cleanup() {

@Test
public void testIncludeDirectives() throws IOException {
String schema = execute(Collections.singletonList("-DincludeDirectives=true"));
String schema = execute(List.of(
"-DincludeDirectives=true",
"-DincludeScalars=true",
"-DincludeSchemaDefinition=true"));
assertTrue(schema.contains("directive @skip"), "Directives should be included: " + schema);
assertTrue(schema.contains("_entities(representations"));
assertTrue(schema.contains("type Foo @key(fields : \"id\")"));
}

private String execute(List<String> arguments) throws IOException {
Expand Down
2 changes: 1 addition & 1 deletion tools/gradle-plugin/testing-project-kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

dependencies {
implementation "io.smallrye:smallrye-graphql:1.3.2"
implementation "io.smallrye:smallrye-graphql:2.10.0"
}

repositories {
Expand Down
4 changes: 3 additions & 1 deletion tools/gradle-plugin/testing-project/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

dependencies {
implementation "io.smallrye:smallrye-graphql:1.3.2"
implementation "io.smallrye:smallrye-graphql:2.10.0"
}

repositories {
Expand All @@ -14,7 +14,9 @@ repositories {

generateSchema {
// FIXME: how to properly pass properties to runs? see the comment in GradlePluginGenerateSchemaTest.java
includeScalars = Boolean.getBoolean("includeScalars")
includeDirectives = Boolean.getBoolean("includeDirectives")
includeSchemaDefinition = Boolean.getBoolean("includeSchemaDefinition")
}

group 'org.acme'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
package org.acme;

import io.smallrye.graphql.api.federation.FieldSet;
import io.smallrye.graphql.api.federation.Key;

@Key(fields = @FieldSet("id"))
public class Foo {
private Integer id;

private Integer number;

public Foo() {
}

public Foo(Integer id, Integer number) {
this.id = id;
this.number = number;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public Integer getNumber() {
return number;
}

public void setNumber(Integer number) {
this.number = number;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@
import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Query;

import java.util.Collections;
import java.util.List;

@GraphQLApi
class TestingApi {

@Query
public Foo getFoo() {
return null;
}


}
}

0 comments on commit 5fe6673

Please sign in to comment.