Skip to content

Commit

Permalink
Added Gitea source code provider
Browse files Browse the repository at this point in the history
Gitea is a open source self-hosted service similar to GitHub,
see https://gitea.io.

This commit implements the support for Gitea service in Nextflow
adding it as an extra provider.

This implemementation was contributed by Akira Sekiguchi.
See pull request #987
  • Loading branch information
pditommaso committed Feb 2, 2019
1 parent ce3bd9d commit ae04fc3
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 41 deletions.
27 changes: 26 additions & 1 deletion docs/sharing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,35 @@ that can be found in your GitLab `account page <https://gitlab.com/profile/accou
}


Gitea credentials
-----------------

`Gitea <https://gitea.io>`_ is a Git repository server with GitHub-like GUI access. Since Gitea installation is quite
easy, it is suitable for building a private development environment in your network. To access your Gitea server, you
have to provide all the credential information below::

providers {

mygitea {
server = 'http://your-domain.org/gitea'
endpoint = 'http://your-domain.org/gitea/api/v1'
platform = 'gitea'
user = 'your-user'
password = 'your-password'
token = 'your-api-token'
}

}


See `Gitea documentation <https://docs.gitea.io/en-us/api-usage/>`_ about how to enable API access on your
server and how to issue a token.


Private server configuration
============================

Nextflow is able to access repositories hosted on private BitBucket, GitHub and GitLab server installations.
Nextflow is able to access repositories hosted on private BitBucket, GitHub, GitLab and Gitea server installations.

In order to use a private SCM installation you will need to set the server name and access credentials
in your `SCM configuration file`_ .
Expand Down
35 changes: 26 additions & 9 deletions modules/nextflow/src/main/groovy/nextflow/scm/AssetManager.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class AssetManager {
String resolveName( String name ) {
assert name

def project = checkForGitUrl(name)
def project = resolveNameFromGitUrl(name)
if( project )
return project

Expand Down Expand Up @@ -278,7 +278,7 @@ class AssetManager {
String getHub() { hub }

@PackageScope
String checkForGitUrl( String repository ) {
String resolveNameFromGitUrl( String repository ) {

if( repository.startsWith('http://') || repository.startsWith('https://') || repository.startsWith('file:/')) {
try {
Expand All @@ -288,12 +288,13 @@ class AssetManager {
if( url.protocol == 'file' ) {
this.hub = "file:${url.domain}"
providerConfigs << new ProviderConfig(this.hub, [path:url.domain])
result = "local/${url.project}"
result = "local/${url.path}"
}
else {
// find the provider config for this server
this.hub = providerConfigs.find { it.domain == url.domain } ?.name
result = url.project
def config = providerConfigs.find { it.domain == url.domain }
this.hub = config?.name
result = resolveProjectName0(url.path, config?.server)
}
log.debug "Repository URL: $repository; Project: $result; Hub provider: $hub"

Expand All @@ -307,6 +308,22 @@ class AssetManager {
return null
}

protected String resolveProjectName0(String path, String server) {
assert path
assert !path.startsWith('/')

def project = path
if( server ) {
// fetch prefix from the server url
def prefix = new URL(server).path?.stripStart('/')
if( path.startsWith(prefix) ) {
project = path.substring(prefix.length())
}
}

return project.stripStart('/')
}

/**
* Creates the RepositoryProvider instance i.e. the object that manages the interaction with
* the remote SCM server (e.g. GitHub, GitLab, etc) using the platform provided API
Expand Down Expand Up @@ -1003,17 +1020,17 @@ class AssetManager {
assert localPath

// find the repository remote URL from the git project config file
final server = getGitConfigRemoteDomain()
if( !server && failFast ) {
final domain = getGitConfigRemoteDomain()
if( !domain && failFast ) {
def message = (localGitConfig.exists()
? "Can't find git repository remote host -- Check config file at path: $localGitConfig"
: "Can't find git repository config file -- Repository may be corrupted: $localPath" )
throw new AbortOperationException(message)
}

final result = providerConfigs.find { it -> it.domain == server }
final result = providerConfigs.find { it -> it.domain == domain }
if( !result && failFast ) {
def message = "Can't find any configured provider for git server `$server` -- Make sure to have specified it in your `scm` file. For details check https://www.nextflow.io/docs/latest/sharing.html#scm-configuration-file"
def message = "Can't find any configured provider for git server `$domain` -- Make sure to have specified it in your `scm` file. For details check https://www.nextflow.io/docs/latest/sharing.html#scm-configuration-file"
throw new AbortOperationException(message)
}

Expand Down
32 changes: 16 additions & 16 deletions modules/nextflow/src/main/groovy/nextflow/scm/GitUrl.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import groovy.transform.ToString
* @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
*/

@ToString(includeFields=true, includes='protocol,user,domain,project')
@EqualsAndHashCode(includeFields=true, includes='protocol,user,domain,project')
@ToString(includeFields=true, includes='protocol,user,domain,path')
@EqualsAndHashCode(includeFields=true, includes='protocol,user,domain,path')
class GitUrl {

private String protocol
Expand All @@ -35,7 +35,7 @@ class GitUrl {

private String domain

private String project
private String path

/**
* Creates a git url object specifying the url components
Expand All @@ -45,11 +45,11 @@ class GitUrl {
* @param domain Either the server domain {@code http} or the path location for local file URL {@code /usr/local/repo}
* @param project The git project name i.e. {@code foo/bar}
*/
GitUrl( String protocol, String user, String domain, String project ) {
GitUrl(String protocol, String user, String domain, String path) {
this.protocol = protocol
this.user = user
this.domain = domain
this.project = project
this.path = path
}

/**
Expand Down Expand Up @@ -111,11 +111,11 @@ class GitUrl {
// remove the remaining part
p = url.indexOf('/')
if( p != -1 ) {
project = url.substring(p)
if( project.endsWith('.git'))
project = project.substring(0,project.size()-4)
if( project.startsWith('/') )
project = project.substring(1)
path = url.substring(p)
if( path.endsWith('.git'))
path = path.substring(0,path.size()-4)
if( path.startsWith('/') )
path = path.substring(1)
url = url.substring(0,p)
}
// remove the user name
Expand All @@ -133,9 +133,9 @@ class GitUrl {
url = url.substring(p+1)
p = url.indexOf(':')
if( p != -1 ) {
project = url.substring(p+1)
if( project.endsWith('.git'))
project = project.substring(0,project.size()-4)
path = url.substring(p+1)
if( path.endsWith('.git'))
path = path.substring(0,path.size()-4)
this.domain = url.substring(0,p)
}
else {
Expand All @@ -149,7 +149,7 @@ class GitUrl {
if( str.endsWith('.git') ) {
str = str.substring(0, str.size()-4)
def items = str.tokenize('/')
project = items[-1]
path = items[-1]
if( items.size()>1 ) {
this.domain = '/' + items[0..-2].join('/')
}
Expand Down Expand Up @@ -181,9 +181,9 @@ class GitUrl {

/**
* @return
* The repository qualified name e.g. given the project repository {@code https://github.com/cbcrg/piper-nf.git}
* The repository project project path eg. {@code https://github.com/cbcrg/piper-nf.git}
* returns the string {@code cbcrg/piper-nf}.
*/
String getProject() { project }
String getPath() { path }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2013-2018, Centre for Genomic Regulation (CRG)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package nextflow.scm

import groovy.transform.CompileStatic

/**
* Implements a repository provider for Gitea service
*
* @author Akira Sekiguchi <pachiras.yokohama@gmail.com>
*/
@CompileStatic
final class GiteaRepositoryProvider extends RepositoryProvider {

GiteaRepositoryProvider(String project, ProviderConfig config=null) {
this.project = project
this.config = config ?: new ProviderConfig('gitea')
}

/** {@inheritDoc} */
@Override
String getName() { "Gitea" }

/** {@inheritDoc} */
@Override
String getEndpointUrl() {
"${config.endpoint}/repos/${project}"
}

/** {@inheritDoc} */
@Override
String getContentUrl( String path ) {
"${config.endpoint}/repos/$project/raw/$path"
}

/** {@inheritDoc} */
@Override
String getCloneUrl() {
Map response = invokeAndParseResponse( getEndpointUrl() )

def result = response.get('clone_url')
if( !result )
throw new IllegalStateException("Missing clone URL for: $project")

return result
}

/** {@inheritDoc} */
@Override
String getRepositoryUrl() {
"${config.server}/$project"
}

/** {@inheritDoc} */
@Override
byte[] readBytes(String path) {

def url = getContentUrl(path)
def contents = invoke(url)
return contents?.getBytes()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ class ProviderConfig {
if( !attr.server ) attr.server = 'https://gitlab.com'
break

case 'gitea':
attr.platform = name
if( !attr.server ) attr.server = 'https://try.gitea.io'
if( !attr.endpoint ) attr.endpoint = attr.server.toString().stripEnd('/') + '/api/v1'
break

case 'bitbucket':
attr.platform = name
if( !attr.server ) attr.server = 'https://bitbucket.org'
Expand Down Expand Up @@ -92,9 +98,7 @@ class ProviderConfig {
result = 'https://' + result

// remove ending slash
while( result.endsWith('/') )
result = result.substring(0,result.size()-1)
return result
return result.stripEnd('/')
}

/**
Expand All @@ -104,7 +108,12 @@ class ProviderConfig {
String getDomain() {
def result = server ?: path
def p = result.indexOf('://')
p != -1 ? result.substring(p+3) : result
if( p != -1 )
result = result.substring(p+3)
p = result.indexOf('/')
if( p != -1 )
result = result.substring(0,p)
return result
}

/**
Expand Down Expand Up @@ -161,7 +170,7 @@ class ProviderConfig {
* the {@link #getServer()} if not defined
*/
String getEndpoint() {
attr.endpoint ?: attr.server
attr.endpoint ? attr.endpoint.toString().stripEnd('/') : server
}

ProviderConfig setUser(String user) {
Expand Down Expand Up @@ -250,6 +259,9 @@ class ProviderConfig {
if( !result.find{ it.name == 'gitlab' })
result << new ProviderConfig('gitlab')

if( !result.find{ it.name == 'gitea' })
result << new ProviderConfig('gitea')

if( !result.find{ it.name == 'bitbucket' })
result << new ProviderConfig('bitbucket')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ abstract class RepositoryProvider {
case 'gitlab':
return new GitlabRepositoryProvider(project, config)

case 'gitea':
return new GiteaRepositoryProvider(project, config)

case 'file':
// remove the 'local' prefix for the file provider
def localName = project.tokenize('/').last()
Expand Down

0 comments on commit ae04fc3

Please sign in to comment.