Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,12 @@ class NetflixOssStrategies {
return { state ->
def nebulaReleaseExtension = project.extensions.findByType(ReleaseExtension)
boolean needsBranchMetadata = true
nebulaReleaseExtension.releaseBranchPatterns.each {
nebulaReleaseExtension.releaseBranchPatterns.get().each {
if (state.currentBranch.name =~ it) {
needsBranchMetadata = false
}
}
String shortenedBranch = (state.currentBranch.name =~ nebulaReleaseExtension.shortenedBranchPattern)[0][1]
String shortenedBranch = (state.currentBranch.name =~ nebulaReleaseExtension.shortenedBranchPattern.get())[0][1]
shortenedBranch = shortenedBranch.replaceAll(/[_\/-]/, '.')
def metadata = needsBranchMetadata ? "${shortenedBranch}.${state.currentHead.abbreviatedId}" : state.currentHead.abbreviatedId
state.copyWith(inferredBuildMetadata: metadata)
Expand Down
36 changes: 22 additions & 14 deletions src/main/groovy/nebula/plugin/release/ReleaseCheck.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,51 @@ package nebula.plugin.release

import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault

@DisableCachingByDefault
class ReleaseCheck extends DefaultTask {
abstract class ReleaseCheck extends DefaultTask {
@Input
String branchName
@Input
ReleaseExtension patterns
abstract Property<String> getBranchName()

@Nested
abstract Property<ReleaseExtension> getPatterns()

@Input
boolean isSnapshotRelease
abstract Property<Boolean> getIsSnapshotRelease()

@TaskAction
void check() {
if (patterns.allowReleaseFromDetached) {
ReleaseExtension patternsValue = patterns.get()
String branch = branchName.get()
boolean isSnapshot = isSnapshotRelease.get()

if (patternsValue.allowReleaseFromDetached.get()) {
return
}
boolean includeMatch = patterns.releaseBranchPatterns.isEmpty()
boolean includeMatch = patternsValue.releaseBranchPatterns.get().isEmpty()

patterns.releaseBranchPatterns.each { String pattern ->
if (getBranchName() ==~ pattern) includeMatch = true
patternsValue.releaseBranchPatterns.get().each { String pattern ->
if (branch ==~ pattern) includeMatch = true
}

boolean excludeMatch = false
patterns.excludeBranchPatterns.each { String pattern ->
if (getBranchName() ==~ pattern) excludeMatch = true
patternsValue.excludeBranchPatterns.get().each { String pattern ->
if (branch ==~ pattern) excludeMatch = true
}

if (!includeMatch && !isSnapshotRelease) {
String message = "Branch ${getBranchName()} does not match one of the included patterns: ${patterns.releaseBranchPatterns}"
if (!includeMatch && !isSnapshot) {
String message = "Branch ${branch} does not match one of the included patterns: ${patternsValue.releaseBranchPatterns.get()}"
logger.error(message)
throw new GradleException(message)
}

if (excludeMatch) {
String message = "Branch ${getBranchName()} matched an excluded pattern: ${patterns.excludeBranchPatterns}"
String message = "Branch ${branch} matched an excluded pattern: ${patternsValue.excludeBranchPatterns.get()}"
logger.error(message)
throw new GradleException(message)
}
Expand Down
34 changes: 28 additions & 6 deletions src/main/groovy/nebula/plugin/release/ReleaseExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,42 @@
*/
package nebula.plugin.release

class ReleaseExtension {
Set<String> releaseBranchPatterns = [/master/, /HEAD/, /main/, /(release(-|\/))?\d+(\.\d+)?\.x/, /v?\d+\.\d+\.\d+/] as Set<String>
Set<String> excludeBranchPatterns = [] as Set<String>
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.Input

import javax.inject.Inject

abstract class ReleaseExtension {
@Input
abstract SetProperty<String> getReleaseBranchPatterns()

@Input
abstract SetProperty<String> getExcludeBranchPatterns()

/**
* This should be a regex pattern with one(1) capture group. By default shortens the typical
* {bugfix|feature|hotfix|release}/branch-name to branch-name. The prefix is optional and a
* dash may be used instead of the forward slash.
*/
String shortenedBranchPattern = /(?:(?:bugfix|feature|hotfix|release)(?:-|\/))?(.+)/
@Input
abstract Property<String> getShortenedBranchPattern()

Boolean allowReleaseFromDetached = false
@Input
abstract Property<Boolean> getAllowReleaseFromDetached()

Boolean checkRemoteBranchOnRelease = false
@Input
abstract Property<Boolean> getCheckRemoteBranchOnRelease()

@Inject
ReleaseExtension(ObjectFactory objects) {
releaseBranchPatterns.convention([/master/, /HEAD/, /main/, /(release(-|\/))?\d+(\.\d+)?\.x/, /v?\d+\.\d+\.\d+/] as Set<String>)
excludeBranchPatterns.convention([] as Set<String>)
shortenedBranchPattern.convention(/(?:(?:bugfix|feature|hotfix|release)(?:-|\/))?(.+)/)
allowReleaseFromDetached.convention(false)
checkRemoteBranchOnRelease.convention(false)
}

void addReleaseBranchPattern(String pattern) {
releaseBranchPatterns.add(pattern)
Expand Down
85 changes: 50 additions & 35 deletions src/main/groovy/nebula/plugin/release/ReleasePlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.gradle.api.execution.TaskExecutionGraph
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.publish.ivy.IvyPublication
import org.gradle.api.publish.ivy.plugins.IvyPublishPlugin
Expand All @@ -51,24 +52,25 @@ class ReleasePlugin implements Plugin<Project> {
static Logger logger = Logging.getLogger(ReleasePlugin)
static final String GROUP = 'Nebula Release'

private final GitBuildService gitBuildService
private final Provider<GitBuildService> gitBuildService
private final File gitRoot

@CompileDynamic
@Inject
ReleasePlugin(Project project, ExecOperations execOperations, ProviderFactory providerFactory) {
this.gitRoot = project.hasProperty('git.root') ? project.file(project.property('git.root')) : project.rootProject.projectDir

this.gitBuildService = project.getGradle().getSharedServices().registerIfAbsent("gitBuildService", GitBuildService.class, spec -> {
spec.getParameters().getGitRootDir().set(gitRoot)
}).get()
})
}

@CompileDynamic
@Override
void apply(Project project) {
this.project = project

boolean isGitRepo = gitBuildService.isGitRepo()
boolean isGitRepo = gitBuildService.get().isGitRepo()
if(!isGitRepo) {
this.project.version = '0.1.0-dev.0.uncommitted'
logger.warn("Git repository not found at $gitRoot -- nebula-release tasks will not be available. Use the git.root Gradle property to specify a different directory.")
Expand All @@ -79,7 +81,7 @@ class ReleasePlugin implements Plugin<Project> {
// Verify user git config only when using release tags and 'release.useLastTag' property is not used
boolean shouldVerifyUserGitConfig = isReleaseTaskThatRequiresTagging(project.gradle.startParameter.taskNames) && !isUsingLatestTag(project)
if(shouldVerifyUserGitConfig) {
gitBuildService.verifyUserGitConfig()
gitBuildService.get().verifyUserGitConfig()
}

checkForBadBranchNames()
Expand All @@ -89,10 +91,10 @@ class ReleasePlugin implements Plugin<Project> {
ReleasePluginExtension releaseExtension = project.extensions.findByType(ReleasePluginExtension)

SemVerStrategy defaultStrategy = replaceDevSnapshots ? NetflixOssStrategies.IMMUTABLE_SNAPSHOT(project) : NetflixOssStrategies.DEVELOPMENT(project)
def propertyBasedStrategy
if (project.hasProperty(DEFAULT_VERSIONING_STRATEGY)) {
propertyBasedStrategy = getPropertyBasedVersioningStrategy()
}

def propertyBasedStrategy = project.providers.gradleProperty(DEFAULT_VERSIONING_STRATEGY)
.map { clazzName -> getPropertyBasedVersioningStrategy(clazzName) }
.getOrNull()
releaseExtension.with {
versionStrategy new OverrideStrategies.NoCommitStrategy()
versionStrategy new OverrideStrategies.ReleaseLastTagStrategy(project)
Expand Down Expand Up @@ -126,56 +128,66 @@ class ReleasePlugin implements Plugin<Project> {

TaskProvider<ReleaseCheck> releaseCheck = project.tasks.register(RELEASE_CHECK_TASK_NAME, ReleaseCheck) {
it.group = GROUP
it.branchName = gitBuildService.currentBranch
it.patterns = nebulaReleaseExtension
it.branchName.set(gitBuildService.map { it.currentBranch })
it.patterns.set(nebulaReleaseExtension)
}

TaskProvider<Task> postReleaseTask = project.tasks.register(POST_RELEASE_TASK_NAME) {
it.group = GROUP
it.dependsOn project.tasks.named('release')
}

TaskProvider snapshotSetupTask = project.tasks.register(SNAPSHOT_SETUP_TASK_NAME)
TaskProvider immutableSnapshotSetupTask = project.tasks.register(IMMUTABLE_SNAPSHOT_SETUP_TASK_NAME)
TaskProvider devSnapshotSetupTask = project.tasks.register(DEV_SNAPSHOT_SETUP_TASK_NAME)
TaskProvider snapshotSetupTask = project.tasks.register(SNAPSHOT_SETUP_TASK_NAME) {
it.group = GROUP
it.dependsOn releaseCheck
}
TaskProvider immutableSnapshotSetupTask = project.tasks.register(IMMUTABLE_SNAPSHOT_SETUP_TASK_NAME) {
it.group = GROUP
it.dependsOn releaseCheck
}
TaskProvider devSnapshotSetupTask = project.tasks.register(DEV_SNAPSHOT_SETUP_TASK_NAME) {
it.group = GROUP
it.dependsOn releaseCheck
}
TaskProvider candidateSetupTask = project.tasks.register(CANDIDATE_SETUP_TASK_NAME) {
it.group = GROUP
it.dependsOn releaseCheck
it.configure {
project.allprojects.each { it.status = 'candidate' }
}
}
TaskProvider finalSetupTask = project.tasks.register(FINAL_SETUP_TASK_NAME) {
it.group = GROUP
it.dependsOn releaseCheck
it.configure {
project.allprojects.each { it.status = 'release' }
}
}
[snapshotSetupTask, immutableSnapshotSetupTask, devSnapshotSetupTask, candidateSetupTask, finalSetupTask].each {
it.configure {
it.group = GROUP
it.dependsOn releaseCheck
}
}

TaskProvider<Task> snapshotTask = project.tasks.register(SNAPSHOT_TASK_NAME) {
it.group = GROUP
it.dependsOn snapshotSetupTask
it.dependsOn postReleaseTask
}
TaskProvider<Task> immutableSnapshotTask = project.tasks.register(IMMUTABLE_SNAPSHOT_TASK_NAME) {
it.group = GROUP
it.dependsOn immutableSnapshotSetupTask
it.dependsOn postReleaseTask
}
TaskProvider<Task> devSnapshotTask = project.tasks.register(DEV_SNAPSHOT_TASK_NAME) {
it.group = GROUP
it.dependsOn devSnapshotSetupTask
it.dependsOn postReleaseTask
}
TaskProvider<Task> candidateTask = project.tasks.register(CANDIDATE_TASK_NAME) {
it.group = GROUP
it.dependsOn candidateSetupTask
it.dependsOn postReleaseTask
}
TaskProvider<Task> finalTask = project.tasks.register(FINAL_TASK_NAME) {
it.group = GROUP
it.dependsOn finalSetupTask
}

[snapshotTask, immutableSnapshotTask, devSnapshotTask, candidateTask, finalTask].each {
it.configure {
it.group = GROUP
it.dependsOn postReleaseTask
}
it.dependsOn postReleaseTask
}

List<String> cliTasks = project.gradle.startParameter.taskNames
Expand All @@ -187,7 +199,7 @@ class ReleasePlugin implements Plugin<Project> {
}

project.gradle.taskGraph.whenReady { TaskExecutionGraph g ->
if (!nebulaReleaseExtension.checkRemoteBranchOnRelease) {
if (!nebulaReleaseExtension.checkRemoteBranchOnRelease.get()) {
removePrepLogic(project)
}
}
Expand Down Expand Up @@ -220,8 +232,7 @@ class ReleasePlugin implements Plugin<Project> {
configureArtifactoryGradlePluginIfPresent()
}

private Object getPropertyBasedVersioningStrategy() {
String clazzName = project.property(DEFAULT_VERSIONING_STRATEGY).toString()
private Object getPropertyBasedVersioningStrategy(String clazzName) {
try {
return Class.forName(clazzName).getDeclaredConstructor().newInstance()
} catch (ClassNotFoundException e) {
Expand Down Expand Up @@ -260,7 +271,7 @@ class ReleasePlugin implements Plugin<Project> {
def isSnapshotRelease = hasSnapshot || hasDevSnapshot || hasImmutableSnapshot || (!hasCandidate && !hasFinal)

releaseCheck.configure {
it.isSnapshotRelease = isSnapshotRelease
it.isSnapshotRelease.set(isSnapshotRelease)
}

if (hasFinal) {
Expand All @@ -286,7 +297,7 @@ class ReleasePlugin implements Plugin<Project> {

private void checkStateForStage(boolean isSnapshotRelease) {
if (!isSnapshotRelease) {
String status = gitBuildService.status
String status = gitBuildService.get().status
if (!status.empty) {
String message = new ErrorMessageFormatter().format(status)
throw new GradleException(message)
Expand All @@ -295,16 +306,20 @@ class ReleasePlugin implements Plugin<Project> {
}

private boolean shouldSkipGitChecks() {
def disableGit = project.hasProperty(DISABLE_GIT_CHECKS) && project.property(DISABLE_GIT_CHECKS) as Boolean
def travis = project.hasProperty('release.travisci') && project.property('release.travisci').toString().toBoolean()
def disableGit = project.providers.gradleProperty(DISABLE_GIT_CHECKS)
.map { it.toBoolean() }
.getOrElse(false)
def travis = project.providers.gradleProperty('release.travisci')
.map { it.toBoolean() }
.getOrElse(false)
disableGit || travis
}

@CompileDynamic
void setupStatus(String status) {
project.plugins.withType(IvyPublishPlugin) {
project.publishing {
publications.withType(IvyPublication) {
publications.withType(IvyPublication).configureEach {
Copy link
Member

Choose a reason for hiding this comment

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

💯

descriptor.status = status
}
}
Expand Down Expand Up @@ -370,7 +385,7 @@ class ReleasePlugin implements Plugin<Project> {
}

void checkForBadBranchNames() {
String currentBranch = gitBuildService.currentBranch
String currentBranch = gitBuildService.get().currentBranch
if (!currentBranch) {
return
}
Expand Down
Loading