Skip to content

Commit

Permalink
Merge pull request #172 from danger/bullet-ts
Browse files Browse the repository at this point in the history
TypeScript support, + danger.d.ts, + danger DSL change
  • Loading branch information
orta committed Mar 19, 2017
2 parents f2a086e + ac25cfc commit bf05e4c
Show file tree
Hide file tree
Showing 22 changed files with 799 additions and 132 deletions.
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ cache:
yarn: true
directories:
- node_modules

matrix:
include:
- node_js: node
before_script:
- npm run build
- npm run link
- yarn run link
- danger
- node_js: '6'
- node_js: '7'

script:
- npm run lint
- npm test -- --coverage --no-cache && rm ./coverage/coverage-final.json
- yarn lint
- yarn test -- --coverage --no-cache && rm ./coverage/coverage-final.json

after_success:
- bash <(curl -s https://codecov.io/bash)
Expand Down
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

// Add your own contribution below

* Initial work on supporting TypeScript Dangerfiles by using Jest infrastructure - orta
* Created a danger.d.ts for VS Code users to get auto-completion etc - orta
* Exposed all global functions ( like `warn`, `fail`, `git`, `schedule`, ... ) on the `danger` object. - orta

This is specifically to simplify building library code. It should not affect end-users. If you want to
look at making a Danger JS Plugin, I'd recommend exposing a function which takes the `danger` object and working from that.


### 0.13.0

* Add `danger.utils` DSL, which includes `danger.utils.href()` and `danger.utils.sentence()` - macklinu
Expand Down
9 changes: 2 additions & 7 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,10 @@ machine:
dependencies:
override:
- yarn
- yarn add danger
cache_directories:
- ~/.cache/yarn

test:
override:
- yarn build
- npm link
- danger

post:
- yarn lint
- yarn test
- yarn danger -- run --dangerfile dangerfile.circle.js
1 change: 1 addition & 0 deletions dangerfile.circle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// This is currently empty. Maybe it can do something in the future, but for now it's 👍 to be empty.
23 changes: 20 additions & 3 deletions dangerfile.js → dangerfile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
// Removed import
// Because we don't get to use the d.ts, we can pass in a subset here.
import {DangerDSL} from "./source/dsl/DangerDSL"
declare var danger: DangerDSL
declare function warn(params: string): void
declare function fail(params: string): void

import fs from "fs"
import includes from "lodash.includes"
import * as fs from "fs"

import * as includesOriginal from "lodash.includes"
// For some reason we're getting type errors on this includes module?
// Wonder if we could move to the includes function in ES2015?
const includes = includesOriginal as Function

// Request a CHANGELOG entry if not declared #trivial
const hasChangelog = includes(danger.git.modified_files, "changelog.md")
Expand All @@ -25,3 +33,12 @@ if (packageChanged && !lockfileChanged) {
const idea = "Perhaps you need to run `yarn install`?"
warn(`${message} - <i>${idea}</i>`)
}

import dtsGenerator from "./scripts/danger-dts"
const currentDTS = dtsGenerator()
const savedDTS = fs.readFileSync("source/danger.d.ts").toString()
if (currentDTS !== savedDTS) {
const message = "There are changes to the Danger DSL which are not reflected in the current danger.d.ts."
const idea = "Please run <code>yarn declarations</code> and update this PR."
fail(`${message} - <i>${idea}</i>`)
}
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@
"test:watch": "jest --watch",
"lint": "tslint \"source/**/*.ts\"",
"lint:fix": "tslint \"source/**/*.ts\" --fix",
"prepublish": "in-publish && npm run build || not-in-publish",
"prepublish": "in-publish && npm run build && yarn declarations || not-in-publish",
"build": "shx rm -rf ./distribution && tsc && madge ./distribution --circular",
"build:watch": "tsc -w",
"link": "npm run build ; chmod +x distribution/commands/danger.js ; npm link"
"link": "npm run build && chmod +x distribution/commands/danger.js && npm link",
"declarations": "ts-node ./scripts/create-danger-dts.ts"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -89,7 +90,7 @@
"madge": "^1.4.4",
"shx": "^0.2.1",
"ts-jest": "^19.0.0",
"ts-node": "^2.0.0",
"ts-node": "^2.1.0",
"tslint": "^4.4.0",
"typescript": "2.2.1"
},
Expand All @@ -98,6 +99,7 @@
"chalk": "^1.1.1",
"commander": "^2.9.0",
"debug": "^2.6.0",
"jest-config": "^18.0.0",
"jest-environment-node": "^18.1.0",
"jest-runtime": "^18.0.0",
"jsome": "^2.3.25",
Expand Down
15 changes: 15 additions & 0 deletions scripts/create-danger-dts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import dts from "./danger-dts"
import * as fs from "fs"

// This could need to exist
if (!fs.existsSync("distribution")) {
fs.mkdirSync("distribution")
}

const output = dts()

// This is so you can get it for this repo 👍
fs.writeFileSync("source/danger.d.ts", output)
fs.writeFileSync("distribution/danger.d.ts", output)

console.log("Awesome - shipped to source/danger.d.ts and distribution/danger.d.ts")
70 changes: 0 additions & 70 deletions scripts/create-flow-typed-export.js

This file was deleted.

48 changes: 48 additions & 0 deletions scripts/danger-dts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as fs from "fs"

const createDTS = () => {
let fileOutput = ""

const extras = ["source/platforms/messaging/violation.ts"]
const dslFiles = fs.readdirSync("source/dsl").map(f => `source/dsl/${f}`)

dslFiles.concat(extras).forEach(file => {
// Sometimes they have more stuff, in those cases
// offer a way to crop the file.
const content = fs.readFileSync(file).toString()
if (content.includes("/// End of Danger DSL definition")) {
fileOutput += content.split("/// End of Danger DSL definition")[0]
} else {
fileOutput += content
}
fileOutput += "\n"
})

// The definition of all the exposed vars is inside
// the Dangerfile.js file.
const allDangerfile = fs.readFileSync("source/runner/Dangerfile.ts").toString()
const moduleContext = allDangerfile.split("/// Start of Danger DSL definition")[1].split("/// End of Danger DSL definition")[0]

// we need to add either `declare function` or `declare var` to the interface
const context = moduleContext.split("\n").map((line: string) => {
if ((line.length === 0) || (line.includes("*"))) { return line }
if (line.includes("(")) { return " function " + line.trim() }
if (line.includes(":")) { return " const " + line.trim() }
return ""
}).join("\n")

fileOutput += `declare namespace danger {
${context}
}
`// last extra line is EOF

// Remove all JS-y bits
fileOutput = fileOutput.split("\n").filter((line) => {
return !line.startsWith("import") &&
!line.includes("* @type ")
}).join("\n")

return fileOutput.replace(/\n\s*\n\s*\n/g, "\n")
}

export default createDTS
1 change: 1 addition & 0 deletions source/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ declare module "lodash.includes";
declare module "lodash.find";
declare module "jest-runtime";
declare module "jest-environment-node";
declare module "jest-config";
declare module "voca";
declare module "jsome";

Expand Down
3 changes: 2 additions & 1 deletion source/commands/danger-pr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Executor } from "../runner/Executor"
import { pullRequestParser } from "../platforms/github/pullRequestParser"
import { runDangerfileEnvironment } from "../runner/DangerfileRunner"
import { DangerContext } from "../runner/Dangerfile"
import { dangerfilePath } from "./utils/file-utils"

const d = debug("danger:pr")

Expand All @@ -19,7 +20,7 @@ program
.option("-r, --repl", "Drop into a Node REPL after evaluating the dangerfile")
.parse(process.argv)

const dangerFile = (program as any).dangerfile || "dangerfile.js"
const dangerFile = dangerfilePath(program)

if (program.args.length === 0) {
console.error("Please include a PR URL to run against")
Expand Down
9 changes: 5 additions & 4 deletions source/commands/danger-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import * as debug from "debug"
import * as fs from "fs"
import { getCISource } from "../ci_source/get_ci_source"
import { getPlatformForEnv } from "../platforms/platform"
import {Executor} from "../runner/Executor"
import { Executor } from "../runner/Executor"
import { dangerfilePath } from "./utils/file-utils"

const d = debug("danger:run")
declare const global: any
Expand All @@ -14,7 +15,7 @@ declare const global: any
program
.option("-v, --verbose", "Verbose output of files")
.option("-c, --external-ci-provider [modulePath]", "Specify custom CI provider")
.option("-d, --dangerfile [filePath]", "Specify custom dangefile other than default dangerfile.js")
.option("-d, --dangerfile [filePath]", "Specify custom dangerfile other than default dangerfile.js")
.parse(process.argv)

process.on("unhandledRejection", function(reason: string, _p: any) {
Expand Down Expand Up @@ -52,7 +53,7 @@ async function run(): Promise<any> {
}

if (platform) {
const dangerFile = (program as any).dangerfile || "dangerfile.js"
const dangerFile = dangerfilePath(program)

console.log(`OK, looks good ${source.name} on ${platform.name}`)

Expand All @@ -64,7 +65,7 @@ async function run(): Promise<any> {
const exec = new Executor(source, platform)
exec.setupAndRunDanger(dangerFile)
} else {
console.log(`looks like specified ${dangerFile} is not valid path`)
console.error(`Looks like specified ${dangerFile} is not a valid path.`)
process.exitCode = 1
}
} catch (error) {
Expand Down
26 changes: 26 additions & 0 deletions source/commands/utils/_tests/file-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
let mockDangerfilePath = ""
jest.mock("fs", () => { return { existsSync: (p) => p === mockDangerfilePath } })

import { dangerfilePath } from "../file-utils"

describe("dangerfilePath", () => {

it("should return anything passed into the program's dangerfile", () => {
expect(dangerfilePath({ dangerfile: "123"})).toEqual("123")
})

it("should find a dangerfile.js if there is no program, and the .js file exists", () => {
mockDangerfilePath = "dangerfile.js"
expect(dangerfilePath({})).toEqual("dangerfile.js")
})

it("should find a dangerfile.ts if there is no program, and the .js file does not exist", () => {
mockDangerfilePath = "dangerfile.ts"
expect(dangerfilePath({})).toEqual("dangerfile.ts")
})

it("should raise if nothing exists", () => {
mockDangerfilePath = "dangerfile.tsjs"
expect(() => dangerfilePath({}) ).toThrow()
})
})
15 changes: 15 additions & 0 deletions source/commands/utils/file-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { existsSync } from "fs"

/**
* Returns a the typical Dangerfile, depending on it's location
* taking into account whether it JS or TS by whether those exists.
*
* Will throw if it isn't found.
*/
export function dangerfilePath(program: any): string {
if (program.dangerfile) { return program.dangerfile }
if (existsSync("dangerfile.ts")) { return "dangerfile.ts" }
if (existsSync("dangerfile.js")) { return "dangerfile.js" }

throw new Error("Could not find a `dangerfile.js` or `dangerfile.ts` in the current working directory.")
}

0 comments on commit bf05e4c

Please sign in to comment.