Code Monkey home page Code Monkey logo

gradle-conjure's Introduction

Autorelease

Gradle Conjure Bintray License

Gradle Conjure is a build tool which allows defining and generating code for Conjure APIs in Java projects.

Overview

gradle-conjure is a set of Gradle plugins which allow you to define and consume Conjure-defined APIs easily.

com.palantir.conjure

To see how to add gradle-conjure to an existing project, please see our getting started guide.

Tasks

  • compileConjure - Generates code for your API definitions in src/main/conjure/**/*.yml
  • compileConjureObjects - Generates Java POJOs from your Conjure definitions.
  • compileConjureTypeScript - Generates TypeScript files and a package.json from your Conjure definitions.
  • compileIr - Converts your Conjure YML files into a single portable JSON file in IR format.
  • compileTypeScript - Runs npm tsc to compile generated TypeScript files into JavaScript files.
  • publishTypeScript - Runs npm publish to publish a TypeScript package generated from your Conjure definitions.

Extension

com.palantir.conjure also exposes a conjure extension, which allows you to configure the behaviour of each supported generator. You configure the generator by specifying properties in a corresponding named closure. These properties are converted into command line options or flags and passed on to the generator CLI.

The supported closures are:

The following is example usage of the extension.

conjure {
    typescript {
        version = "0.0.0"
    }

    java {
        useImmutableBytes = true
    }
}

Service dependencies

To help consumers correlate generated Conjure API artifacts with a real server that implements this API, the com.palantir.conjure plugin supports embedding optional 'service dependencies' in generated artifacts. (Requires gradle-conjure 4.6.2+.)

This information can be defined using the serviceDependencies extension on your API project. You must specify the 'group' and 'name' of the server that implements this API, along with a minimum, maximum and recommended version for the server.

apply plugin: 'com.palantir.conjure'

serviceDependencies {
    serviceDependency {
        productGroup = 'com.palantir.group'
        productName = 'foo'
        minimumVersion = "${project.version}"
        maximumVersion = "${project.version.tokenize('.')[0]}.x.x"
        recommendedVersion = "${project.version}"
    }
}

For conjure-typescript, this information is passed as an extra flag, --productDependencies=your-project/build/service-dependencies.json, which is used to embed information in the resultant package.json.

For conjure-java, this information is directly embedded into the Jar for the -jersey and -dialogue projects. It is stored as a manifest property, Sls-Recommended-Product-Dependencies, which can be detected by sls-packaging.

Typescript

Typescript projects provide generateNpmrc task that generates .npmrc for publishing to configured repository. Credentials are configured using properties username and password and you can provide custom registry with registryUri parameter

generateNpmrc.registryUri = "https://my-custom-registry.com"
generateNpmrc.token = "<registry-token>" // System.env.<TOKEN>

Alternatively you can use username and password and the plugin will perform the login operation to obtain a publish token for you.

generateNpmrc.username = "<username>" // System.env.<USERNAME>
generateNpmrc.password = "<password>" // System.env.<PASSWORD>

com.palantir.conjure-publish

To enable publishing of your API definition for external consumption, add the com.palantir.conjure-publish which applies com.palantir.conjure and also creates a new "conjure" publication.

com.palantir.conjure-local

Tasks

  • generateConjure - Generates code for all Conjure dependencies
  • generateTypeScript - Generates TypeScript bindings for all Conjure dependencies
  • generatePython - Generates Python bindings for all Conjure dependencies
  • generate<language> - Task rule which will generates <language> bindings for all Conjure dependencies, where <language> is the name of the generator to be used

Configurations

  • conjure - Configuration for adding Conjure API dependencies
  • conjureGenerators - Configuration for adding generator dependencies

Using the conjure extension you can depend upon multiple Conjure APIs at once

dependencies {
    conjure 'com.company.product:some-api:1.0.0'
    conjure 'com.company.other.product:other-api:1.0.0'
}

Using the conjureGenerators extension allows you to use use any Conjure generator which conforms to RFC 002

 dependencies {
     conjure 'com.company.product:some-api:1.0.0'
     conjure 'com.company.other.product:other-api:1.0.0'

+    conjureGenerators 'com.palantir.conjure.postman:conjure-postman:0.1.0'
 }

For each generator specified referenced by the configuration you must also add a project with the corresponding name

 include 'conjure-api'
+include 'conjure-api:postman'

com.palantir.conjure-java-local

com.palantir.conjure-java-local helps to generate Java code from the conjure definition other services publish.

apply plugin: 'com.palantir.conjure-java-local'

conjure {
    java {
        addFlag 'objects'
        addFlag 'strictObjects'
        // addFlag 'undertow' as an implementer
        // addFlag 'dialogue' as a consumer
    }
}

dependencies {
    conjure 'com.company.product:[email protected]'
}

subprojects {
    dependencies {
        // api 'com.palantir.conjure.java:conjure-undertow-lib' as an implementer
        // implementation 'com.palantir.dialogue:dialogue-target' as a consumer
    }
}

Contributing

See the CONTRIBUTING.md document.

gradle-conjure's People

Contributors

ahggns avatar alexlandau avatar bjlaub avatar blizzara avatar bulldozer-bot[bot] avatar carterkozak avatar crogers avatar dansanduleac avatar ejarleberg avatar ericanderson avatar esword avatar fawind avatar felixdesouza avatar ferozco avatar helenyugithub avatar iamdanfox avatar j-baker avatar lycarter avatar nmiyake avatar pkoenig10 avatar qinfchen avatar robert3005 avatar rzpt avatar svc-autorelease avatar svc-excavator-bot avatar vcatalano avatar walkerburgin avatar ylee088 avatar ypan0411 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gradle-conjure's Issues

Allow users to leverage Gradle build cache

The Gradle build cache is a cache mechanism that aims to save time by reusing outputs produced by other builds. The build cache works by storing (locally or remotely) build outputs and allowing builds to fetch these outputs from the cache when it is determined that inputs have not changed, avoiding the expensive work of regenerating them.

All our compilation should be deterministic, so we should be able to mark these tasks as cacheable!

https://docs.gradle.org/current/userguide/build_cache.html#sec:task_output_caching_details

Copy IR into target projects as resource

What happened?

I am working on something that does build-time analysis in java projects that consume conjure APIs to determine what endpoints are called. I need access to the IR for this to work. I have a hacky way to figure out the name of the IR artifact for a given conjure-jar dependency and go download it (e.g. if a project has 'my-company:my-api-dialogue' as a dependency, I can figure out that the IR artifact is 'my-company:my-api' and search repostories for where to download it). It would be much cleaner though if the IR was in the jar itself as a resource file.

What did you want to happen?

Put the conjure.json file in the jar at the root level, preferably with a standard name like just "conjure.json". Or, if there will ever be multiple conjure.json files in a jar, could just keep them with the name of the generated file directly as it comes from the compileIr task.

Proposed Solutions

I have experimented with a couple of ways to do this:

  1. Add the output directory of the compileIR task directly as a resource directory of the derived projects. Can also make tweaks to the ConjureJavaLocalCodegenPlugin and ConjureLocalPlugin to pass in their source IRs as well in a similar way. This takes the least amount of code, but is not canonical gradle because the derived project is then reaching outside of it's project directory for some of it's resources.

  2. Add a new copyIrToXXX task to the derived java projects (objects, retrofit, jersey, etc) that copies the IR into src/generated/resources. This is the most obvious way to do things and doesn't require much code, but it is more than the first option and also doesn't easily extend to generic generators (which I have)

  3. Add an optional to property to ConjureGeneratorTask for irOutputDirectory. If set, the generator task will copy over the source IRs to the directory. This is the least intrusive and makes it easy for anything else that configures a generator (including the local stuff and generic generators) to copy the IR.

Thoughts?

Support local code-gen for external IR files

I would like to be able to generate local jars from an IR file that has been produced by another project. Currently in an unfortunate position of having a non-java repo publish an IR file to artifactory. I'd like to consume that IR file in a java repo and generate jars from it so I can build a client.

cc @ferozco

Confusing that the conjureJava configuration is only valid if a project with the proper suffix exist

What happened?

I had not added the project with a java suffix yet but following the getting_started guide. I got stuck with gradle saying the conjureJava configuration did not exist without any informative error.

This is the guilty line:

if (javaProjectSuffixes.stream().anyMatch(suffix -> project.findProject(project.getName() + suffix) != null)) {

What did you want to happen?

Maybe we could consider that the configuration should be set irrelevant of the project existing or not, but that configuration having a non-empty classpath or the project existence would be both flags and that if one is present but not the other, show an informative error.

5.0.0 hangs builds

What happened?

compile tasks on CI fail after upgrade from 4.27.2 to 5.0.0. ./gradlew --parallel --stacktrace --rerun-tasks classes testClasses consistently reproduced the problem on internal repo, please reach out for a link.

What did you want to happen?

Builds are not hanging.

Cannot use a bootstrapped installation of Node/npm when generating TypeScript

(This is not a current concern for me; we ended up setting up a build that doesn't use gradle-conjure, but noticed this during the development process. I felt it was worth documenting here.)

It's common for Gradle builds involving Node to bootstrap it so the user doesn't need to have a correct version of it installed on their machine (e.g. as supported by gradle-node-plugin).

However, using gradle-conjure to generate, build, and publish a TypeScript package will run node and npm from the default PATH, with no way to specify another location AFAICT. (This includes the invocation of the TypeScript generator, for which the entry point is a Node.js script.) This requires developers and CI images to have Node already installed, and in theory could lead to different results across machines if different versions are installed.

It would be nice if the location of the node and npm executables to use could be configured, so they could be pointed at a bootstrapped installation.

Existing product dependencies are overwritten

After #54, gradle-conjure will overwrite any existing product dependency recommendations with the ones configured in the serviceDependencies extension. As a result, if consumers upgrade gradle-conjure without switching to use the new product dependency recommendation, they will lose any existing product dependency recommendations.

confusing error if no conjure definitions present

What happened?

* What went wrong:
A problem was found with the configuration of task ':witchcraft-core:compileIr'.
> Directory '/Volumes/git/witchcraft/witchcraft-core/build/conjure' specified for property 'inputDirectory' does not exist.

What did you want to happen?

A problem was found with the configuration of task ':witchcraft-core:compileIr'.
> no conjure definitions found.

Conjure subprojects don't mark src/generated/java as a source root in intellij

On 4.13.1, I get iml files with

<content url="file://$MODULE_DIR$/">
      <sourceFolder url="file://$MODULE_DIR$/generated_src" isTestSource="false" generated="true"/>
      <sourceFolder url="file://$MODULE_DIR$/src/generated/java" isTestSource="false" generated="true"/>
      <sourceFolder url="file://$MODULE_DIR$/generated_testSrc" isTestSource="true" generated="true"/>
      <excludeFolder url="file://$MODULE_DIR$/.gradle"/>
      <excludeFolder url="file://$MODULE_DIR$/build"/>
      <sourceFolder url="file://$MODULE_DIR$/generated_src" isTestSource="false" generated="true"/>
      <sourceFolder url="file://$MODULE_DIR$/generated_testSrc" isTestSource="true" generated="true"/>
</content>

On 4.13.3 (the latest release) I get

<content url="file://$MODULE_DIR$/">
      <excludeFolder url="file://$MODULE_DIR$/.gradle"/>
      <excludeFolder url="file://$MODULE_DIR$/build"/>
      <sourceFolder url="file://$MODULE_DIR$/generated_src" isTestSource="false" generated="true"/>
      <sourceFolder url="file://$MODULE_DIR$/generated_testSrc" isTestSource="true" generated="true"/>
</content>

Fix SLF4J warnings

Looks like we need an slf4j impl here

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

Unable to traverse dependencies of projects generated by this plugin

If you try to traverse dependencies via evaluationDependsOn(...) and Configuration#getDependencies you will notice that subprojects like <project>-jersey only have their dependencies registered once <project> is evaluated but that never exists anywhere in dependency chain. Would be great to avoid dynamically adding dependencies in subprojects from parent project

README needs to mention `com.palantir.conjure-local`

#36 introduced a new plugin, but it's not documented. I think we should cover:

  • what the project structure will look like
  • what tasks will be created
  • when this should be used compared to the regular com.palantir.conjure plugin.

support publish conda task

What happened?

There's a publish npm task for typescript but no corresponding task for python.

What did you want to happen?

A way to publish python code to a conda or pypi repository

Renaming service package ends up generating classes for both old and new packages.

What happened?

I try to rename the package of a conjure service definition and old package is still being generated. I assume that the conjure ir or yml file is being cached somewhere, but ./gradlew clean doesn't seem to clean the cache.

What did you want to happen?

Ideally, ./gradlew compileConjure will remove the generated classes under the old package and generated the new ones only.

com.palantir.conjure doesn't support generic generators

It appears that only com.palantir.conjure-local supports generic generators, but that doesn't support the naming conventions that com.palantir.conjure does. It seems like com.palantir.conjure itself should support custom generators as well.

windows compat of compileIrTask

I think conjure 4.0 / 41bf5fc#diff-1036bc6316fc17fcb315276f5008e379 might have broken Windows compat for the compileIR task, from both gradle usage in cygwin and gradle usage in native shell.

no big deal and not a blocker for me since it still works fine in my Windows Subsystem for Linux shell, but thought you might want to know about the compat break.

Execution failed for task ':myProject-api:compileIr'.
> A problem occurred starting process 'command 'C:\Users\clockfort\code\myProject\myProject-api\build\conjureCompiler\bin\conjure''

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':myProject-api:compileIr'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:110)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipCachedTaskExecuter.execute(SkipCachedTaskExecuter.java:105)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:59)
        at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ResolveBuildCacheKeyExecuter.execute(ResolveBuildCacheKeyExecuter.java:66)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:59)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
        at org.gradle.api.internal.tasks.execution.FinalizeInputFilePropertiesTaskExecuter.execute(FinalizeInputFilePropertiesTaskExecuter.java:44)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
        at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:59)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.run(EventFiringTaskExecuter.java:51)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:46)
        at org.gradle.execution.taskgraph.LocmyProjectskInfoExecutor.execute(LocmyProjectskInfoExecutor.java:42)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:273)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:258)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:135)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:130)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.execute(DefaultTaskPlanExecutor.java:200)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.executeWithWork(DefaultTaskPlanExecutor.java:191)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.run(DefaultTaskPlanExecutor.java:130)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: org.gradle.process.internal.ExecException: A problem occurred starting process 'command 'C:\Users\clockfort\code\myProject\myProject-api\build\conjureCompiler\bin\conjure''
        at org.gradle.process.internal.DefaultExecHandle.execExceptionFor(DefaultExecHandle.java:231)
        at org.gradle.process.internal.DefaultExecHandle.setEndStateInfo(DefaultExecHandle.java:209)
        at org.gradle.process.internal.DefaultExecHandle.failed(DefaultExecHandle.java:355)
        at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:85)
        at org.gradle.internal.operations.CurrentBuildOperationPreservingRunnable.run(CurrentBuildOperationPreservingRunnable.java:42)
        ... 3 more
Caused by: net.rubygrapefruit.platform.NativeException: Could not start 'C:\Users\clockfort\code\myProject\myProject-api\build\conjureCompiler\bin\conjure'
        at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:27)
        at net.rubygrapefruit.platform.internal.WindowsProcessLauncher.start(WindowsProcessLauncher.java:22)
        at net.rubygrapefruit.platform.internal.WrapperProcessLauncher.start(WrapperProcessLauncher.java:36)
        at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:67)
        ... 4 more
Caused by: java.io.IOException: Cannot run program "C:\Users\clockfort\code\myProject\myProject-api\build\conjureCompiler\bin\conjure" (in directory "C:\Users\clockfort\code\myProject\myProject-api"): CreateProcess error=193, %1 is not a valid Win32 application
        at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:25)
        ... 7 more
Caused by: java.io.IOException: CreateProcess error=193, %1 is not a valid Win32 application
        ... 8 more

[conjure-java-local] Replace external imports with the base type

What happened?

When running conjure-java-locally to generate client bindings for a remotely-published conjure file, the local generation fails if the remote conjure file has external imports that are unavailable locally.

There have been a few categories of external imports that I've seen so far:

  1. external import of a Java class generated from the current conjure project (an antipattern; I fixed that instance)
  2. external import of a Java class included in the remote conjure project's published jar. For many users of conjure-java-local, a desired outcome is to sever the gradle dependency on the remote project's published jar, so they want to avoid re-introducing it.
  3. external import of a Java class part of the JDK (e.g. java.time classes). These are probably fine to keep in the locally-generated client

What did you want to happen?

I'd like local generation of the conjure client to succeed even if the remote conjure file uses external imports.

To fix, @carterkozak suggests that the generation of the local client should fall back to the base type. For most of the imports I'm observing, I think that would be String

automatically add javax validation api dependency if requireNotNullAuthAndBodyParams flag is set

What happened?

When enabling the requireNotNullAuthAndBodyParams flag to generate code with @NotNull annotations, in order to actually get validation it's necessary to manually add the javax.validation:validation-api dependency manually to the -jersey subproject.

What did you want to happen?

Just like we add conjure-lib, retrofit etc automatically as dependencies in the right places, it'd be if the validation-api dependency was added automatically.

(I tried to take a stab at this, but couldn't figure out the point at which I both have my hands on the generator options but dependencies aren't yet frozen - i.e. my attempt ended in a org.gradle.api.InvalidUserDataException: cannot change dependencies of configuration ":api:api-jersey:compile" after it has been included in dependency resolution.")

Windows compatibility with compileConjure task

What happened?

When attempting to run compileConjure from a Windows 10 machine with IntelliJ, our team receives the following stack trace:

Failed to generate conjure IR. The command '[C:\conjure-java-example\recipe-example-api\build\conjureCompiler\bin\conjure.bat, compile, C:\conjure-java-example\recipe-example-api\build\conjure, C:\conjure-java-example\recipe-example-api\build\conjure-ir\recipe-example-api.conjure.json, --extensions, {"recommended-product-dependencies":[]}]' failed with exit code 1. Output:

com.palantir.logsafe.exceptions.SafeIllegalArgumentException: Failed to parse extensions
at com.palantir.conjure.cli.ConjureCli.parseExtensions(ConjureCli.java:116)
at java.base/java.util.Optional.map(Optional.java:265)
at com.palantir.conjure.cli.ConjureCli$CompileCommand.getConfiguration(ConjureCli.java:107)
at com.palantir.conjure.cli.ConjureCli$CompileCommand.run(ConjureCli.java:84)
at picocli.CommandLine.executeUserObject(CommandLine.java:1919)
at picocli.CommandLine.access$1100(CommandLine.java:145)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2332)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2326)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2291)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2159)
at picocli.CommandLine.execute(CommandLine.java:2058)
at com.palantir.conjure.cli.ConjureCli.main(ConjureCli.java:46)
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('r' (code 114)): was expecting double-quote to start field name
at [Source: (String)"{recommended-product-dependencies:[]}"; line: 1, column: 3]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1851)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:707)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:632)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddName(ReaderBasedJsonParser.java:1809)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextFieldName(ReaderBasedJsonParser.java:936)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:513)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:377)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4524)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3466)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3449)
at com.palantir.conjure.cli.ConjureCli.parseExtensions(ConjureCli.java:114)
... 11 more

To reproduce this issue, you will need to clone the current Conjure Java example project (https://github.com/palantir/conjure-java-example) and attempt to run the compileConjure method with IntellJ or Windows Command Prompt.

It appears that the --extensions option is not being parsed properly by the ConjureCli.java class: {"recommended-product-dependencies":[]}

What did you want to happen?

We expect the Conjure library to be compatible with Windows 10.

Allow *.ir.json as alternative IR filename

This line is strict for *.conjure.json: https://github.com/palantir/gradle-conjure/blob/develop/gradle-conjure/src/main/java/com/palantir/gradle/conjure/ConjureLocalGenerateGenericTask.java#L30

But the Conjure Godel plugin generates *.ir.json files making them unusable: https://github.com/palantir/godel-conjure-plugin/blob/96bccdf6c9de1eec90a94a601a677b0bd2182d39/conjureplugin/publish.go#L65

It may be easier to relax this plugin so it works against all previously published IR files even if we go on to fix the godel plugin too.

Renamed Conjure types result in leftover (old) generated files

What happened?

If you define a conjure type, run ./gradlew compileConjureObjects, then rename the type and run ./gradlew compileConjureObjects again, you'll end up with both the old and the new name in your src/generated/java directory.

This is especially dangerous when combined with the build-cache, because it means a git clean -xdf may restore the same overloaded cache again and again. Users may then write code that compiles against the old type, see compilation pass locally, and then have it fail on CI because the old type doesn't exist.

cc @ashrayjain

What did you want to happen?

The src/generated/java directory should be minimal any extraneous files should be deleted automatically!

Published Conjure IR should include service dependency information

There are two ways of consuming an external service's Conjure API:

  1. You consume generated code published by the external service.
  2. You consume Conjure IR published by the external service and generate code from it locally.

In case 1, we embed service dependency information in the generated library which can be picked up by build tooling for your service. However, that is not true in case 2. In particular, Rust services always use case 2 since we don't expect all services to be publishing Rust crates for their Conjure APIs. Local generation also has advantages in that you are able to configure the codegen how you like (WRT things like staged builders) instead of having to deal with whatever the external service decided.

Unfortunately, we currently publish the Conjure IR JSON directly. We could either add service dependency information to the Conjure IR spec itself, or make a breaking change to IR publishing and wrap it in a tarball, allowing us to stick the service dependency information next to it.

Mention compatibility of gradle versions

Someone recently tried to use this with Gradle 3.0 but it didn't work. We should either add some kind of error handling or document the plugin's gradle compatibility:

* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating project ':my-project-api'.
        at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:92)
        at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl$2.run(DefaultScriptPluginFactory.java:177)
        at org.gradle.configuration.ProjectScriptTarget.addConfiguration(ProjectScriptTarget.java:77)
        at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:182)
        at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:38)
        at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:25)
        at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34)
        at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:55)
        at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:573)
        at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:125)
        at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:47)
        at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:38)
        at org.gradle.initialization.DefaultGradleLauncher$2.run(DefaultGradleLauncher.java:124)
        at org.gradle.internal.Factories$1.create(Factories.java:22)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:121)
        at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
        at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
        at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:94)
        at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
        at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:43)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:28)
        at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:82)
        at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
        at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:59)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:49)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
        at org.gradle.util.Swapper.swap(Swapper.java:38)
        at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.HintGCAfterBuild.execute(HintGCAfterBuild.java:44)
        at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:240)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
Caused by: java.lang.NoSuchMethodError: org.gradle.api.Project.project(Ljava/lang/String;Lorg/gradle/api/Action;)Lorg/gradle/api/Project;
        at com.palantir.conjure.gradle.ConjurePlugin.setupConjureObjectsProject(ConjurePlugin.java:94)
        at com.palantir.conjure.gradle.ConjurePlugin.apply(ConjurePlugin.java:78)
        at com.palantir.conjure.gradle.ConjurePlugin.apply(ConjurePlugin.java:33)
        at org.gradle.api.internal.plugins.ImperativeOnlyPluginApplicator.applyImperative(ImperativeOnlyPluginApplicator.java:35)
        at org.gradle.api.internal.plugins.RuleBasedPluginApplicator.applyImperative(RuleBasedPluginApplicator.java:43)
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:139)
        at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:112)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyType(DefaultObjectConfigurationAction.java:113)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.access$200(DefaultObjectConfigurationAction.java:36)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction$3.run(DefaultObjectConfigurationAction.java:80)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.execute(DefaultObjectConfigurationAction.java:136)
        at org.gradle.api.internal.project.AbstractPluginAware.apply(AbstractPluginAware.java:44)
        at org.gradle.api.internal.project.ProjectScript.apply(ProjectScript.java:34)
        at org.gradle.api.Script$apply$0.callCurrent(Unknown Source)

Define publishTypeScript task in separate plugin

This plugin is responsible for creating the gradle tasks necessary to generate conjure files. This plugin does not provide publishing tasks for Java projects so having a publishing task for Typescript projects seems out-of-place.

There is no easy way for clients to disable typescript publishing since it is automatically created as a dependency of the global publish task. In order to disable typescript publishing, clients have to add:

publishTypeScript.enabled = false

Support Conjure generators on local project

Right now if I have a project called my-service-api, I can create a new project called my-service-local-api, add conjure-local, pull down my published Conjure IR from my-service-api, and use that to generate, say, a Postman collection.

Instead, I'd like to add some plug-in(s) to my existing my-service-api project that give(s) me a gradle generateConjurePostman task that I can run right from my project to generate a Postman collection from the current local Conjure files.

cc @ferozco

Conjure seems to now fail silently if the IR definition is invalid

I don't know whether you'd like to class this as a gradle-conjure issue or a conjure-java issue.

If your conjure definition is invalid (in my case, I changed it from):

MyType:
  fields:
    existing: string

to

NewType:
  alias: int

MyType:
  fields:
    existing: string
    newField: optional<NewType>

This is invalid because it's integer, not int. But the IR compilation does not error and instead produces no output (the output IR folder is empty). This then causes conjureJava to no-op, since it now has no source (gradle skips the task). It also does not clear out previously generated files.

I think that in the past, Conjure-java used to fail if the file did not exist. Additionally conjure used to hard fail if it wasn't going to produce any output.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.