Skip to content

Commit

Permalink
[#6][#7] Server credentials from MavenDeployer and Gradle properties
Browse files Browse the repository at this point in the history
  • Loading branch information
szpak committed Mar 8, 2015
1 parent 08472c5 commit 1614604
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package io.codearte.gradle.nexus

import groovy.transform.CompileStatic
import groovy.transform.ToString
import groovy.util.logging.Slf4j
import org.gradle.api.Incubating

@CompileStatic
@Slf4j
@ToString(includeFields = true, includeNames = true, includePackage = false)
class NexusStagingExtension {

String serverUrl
Expand Down
89 changes: 66 additions & 23 deletions src/main/groovy/io/codearte/gradle/nexus/NexusStagingPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@ package io.codearte.gradle.nexus
import io.codearte.gradle.nexus.logic.OperationRetrier
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.maven.MavenDeployer
import org.gradle.api.execution.TaskExecutionGraph
import org.gradle.api.tasks.Upload

class NexusStagingPlugin implements Plugin<Project> {

private static final String GET_STAGING_PROFILE_TASK_NAME = "getStagingProfile"
private static final String CLOSE_REPOSITORY_TASK_NAME = "closeRepository"
private static final String PROMOTE_REPOSITORY_TASK_NAME = "promoteRepository"

private static final Set<Class> STAGING_TASK_CLASSES = [GetStagingProfileTask2, CloseRepositoryTask, PromoteRepositoryTask]

private static final String NEXUS_USERNAME_PROPERTY = 'nexusUsername'
private static final String NEXUS_PASSWORD_PROPERTY = 'nexusPassword'

private Project project
private NexusStagingExtension extension

Expand All @@ -20,16 +31,16 @@ class NexusStagingPlugin implements Plugin<Project> {
def closeRepositoryTask = createAndConfigureCloseRepositoryTask(project)
def promoteRepositoryTask = createAndConfigurePromoteRepositoryTask(project)
promoteRepositoryTask.mustRunAfter(closeRepositoryTask)
tryToGetCredentialsFromUploadArchivesTask(project, extension)
tryToDetermineCredentials(project, extension)
}

void emitWarningIfAppliedNotToRootProject(Project project) {
private void emitWarningIfAppliedNotToRootProject(Project project) {
if (project != project.rootProject) {
project.logger.warn("WARNING. Nexus staging plugin should only be applied to the root project in build.")
}
}

NexusStagingExtension createAndConfigureExtension(Project project) {
private NexusStagingExtension createAndConfigureExtension(Project project) {
def extension = project.extensions.create("nexusStaging", NexusStagingExtension)
extension.with {
serverUrl = "https://oss.sonatype.org/service/local/"
Expand All @@ -39,17 +50,17 @@ class NexusStagingPlugin implements Plugin<Project> {
return extension
}

void createAndConfigureGetStagingProfileTask2(Project project) {
GetStagingProfileTask2 task = project.tasks.create("getStagingProfile", GetStagingProfileTask2)
private void createAndConfigureGetStagingProfileTask2(Project project) {
GetStagingProfileTask2 task = project.tasks.create(GET_STAGING_PROFILE_TASK_NAME, GetStagingProfileTask2)
task.with {
description = "Gets staging profile id in Nexus - diagnostic tasks"
group = "release"
}
setTaskDefaults(task)
}

CloseRepositoryTask createAndConfigureCloseRepositoryTask(Project project) {
CloseRepositoryTask task = project.tasks.create("closeRepository", CloseRepositoryTask)
private CloseRepositoryTask createAndConfigureCloseRepositoryTask(Project project) {
CloseRepositoryTask task = project.tasks.create(CLOSE_REPOSITORY_TASK_NAME, CloseRepositoryTask)
task.with {
description = "Closes open artifacts repository in Nexus"
group = "release"
Expand All @@ -58,8 +69,8 @@ class NexusStagingPlugin implements Plugin<Project> {
return task
}

PromoteRepositoryTask createAndConfigurePromoteRepositoryTask(Project project) {
PromoteRepositoryTask task = project.tasks.create("promoteRepository", PromoteRepositoryTask)
private PromoteRepositoryTask createAndConfigurePromoteRepositoryTask(Project project) {
PromoteRepositoryTask task = project.tasks.create(PROMOTE_REPOSITORY_TASK_NAME, PromoteRepositoryTask)
task.with {
description = "Promotes/releases closed artifacts repository in Nexus"
group = "release"
Expand All @@ -68,7 +79,7 @@ class NexusStagingPlugin implements Plugin<Project> {
return task
}

void setTaskDefaults(BaseStagingTask task) {
private void setTaskDefaults(BaseStagingTask task) {
task.conventionMapping.with {
serverUrl = { extension.serverUrl }
username = { extension.username }
Expand All @@ -80,23 +91,55 @@ class NexusStagingPlugin implements Plugin<Project> {
}
}

private void tryToGetCredentialsFromUploadArchivesTask(Project project, NexusStagingExtension extension) {
//TODO: Extract to separate class
private void tryToDetermineCredentials(Project project, NexusStagingExtension extension) {
project.afterEvaluate {
if (extension.username != null) {
return //username already set manually
project.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
if (isAnyOfStagingTasksInTaskGraph(taskGraph)) {
tryToGetCredentialsFromUploadArchivesTask(project, extension)
tryToGetCredentialsFromGradleProperties(project, extension)
} else {
project.logger.debug("No staging task will be executed - skipping determination of Nexus credentials")
}
}
}
}

Upload uploadTask = project.tasks.findByPath("uploadArchives")
uploadTask?.repositories.withType(MavenDeployer).each { MavenDeployer deployer ->
project.logger.debug("Trying to read credentials from repository '${deployer.name}'")
def authentication = deployer.repository.authentication //Not to use class names as maven-ant-task is not on classpath when plugin is executed
if (authentication.userName != null) {
extension.username = authentication.userName
extension.password = authentication.password
project.logger.info("Using username '${extension.username}' and password from repository '${deployer.name}'")
return //from each
}
private boolean isAnyOfStagingTasksInTaskGraph(TaskExecutionGraph taskGraph) {
return taskGraph.allTasks.find { Task task ->
STAGING_TASK_CLASSES.find { Class stagingTaskClass ->
//GetStagingProfileTask_Decorated is not assignable from GetStagingProfileTask, but its superclass is GetStagingProfileTask...
task.getClass().superclass.isAssignableFrom(stagingTaskClass)
}
}
}

private void tryToGetCredentialsFromUploadArchivesTask(Project project, NexusStagingExtension extension) {
if (extension.username != null && extension.password != null) {
return //username and password already set
}

Upload uploadTask = project.tasks.findByPath("uploadArchives")
uploadTask?.repositories?.withType(MavenDeployer).each { MavenDeployer deployer ->
project.logger.debug("Trying to read credentials from repository '${deployer.name}'")
def authentication = deployer.repository?.authentication //Not to use class names as maven-ant-task is not on classpath when plugin is executed
if (authentication?.userName != null) {
extension.username = authentication.userName
extension.password = authentication.password
project.logger.info("Using username '${extension.username}' and password from repository '${deployer.name}'")
return //from each
}
}
}

private void tryToGetCredentialsFromGradleProperties(Project project, NexusStagingExtension extension) {
if (extension.username == null && project.hasProperty(NEXUS_USERNAME_PROPERTY)) {
extension.username = project.property(NEXUS_USERNAME_PROPERTY)
project.logger.info("Using username '${extension.username}' from Gradle property '${NEXUS_USERNAME_PROPERTY}'")
}
if (extension.password == null && project.hasProperty(NEXUS_PASSWORD_PROPERTY)) {
extension.password = project.property(NEXUS_PASSWORD_PROPERTY)
project.logger.info("Using password '*****' from Gradle property '${NEXUS_PASSWORD_PROPERTY}'")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ class SimplifiedHttpJsonRestClient {

private void setUriAndAuthentication(String uri) {
restClient.uri = uri
restClient.auth.basic(username, password) //has to be after URI is set
if (username != null) {
restClient.auth.basic(username, password) //has to be after URI is set
}
}

void post(String uri, Map content) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
package io.codearte.gradle.nexus.functional

import org.codehaus.groovy.runtime.StackTraceUtils

class PasswordFunctionalSpec extends BaseNexusStagingFunctionalSpec {

def "should read password from repository configured in uploadArchives"() {
given:
copyResources("sampleProjects//uploadArchives", "")
file("gradle.properties") << "\nsonatypeUsername=testUsername" << "\nsonatypePassword=testPassword"
when:
def result = runTasksSuccessfully('tasks')
def result = runTasksWithFailure('getStagingProfile')
then:
assertFailureWithConnectionRefused(result.failure)
and:
result.standardOutput.contains("Using username 'testUsername' and password from repository 'Test repo'")
}

def "should read username and password from property when available"() {
given:
copyResources("sampleProjects//uploadArchives", "")
file("gradle.properties") << "\nnexusUsername=nexusTestUsername" << "\nnexusPassword=nexusTestPassword"
when:
def result = runTasksWithFailure('getStagingProfile', '--build-file', 'build-property.gradle')
then:
assertFailureWithConnectionRefused(result.failure)
and:
//Cannot assert precisely as those values can be overridden by user's ~/.gradle/gradle.properties
result.standardOutput.contains("Using password '*****' from Gradle property") //TODO: matching with regexp
}

def "should not try read username and password when release tasks are not executed"() {
given:
copyResources("sampleProjects//uploadArchives", "")
file("gradle.properties") << "\nnexusUsername=nexusTestUsername" << "\nnexusPassword=nexusTestPassword"
when:
def result = runTasksSuccessfully('tasks', '--build-file', 'build-property.gradle')
then:
!result.standardOutput.contains("Using password '*****' from Gradle property") //TODO: matching with regexp
}

private static void assertFailureWithConnectionRefused(Throwable failure) {
Throwable rootCause = StackTraceUtils.extractRootCause(failure)
rootCause.getClass() == ConnectException
rootCause.message == "Connection refused"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apply plugin: 'groovy'
apply plugin: 'io.codearte.nexus-staging'

repositories {
mavenCentral()
}

dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.7'

testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'junit:junit:4.11'
}

artifacts {
archives jar
}

nexusStaging {
serverUrl = 'http://localhost:8089/nexus/'
packageGroup = "io.codearte"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
group=com.example.upload1
version=0.0.1-SNAPSHOT
sonatypeUsername=testUsername
sonatypePassword=testPassword

0 comments on commit 1614604

Please sign in to comment.