All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.researchgate.release.ReleasePlugin.groovy Maven / Gradle / Ivy

Go to download

gradle-release is a plugin for providing a Maven-like release process to project using Gradle.

There is a newer version: 2.4.0
Show newest version
package net.researchgate.release

import java.util.regex.Matcher

import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Dependency
import org.gradle.api.tasks.GradleBuild
import org.gradle.api.tasks.TaskState

/**
 * @author elberry
 * @author evgenyg
 * Created: Tue Aug 09 15:32:00 PDT 2011
 */
class ReleasePlugin extends PluginHelper implements Plugin {
	static final String RELEASE_GROUP = "Release"

	@SuppressWarnings('StatelessClass')
	private BaseScmPlugin scmPlugin

	void apply(Project project) {
		this.project = project

		setConvention('release', new ReleasePluginConvention())

		def preCommitText = findProperty("release.preCommitText") ?: findProperty("preCommitText")
		if (preCommitText) {
			releaseConvention().preCommitText = preCommitText
		}
		this.scmPlugin = applyScmPlugin()

		project.task('release', description: 'Verify project, release, and update version to next.', group: RELEASE_GROUP, type: GradleBuild) {
			startParameter = project.getGradle().startParameter.newInstance()

			tasks = [
					//  0. (This Plugin) Initializes the corresponding SCM plugin (Git/Bazaar/Svn/Mercurial).
					'initScmPlugin',
					//  1. (SCM Plugin) Check to see if source needs to be checked in.
					'checkCommitNeeded',
					//  2. (SCM Plugin) Check to see if source is out of date
					'checkUpdateNeeded',
					//  3. (This Plugin) Update Snapshot version if used
					//     Needs to be done before checking for snapshot versions since the project might depend on other
					//     Modules within the same project.
					'unSnapshotVersion',
					//  4. (This Plugin) Confirm this release version
					'confirmReleaseVersion',
					//  5. (This Plugin) Check for SNAPSHOT dependencies if required.
					'checkSnapshotDependencies',
					//  6. (This Plugin) Build && run Unit tests
					'build',
					//  7. (This Plugin) Commit Snapshot update (if done)
					'preTagCommit',
					//  8. (SCM Plugin) Create tag of release.
					'createReleaseTag',
					//  9. (This Plugin) Update version to next version.
					'updateVersion',
					// 10. (This Plugin) Commit version update.
					'commitNewVersion'
			]
		}

		project.task('initScmPlugin', group: RELEASE_GROUP,
				description: 'Initializes the SCM plugin (based on hidden directories in your project\'s directory)') << this.&initScmPlugin
		project.task('checkSnapshotDependencies', group: RELEASE_GROUP,
				description: 'Checks to see if your project has any SNAPSHOT dependencies.') << this.&checkSnapshotDependencies
		project.task('unSnapshotVersion', group: RELEASE_GROUP,
				description: 'Removes "-SNAPSHOT" from your project\'s current version.') << this.&unSnapshotVersion
		project.task('confirmReleaseVersion', group: RELEASE_GROUP,
				description: 'Prompts user for this release version. Allows for alpha or pre releases.') << this.&confirmReleaseVersion
		project.task('preTagCommit', group: RELEASE_GROUP,
				description: 'Commits any changes made by the Release plugin - eg. If the unSnapshotVersion tas was executed') << this.&preTagCommit
		project.task('updateVersion', group: RELEASE_GROUP,
				description: 'Prompts user for the next version. Does it\'s best to supply a smart default.') << this.&updateVersion
		project.task('commitNewVersion', group: RELEASE_GROUP,
				description: 'Commits the version update to your SCM') << this.&commitNewVersion
		project.task('createReleaseTag', group: RELEASE_GROUP,
				description: 'Creates a tag in SCM for the current (un-snapshotted) version.') << this.&commitTag


		project.gradle.taskGraph.afterTask { Task task, TaskState state ->
			if (state.failure && task.name == "release") {
				if (releaseConvention().revertOnFail && project.file(releaseConvention().versionPropertyFile)?.exists()) {
					log.error("Release process failed, reverting back any changes made by Release Plugin.")
					this.scmPlugin.revert()
				} else {
					log.error("Release process failed, please remember to revert any uncommitted changes made by the Release Plugin.")
				}
			}
		}
	}

	void initScmPlugin() {
        checkPropertiesFile()
		scmPlugin.init()
	}

	void checkSnapshotDependencies() {
		def matcher = { Dependency d -> d.version?.contains('SNAPSHOT') }
		def collector = { Dependency d -> "${d.group ?: ''}:${d.name}:${d.version ?: ''}" }

		def message = ""

		project.allprojects.each { project ->
			def snapshotDependencies = [] as Set
			project.configurations.each { cfg ->
				snapshotDependencies += cfg.dependencies?.matching(matcher)?.collect(collector)
			}
			if (snapshotDependencies.size() > 0) {
				message += "\n\t${project.name}: ${snapshotDependencies}"
			}
		}

		if (message) {
			message = "Snapshot dependencies detected: ${message}"
			warnOrThrow(releaseConvention().failOnSnapshotDependencies, message)
		}
	}

	void commitTag() {
		def message = releaseConvention().tagCommitMessage +
				" '${tagName()}'."
		if (releaseConvention().preCommitText) {
			message = "${releaseConvention().preCommitText} ${message}"
		}
		scmPlugin.createReleaseTag(message)
	}

	void confirmReleaseVersion() {
		def version = getReleaseVersion();
		updateVersionProperty(version)
	}

    String getReleaseVersion(String candidateVersion = "${project.version}") {
        String releaseVersion = project.properties['releaseVersion'];

        if (useAutomaticVersion()) {
            return releaseVersion ?: candidateVersion;
        }

        return readLine("This release version:", releaseVersion ?: candidateVersion);
    }

	void unSnapshotVersion() {
		def version = project.version.toString()

		if (version.contains('-SNAPSHOT')) {
			project.ext.set('usesSnapshot', true)
			project.ext.set('snapshotVersion', version)
			version -= '-SNAPSHOT'
			updateVersionProperty(version)
		} else {
			project.ext.set('usesSnapshot', false)
		}
	}

	void preTagCommit() {
		if (project.properties['usesSnapshot'] || project.properties['versionModified']) {
			// should only be committed if the project was using a snapshot version.
			def message = releaseConvention().preTagCommitMessage +
					" '${tagName()}'."

			if (releaseConvention().preCommitText) {
				message = "${releaseConvention().preCommitText} ${message}"
			}
			scmPlugin.commit(message)
		}
	}

	void updateVersion() {
		def version = project.version.toString()
		Map patterns = releaseConvention().versionPatterns

		for (entry in patterns) {

			String pattern = entry.key
			//noinspection GroovyUnusedAssignment
			Closure handler = entry.value
			Matcher matcher = version =~ pattern

			if (matcher.find()) {
				String nextVersion = handler(matcher, project)
				if (project.properties['usesSnapshot']) {
					nextVersion += '-SNAPSHOT'
				}

				nextVersion = getNextVersion(nextVersion);

				project.ext.set("release.oldVersion", project.version)
				project.ext.set("release.newVersion", nextVersion)
				updateVersionProperty(nextVersion)
				return
			}
		}

		throw new GradleException("Failed to increase version [$version] - unknown pattern")
	}

    String getNextVersion(String candidateVersion) {
        String nextVersion = project.properties['newVersion'];

        if (useAutomaticVersion()) {
            return nextVersion ?: candidateVersion;
        }

        return readLine("Enter the next version (current one released as [${project.version}]):", nextVersion ?: candidateVersion);
    }

	def commitNewVersion() {
		def message = releaseConvention().newVersionCommitMessage +
				" '${tagName()}'."
		if (releaseConvention().preCommitText) {
			message = "${releaseConvention().preCommitText} ${message}"
		}
		scmPlugin.commit(message)
	}


	def checkPropertiesFile() {
		File propertiesFile = findPropertiesFile()

		Properties properties = new Properties()
		propertiesFile.withReader { properties.load(it) }

		assert properties.version, "[$propertiesFile.canonicalPath] contains no 'version' property"
		assert releaseConvention().versionPatterns.keySet().any { (properties.version =~ it).find() },               \
                             "[$propertiesFile.canonicalPath] version [$properties.version] doesn't match any of known version patterns: " +
				releaseConvention().versionPatterns.keySet()
        // set the project version from the properties file if it was not otherwise specified
        if ( !isVersionDefined() ) {
            project.version = properties.version
        }

		try {
			// test to make sure the version property is in the correct version=[version] format.
			project.ant.replace(file: propertiesFile, token: "version=${project.version}", value: "version=${project.version}", failOnNoReplacements: true, preserveLastModified: true)
		} catch (org.apache.tools.ant.BuildException be) {
			throw new GradleException("Unable to update version property. Please check file permissions, and ensure property is in \"version=${project.version}\" format.")
		}
	}

	/**
	 * Looks for special directories in the project folder, then applies the correct SCM Release Plugin for the SCM type.
	 * @param project
	 */
	private BaseScmPlugin applyScmPlugin() {

		def projectPath = project.rootProject.projectDir.canonicalFile

		Class c = findScmType(projectPath)

		if (!c) {
			throw new GradleException(
					'Unsupported SCM system, no .svn, .bzr, .git, or .hg found in ' +
							"[${ projectPath }] or its parent directories.")
		}

		assert BaseScmPlugin.isAssignableFrom(c)

		project.apply plugin: c
		project.plugins.findPlugin(c)
	}

	/**
	 * Recursively look for the type of the SCM we are dealing with, if no match is found look in parent directory
	 * @param directory the directory to start from
	 */
	protected Class findScmType(File directory) {

		Class c = (Class) directory.list().with {
			delegate.grep('.svn') ? SvnReleasePlugin :
				delegate.grep('.bzr') ? BzrReleasePlugin :
					delegate.grep('.git') ? GitReleasePlugin :
						delegate.grep('.hg') ? HgReleasePlugin :
							null
		}

		if (!c && directory.parentFile) {
			c = findScmType(directory.parentFile)
		}

		c
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy