/*
* Copyright (C) 2010 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.bamboo.builder;
import com.atlassian.bamboo.configuration.AdministrationConfiguration;
import com.atlassian.bamboo.configuration.AdministrationConfigurationAccessor;
import com.atlassian.bamboo.utils.EscapeChars;
import com.atlassian.bamboo.v2.build.BuildContext;
import com.atlassian.spring.container.ContainerManager;
import com.google.common.collect.Maps;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.jfrog.bamboo.admin.ServerConfigManager;
import org.jfrog.bamboo.configuration.BuildParamsOverrideManager;
import org.jfrog.bamboo.configuration.ConfigurationHelper;
import org.jfrog.bamboo.context.AbstractBuildContext;
import org.jfrog.bamboo.util.Utils;
import org.jfrog.build.api.BuildInfoConfigProperties;
import org.jfrog.build.api.BuildInfoProperties;
import org.jfrog.build.extractor.BuildInfoExtractorUtils;
import org.jfrog.build.extractor.clientConfiguration.ClientProperties;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import static org.jfrog.bamboo.util.ConstantValues.BUILD_SERVLET_CONTEXT_NAME;
import static org.jfrog.bamboo.util.ConstantValues.BUILD_SERVLET_KEY_PARAM;
/**
* @author Noam Y. Tenne
*/
public abstract class BaseBuildInfoHelper {
@SuppressWarnings({"UnusedDeclaration"})
private static final Logger log = Logger.getLogger(BaseBuildInfoHelper.class);
protected BuildContext context;
protected ServerConfigManager serverConfigManager;
protected AdministrationConfiguration administrationConfiguration;
protected AdministrationConfigurationAccessor administrationConfigurationAccessor;
private HttpClient httpClient;
protected String bambooBaseUrl;
protected BuildParamsOverrideManager buildParamsOverrideManager;
public void init(BuildParamsOverrideManager buildParamsOverrideManager, BuildContext context) {
this.context = context;
serverConfigManager = ServerConfigManager.getInstance();
ContainerManager.autowireComponent(this);
httpClient = new HttpClient();
bambooBaseUrl = determineBambooBaseUrl();
this.buildParamsOverrideManager = buildParamsOverrideManager;
}
public void setAdministrationConfiguration(AdministrationConfiguration administrationConfiguration) {
this.administrationConfiguration = administrationConfiguration;
}
public void setAdministrationConfigurationAccessor(
AdministrationConfigurationAccessor administrationConfigurationAccessor) {
this.administrationConfigurationAccessor = administrationConfigurationAccessor;
}
/**
* Returns the full name of the build with the given key
*
* @param triggeringBuildKey Key of build to retrieve
* @return Build full name
*/
protected String getBuildName(String triggeringBuildKey) {
try {
Map<String, String> params = Maps.newHashMap();
params.put(BUILD_SERVLET_KEY_PARAM, triggeringBuildKey);
return getStringResource(BUILD_SERVLET_CONTEXT_NAME, params);
} catch (IOException ioe) {
log.error("Unable to determine triggering build name.", ioe);
return null;
}
}
protected String getPublishingRepoKey(AbstractBuildContext buildContext, Map<String, String> environment) {
// In case this is a Release Staging build, return the publishing repo configured
// in the Release Staging configuration page:
String releaseManagementPublishRepo = environment.get("bamboo_release_management_repoKey");
if (StringUtils.isNotBlank(releaseManagementPublishRepo)) {
return releaseManagementPublishRepo;
}
// Take the publishing repo defined as a Bamboo variable or, if not defined, take the value
// configured in the task configuration page:
return overrideParam(
buildContext.getPublishingRepo(),
BuildParamsOverrideManager.OVERRIDE_ARTIFACTORY_DEPLOY_REPO);
}
/**
* Returns the String value of the remote resource
*
* @param servletName Name of servlet to query
* @param params Parameters to pass in the request
* @return String value if found, Null if not
*/
private String getStringResource(String servletName, Map<String, String> params) throws IOException {
String requestUrl = prepareRequestUrl(servletName, params);
GetMethod getMethod = new GetMethod(requestUrl);
try {
executeMethod(requestUrl, getMethod);
return getMethod.getResponseBodyAsString();
} finally {
getMethod.releaseConnection();
}
}
/**
* Filters Bamboo global variables for build info model and matrix params
*/
protected Map<String, String> filterAndGetGlobalVariables() {
Map<String, String> variablesToReturn = Maps.newHashMap();
Map<String, String> globalVariables = ConfigurationHelper.getInstance().getAllVariables(context.getTypedPlanKey());
String propFilePath = globalVariables.get(BuildInfoConfigProperties.PROP_PROPS_FILE);
if (StringUtils.isNotBlank(propFilePath)) {
File propFile = new File(propFilePath);
if (propFile.isFile()) {
Properties fileProperties = new Properties();
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(propFile);
fileProperties.load(inputStream);
} catch (IOException ioe) {
log.error("Error occurred while trying to resolve build info properties from: " + propFilePath,
ioe);
} finally {
IOUtils.closeQuietly(inputStream);
}
Properties filteredProperties = new Properties();
filteredProperties.putAll(BuildInfoExtractorUtils.
filterDynamicProperties(fileProperties, BuildInfoExtractorUtils.MATRIX_PARAM_PREDICATE));
filteredProperties.putAll(BuildInfoExtractorUtils.
filterDynamicProperties(fileProperties, BuildInfoExtractorUtils.BUILD_INFO_PROP_PREDICATE));
for (Map.Entry filteredProperty : filteredProperties.entrySet()) {
setVariable(variablesToReturn, ((String) filteredProperty.getKey()),
((String) filteredProperty.getValue()));
}
}
}
addGlobalVariables(variablesToReturn,
Utils.filterMapKeysByPrefix(globalVariables, ClientProperties.PROP_DEPLOY_PARAM_PROP_PREFIX));
addGlobalVariables(variablesToReturn,
Utils.filterMapKeysByPrefix(globalVariables, BuildInfoProperties.BUILD_INFO_PROP_PREFIX));
return variablesToReturn;
}
/**
* Adds the given filtered global variables to the given properties collection
*/
private void addGlobalVariables(Map<String, String> variablesToReturn,
Map<String, String> filteredGlobalVariables) {
for (Map.Entry<String, String> filteredGlobalVariable : filteredGlobalVariables.entrySet()) {
setVariable(variablesToReturn, filteredGlobalVariable.getKey(), filteredGlobalVariable.getValue());
}
}
private void setVariable(Map<String, String> variables, String propertyKey, String propertyValue) {
if (StringUtils.isNotBlank(propertyValue)) {
variables.put(propertyKey, propertyValue);
}
}
private String prepareRequestUrl(String servletName, Map<String, String> params) {
StringBuilder builder = new StringBuilder(bambooBaseUrl);
if (!bambooBaseUrl.endsWith("/")) {
builder.append("/");
}
StringBuilder requestUrlBuilder = builder.append("plugins/servlet/").append(servletName);
if (params.size() != 0) {
requestUrlBuilder.append("?");
for (Map.Entry<String, String> param : params.entrySet()) {
if (!requestUrlBuilder.toString().endsWith("?")) {
requestUrlBuilder.append("&");
}
requestUrlBuilder.append(param.getKey()).append("=").append(EscapeChars.forFormSubmission(param.getValue()));
}
}
return requestUrlBuilder.toString();
}
/**
* Executes the given HTTP method
*
* @param requestUrl Full request URL
* @param getMethod HTTP GET method
*/
private void executeMethod(String requestUrl, GetMethod getMethod) throws IOException {
int responseCode = httpClient.executeMethod(getMethod);
if (responseCode == HttpStatus.SC_NOT_FOUND) {
throw new IOException("Unable to find requested resource: " + requestUrl);
} else if (responseCode != HttpStatus.SC_OK) {
throw new IOException("Failed to retrieve requested resource: " + requestUrl + ". Response code: " +
responseCode + ", Message: " + getMethod.getStatusText());
}
}
/**
* Determines the base URL of this Bamboo instance.<br> This method is needed since we query the plugin's servlets
* for build information that isn't accessible to a remote agent.<br> The URL can generally be found in {@link
* com.atlassian.bamboo.configuration.AdministrationConfiguration}
*
* @return Bamboo base URL if found. Null if running in an un-recognized type of agent.
*/
protected String determineBambooBaseUrl() {
if (administrationConfiguration != null) {
return administrationConfiguration.getBaseUrl();
} else if (administrationConfigurationAccessor != null) {
return administrationConfigurationAccessor.getAdministrationConfiguration().getBaseUrl();
}
return null;
}
/**
* Checks if a Bamboo variable was defined to override the task configured value.
* If so then returns the value defined for the variable, else return the original value
*
* @param originalValue Value from the task configuration.
* @param overrideKey Bamboo variable name.
* @return The Bamboo variable if defined. If not, the configured value.
*/
public String overrideParam(String originalValue, String overrideKey) {
String overriddenValue = buildParamsOverrideManager.getOverrideValue(overrideKey);
return overriddenValue.isEmpty() ? originalValue : overriddenValue;
}
}