Search in sources :

Example 21 with RepositoryConfiguration

use of com.palantir.stash.stashbot.persistence.RepositoryConfiguration 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);
    }
}
Also used : SQLException(java.sql.SQLException) PullRequest(com.atlassian.stash.pull.PullRequest) JobTemplate(com.palantir.stash.stashbot.persistence.JobTemplate) ServletException(javax.servlet.ServletException) SQLException(java.sql.SQLException) IOException(java.io.IOException) BuildStatusAddOperation(com.palantir.stash.stashbot.util.BuildStatusAddOperation) Repository(com.atlassian.stash.repository.Repository) StashUser(com.atlassian.stash.user.StashUser) State(com.atlassian.stash.build.BuildStatus.State) BuildStatus(com.atlassian.stash.build.BuildStatus) InternalBuildStatus(com.atlassian.stash.internal.build.InternalBuildStatus) PullRequestCommentAddOperation(com.palantir.stash.stashbot.util.PullRequestCommentAddOperation) RepoIdFetcherOperation(com.palantir.stash.stashbot.util.RepoIdFetcherOperation) PullRequestFetcherOperation(com.palantir.stash.stashbot.util.PullRequestFetcherOperation) RepositoryConfiguration(com.palantir.stash.stashbot.persistence.RepositoryConfiguration) JenkinsServerConfiguration(com.palantir.stash.stashbot.persistence.JenkinsServerConfiguration)

Example 22 with RepositoryConfiguration

use of com.palantir.stash.stashbot.persistence.RepositoryConfiguration in project stashbot by palantir.

the class ConfigurationV2UpgradeTask method upgrade.

/* This is safe to do because the ao.migrate() API uses varargs with a templated type
     * and there's no way around that, but it's just classes and how the API works, so I
     * think it's safe.
     */
@SuppressWarnings("unchecked")
@Override
public void upgrade(ModelVersion currentVersion, ActiveObjects ao) {
    if (!currentVersion.isSame(ModelVersion.valueOf("1"))) {
        throw new IllegalStateException("ConfigurationV2UpgradeTask can only upgrade from version 1");
    }
    // Migrate the old table to base the info off it.
    ao.migrate(RepositoryConfiguration.class);
    // Migrate the new table so we can populate it
    ao.migrate(JobTypeStatusMapping.class);
    for (RepositoryConfiguration rc : ao.find(RepositoryConfiguration.class)) {
        for (JobType jt : ImmutableList.of(JobType.PUBLISH, JobType.VERIFY_COMMIT, JobType.VERIFY_PR)) {
            ao.create(JobTypeStatusMapping.class, new DBParam("REPO_CONFIG_ID", rc.getID()), new DBParam("IS_ENABLED", true), new DBParam("JOB_TYPE_RAW", jt.name()));
        }
    }
}
Also used : JobType(com.palantir.stash.stashbot.jobtemplate.JobType) DBParam(net.java.ao.DBParam) RepositoryConfiguration(com.palantir.stash.stashbot.persistence.RepositoryConfiguration)

Example 23 with RepositoryConfiguration

use of com.palantir.stash.stashbot.persistence.RepositoryConfiguration in project stashbot by palantir.

the class ConfigurationTest method storesRepoData.

@Test
public void storesRepoData() throws Exception {
    Repository repo = Mockito.mock(Repository.class);
    Mockito.when(repo.getId()).thenReturn(1);
    Mockito.when(repo.getName()).thenReturn("repoName");
    int size = ao.count(RepositoryConfiguration.class);
    cpm.setRepositoryConfigurationForRepository(repo, true, "verifyBranchRegex", "verifyBuildCommand", false, "N/A", "publishBranchRegex", "publishBuildCommand", false, "N/A", "prebuildCommand", "default", true, false, "N/A", false, "N/A", size, new EmailSettings(true, "a@a.a", true, true, true), false, false);
    RepositoryConfiguration rc = cpm.getRepositoryConfigurationForRepository(repo);
    Assert.assertEquals("publishBranchRegex", rc.getPublishBranchRegex());
    Assert.assertEquals("publishBuildCommand", rc.getPublishBuildCommand());
    Assert.assertEquals("verifyBranchRegex", rc.getVerifyBranchRegex());
    Assert.assertEquals("verifyBuildCommand", rc.getVerifyBuildCommand());
    Assert.assertEquals("prebuildCommand", rc.getPrebuildCommand());
    Assert.assertEquals("default", rc.getJenkinsServerName());
    Assert.assertTrue(rc.getCiEnabled());
    Assert.assertTrue(rc.getEmailNotificationsEnabled());
    Assert.assertFalse(rc.getPreserveJenkinsJobConfig());
    Assert.assertEquals(size + 1, ao.count(RepositoryConfiguration.class));
}
Also used : Repository(com.atlassian.stash.repository.Repository) EmailSettings(com.palantir.stash.stashbot.config.ConfigurationPersistenceService.EmailSettings) RepositoryConfiguration(com.palantir.stash.stashbot.persistence.RepositoryConfiguration) Test(org.junit.Test)

Example 24 with RepositoryConfiguration

use of com.palantir.stash.stashbot.persistence.RepositoryConfiguration in project stashbot by palantir.

the class PullRequestBuildSuccessMergeCheck method check.

@Override
public void check(@Nonnull MergeRequest mr) {
    PullRequest pr = mr.getPullRequest();
    Repository repo = pr.getToRef().getRepository();
    RepositoryConfiguration rc;
    try {
        rc = cpm.getRepositoryConfigurationForRepository(repo);
    } catch (SQLException e) {
        throw new RuntimeException("Unable to get RepositoryConfiguration", e);
    }
    if (!rc.getCiEnabled()) {
        return;
    }
    if (!cpm.getJobTypeStatusMapping(rc, JobType.VERIFY_PR)) {
        // speculative merge builds are disabled
        return;
    }
    if (!pr.getToRef().getId().matches(rc.getVerifyBranchRegex())) {
        log.debug("Pull Request " + pr.toString() + " ignored, branch " + pr.getToRef().getId() + " doesn't match verify regex");
        return;
    }
    // First, if strict mode is on, we want to veto for each commit in the PR that is missing a successful verify build
    if (rc.getStrictVerifyMode()) {
        ChangesetsBetweenRequest cbr = new ChangesetsBetweenRequest.Builder(pr).build();
        PageRequest pageReq = new PageRequestImpl(0, 500);
        Page<? extends Changeset> page = cs.getChangesetsBetween(cbr, pageReq);
        while (true) {
            for (Changeset c : page.getValues()) {
                log.trace("Processing commit " + c.getId());
                BuildStats bs = bss.getStats(c.getId());
                if (bs.getSuccessfulCount() == 0) {
                    mr.veto("Commit " + c.getId() + " not verified", "When in strict verification mode, each commit in the PR must have at least one successful build");
                }
            }
            if (page.getIsLastPage()) {
                break;
            }
            pageReq = page.getNextPageRequest();
            page = cs.getChangesetsBetween(cbr, pageReq);
        }
    }
    PullRequestMetadata prm = null;
    if (!rc.getRebuildOnTargetUpdate()) {
        // we want a PRM which simply matches the fromSha and the pull request ID.
        Collection<PullRequestMetadata> prms = cpm.getPullRequestMetadataWithoutToRef(pr);
        for (PullRequestMetadata cur : prms) {
            if (cur.getFromSha().equals(pr.getFromRef().getLatestChangeset()) && (cur.getOverride() || cur.getSuccess())) {
                log.debug("Found match PRM");
                log.debug("PRM: success " + cur.getSuccess().toString() + " override " + cur.getOverride().toString());
                return;
            }
        }
        prm = cpm.getPullRequestMetadata(pr);
    } else {
        // Then we want to ensure a build that matches exactly succeeded / was overridden
        prm = cpm.getPullRequestMetadata(pr);
    }
    // Override || Success
    if (prm.getOverride() || prm.getSuccess()) {
        return;
    }
    // in all other cases, we want to veto for some reason - but figure out the most accurate reason here.
    MergeCheckStatus status;
    if (prm.getFailed()) {
        status = MergeCheckStatus.BUILD_FAILED;
    } else if (prm.getBuildStarted()) {
        status = MergeCheckStatus.BUILD_IN_PROGRESS;
    } else {
        status = MergeCheckStatus.NO_BUILD;
    }
    mr.veto(status.getSummary(), status.getDescription());
}
Also used : SQLException(java.sql.SQLException) PullRequest(com.atlassian.stash.pull.PullRequest) ChangesetsBetweenRequest(com.atlassian.stash.content.ChangesetsBetweenRequest) BuildStats(com.atlassian.stash.build.BuildStats) Repository(com.atlassian.stash.repository.Repository) PageRequest(com.atlassian.stash.util.PageRequest) PullRequestMetadata(com.palantir.stash.stashbot.persistence.PullRequestMetadata) PageRequestImpl(com.atlassian.stash.util.PageRequestImpl) RepositoryConfiguration(com.palantir.stash.stashbot.persistence.RepositoryConfiguration) Changeset(com.atlassian.stash.content.Changeset)

Aggregations

RepositoryConfiguration (com.palantir.stash.stashbot.persistence.RepositoryConfiguration)24 SQLException (java.sql.SQLException)16 Repository (com.atlassian.stash.repository.Repository)13 JenkinsServerConfiguration (com.palantir.stash.stashbot.persistence.JenkinsServerConfiguration)9 IOException (java.io.IOException)8 PullRequest (com.atlassian.stash.pull.PullRequest)6 JobTemplate (com.palantir.stash.stashbot.persistence.JobTemplate)5 JenkinsServer (com.offbytwo.jenkins.JenkinsServer)4 Job (com.offbytwo.jenkins.model.Job)4 URISyntaxException (java.net.URISyntaxException)4 ServletException (javax.servlet.ServletException)4 DBParam (net.java.ao.DBParam)3 EventListener (com.atlassian.event.api.EventListener)2 Changeset (com.atlassian.stash.content.Changeset)2 AuthorisationException (com.atlassian.stash.exception.AuthorisationException)2 PageRequest (com.atlassian.stash.util.PageRequest)2 PageRequestImpl (com.atlassian.stash.util.PageRequestImpl)2 ImmutableList (com.google.common.collect.ImmutableList)2 ImmutableMap (com.google.common.collect.ImmutableMap)2 PullRequestMetadata (com.palantir.stash.stashbot.persistence.PullRequestMetadata)2