Skip to content

Commit

Permalink
Merge pull request #153 from danger/scheduler
Browse files Browse the repository at this point in the history
Support for a scheduler
  • Loading branch information
orta authored Oct 4, 2017
2 parents 7abdc91 + 486383d commit 69abe93
Show file tree
Hide file tree
Showing 18 changed files with 314 additions and 40 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"jsonwebtoken": "^7.2.1",
"node-fetch": "^1.6.3",
"node-pg-migrate": "^2.7.0",
"node-schedule": "^1.2.5",
"pg-promise": "^6.1.0",
"ts-jest": "^21",
"ts-node": "^3.0.2",
Expand Down
33 changes: 31 additions & 2 deletions source/danger/_tests/_danger_run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ describe("for ping", () => {
const rules = { ping: "dangerfile.js" }
expect(dangerRunForRules("ping", null, rules)).toEqual({
action: null,
branch: "master",
dangerfilePath: "dangerfile.js",
dslType: dsl.import,
event: "ping",
feedback: feedback.silent,
repoSlug: undefined,
})
})

Expand All @@ -30,10 +32,12 @@ describe("for PRs", () => {
const rules = { pull_request: "dangerfile.js" }
expect(dangerRunForRules("pull_request", "created", rules)).toEqual({
action: "created",
branch: "master",
dangerfilePath: "dangerfile.js",
dslType: dsl.pr,
event: "pull_request",
feedback: feedback.commentable,
repoSlug: undefined,
})
})

Expand All @@ -42,10 +46,12 @@ describe("for PRs", () => {
const rules = { "pull_request.*": "dangerfile.js" }
expect(dangerRunForRules("pull_request", "updated", rules)).toEqual({
action: "updated",
branch: "master",
dangerfilePath: "dangerfile.js",
dslType: dsl.pr,
event: "pull_request",
feedback: feedback.commentable,
repoSlug: undefined,
})
})

Expand All @@ -58,29 +64,52 @@ describe("for PRs", () => {
const rules = { "pull_request.deleted": "dangerfile.js" }
expect(dangerRunForRules("pull_request", "deleted", rules)).toEqual({
action: "deleted",
branch: "master",
dangerfilePath: "dangerfile.js",
dslType: dsl.pr,
event: "pull_request",
feedback: feedback.commentable,
repoSlug: undefined,
})
})
})

describe("dangerRepresentationforPath", () => {
it("returns just the path when there is no repo reference", () => {
it("returns just the path with master and no repo with just a path", () => {
const path = "dangerfile.ts"
expect(dangerRepresentationforPath(path)).toEqual({
branch: "master",
dangerfilePath: "dangerfile.ts",
repoSlug: undefined,
})
})

it("returns just the path when there is no repo reference", () => {
it("returns the path and repo", () => {
const path = "orta/eigen@dangerfile.ts"
expect(dangerRepresentationforPath(path)).toEqual({
branch: "master",
dangerfilePath: "dangerfile.ts",
repoSlug: "orta/eigen",
})
})

it("returns just the path when there is no repo reference", () => {
const path = "orta/eigen@dangerfile.ts#branch"
expect(dangerRepresentationforPath(path)).toEqual({
branch: "branch",
dangerfilePath: "dangerfile.ts",
repoSlug: "orta/eigen",
})
})

it("handles a branch with no repo ref", () => {
const path = "dangerfile.ts#branch"
expect(dangerRepresentationforPath(path)).toEqual({
branch: "branch",
dangerfilePath: "dangerfile.ts",
repoSlug: undefined,
})
})
})

describe("dslTypeForEvent", () => {
Expand Down
26 changes: 13 additions & 13 deletions source/danger/danger_run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,11 @@ export enum feedback {
}

/** Represents runs that Danger should do based on Rules and Events */
export interface DangerRun {
export interface DangerRun extends RepresentationForURL {
/** What event name triggered this */
event: string
/** What action inside that event trigger this run */
action: string | null
/** What slug should this run come from? */
repoSlug?: string
/** Where should we look in that repo for the Dangerfile? */
dangerfilePath: string
/** What type of DSL should the run use? */
dslType: dsl
/** Can Danger provide commentable feedback? */
Expand Down Expand Up @@ -69,15 +65,19 @@ export const dangerRunForRules = (
}
}

interface RepresentationForURL {
dangerfilePath: string
branch: string
repoSlug: string | undefined
}

/** Takes a DangerfileReferenceString and lets you know where to find it globally */
export const dangerRepresentationforPath = (value: DangerfileReferenceString) => {
if (!value.includes("@")) {
return { dangerfilePath: value }
} else {
return {
dangerfilePath: value.split("@")[1] as string,
repoSlug: value.split("@")[0] as string,
}
export const dangerRepresentationforPath = (value: DangerfileReferenceString): RepresentationForURL => {
const afterAt = value.includes("@") ? value.split("@")[1] : value
return {
branch: value.includes("#") ? value.split("#")[1] : "master",
dangerfilePath: afterAt.split("#")[0],
repoSlug: value.includes("@") ? value.split("@")[0] : undefined,
}
}

Expand Down
4 changes: 1 addition & 3 deletions source/danger/danger_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import { getTemporaryAccessTokenForInstallation } from "../api/github"
import perilPlatform from "./peril_platform"

/** Logs */
const log = (message: string) => {
winston.info(`[runner] - ${message}`)
}
const log = (message: string) => winston.info(`[runner] - ${message}`)

// What does the Peril object look like inside the runtime
// TODO: Expose this usefully somehow
Expand Down
1 change: 1 addition & 0 deletions source/db/_tests/__snapshots__/_json.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Object {
"issue": "orta/peril@issue.ts",
"pull_request": "orta/peril@pr.ts",
},
"scheduler": Object {},
"settings": Object {
"env_vars": Array [],
"ignored_repos": Array [],
Expand Down
47 changes: 46 additions & 1 deletion source/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,58 @@ export interface GitHubInstallation {
*/
id: number
/**
* In our DB this is represented as a JSON type, so you should always have settings
* In our DB this is represented as a JSON type, so you should anticipate have settings
* as a nullable type. These are the entire installation settings.
*/
settings: GitHubInstallationSettings

/** Having rules in here would mean that it would happen on _any_ event, another JSON type in the DB */
rules: RunnerRuleset

/**
* Scheduled tasks to run using a cron-like syntax.
*
* This uses [node-schedule](https://github.com/node-schedule/node-schedule) under the hood. The
* object is similar to the rules section, in that you define a cron-string with the following format:
*
* * * * * * *
* ┬ ┬ ┬ ┬ ┬ ┬
* │ │ │ │ │ |
* │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
* │ │ │ │ └───── month (1 - 12)
* │ │ │ └────────── day of month (1 - 31)
* │ │ └─────────────── hour (0 - 23)
* │ └──────────────────── minute (0 - 59)
* └───────────────────────── second (0 - 59, OPTIONAL)
*
* Which would look something like:
*
* "scheduler": {
* "0 0 12 * * ?": "schedule/daily_at_twelve.ts",
* "0 9 * * 1-5": "schedule/weekday_wakeup_email.ts"
* }
*
* in practice. There's a lot of great resources on the net showing the general syntax.
*/
scheduler: RunnerRuleset

/**
* A set of repos and their additional event hooks, these are
* in addition to the ones provided by `"rules"` which are applied
* to every repo.
*
* "repos" : {
* "orta/ORStackView": {
* "issue.created": "orta/peril@lock_issues.ts"
* }
* }
*
*/
repos: UniqueRepoRuleset
}

export interface UniqueRepoRuleset {
[name: string]: RunnerRuleset
}

export interface RunnerRuleset {
Expand Down
34 changes: 23 additions & 11 deletions source/db/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ For example:
*/

/** Logs */
const info = (message: string) => winston.info(`[db] - ${message}`)
const info = (message: string) => winston.info(`[json db] - ${message}`)
const error = (message: string) => winston.error(`[json db] - ${message}`)

const getInstallationId = (id: string | undefined): number => {
let installationId: number | undefined = parseInt(id as string, 10)
Expand Down Expand Up @@ -56,8 +57,7 @@ const jsonDatabase = (dangerFilePath: DangerfileReferenceString): DatabaseAdapto

/** Gets a Github repo from the DB */
getRepo: async (installationID: number, repoName: string): Promise<GithubRepo | null> => {
// Type this?
const repos = (org as any).repos
const repos = org.repos
if (!repos[repoName]) {
return null
}
Expand Down Expand Up @@ -101,19 +101,31 @@ const jsonDatabase = (dangerFilePath: DangerfileReferenceString): DatabaseAdapto
throwNoJSONFileFound(dangerFilePath)
}

org = JSON.parse(file)
// Ensure settings are non-null
org.settings.env_vars = org.settings.env_vars || []
org.settings.ignored_repos = org.settings.ignored_repos || []
org.settings.modules = org.settings.modules || []
org.id = getInstallationId(PERIL_ORG_INSTALLATION_ID)
const parsedOrg = JSON.parse(file) as Partial<GitHubInstallation>
if (!parsedOrg) {
error(`Could not run JSON.parse on the contents of ${dangerFilePath}.`)
process.exitCode = 1
} else {
// Set our write-once org variable that is then re-used for all of the different
// installation related calls

org = {
id: getInstallationId(PERIL_ORG_INSTALLATION_ID),
repos: parsedOrg.repos || {},
rules: parsedOrg.rules || {},
scheduler: parsedOrg.scheduler || {},
settings: {
env_vars: (parsedOrg.settings && parsedOrg.settings.env_vars) || [],
ignored_repos: (parsedOrg.settings && parsedOrg.settings.ignored_repos) || [],
modules: (parsedOrg.settings && parsedOrg.settings.modules) || [],
},
}
}
},
})

export default jsonDatabase

// Some error handling.

const throwNoPerilInstallationID = () => {
/* tslint:disable: max-line-length */
const msg =
Expand Down
7 changes: 3 additions & 4 deletions source/db/postgres.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ const info = (message: string) => {
}

const database: DatabaseAdaptor = {
setup: async () => {
db = pg()(DATABASE_URL as string)
},

/** Saves an Integration */
saveInstallation: async (installation: GitHubInstallation) => {
info(`Saving installation with id: ${installation.id}`)
Expand All @@ -39,6 +35,9 @@ const database: DatabaseAdaptor = {
)
},

setup: async () => {
db = pg()(DATABASE_URL as string)
},
/** Gets an Integration */
getInstallation: async (installationID: number): Promise<GitHubInstallation | null> => {
return db.oneOrNone("select * from installations where id=$1", [installationID])
Expand Down
12 changes: 12 additions & 0 deletions source/github/events/_tests/_github_runner-runs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ const getSettings = (overwrites: Partial<GitHubRunSettings>) => ({
it("handles a platform only run", () => {
const installation = {
id: 12,
repos: {},
rules: {
pull_request: "orta/peril-dangerfiles@pr.ts",
},
scheduler: {},
settings: defaultSettings,
}

Expand All @@ -44,6 +46,7 @@ it("handles a platform only run", () => {
expect(runs).toEqual([
{
action: "created",
branch: "master",
dangerfilePath: "pr.ts",
dslType: 0,
event: "pull_request",
Expand All @@ -56,9 +59,11 @@ it("handles a platform only run", () => {
it("gets the expected runs for platform + repo rules", () => {
const installation: GitHubInstallation = {
id: 12,
repos: {},
rules: {
pull_request: "orta/peril-dangerfiles@pr.ts",
},
scheduler: {},
settings: defaultSettings,
}

Expand All @@ -68,6 +73,7 @@ it("gets the expected runs for platform + repo rules", () => {
expect(runs).toEqual([
{
action: "created",
branch: "master",
dangerfilePath: "pr.ts",
dslType: 0,
event: "pull_request",
Expand All @@ -76,20 +82,24 @@ it("gets the expected runs for platform + repo rules", () => {
},
{
action: "created",
branch: "master",
dangerfilePath: "pr.ts",
dslType: 0,
event: "pull_request",
feedback: 0,
repoSlug: undefined,
},
])
})

it("gets the expected runs for platform", () => {
const installation = {
id: 12,
repos: {},
rules: {
pull_request: "orta/peril-dangerfiles@pr.ts",
},
scheduler: {},
settings: defaultSettings,
}

Expand All @@ -108,10 +118,12 @@ it("gets the expected runs for platform", () => {
expect(runs).toEqual([
{
action: "created",
branch: "master",
dangerfilePath: "pr.ts",
dslType: 1,
event: "issues",
feedback: 0,
repoSlug: undefined,
},
])
})
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ it("Does not run a dangerfile in an ignored repo", async () => {

const installationSettings: GitHubInstallation = {
id: 123,
repos: {},
rules: {},
scheduler: {},
settings: {
env_vars: [],
ignored_repos: [body.pull_request.head.repo.full_name],
Expand Down
Loading

0 comments on commit 69abe93

Please sign in to comment.