in src/main/java/CodeBuilder.java [268:590]
public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath ws, @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws InterruptedException, IOException {
descriptor = getDescriptor();
envVars = build.getEnvironment(listener);
AWSClientFactory awsClientFactory;
try {
awsClientFactory = new AWSClientFactory(
getParameterized(this.credentialsType),
getParameterized(this.credentialsId),
getParameterized(this.proxyHost),
getParameterized(this.proxyPort),
getParameterized(this.awsAccessKey),
this.awsSecretKey,
getParameterized(this.awsSessionToken),
getParameterized(this.region),
build,
this.stepContext);
} catch (Exception e) {
failBuild(build, listener, authorizationError, e.getMessage());
return;
}
String projectConfigError = CodeBuilderValidation.checkEssentialConfig(this);
if(!projectConfigError.isEmpty()) {
failBuild(build, listener, configuredImproperlyError, projectConfigError);
return;
}
String overridesErrorMessage = CodeBuilderValidation.checkStartBuildOverridesConfig(this);
if(!overridesErrorMessage.isEmpty()) {
failBuild(build, listener, configuredImproperlyError, overridesErrorMessage);
return;
}
Collection<EnvironmentVariable> codeBuildEnvVars = null;
try {
codeBuildEnvVars = mapEnvVariables(getParameterized(envVariables), EnvironmentVariableType.PLAINTEXT);
codeBuildEnvVars.addAll(mapEnvVariables(getParameterized(envParameters), EnvironmentVariableType.PARAMETER_STORE));
} catch(InvalidInputException e) {
failBuild(build, listener, configuredImproperlyError, e.getMessage());
return;
}
if(CodeBuilderValidation.envVariablesHaveRestrictedPrefix(codeBuildEnvVars)) {
failBuild(build, listener, configuredImproperlyError, envVariableNameSpaceError);
return;
}
LoggingHelper.log(listener, awsClientFactory.getCredentialsDescriptor());
final AWSCodeBuildClient cbClient;
try {
cbClient = awsClientFactory.getCodeBuildClient();
} catch (Exception e) {
failBuild(build, listener, "Error when constructing CodeBuild client: ", e.getMessage());
return;
}
StartBuildRequest startBuildRequest = new StartBuildRequest().withProjectName(getParameterized(projectName)).
withEnvironmentVariablesOverride(codeBuildEnvVars).withBuildspecOverride(getParameterized(buildSpecFile)).
withTimeoutInMinutesOverride(parseInt(getParameterized(buildTimeoutOverride)));
ProjectArtifacts artifactsOverride = generateStartBuildArtifactOverride();
if(artifactsOverride != null) {
startBuildRequest.setArtifactsOverride(artifactsOverride);
}
ProjectCache cacheOverride = generateStartBuildCacheOverride();
if(cacheOverride != null) {
startBuildRequest.setCacheOverride(cacheOverride);
}
LogsConfig logsConfigOverride = generateStartBuildLogsConfigOverride();
if(logsConfigOverride != null) {
startBuildRequest.setLogsConfigOverride(logsConfigOverride);
}
if(!getParameterized(environmentTypeOverride).isEmpty()) {
startBuildRequest.setEnvironmentTypeOverride(getParameterized(environmentTypeOverride));
}
if(!getParameterized(imageOverride).isEmpty()) {
startBuildRequest.setImageOverride(getParameterized(imageOverride));
}
if(!getParameterized(computeTypeOverride).isEmpty()) {
startBuildRequest.setComputeTypeOverride(getParameterized(computeTypeOverride));
}
if(!getParameterized(certificateOverride).isEmpty()) {
startBuildRequest.setCertificateOverride(getParameterized(certificateOverride));
}
if(!getParameterized(serviceRoleOverride).isEmpty()) {
startBuildRequest.setServiceRoleOverride(getParameterized(serviceRoleOverride));
}
if(!getParameterized(insecureSslOverride).isEmpty()) {
startBuildRequest.setInsecureSslOverride(Boolean.parseBoolean(getParameterized(insecureSslOverride)));
}
if(!getParameterized(privilegedModeOverride).isEmpty()) {
startBuildRequest.setPrivilegedModeOverride(Boolean.parseBoolean(getParameterized(privilegedModeOverride)));
}
List<ProjectSource> secondarySources;
List<ProjectSourceVersion> secondarySourceVersions;
List<ProjectArtifacts> secondaryArtifacts;
try {
secondarySources = Utils.parseDataList(getParameterized(secondarySourcesOverride), ProjectSource.class);
secondarySourceVersions = Utils.parseDataList(getParameterized(secondarySourcesVersionOverride), ProjectSourceVersion.class);
secondaryArtifacts = Utils.parseDataList(getParameterized(secondaryArtifactsOverride), ProjectArtifacts.class);
} catch (InvalidInputException e) {
failBuild(build, listener, invalidSecondarySourceArtifacts, e.getMessage());
return;
}
if(secondarySources != null && !secondarySources.isEmpty()) {
startBuildRequest.setSecondarySourcesOverride(secondarySources);
}
if(secondarySourceVersions != null && !secondarySourceVersions.isEmpty()) {
startBuildRequest.setSecondarySourcesVersionOverride(secondarySourceVersions);
}
if(secondaryArtifacts != null && !secondaryArtifacts.isEmpty()) {
startBuildRequest.setSecondaryArtifactsOverride(secondaryArtifacts);
}
if(SourceControlType.JenkinsSource.toString().equals(getParameterized(sourceControlType))) {
String buildSourceLocation = "";
if(!getParameterized(sourceTypeOverride).isEmpty() || !getParameterized(sourceLocationOverride).isEmpty()) {
if(!CodeBuilderValidation.checkJenkinsSourceOverrides(getParameterized(sourceTypeOverride), getParameterized(sourceLocationOverride))) {
failBuild(build, listener, configuredImproperlyError, jenkinsSourceOverrideError);
return;
}
buildSourceLocation = getParameterized(sourceLocationOverride);
} else {
try {
buildSourceLocation = retrieveProjectSourceInfo(cbClient);
} catch(Exception e) {
failBuild(build, listener, configuredImproperlyError, e.getMessage());
return;
}
}
String sourceS3Bucket = Utils.getS3BucketFromObjectArn(buildSourceLocation);
String sourceS3Key = Utils.getS3KeyFromObjectArn(buildSourceLocation);
if(!CodeBuilderValidation.checkBucketIsVersioned(sourceS3Bucket, awsClientFactory)) {
failBuild(build, listener, notVersionsedS3BucketError, "");
return;
}
S3DataManager s3DataManager = new S3DataManager(awsClientFactory.getS3Client(), sourceS3Bucket, sourceS3Key, getParameterized(sseAlgorithm), getParameterized(localSourcePath), getParameterized(workspaceSubdir));
String uploadedSourceVersion = "";
try {
UploadToS3Output uploadToS3Output = s3DataManager.uploadSourceToS3(listener, ws);
// Override source version to object version id returned by S3
if(uploadToS3Output.getObjectVersionId() != null) {
uploadedSourceVersion = uploadToS3Output.getObjectVersionId();
} else {
failBuild(build, listener, notVersionsedS3BucketError, "");
return;
}
LoggingHelper.log(listener, "S3 object version id for uploaded source is " + uploadedSourceVersion);
} catch (Exception e) {
failBuild(build, listener, "Error when uploading source to S3: ", e.getMessage());
return;
}
startBuildRequest.setSourceVersion(uploadedSourceVersion);
logStartBuildMessage(listener, uploadedSourceVersion);
} else {
startBuildRequest.setSourceVersion(getParameterized(sourceVersion));
startBuildRequest.setGitCloneDepthOverride(generateStartBuildGitCloneDepthOverride());
if(!getParameterized(reportBuildStatusOverride).isEmpty()) {
startBuildRequest.setReportBuildStatusOverride(Boolean.parseBoolean(getParameterized(reportBuildStatusOverride)));
}
logStartBuildMessage(listener, getParameterized(sourceVersion));
}
if(!getParameterized(sourceTypeOverride).isEmpty()) {
startBuildRequest.setSourceTypeOverride(getParameterized(sourceTypeOverride));
SourceAuth auth = generateStartBuildSourceAuthOverride(getParameterized(sourceTypeOverride));
if(auth != null) {
startBuildRequest.setSourceAuthOverride(auth);
}
}
if(!getParameterized(sourceLocationOverride).isEmpty()) {
startBuildRequest.setSourceLocationOverride(getParameterized(sourceLocationOverride));
}
final StartBuildResult sbResult;
try {
sbResult = cbClient.startBuild(startBuildRequest);
} catch (Exception e) {
failBuild(build, listener, "Error when calling CodeBuild StartBuild: ", e.getMessage());
return;
}
Build currentBuild = new Build().withBuildStatus(StatusType.IN_PROGRESS);
String buildId = sbResult.getBuild().getId();
LoggingHelper.log(listener, "Build id: " + buildId);
LoggingHelper.log(listener, "CodeBuild dashboard: " + generateDashboardURL(buildId));
boolean haveInitializedAction = false;
CodeBuildAction action = null;
CloudWatchMonitor logMonitor = null;
//poll buildResult for build status until it's complete.
do {
try {
List<Build> buildsForId = cbClient.batchGetBuilds(new BatchGetBuildsRequest().withIds(buildId)).getBuilds();
if(buildsForId.size() != 1) {
throw new Exception("Multiple builds mapped to this build id.");
}
currentBuild = buildsForId.get(0);
if(!haveInitializedAction) {
logMonitor = new CloudWatchMonitor(awsClientFactory.getCloudWatchLogsClient(), Boolean.parseBoolean(getParameterized(cwlStreamingDisabled)));
action = new CodeBuildAction(build);
//only need to set these once, the others will need to be updated below as the build progresses.
String buildARN = currentBuild.getArn();
codeBuildResult.setBuildInformation(currentBuild.getId(), buildARN);
action.setBuildId(buildId);
action.setBuildARN(buildARN);
action.setStartTime(currentBuild.getStartTime().toString());
ProjectSource source = currentBuild.getSource();
if(source != null) {
action.setSourceType(source.getType());
action.setSourceLocation(source.getLocation());
if(currentBuild.getSourceVersion() == null) {
action.setSourceVersion("");
} else {
action.setSourceVersion(currentBuild.getSourceVersion());
}
Integer depth = source.getGitCloneDepth();
if(depth == null || depth == 0) {
action.setGitCloneDepth("Full");
} else {
action.setGitCloneDepth(String.valueOf(depth));
}
Boolean status = source.getReportBuildStatus();
if(status != null) {
action.setReportBuildStatus(String.valueOf(status));
}
}
action.setArtifactTypeOverride(getParameterized(artifactTypeOverride));
action.setCodeBuildDashboardURL(generateDashboardURL(buildId));
action.setLogs(new ArrayList());
action.setCloudWatchLogsURL("");
action.setS3LogsURL("");
build.addAction(action);
haveInitializedAction = true;
}
updateDashboard(currentBuild, action, logMonitor, listener);
Thread.sleep(getSleepTime(descriptor));
} catch(Exception e) {
if(e.getClass().equals(InterruptedException.class)) {
//Request to stop Jenkins build has been made. First make sure the build is stoppable
List<Build> buildsForId = cbClient.batchGetBuilds(new BatchGetBuildsRequest().withIds(buildId)).getBuilds();
currentBuild = buildsForId.get(0);
if(!currentBuild.getCurrentPhase().equals(BuildPhaseType.COMPLETED.toString())) {
cbClient.stopBuild(new StopBuildRequest().withId(buildId));
//Wait for the build to actually stop
do {
buildsForId = cbClient.batchGetBuilds(new BatchGetBuildsRequest().withIds(buildId)).getBuilds();
currentBuild = buildsForId.get(0);
Thread.sleep(5000L);
logMonitor.pollForLogs(listener);
updateDashboard(currentBuild, action, logMonitor, listener);
} while (!currentBuild.getCurrentPhase().equals(BuildPhaseType.COMPLETED.toString()));
}
if (action != null) {
action.setJenkinsBuildSucceeds(false);
}
this.codeBuildResult.setStopped();
build.setResult(Result.ABORTED);
return;
} else if(e.getMessage().contains(CodeBuildClientRetryCondition.HTTP_ERROR_MESSAGE)) {
Thread.sleep(getSleepTime(descriptor));
continue;
} else {
if (action != null) {
action.setJenkinsBuildSucceeds(false);
}
failBuild(build, listener, "Error while polling build: ", e.getMessage());
return;
}
}
} while(currentBuild.getBuildStatus().equals(StatusType.IN_PROGRESS.toString()));
// Read artifacts location once the build is complete and artifact name finalized
codeBuildResult.setArtifactsLocation(currentBuild.getArtifacts() != null ? currentBuild.getArtifacts().getLocation() : null);
// Download build artifacts
if(downloadArtifacts.equalsIgnoreCase(Boolean.TRUE.toString())) {
downloadArtifactsFromS3(listener, awsClientFactory.getS3Client(), currentBuild, this.getArtifactRoot(ws));
}
if(currentBuild.getBuildStatus().equals(StatusType.SUCCEEDED.toString().toUpperCase(Locale.ENGLISH))) {
action.setJenkinsBuildSucceeds(true);
this.codeBuildResult.setSuccess();
build.setResult(Result.SUCCESS);
} else {
action.setJenkinsBuildSucceeds(false);
failBuild(build, listener, "Build " + currentBuild.getId() + " failed", action.getPhaseErrorMessage());
}
return;
}