/*
* Copyright (C) 2011 JFrog Ltd.
*
* 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 org.jfrog.hudson.release.gradle;
import com.google.common.collect.Maps;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.model.Run;
import org.apache.commons.lang.StringUtils;
import org.jfrog.hudson.release.ReleaseAction;
import org.jfrog.hudson.release.scm.AbstractScmCoordinator;
import org.jfrog.hudson.release.scm.ScmCoordinator;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A release wrapper for Gradle projects. Allows performing release steps on Gradle. This class is not a direct {@link
* hudson.tasks.BuildWrapper} but is called from the {@link org.jfrog.hudson.gradle.ArtifactoryGradleConfigurator} as
* part of the release procedure.
*
* @author Tomer Cohen
*/
public class GradleReleaseWrapper {
private final static Logger debuggingLogger = Logger.getLogger(GradleReleaseWrapper.class.getName());
private String tagPrefix;
private String releaseBranchPrefix;
private String targetRemoteName;
private String alternativeTasks;
private String releasePropsKeys;
private String nextIntegPropsKeys;
private String defaultReleaseStagingRepository;
private transient ScmCoordinator scmCoordinator;
private boolean useReleaseBranch;
@DataBoundConstructor
public GradleReleaseWrapper(String releaseBranchPrefix, String tagPrefix, String targetRemoteName, String alternativeTasks,
String releasePropsKeys, String nextIntegPropsKeys, String defaultReleaseStagingRepository, boolean useReleaseBranch) {
this.releaseBranchPrefix = releaseBranchPrefix;
this.tagPrefix = tagPrefix;
this.targetRemoteName = targetRemoteName;
this.alternativeTasks = alternativeTasks;
this.releasePropsKeys = releasePropsKeys;
this.nextIntegPropsKeys = nextIntegPropsKeys;
this.defaultReleaseStagingRepository = defaultReleaseStagingRepository;
this.useReleaseBranch = useReleaseBranch;
}
public ScmCoordinator getScmCoordinator() {
return scmCoordinator;
}
@SuppressWarnings({"UnusedDeclaration"})
public String getTagPrefix() {
return tagPrefix;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setTagPrefix(String tagPrefix) {
this.tagPrefix = tagPrefix;
}
public String getTargetRemoteName() {
return targetRemoteName;
}
public void setTargetRemoteName(String targetRemoteName) {
this.targetRemoteName = targetRemoteName;
}
public String getReleasePropsKeys() {
return releasePropsKeys;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setReleasePropsKeys(String releasePropsKeys) {
this.releasePropsKeys = releasePropsKeys;
}
public String getNextIntegPropsKeys() {
return nextIntegPropsKeys;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setNextIntegPropsKeys(String nextIntegPropsKeys) {
this.nextIntegPropsKeys = nextIntegPropsKeys;
}
public String getReleaseBranchPrefix() {
return releaseBranchPrefix;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setReleaseBranchPrefix(String releaseBranchPrefix) {
this.releaseBranchPrefix = releaseBranchPrefix;
}
@SuppressWarnings({"UnusedDeclaration"})
public String getAlternativeTasks() {
return alternativeTasks;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setAlternativeTasks(String alternativeTasks) {
this.alternativeTasks = alternativeTasks;
}
@SuppressWarnings({"UnusedDeclaration"})
public String getDefaultReleaseStagingRepository() {
return defaultReleaseStagingRepository;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setDefaultReleaseStagingRepository(String defaultReleaseStagingRepository) {
this.defaultReleaseStagingRepository = defaultReleaseStagingRepository;
}
@SuppressWarnings({"UnusedDeclaration"})
public boolean isUseReleaseBranch() {
return this.useReleaseBranch;
}
@SuppressWarnings({"UnusedDeclaration"})
public void setUseReleaseBranch(boolean useReleaseBranch) {
this.useReleaseBranch = useReleaseBranch;
}
public String[] getReleasePropsKeysList() {
return stringToArray(getReleasePropsKeys());
}
public String[] getNextIntegPropsKeysList() {
return stringToArray(getNextIntegPropsKeys());
}
private String[] stringToArray(String commaSeparatedString) {
commaSeparatedString = StringUtils.trimToEmpty(commaSeparatedString);
return StringUtils.split(commaSeparatedString, ", ");
}
public void setUp(AbstractBuild build, Launcher launcher, BuildListener listener)
throws IOException, InterruptedException {
BaseGradleReleaseAction releaseAction = build.getAction(GradleReleaseAction.class);
if (releaseAction == null) {
releaseAction = build.getAction(GradleReleaseApiAction.class);
}
if (releaseAction == null) {
// this is a normal non release build, continue with normal environment
return;
}
log(listener, "Release build triggered");
scmCoordinator = AbstractScmCoordinator.createScmCoordinator(build, listener, releaseAction);
scmCoordinator.prepare();
// TODO: replace the versioning mode with something else
if (!releaseAction.getVersioning().equals(ReleaseAction.VERSIONING.NONE)) {
scmCoordinator.beforeReleaseVersionChange();
// change to release properties values
boolean modified = changeProperties(build, releaseAction, true, listener);
scmCoordinator.afterReleaseVersionChange(modified);
}
}
public boolean tearDown(AbstractBuild build, BuildListener listener) {
Result result = build.getResult();
if (result == null || result.isWorseThan(Result.SUCCESS)) {
// revert will happen by the listener
return true;
}
BaseGradleReleaseAction releaseAction = build.getAction(GradleReleaseAction.class);
if (releaseAction == null) {
releaseAction = build.getAction(GradleReleaseApiAction.class);
}
try {
scmCoordinator.afterSuccessfulReleaseVersionBuild();
if (!releaseAction.getVersioning().equals(ReleaseAction.VERSIONING.NONE)) {
scmCoordinator.beforeDevelopmentVersionChange();
boolean modified = changeProperties(build, releaseAction, false, listener);
scmCoordinator.afterDevelopmentVersionChange(modified);
}
} catch (Exception e) {
listener.getLogger().println("Failure in post build SCM action: " + e.getMessage());
debuggingLogger.log(Level.FINE, "Failure in post build SCM action: ", e);
return false;
}
return true;
}
private boolean changeProperties(AbstractBuild build, BaseGradleReleaseAction release, boolean releaseVersion,
BuildListener listener) throws IOException, InterruptedException {
FilePath root = release.getModuleRoot(build.getEnvironment(listener));
debuggingLogger.fine("Root directory is: " + root.getRemote());
String[] modules = release.getReleaseProperties();
Map<String, String> modulesByName = Maps.newHashMap();
for (String module : modules) {
String version = releaseVersion ? release.getReleaseVersionFor(module) :
release.getCurrentVersionFor(module);
modulesByName.put(module, version);
}
String[] additionalModuleProperties = release.getNextIntegProperties();
for (String property : additionalModuleProperties) {
String version = releaseVersion ? release.getReleaseVersionFor(property) :
release.getNextVersionFor(property);
modulesByName.put(property, version);
}
debuggingLogger.fine("Changing version of gradle properties");
FilePath gradlePropertiesFilePath = new FilePath(root, "gradle.properties");
String next = releaseVersion ? "release" : "development";
log(listener,
"Changing gradle.properties at " + gradlePropertiesFilePath.getRemote() + " for " + next + " version");
scmCoordinator.edit(gradlePropertiesFilePath);
boolean modified = gradlePropertiesFilePath.act(new GradlePropertiesTransformer(modulesByName));
if (!modified && !modulesByName.isEmpty() && releaseVersion) {
build.setResult(Result.FAILURE);
listener.fatalError("Could not find the defined release properties in this build's gradle.properties . Please check the release properties defined in the job configuration.\n");
throw new Run.RunnerAbortedException();
}
return modified;
}
private void log(BuildListener listener, String message) {
listener.getLogger().println("[RELEASE] " + message);
}
}