Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 publishPlugin
```

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
* `publishPlugin` - publish the assembled plugin to the plugin registry

You should also ensure that your project's `settings.gradle` declares the plugin name, eg:
```gradle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
131 changes: 131 additions & 0 deletions src/test/groovy/io/nextflow/gradle/NextflowPluginTest.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.nextflow.gradle

import io.nextflow.gradle.registry.RegistryPublishConfig
import org.gradle.api.Project
import org.gradle.testfixtures.ProjectBuilder
import spock.lang.Specification
Expand Down Expand Up @@ -86,4 +87,134 @@ class NextflowPluginTest extends Specification {
project.tasks.findByName('publishPlugin') == null
}

def "should resolve registry URL from explicit configuration"() {
given:
def config = new RegistryPublishConfig(project)
config.url = 'https://custom-registry.com/api'

when:
def resolvedUrl = config.getResolvedUrl()

then:
resolvedUrl == 'https://custom-registry.com/api'
}

def "should resolve registry URL from gradle property"() {
given:
project.ext.set('npr.apiUrl', 'https://gradle-prop-registry.com/api')
def config = new RegistryPublishConfig(project)

when:
def resolvedUrl = config.getResolvedUrl()

then:
resolvedUrl == 'https://gradle-prop-registry.com/api'
}

def "should resolve registry URL from environment variable"() {
given:
def config = new RegistryPublishConfig(project) {
@Override
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()
}

// Mock environment variable for test (NPR_API_URL)
return 'https://env-registry.com/api'
}
}

when:
def resolvedUrl = config.getResolvedUrl()

then:
resolvedUrl == 'https://env-registry.com/api'
}

def "should use default registry URL when none provided"() {
given:
def config = new RegistryPublishConfig(project)

when:
def resolvedUrl = config.getResolvedUrl()

then:
resolvedUrl == 'https://plugin-registry.seqera.io/api'
}

def "should resolve API key from explicit configuration"() {
given:
def config = new RegistryPublishConfig(project)
config.apiKey = 'explicit-api-key'

when:
def resolvedApiKey = config.getResolvedApiKey()

then:
resolvedApiKey == 'explicit-api-key'
}

def "should resolve API key from gradle property"() {
given:
project.ext.set('npr.apiKey', 'gradle-prop-api-key')
def config = new RegistryPublishConfig(project)

when:
def resolvedApiKey = config.getResolvedApiKey()

then:
resolvedApiKey == 'gradle-prop-api-key'
}

def "should resolve API key from environment variable"() {
given:
def config = new RegistryPublishConfig(project) {
@Override
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()
}

// Mock environment variable for test
return 'env-api-key'
}
}

when:
def resolvedApiKey = config.getResolvedApiKey()

then:
resolvedApiKey == 'env-api-key'
}

def "should throw error when no API key provided"() {
given:
def config = new RegistryPublishConfig(project)

when:
config.getResolvedApiKey()

then:
def ex = thrown(RuntimeException)
ex.message.contains('Registry API key not provided')
ex.message.contains('nextflowPlugin.publishing.registry.apiKey')
ex.message.contains('npr.apiKey')
ex.message.contains('NPR_API_KEY')
}

}