diff --git a/changelog.md b/changelog.md index 494e86e6e..4437003a6 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ### Master +- Posts status reports for passing/failing builds, if the account for danger has access - orta - Adds prettier to the codebase - orta - Converts a bunch of Danger's dangerfile into a plugin - [danger-plugin-yarn](https://github.com/orta/danger-plugin-yarn) - orta diff --git a/source/platforms/FakePlatform.ts b/source/platforms/FakePlatform.ts index 92dc1ba34..6dfaa3b70 100644 --- a/source/platforms/FakePlatform.ts +++ b/source/platforms/FakePlatform.ts @@ -41,4 +41,8 @@ export class FakePlatform implements Platform { async editMainComment(_comment: string): Promise { return true } + + async updateStatus(_success: boolean, _message: string): Promise { + return true + } } diff --git a/source/platforms/GitHub.ts b/source/platforms/GitHub.ts index feb184bef..7e53d85e8 100644 --- a/source/platforms/GitHub.ts +++ b/source/platforms/GitHub.ts @@ -40,6 +40,15 @@ export class GitHub { return issue || { labels: [] } } + /** + * Fails the current build, if status setting succeeds + * then return true. + */ + + async updateStatus(passed: boolean, message: string): Promise { + return await this.api.updateStatus(passed, message) + } + /** * Returns the `github` object on the Danger DSL * diff --git a/source/platforms/github/GitHubAPI.ts b/source/platforms/github/GitHubAPI.ts index 7617599f9..887f5ce5e 100644 --- a/source/platforms/github/GitHubAPI.ts +++ b/source/platforms/github/GitHubAPI.ts @@ -201,6 +201,26 @@ export class GitHubAPI { return res.ok ? res.json() : { labels: [] } } + + async updateStatus(passed: boolean, message: string): Promise { + const repo = this.repoMetadata.repoSlug + + const prJSON = await this.getPullRequestInfo() + const ref = prJSON.head.sha + const res = await this.post( + `repos/${repo}/statuses/${ref}`, + {}, + { + state: passed ? "success" : "failure", + context: "Danger", + target_url: "https://danger.systems/js", + description: message, + } + ) + + return res.ok + } + // API Helpers private api(path: string, headers: any = {}, body: any = {}, method: string) { diff --git a/source/platforms/platform.ts b/source/platforms/platform.ts index ed6b8c42e..e35a140af 100644 --- a/source/platforms/platform.ts +++ b/source/platforms/platform.ts @@ -43,20 +43,10 @@ export interface Platform { editMainComment: (newComment: string) => Promise /** Replace the main Danger comment */ updateOrCreateComment: (newComment: string) => Promise + /** Sets the current PR's status */ + updateStatus: (passed: boolean, message: string) => Promise } -// /** Download all the comments in a PR */ -// async downloadComments: (id: string) => Promise; - -// /** Create a comment on a PR */ -// async createComment: (body: string) => Promise; - -// /** Delete comments on a PR */ -// async deleteComment: (env: any) => Promise; - -// /** Edit an existing comment */ -// async editComment: (comment: Comment, newBody: string) => Promise; - /** * Pulls out a platform for Danger to communicate on based on the environment * @param {Env} env The environment. diff --git a/source/runner/Executor.ts b/source/runner/Executor.ts index c732620d0..ecf4bf5fb 100644 --- a/source/runner/Executor.ts +++ b/source/runner/Executor.ts @@ -145,6 +145,9 @@ export class Executor { this.d(results) + const failed = fails.length > 0 + const successPosting = await this.platform.updateStatus(!failed, messageForResults(results)) + if (failureCount + messageCount === 0) { console.log("No issues or messages were sent. Removing any existing messages.") await this.platform.deleteMainComment() @@ -153,7 +156,9 @@ export class Executor { const s = fails.length === 1 ? "" : "s" const are = fails.length === 1 ? "is" : "are" console.log(`Failing the build, there ${are} ${fails.length} fail${s}.`) - process.exitCode = 1 + if (!successPosting) { + process.exitCode = 1 + } } else if (warnings.length > 0) { console.log("Found only warnings, not failing the build.") } else if (messageCount > 0) { @@ -185,3 +190,16 @@ export class Executor { } } } + +const compliment = () => { + const compliments = ["Well done.", "Congrats.", "Woo!", "Yay.", "Jolly good show.", "Good on 'ya.", "Nice work."] + return compliments[Math.floor(Math.random() * compliments.length)] +} + +const messageForResults = (results: DangerResults) => { + if (!results.fails.length && !results.warnings.length) { + return `All green. ${compliment()}` + } else { + return "⚠️ Danger found some issues. Don't worry, everything is fixable." + } +} diff --git a/source/runner/_tests/_executor.test.ts b/source/runner/_tests/_executor.test.ts index 1addc80b9..63803e006 100644 --- a/source/runner/_tests/_executor.test.ts +++ b/source/runner/_tests/_executor.test.ts @@ -1,7 +1,7 @@ import { Executor } from "../Executor" import { FakeCI } from "../../ci_source/providers/Fake" import { FakePlatform } from "../../platforms/FakePlatform" -import { emptyResults, warnResults } from "./fixtures/ExampleDangerResults" +import { emptyResults, warnResults, failsResults } from "./fixtures/ExampleDangerResults" const defaultConfig = { stdoutOnly: false, @@ -65,4 +65,39 @@ describe("setup", () => { await exec.handleResults(warnResults) expect(platform.updateOrCreateComment).toBeCalled() }) + + it("Updates or Creates comments for warnings", async () => { + const platform = new FakePlatform() + const exec = new Executor(new FakeCI({}), platform, defaultConfig) + platform.updateOrCreateComment = jest.fn() + + await exec.handleResults(warnResults) + expect(platform.updateOrCreateComment).toBeCalled() + }) + + it("Updates the status with success for a passed results", async () => { + const platform = new FakePlatform() + const exec = new Executor(new FakeCI({}), platform, defaultConfig) + platform.updateOrCreateComment = jest.fn() + platform.updateStatus = jest.fn() + + await exec.handleResults(warnResults) + expect(platform.updateStatus).toBeCalledWith( + true, + "⚠️ Danger found some issues. Don't worry, everything is fixable." + ) + }) + + it("Updates the status with success for a passed results", async () => { + const platform = new FakePlatform() + const exec = new Executor(new FakeCI({}), platform, defaultConfig) + platform.updateOrCreateComment = jest.fn() + platform.updateStatus = jest.fn() + + await exec.handleResults(failsResults) + expect(platform.updateStatus).toBeCalledWith( + false, + "⚠️ Danger found some issues. Don't worry, everything is fixable." + ) + }) }) diff --git a/source/runner/_tests/fixtures/ExampleDangerResults.ts b/source/runner/_tests/fixtures/ExampleDangerResults.ts index eeb4af0eb..db17728fd 100644 --- a/source/runner/_tests/fixtures/ExampleDangerResults.ts +++ b/source/runner/_tests/fixtures/ExampleDangerResults.ts @@ -8,7 +8,7 @@ export const emptyResults: DangerResults = { } export const failsResultsWithoutMessages: DangerResults = { - fails: [{}, {}], + fails: [{} as any, {} as any], warnings: [], messages: [], markdowns: [],