diff --git a/README.md b/README.md index 8b93508..fbadef4 100644 --- a/README.md +++ b/README.md @@ -38,17 +38,54 @@ nextflowPlugin { publishing { registry { - url = 'https://plugins.nextflow.io/api' - authToken = project.findProperty('registry_access_token') + // Registry URL (optional, defaults to plugin-registry.seqera.io/api) + url = 'https://plugin-registry.seqera.io/api' + + // API key for authentication (required) + apiKey = project.findProperty('npr.apiKey') } } } ``` +### Registry Configuration + +The registry publishing configuration supports multiple ways to provide the URL and API key: + +#### Registry URL +The registry URL can be configured via (in order of priority): +1. `nextflowPlugin.publishing.registry.url` in build.gradle +2. Gradle property: `-Pnpr.apiUrl=https://your-registry.com/api` +3. Environment variable: `NPR_API_URL=https://your-registry.com/api` +4. Default: `https://plugin-registry.seqera.io/api` + +#### API Key +The API key can be configured via (in order of priority): +1. `nextflowPlugin.publishing.registry.apiKey` in build.gradle +2. Gradle property: `-Pnpr.apiKey=your-api-key` +3. Environment variable: `NPR_API_KEY=your-api-key` + +**Note:** The API key is required for publishing. If none is provided, the plugin will show an error with configuration instructions. + +#### Example Configurations + +Using gradle.properties: +```properties +npr.apiUrl=https://my-custom-registry.com/api +npr.apiKey=your-secret-api-key +``` + +Using environment variables: +```bash +export NPR_API_URL=https://my-custom-registry.com/api +export NPR_API_KEY=your-secret-api-key +./gradlew releasePlugin +``` + This will add some useful tasks to your Gradle build: -* `assemble` - compile the Nextflow plugin code and assemble it into a zip file -* `installPlugin` - copy the assembled plugin into your local Nextflow plugins dir -* `releasePlugin` - publish the assembled plugin to the plugin registry +* `assemble` - Compile the Nextflow plugin code and assemble it into a zip file +* `installPlugin` - Copy the assembled plugin into your local Nextflow plugins dir +* `releasePlugin` - Release the assembled plugin to the plugin registry You should also ensure that your project's `settings.gradle` declares the plugin name, eg: ```gradle @@ -92,5 +129,5 @@ Then use this command: ``` -./gradlew publishPlugins +./gradlew releasePlugins ``` diff --git a/src/main/groovy/io/nextflow/gradle/NextflowPlugin.groovy b/src/main/groovy/io/nextflow/gradle/NextflowPlugin.groovy index fe84ef2..ccda9fd 100644 --- a/src/main/groovy/io/nextflow/gradle/NextflowPlugin.groovy +++ b/src/main/groovy/io/nextflow/gradle/NextflowPlugin.groovy @@ -129,22 +129,22 @@ class NextflowPlugin implements Plugin { // add registry publish task, if configured if (config.publishing.registry) { - // publishPluginToRegistry - publishes plugin to a plugin registry - project.tasks.register('publishPluginToRegistry', RegistryUploadTask) - project.tasks.publishPluginToRegistry.dependsOn << project.tasks.packagePlugin - publishTasks << project.tasks.publishPluginToRegistry + // releasePluginToRegistry - publishes plugin to a plugin registry + project.tasks.register('releasePluginToRegistry', RegistryUploadTask) + project.tasks.releasePluginToRegistry.dependsOn << project.tasks.packagePlugin + publishTasks << project.tasks.releasePluginToRegistry } - // finally, configure the destination-agnostic 'publish' task + // finally, configure the destination-agnostic 'release' task if (!publishTasks.isEmpty()) { - // publishPlugin - all the release/publishing actions - project.tasks.register('publishPlugin', { + // releasePlugin - all the release/publishing actions + project.tasks.register('releasePlugin', { group = 'Nextflow Plugin' - description = 'publish plugin to configured destinations' + description = 'Release plugin to configured destination' }) for (task in publishTasks) { - project.tasks.publishPlugin.dependsOn << task + project.tasks.releasePlugin.dependsOn << task } } } diff --git a/src/main/groovy/io/nextflow/gradle/registry/RegistryClient.groovy b/src/main/groovy/io/nextflow/gradle/registry/RegistryClient.groovy index d217c81..7c51703 100644 --- a/src/main/groovy/io/nextflow/gradle/registry/RegistryClient.groovy +++ b/src/main/groovy/io/nextflow/gradle/registry/RegistryClient.groovy @@ -15,18 +15,18 @@ class RegistryClient { private final Gson gson = new Gson() private final URI url - private final String authToken + private final String apiKey - RegistryClient(URI url, String authToken) { + RegistryClient(URI url, String apiKey) { this.url = !url.toString().endsWith("/") ? URI.create(url.toString() + "/") : url - this.authToken = authToken + this.apiKey = apiKey } def publish(String id, String version, File file) { def req = new HttpPost(url.resolve("publish")) - req.addHeader("Authorization", "Bearer ${authToken}") + req.addHeader("Authorization", "Bearer ${apiKey}") req.setEntity(MultipartEntityBuilder.create() .addTextBody("id", id) .addTextBody("version", version) diff --git a/src/main/groovy/io/nextflow/gradle/registry/RegistryPublishConfig.groovy b/src/main/groovy/io/nextflow/gradle/registry/RegistryPublishConfig.groovy index b97fab0..3f335d8 100644 --- a/src/main/groovy/io/nextflow/gradle/registry/RegistryPublishConfig.groovy +++ b/src/main/groovy/io/nextflow/gradle/registry/RegistryPublishConfig.groovy @@ -10,14 +10,67 @@ class RegistryPublishConfig { /** * Location of the registry api */ - String url = 'https://plugins.nextflow.io/api' + String url /** - * Registry authentication token + * Registry API key */ - String authToken + String apiKey RegistryPublishConfig(Project project) { this.project = project } + + /** + * Get the registry URL, checking fallbacks if not explicitly set + */ + String getResolvedUrl() { + // If explicitly set, use it + if (url) { + return url + } + + // Try gradle property + def gradleProp = project.findProperty('npr.apiUrl') + if (gradleProp) { + return gradleProp.toString() + } + + // Try environment variable + def envVar = System.getenv('NPR_API_URL') + if (envVar) { + return envVar + } + + // Default URL + return 'https://plugin-registry.seqera.io/api' + } + + /** + * Get the API key, checking fallbacks if not explicitly set + */ + String getResolvedApiKey() { + // If explicitly set, use it + if (apiKey) { + return apiKey + } + + // Try gradle property + def gradleProp = project.findProperty('npr.apiKey') + if (gradleProp) { + return gradleProp.toString() + } + + // Try environment variable + def envVar = System.getenv('NPR_API_KEY') + if (envVar) { + return envVar + } + + // No API key found + throw new RuntimeException('Registry API key not provided. Set it via:\n' + + ' - nextflowPlugin.publishing.registry.apiKey in build.gradle\n' + + ' - gradle property: npr.apiKey\n' + + ' - environment variable: NPR_API_KEY') + } } diff --git a/src/main/groovy/io/nextflow/gradle/registry/RegistryUploadTask.groovy b/src/main/groovy/io/nextflow/gradle/registry/RegistryUploadTask.groovy index 72a76e8..cd4ad6a 100644 --- a/src/main/groovy/io/nextflow/gradle/registry/RegistryUploadTask.groovy +++ b/src/main/groovy/io/nextflow/gradle/registry/RegistryUploadTask.groovy @@ -30,7 +30,7 @@ class RegistryUploadTask extends DefaultTask { final plugin = project.extensions.getByType(NextflowPluginConfig) final config = plugin.publishing.registry - def client = new RegistryClient(new URI(config.url), config.authToken) + def client = new RegistryClient(new URI(config.getResolvedUrl()), config.getResolvedApiKey()) client.publish(project.name, version, project.file(zipFile)) } } diff --git a/src/test/groovy/io/nextflow/gradle/NextflowPluginTest.groovy b/src/test/groovy/io/nextflow/gradle/NextflowPluginTest.groovy index 759bca5..acf92ce 100644 --- a/src/test/groovy/io/nextflow/gradle/NextflowPluginTest.groovy +++ b/src/test/groovy/io/nextflow/gradle/NextflowPluginTest.groovy @@ -19,7 +19,7 @@ class NextflowPluginTest extends Specification { project.pluginManager.apply('io.nextflow.nextflow-plugin') } - def "should register publishPlugin task when publishing is configured"() { + def "should register releasePlugin task when publishing is configured"() { given: project.nextflowPlugin { description = 'A test plugin' @@ -38,13 +38,13 @@ class NextflowPluginTest extends Specification { project.evaluate() then: - project.tasks.findByName('publishPlugin') != null - project.tasks.publishPlugin.group == 'Nextflow Plugin' - project.tasks.publishPlugin.description == 'publish plugin to configured destinations' + project.tasks.findByName('releasePlugin') != null + project.tasks.releasePlugin.group == 'Nextflow Plugin' + project.tasks.releasePlugin.description == 'Release plugin to configured destination' } - def "should make publishPlugin depend on registry publishing task"() { + def "should make releasePlugin depend on registry publishing task"() { given: project.nextflowPlugin { description = 'A test plugin' @@ -63,13 +63,13 @@ class NextflowPluginTest extends Specification { project.evaluate() then: - def publishPlugin = project.tasks.publishPlugin - def publishToRegistry = project.tasks.publishPluginToRegistry - publishPlugin.taskDependencies.getDependencies(publishPlugin).contains(publishToRegistry) + def releasePlugin = project.tasks.releasePlugin + def releaseToRegistry = project.tasks.releasePluginToRegistry + releasePlugin.taskDependencies.getDependencies(releasePlugin).contains(releaseToRegistry) } - def "should not register publishPlugin task when no publishing is configured"() { + def "should not register releasePlugin task when no publishing is configured"() { given: project.nextflowPlugin { description = 'A test plugin' @@ -83,7 +83,7 @@ class NextflowPluginTest extends Specification { project.evaluate() then: - project.tasks.findByName('publishPlugin') == null + project.tasks.findByName('releasePlugin') == null } -} \ No newline at end of file +}