Skip to content

Commit

Permalink
Case changes
Browse files Browse the repository at this point in the history
  • Loading branch information
orta committed Oct 29, 2016
1 parent 4c4e196 commit ae66317
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 3 deletions.
18 changes: 18 additions & 0 deletions source/ci_source/Fake.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @flow
"use strict"

import type { Env } from "./ci_source"

export default class FakeCI {
env: Env
constructor(env: Env) { this.env = env }
get name(): string { return "Fake Testing CI" }

get isCI() : boolean { return true }
get isPR() : boolean { return true }

get pullRequestID(): string { return "327" }
get repoSlug(): string { return "artsy/emission" }
get repoURL(): string { return "maybe not needed?" }
get supportedPlatforms() : string[] { return ["github"] }
}
26 changes: 26 additions & 0 deletions source/ci_source/Travis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// @flow
"use strict"

import type { Env } from "./ci_source"
import { ensureEnvKeysExist, ensureEnvKeysAreInt } from "./ci_source_helpers"
export default class Travis {
env: Env
constructor(env: Env) { this.env = env }

get name(): string { return "Travis CI" }

get isCI() : boolean {
return ensureEnvKeysExist(this.env, ["HAS_JOSH_K_SEAL_OF_APPROVAL"])
}

get isPR() : boolean {
const mustHave = ["HAS_JOSH_K_SEAL_OF_APPROVAL", "TRAVIS_PULL_REQUEST"]
const mustBeInts = ["TRAVIS_REPO_SLUG"]
return ensureEnvKeysExist(this.env, mustHave) && ensureEnvKeysAreInt(this.env, mustBeInts)
}

get pullRequestID(): string { return this.env.TRAVIS_PULL_REQUEST }
get repoSlug(): string { return this.env.TRAVIS_REPO_SLUG }
get repoURL(): string { return "maybe not needed?" }
get supportedPlatforms() : string[] { return ["github"] }
}
4 changes: 2 additions & 2 deletions source/ci_source/ci_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export interface CISource {
name: string
}

import Travis from "./travis"
import Fake from "./fake"
import Travis from "./Travis"
import Fake from "./Fake"

/**
* Gets a CI Source form the current environment, by asking all known
Expand Down
202 changes: 202 additions & 0 deletions source/platforms/GitHub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// @flow
"use strict"

import type { GitDSL } from "../dsl/git"
import type { CISource } from "../ci_source/ci_source"
import parseDiff from "parse-diff"

import fetch from "node-fetch"
import "babel-polyfill"

// This pattern of re-typing specific strings has worked well for Artsy in Swift
// so, I'm willing to give it a shot here.

export type APIToken = string;

/** This represent the GitHub API, and conforming to the Platform Interface */

export class GitHub {
token: APIToken
ciSource: CISource
name: string

constructor(token: APIToken, ciSource: CISource) {
this.token = token
this.ciSource = ciSource
this.name = "GitHub"
}

/**
* Get the Code Review description metadata
*
* @returns {Promise<any>} JSON representation
*/
async getReviewInfo() : Promise<any> {
const deets = await this.getPullRequestInfo()
return await deets.json()
}

/**
* Get the Code Review diff representation
*
* @returns {Promise<GitDSL>} the git DSL
*/
async getReviewDiff() : Promise<GitDSL> {
const diffReq = await this.getPullRequestDiff()
const diff = await diffReq.text()

// Worth trying to add a flow-typed for this as a tester?
const fileDiffs: [any] = parseDiff(diff)

const addedDiffs = fileDiffs.filter((diff: any) => diff["new"])
const removedDiffs = fileDiffs.filter((diff: any) => diff["deleted"])
const modifiedDiffs = fileDiffs.filter((diff: any) => !addedDiffs.includes(diff) && !removedDiffs.includes(diff))

return {
modified_files: modifiedDiffs.map((d: any) => d.to),
created_files: addedDiffs.map((d: any) => d.to),
deleted_files: removedDiffs.map((d: any) => d.from)
}
}

async updateOrCreateComment(newComment: string): Promise<bool> {
const commentID = await this.getDangerCommentID()
if (commentID) { await this.updateCommentWithID(commentID, newComment) }
else { await this.createComment(newComment) }
return true
}

/**
* Returns the response for the new comment
*
* @param {string} comment you want to post
* @returns {Promise<any>} JSON response of new comment
*/
async createComment(comment: string): Promise<any> {
return this.postPRComment(comment)
}

// In Danger RB we support a danger_id property,
// this should be handled at some point

/**
* Deletes the main Danger comment, used when you have
* fixed all your failures.
*
* @returns {Promise<bool>} did it work?
*/
async deleteMainComment(): Promise<bool> {
const commentID = await this.getDangerCommentID()
if (commentID) { await this.deleteCommentWithID(commentID) }
return commentID !== null
}

/**
* Updates the main Danger comment, when Danger has run
* more than once
*
* @param {string} comment updated text
*
* @returns {Promise<bool>} did it work?
*/
async editMainComment(comment: string): Promise<bool> {
const commentID = await this.getDangerCommentID()
if (commentID) { await this.updateCommentWithID(commentID, comment) }
return commentID !== null
}

// The above is the API for Platform

async getDangerCommentID(): Promise<?number> {
const userID = await this.getUserID()
const allCommentsResponse = await this.getPullRequestComments()
const allComments: any[] = await allCommentsResponse.json()
const dangerComment = allComments.find((comment: any) => comment.user.id === userID)
return dangerComment ? dangerComment.id : null
}

async updateCommentWithID(id: number, comment: string): Promise<Response> {
const repo = this.ciSource.repoSlug
return this.patch(`repos/${repo}/issues/comments/${id}`, {}, {
body: comment
})
}

async deleteCommentWithID(id: number): Promise<Response> {
const repo = this.ciSource.repoSlug
return this.get(`repos/${repo}/issues/comments/${id}`, {}, {}, "DELETE")
}

async getUserID(): Promise<number> {
const info = await this.getUserInfo()
return info.id
}

postPRComment(comment: string): Promise<Response> {
const repo = this.ciSource.repoSlug
const prID = this.ciSource.pullRequestID
return this.post(`repos/${repo}/issues/${prID}/comments`, {}, {
body: comment
})
}

getPullRequestInfo(): Promise<Response> {
const repo = this.ciSource.repoSlug
const prID = this.ciSource.pullRequestID
return this.get(`repos/${repo}/pulls/${prID}`)
}

async getUserInfo(): Promise<any> {
const response:Response = await this.get("user")
return await response.json()
}

// TODO: This does not handle pagination
getPullRequestComments(): Promise<Response> {
const repo = this.ciSource.repoSlug
const prID = this.ciSource.pullRequestID
return this.get(`repos/${repo}/issues/${prID}/comments`)
}

getPullRequestDiff(): Promise<Response> {
const repo = this.ciSource.repoSlug
const prID = this.ciSource.pullRequestID
return this.get(`repos/${repo}/pulls/${prID}`, {
accept: "application/vnd.github.v3.diff"
})
}

// maybe this can move into the stuff below
post(path: string, headers: any = {}, body: any = {}, method: string = "POST"): Promise<Response> {
return fetch(`https://api.github.com/${path}`, {
method: method,
body: JSON.stringify(body),
headers: {
"Authorization": `token ${this.token}`,
"Content-Type": "application/json",
...headers }
})
}

get(path: string, headers: any = {}, body: any = {}, method: string = "GET"): Promise<Response> {
return fetch(`https://api.github.com/${path}`, {
method: method,
body: body,
headers: {
"Authorization": `token ${this.token}`,
"Content-Type": "application/json",
...headers }
})
}

patch(path: string, headers: any = {}, body: any = {}, method: string = "PATCH"): Promise<Response> {
return fetch(`https://api.github.com/${path}`, {
method: method,
body: JSON.stringify(body),
headers: {
"Authorization": `token ${this.token}`,
"Content-Type": "application/json",
...headers }
})
}
}
2 changes: 1 addition & 1 deletion source/platforms/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export interface Platform {
// async editComment: (comment: Comment, newBody: string) => Promise<boolean>;
// }

import { GitHub } from "./github"
import { GitHub } from "./GitHub"

/**
* Pulls out a platform for Danger to communicate on based on the environment
Expand Down

0 comments on commit ae66317

Please sign in to comment.