Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add manifest.contributors config option #5322

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
23 changes: 17 additions & 6 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ The following settings are available:
: :::{versionadded} 24.04.0
:::
: *Used only by the {ref}`slurm-executor`, {ref}`lsf-executor`, {ref}`pbs-executor` and {ref}`pbspro-executor` executors.*
: Allows specifying the project or organisation account that should be charged for running the pipeline jobs.
: Allows specifying the project or organization account that should be charged for running the pipeline jobs.

`executor.cpus`
: The maximum number of CPUs made available by the underlying system. Used only by the `local` executor.
Expand Down Expand Up @@ -1144,8 +1144,22 @@ The `manifest` scope allows you to define some meta-data information needed when
The following settings are available:

`manifest.author`
: :::{deprecated} 24.09.0-edge
Use `manifest.contributors` instead.
:::
: Project author name (use a comma to separate multiple names).

`manifest.contributors`
: :::{versionadded} 24.09.0-edge
:::
: List of project contributors. Should be a list of maps. The following fields are supported in the contributor map:
- `name`: the contributor's name
- `affiliation`: the contributor's affiliated organization
- `email`: the contributor's email address
- `github`: the contributor's GitHub URL
pditommaso marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `github`: the contributor's GitHub URL
- `github`: the contributor's Git(Hub/Lab etc.) URL

Re @pditommaso 's comment, what about this instead to make it clearer it's just the handle you use in any git context?

Also do you give the full URL or just the handle itself?

- `contribution`: list of contribution types, each element can be one of `'author'`, `'maintainer'`, or `'contributor'`
- `orcid`: the contributor's [ORCID](https://orcid.org/) URL

`manifest.defaultBranch`
: Git repository default branch (default: `master`).

Expand All @@ -1170,9 +1184,6 @@ The following settings are available:
`manifest.mainScript`
: Project main script (default: `main.nf`).

`manifest.maintainer`
: Project maintainer name (use a comma to separate multiple names).

`manifest.name`
: Project short name.

Expand All @@ -1189,8 +1200,8 @@ The following settings are available:
manifest.nextflowVersion = '!>=1.2' // with ! prefix, stop execution if current version does not match required version.
```

`manifest.organisation`
: Project organisation
`manifest.organization`
: Project organization
pditommaso marked this conversation as resolved.
Show resolved Hide resolved

`manifest.recurseSubmodules`
: Pull submodules recursively from the Git repository.
Expand Down
78 changes: 68 additions & 10 deletions modules/nextflow/src/main/groovy/nextflow/config/Manifest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

package nextflow.config

import java.util.stream.Collectors

import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.util.logging.Slf4j
import nextflow.exception.AbortOperationException

import static nextflow.Const.DEFAULT_BRANCH
import static nextflow.Const.DEFAULT_MAIN_FILE_NAME
/**
Expand Down Expand Up @@ -63,6 +67,21 @@ class Manifest {
target.author
}

List<Contributor> getContributors() {
if( !target.contributors )
return Collections.emptyList()

try {
final contributors = target.contributors as List<Map>
return contributors.stream()
.map(opts -> new Contributor(opts))
.collect(Collectors.toList())
}
catch( ClassCastException | IllegalArgumentException e ){
throw new AbortOperationException("Invalid config option `manifest.contributors` -- should be a list of maps")
}
}

String getMainScript() {
target.mainScript ?: DEFAULT_MAIN_FILE_NAME
}
Expand Down Expand Up @@ -102,25 +121,24 @@ class Manifest {
target.docsUrl
}

String getIcon(){
String getIcon() {
target.icon
}

String getMaintainer(){
target.maintainer
}

String getOrganisation(){
target.organisation
String getOrganization() {
target.organization
}

String getLicense(){
String getLicense() {
target.license
}

Map toMap() {
final result = new HashMap(15)
result.author = getAuthor()
result.contributors = getContributors().stream()
.map(c -> c.toMap())
.collect(Collectors.toList())
result.defaultBranch = getDefaultBranch()
result.description = getDescription()
result.homePage = homePage
Expand All @@ -131,9 +149,49 @@ class Manifest {
result.doi = getDoi()
result.docsUrl = getDocsUrl()
result.icon = getIcon()
result.maintainer = getMaintainer()
result.organisation = getOrganisation()
result.organization = getOrganization()
result.license = getLicense()
return result
}

@EqualsAndHashCode
static class Contributor {
String name
String affiliation
String email
String github
Set<ContributionType> contribution
String orcid

Contributor(Map opts) {
name = opts.name as String
affiliation = opts.affiliation as String
email = opts.email as String
github = opts.github as String
contribution = (opts.contribution as List<String>).stream()
.map(c -> ContributionType.valueOf(c.toUpperCase()))
.collect(Collectors.toSet())
orcid = opts.orcid as String
}

Map toMap() {
final result = new HashMap(6)
result.name = name
result.affiliation = affiliation
result.email = email
result.github = github
result.contribution = contribution.stream()
.map(c -> c.toString().toLowerCase())
.sorted()
.collect(Collectors.toList())
result.orcid = orcid
return result
}
}

static enum ContributionType {
AUTHOR,
MAINTAINER,
CONTRIBUTOR
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class AssetManager {

/**
* The pipeline name. It must be in the form {@code username/repo} where 'username'
* is a valid user name or organisation account, while 'repo' is the repository name
* is a valid user name or organization account, while 'repo' is the repository name
* containing the pipeline code
*/
private String project
Expand Down
142 changes: 111 additions & 31 deletions modules/nextflow/src/test/groovy/nextflow/config/ManifestTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package nextflow.config

import nextflow.exception.AbortOperationException
import spock.lang.Specification

import static nextflow.config.Manifest.ContributionType
/**
*
* @author Paolo Di Tommaso <[email protected]>
Expand All @@ -26,49 +29,126 @@ class ManifestTest extends Specification {
def 'should check manifest object' () {

given:
def MAN = [author: 'pablo', nextflowVersion: '1.2.3', name: 'foo',
maintainer: 'john', organisation: 'My Organisation', icon: 'icon.png',
docsUrl: 'https://docs.io', license: 'Apache v2']
def MAP = [
author: 'pablo',
contributors: [
[
name: 'Alice',
affiliation: 'University',
email: '[email protected]',
contribution: ['author', 'maintainer'],
orcid: 'https://orcid.org/0000-0000-0000-0000'
],
[
name: 'Bob',
affiliation: 'Company',
email: '[email protected]',
contribution: ['contributor'],
]
],
nextflowVersion: '1.2.3',
name: 'foo',
organization: 'My Organization',
icon: 'icon.png',
docsUrl: 'https://docs.io',
license: 'Apache v2'
]
when:
def manifest = new Manifest(MAN)
def manifest = new Manifest(MAP)
then:
manifest.with {
author == 'pablo'
nextflowVersion == '1.2.3'
name == 'foo'
maintainer == 'john'
organisation == 'My Organisation'
icon == 'icon.png'
docsUrl == 'https://docs.io'
license == 'Apache v2'
}
manifest.author == 'pablo'
manifest.contributors.size() == 2
manifest.contributors[0].name == 'Alice'
manifest.contributors[0].affiliation == 'University'
manifest.contributors[0].email == '[email protected]'
manifest.contributors[0].contribution == [ContributionType.AUTHOR, ContributionType.MAINTAINER] as Set
manifest.contributors[0].orcid == 'https://orcid.org/0000-0000-0000-0000'
manifest.contributors[1].name == 'Bob'
manifest.contributors[1].affiliation == 'Company'
manifest.contributors[1].email == '[email protected]'
manifest.contributors[1].contribution == [ContributionType.CONTRIBUTOR] as Set
manifest.nextflowVersion == '1.2.3'
manifest.name == 'foo'
manifest.organization == 'My Organization'
manifest.icon == 'icon.png'
manifest.docsUrl == 'https://docs.io'
manifest.license == 'Apache v2'

}

def 'should check empty manifest' () {

// check empty manifest
when:
def manifest = new Manifest(new ConfigObject())
then:
manifest.with {
homePage == null
defaultBranch == 'master'
description == null
author == null
mainScript == 'main.nf'
gitmodules == null
nextflowVersion == null
version == null
name == null
maintainer == null
docsUrl == null
organisation == null
icon == null
license == null
}
manifest.homePage == null
manifest.defaultBranch == 'master'
manifest.description == null
manifest.author == null
manifest.contributors == []
manifest.mainScript == 'main.nf'
manifest.gitmodules == null
manifest.nextflowVersion == null
manifest.version == null
manifest.name == null
manifest.docsUrl == null
manifest.organization == null
manifest.icon == null
manifest.license == null

}

def 'should convert manifest to map' () {

when:
def MAP = [
name: 'Alice',
affiliation: 'University',
email: '[email protected]',
contribution: ['author', 'maintainer'],
orcid: 'https://orcid.org/0000-0000-0000-0000'
]
then:
new Manifest.Contributor(MAP).toMap() == [
name: 'Alice',
affiliation: 'University',
email: '[email protected]',
github: null,
contribution: ['author', 'maintainer'],
orcid: 'https://orcid.org/0000-0000-0000-0000'
]
}

def 'should throw error on invalid manifest' () {
when:
def manifest = new Manifest([
contributors: [ 'Alice' ]
])
manifest.contributors
then:
thrown(AbortOperationException)

when:
manifest = new Manifest([
contributors: [[
name: 'Alice',
contribution: 'author'
]]
])
manifest.contributors
then:
thrown(AbortOperationException)

when:
manifest = new Manifest([
contributors: [[
name: 'Alice',
contribution: [ 'owner' ]
]]
])
manifest.contributors
then:
thrown(AbortOperationException)
}

}