use of com.palantir.stash.stashbot.persistence.JobTemplate in project stashbot by palantir.
the class BuildSuccessReportingServlet method doGet.
@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
try {
// Look at JenkinsManager class if you change this:
// final two arguments could be empty...
final String URL_FORMAT = "BASE_URL/REPO_ID/TYPE/STATE/BUILD_NUMBER/BUILD_HEAD[/MERGE_HEAD/PULLREQUEST_ID]";
final String pathInfo = req.getPathInfo();
final String[] parts = pathInfo.split("/");
if (parts.length != 6 && parts.length != 8) {
throw new IllegalArgumentException("The format of the URL is " + URL_FORMAT);
}
final int repoId;
final RepositoryConfiguration rc;
try {
repoId = Integer.valueOf(parts[1]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("The format of the URL is " + URL_FORMAT, e);
}
// This is necessary if we want unauthenticated users to be able to call this. *sigh*
RepoIdFetcherOperation getRepoId = new RepoIdFetcherOperation(repositoryService, repoId);
ss.withPermission(Permission.REPO_READ, "BUILD SUCCESS REPORT").call(getRepoId);
final Repository repo = getRepoId.getRepo();
rc = configurationPersistanceManager.getRepositoryConfigurationForRepository(repo);
if (repo == null) {
throw new IllegalArgumentException("Unable to get a repository for id " + repoId);
}
JobTemplate jt = jtm.fromString(rc, parts[2].toLowerCase());
if (jt == null) {
throw new IllegalArgumentException("Unable to get a valid JobTemplate from " + parts[2]);
}
final State state = BuildStatus.State.fromString(parts[3]);
if (state == null) {
throw new IllegalArgumentException("The state must be 'successful', 'failed', or 'inprogress'");
}
final long buildNumber;
try {
buildNumber = Long.parseLong(parts[4]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Unable to parse build number", e);
}
// TODO: ensure this hash actually exists?
final String buildHead = parts[5];
final String mergeHead;
final long pullRequestId;
final PullRequest pullRequest;
final String retUrl;
if (parts.length == 8 && !parts[6].isEmpty() && !parts[7].isEmpty()) {
mergeHead = parts[6];
try {
// This is a pull request, so add a comment
pullRequestId = Long.parseLong(parts[7]);
PullRequestFetcherOperation prfo = new PullRequestFetcherOperation(pullRequestService, repoId, pullRequestId);
ss.withPermission(Permission.REPO_READ, "BUILD SUCCESS REPORT").call(prfo);
pullRequest = prfo.getPullRequest();
if (pullRequest == null) {
throw new IllegalArgumentException("Unable to find pull request for repo id " + repo.getId().toString() + " pr id " + Long.toString(pullRequestId));
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Unable to parse pull request id " + parts[7], e);
}
retUrl = ub.getJenkinsTriggerUrl(repo, jt.getJobType(), buildHead, pullRequest);
} else {
mergeHead = null;
pullRequestId = 0;
pullRequest = null;
retUrl = ub.getJenkinsTriggerUrl(repo, jt.getJobType(), buildHead, null);
}
if (mergeHead == null) {
BuildStatus bs;
bs = getSuccessStatus(repo, jt, state, buildNumber, buildHead);
log.debug("Registering build status for buildHead " + buildHead + " " + bsToString(bs));
BuildStatusAddOperation bssAdder = new BuildStatusAddOperation(buildStatusService, buildHead, bs);
// Yeah, I know what you are thinking... "Admin permission? To add a build status?"
// I tried REPO_WRITE and REPO_ADMIN and neither was enough, but this worked!
ss.withPermission(Permission.SYS_ADMIN, "BUILD SUCCESS REPORT").call(bssAdder);
printOutput(req, res);
return;
}
// arg order for bools is started, success, override, failed
if (state.equals(State.SUCCESSFUL)) {
configurationPersistanceManager.setPullRequestMetadata(pullRequest, mergeHead, buildHead, null, true, null, false);
} else if (state.equals(State.INPROGRESS)) {
configurationPersistanceManager.setPullRequestMetadata(pullRequest, mergeHead, buildHead, true, false, null, null);
} else if (state.equals(State.FAILED)) {
configurationPersistanceManager.setPullRequestMetadata(pullRequest, mergeHead, buildHead, null, false, null, true);
}
// mergeHead is not null *and* pullRequest is not null if we reach
// here.
final StringBuffer sb = new StringBuffer();
final String url = getJenkinsUrl(repo, jt, buildNumber);
/* NOTE: mergeHead and buildHead are the reverse of what you might
* think, because we have to check out the "toRef" becasue it is
* the ref that is guaranteed to be in the correct repo.
* Nonetheless, buildHead is the commit that is being merged "into"
* the target branch, which is the mergeHead variable here.
*/
final int hashLength = 4;
final String shortMergeHead = mergeHead.substring(0, hashLength);
final String shortBuildHead = buildHead.substring(0, hashLength);
final String mergeHeadUrl = ub.buildStashCommitUrl(repo, mergeHead);
final String buildHeadUrl = ub.buildStashCommitUrl(repo, buildHead);
final String mergeHeadLink = "[" + shortMergeHead + "](" + mergeHeadUrl + ")";
final String buildHeadLink = "[" + shortBuildHead + "](" + buildHeadUrl + ")";
final String consoleUrl = url + "/console";
sb.append("*[Build #" + buildNumber + "](" + url + ") ");
sb.append("(merging " + mergeHeadLink + " into " + buildHeadLink + ") ");
switch(state) {
case INPROGRESS:
sb.append("is in progress...*");
break;
case SUCCESSFUL:
sb.append("has **passed ✓**.*");
break;
case FAILED:
sb.append("has* **FAILED ✖**. ");
sb.append("([*Retrigger this build* ⟳](" + retUrl + ") *or* [*view console output* ☰](" + consoleUrl + ").)");
break;
}
log.debug("Registering comment on pr for buildHead " + buildHead + " mergeHead " + mergeHead);
// Still make comment so users can see links to build
PullRequestCommentAddOperation prcao = new PullRequestCommentAddOperation(pullRequestService, repo.getId(), pullRequest.getId(), sb.toString());
// So in order to create comments, we have to do it AS some user. ss.doAsUser rather than ss.doWithPermission is the magic sauce here.
JenkinsServerConfiguration jsc = configurationPersistanceManager.getJenkinsServerConfiguration(rc.getJenkinsServerName());
StashUser user = us.findUserByNameOrEmail(jsc.getStashUsername());
ss.impersonating(user, "BUILD SUCCESS REPORT").call(prcao);
printOutput(req, res);
} catch (SQLException e) {
throw new RuntimeException("Unable to get configuration", e);
} catch (Exception e) {
throw new RuntimeException("Unable to report build status", e);
}
}
use of com.palantir.stash.stashbot.persistence.JobTemplate in project stashbot by palantir.
the class JenkinsJobXmlFormatter method generateJobXml.
public String generateJobXml(JobTemplate jobTemplate, Repository repo) throws SQLException {
final VelocityContext vc = velocityManager.getVelocityContext();
final RepositoryConfiguration rc = cpm.getRepositoryConfigurationForRepository(repo);
final JenkinsServerConfiguration jsc = cpm.getJenkinsServerConfiguration(rc.getJenkinsServerName());
RepositoryCloneLinksRequest rclr = new RepositoryCloneLinksRequest.Builder().repository(repo).protocol("http").user(null).build();
String repositoryUrl = rs.getCloneLinks(rclr).iterator().next().getHref();
String cleanRepositoryUrl = repositoryUrl;
// Handle the various Authentication modes
switch(jsc.getAuthenticationMode()) {
case USERNAME_AND_PASSWORD:
// manually insert the username and pw we are configured to use
repositoryUrl = repositoryUrl.replace("://", "://" + jsc.getStashUsername() + ":" + jsc.getStashPassword() + "@");
break;
case CREDENTIAL_MANUALLY_CONFIGURED:
vc.put("credentialUUID", jsc.getStashPassword());
break;
}
vc.put("repositoryUrl", repositoryUrl);
vc.put("cleanRepositoryUrl", cleanRepositoryUrl);
vc.put("prebuildCommand", prebuildCommand(rc.getPrebuildCommand()));
// TODO: figure out build command some other way?
switch(jobTemplate.getJobType()) {
case VERIFY_COMMIT:
vc.put("buildCommand", buildCommand(rc.getVerifyBuildCommand()));
break;
case VERIFY_PR:
vc.put("buildCommand", buildCommand(rc.getVerifyBuildCommand()));
break;
case PUBLISH:
vc.put("buildCommand", buildCommand(rc.getPublishBuildCommand()));
break;
case NOOP:
vc.put("buildCommand", buildCommand("/bin/true"));
break;
}
// Add email notification stuff for all build types
vc.put("isEmailNotificationsEnabled", rc.getEmailNotificationsEnabled());
vc.put("emailRecipients", rc.getEmailRecipients());
vc.put("isEmailForEveryUnstableBuild", rc.getEmailForEveryUnstableBuild());
vc.put("isEmailSendToIndividuals", rc.getEmailSendToIndividuals());
vc.put("isEmailPerModuleEmail", rc.getEmailPerModuleEmail());
vc.put("startedCommand", curlCommandBuilder(repo, jobTemplate, rc, repositoryUrl, "inprogress"));
vc.put("successCommand", curlCommandBuilder(repo, jobTemplate, rc, repositoryUrl, "successful"));
vc.put("failedCommand", curlCommandBuilder(repo, jobTemplate, rc, repositoryUrl, "failed"));
vc.put("repositoryLink", navBuilder.repo(repo).browse().buildAbsolute());
vc.put("repositoryName", repo.getProject().getName() + " " + repo.getName());
// Parameters are type-dependent for now
ImmutableList.Builder<Map<String, String>> paramBuilder = new ImmutableList.Builder<Map<String, String>>();
switch(jobTemplate.getJobType()) {
case VERIFY_COMMIT:
// repoId
paramBuilder.add(ImmutableMap.of("name", "repoId", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "stash repository Id", "defaultValue", "unknown"));
// buildHead
paramBuilder.add(ImmutableMap.of("name", "buildHead", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "the change to build", "defaultValue", "head"));
break;
case VERIFY_PR:
// repoId
paramBuilder.add(ImmutableMap.of("name", "repoId", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "stash repository Id", "defaultValue", "unknown"));
// buildHead
paramBuilder.add(ImmutableMap.of("name", "buildHead", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "the change to build", "defaultValue", "head"));
// pullRequestId
paramBuilder.add(ImmutableMap.of("name", "pullRequestId", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "the pull request Id", "defaultValue", ""));
break;
case PUBLISH:
// repoId
paramBuilder.add(ImmutableMap.of("name", "repoId", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "stash repository Id", "defaultValue", "unknown"));
// buildHead
paramBuilder.add(ImmutableMap.of("name", "buildHead", "typeName", JenkinsBuildParamType.StringParameterDefinition.toString(), "description", "the change to build", "defaultValue", "head"));
break;
case NOOP:
// no params
break;
}
vc.put("paramaterList", paramBuilder.build());
// Junit settings
vc.put("isJunit", rc.getJunitEnabled());
vc.put("junitPath", rc.getJunitPath());
// Artifact settings
vc.put("artifactsEnabled", rc.getArtifactsEnabled());
vc.put("artifactsPath", rc.getArtifactsPath());
// insert pinned data
switch(jobTemplate.getJobType()) {
case VERIFY_COMMIT:
case VERIFY_PR:
vc.put("isPinned", rc.getVerifyPinned());
vc.put("label", rc.getVerifyLabel());
break;
case PUBLISH:
vc.put("isPinned", rc.getPublishPinned());
vc.put("label", rc.getPublishLabel());
break;
case NOOP:
vc.put("isPinned", false);
break;
}
StringWriter xml = new StringWriter();
VelocityEngine ve = velocityManager.getVelocityEngine();
Template template = ve.getTemplate(jobTemplate.getTemplateFile());
template.merge(vc, xml);
return xml.toString();
}
use of com.palantir.stash.stashbot.persistence.JobTemplate in project stashbot by palantir.
the class JenkinsJobTest method testNewJobWorkflow.
@Test
public void testNewJobWorkflow() throws Exception {
int sizeOfData = ao.count(JobTemplate.class);
final String NEW_JOB = "newJobName";
final String TEMPLATE_FILE = "verify-template.xml";
JobTemplate newjob = jtm.getJobTemplate(NEW_JOB);
Assert.assertEquals(newjob.getName(), NEW_JOB);
Assert.assertEquals(newjob.getTemplateFile(), TEMPLATE_FILE);
Assert.assertEquals(newjob.getJobType(), JobType.NOOP);
int newSizeOfData = ao.count(JobTemplate.class);
Assert.assertTrue(newSizeOfData == sizeOfData + 1);
}
use of com.palantir.stash.stashbot.persistence.JobTemplate in project stashbot by palantir.
the class JenkinsJobTest method testCreatesDefaultObjects.
@Test
public void testCreatesDefaultObjects() throws Exception {
JobTemplate jjtV = jtm.getDefaultVerifyJob();
JobTemplate jjtP = jtm.getDefaultPublishJob();
JobTemplate jjtPR = jtm.getDefaultVerifyPullRequestJob();
Assert.assertEquals(jjtV.getName(), "verification");
Assert.assertEquals(jjtPR.getName(), "verify-pr");
Assert.assertEquals(jjtP.getName(), "publish");
int newSizeOfData = ao.count(JobTemplate.class);
Assert.assertTrue(newSizeOfData == 3);
}
use of com.palantir.stash.stashbot.persistence.JobTemplate in project stashbot by palantir.
the class JenkinsManagerTest method testUpdateJob.
@Test
public void testUpdateJob() throws Exception {
String jobName = "somename_verification";
Job existingJob = Mockito.mock(Job.class);
Map<String, Job> jobMap = new HashMap<String, Job>();
jobMap.put(jobName, existingJob);
Mockito.when(jenkinsServer.getJobs()).thenReturn(jobMap);
JobTemplate jt = jtm.getDefaultVerifyJob();
jenkinsManager.updateJob(repo, jt);
ArgumentCaptor<String> xmlCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(xmlFormatter).generateJobXml(jt, repo);
Mockito.verify(jenkinsServer).updateJob(Mockito.anyString(), xmlCaptor.capture());
Mockito.verify(jenkinsServer, Mockito.never()).createJob(Mockito.anyString(), Mockito.anyString());
Assert.assertEquals(XML_STRING, xmlCaptor.getValue());
}
Aggregations