Last active
August 8, 2018 16:09
-
-
Save stevethomp/62aa48393065bdbd5d6aa92c57f1685d to your computer and use it in GitHub Desktop.
Dangerfile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { danger, warn, fail, markdown, message } from "danger"; | |
import jiraIssue from "danger-plugin-jira-issue"; | |
import { readFileSync } from "fs"; | |
/* | |
Danger will post all these fail/warn/message's as a comment on the PR, from the jenkins user. Over time, as commits are added, the comment is amended. | |
No comment means you're all good and the PR passes these checks. | |
Check out http://danger.systems/js/ for how this all works, and http://danger.systems/js/guides/the_dangerfile.html for creating more rules. | |
*/ | |
// ** Setup ** | |
var updatedFiles = danger.git.created_files.concat(danger.git.modified_files) | |
var swiftFiles = updatedFiles.filter(path => stringContains(path, ".swift")) | |
class LintResult { | |
character: number | |
file: string | |
line: number | |
reason: string | |
rule_id: string | |
severity: string | |
type: string | |
constructor(object: any) { | |
this.character = object["character"] as number | |
this.file = object["file"] as string | |
this.line = object["line"] as number | |
this.reason = object["reason"] as string | |
this.rule_id = object["rule_id"] as string | |
this.severity = object["severity"] as string | |
this.type = object["type"] as string | |
} | |
} | |
// ** Rules ** | |
// No PR is too small to include a description of why you made a change | |
if (danger.github.pr.body.length < 10) { | |
warn('Please include a description of your PR changes.'); | |
} | |
// Check that someone has been assigned to this PR | |
if (danger.github.requested_reviewers.users.length == 0) { | |
warn('Please assign someone to review this PR.'); | |
} | |
// Check that additions are less than 500 (with 50 line buffer) | |
const bigPRThreshold = 550; | |
if (danger.github.pr.additions >= bigPRThreshold) { | |
warn(':exclamation: Big PR'); | |
markdown(`Please try to keep your PR size under ${bigPRThreshold} lines. If your PR contains multiple changes, consider splitting it into multiple PRs to help make reviews faster and easier.`); | |
} | |
// Congratulate PRs that simplify things | |
if (danger.github.pr.deletions > danger.github.pr.additions) { | |
message('👏 Great job! This PR deletes more than it adds. Thanks for keeping us lean!'); | |
} | |
// Checks for a JIRA issue in the title of the PR and links to it, eg: "ABC-101". Opt out by including "No Jira" | |
// yarn add danger-plugin-jira-issue --dev | |
if (!stringContainsAny(danger.github.pr.title.toLocaleLowerCase(), ["no jira", "nojira", "no-jira"])) { | |
jiraIssue({ | |
key: ['ABC', 'abc'], | |
url: 'https://abc.atlassian.net/browse', | |
emoji: ':paperclip:', | |
format(emoji, jiraUrls) { // Optional Formatter | |
return `${emoji} ${jiraUrls.join(", ")} Check it out on JIRA`; | |
} | |
}) | |
} | |
// Runs Swiftlint against added + modified files, and comments the results inline | |
var process = require('child_process'); | |
swiftFiles.forEach(filePath => { | |
var escapedFilePath = filePath.replace(" ", "\\ "); | |
let output = process.execSync("Pods/SwiftLint/swiftlint --config Scripts/.swiftlint.yml --path " + escapedFilePath + " --reporter json") | |
const jsonOutput = JSON.parse(output) | |
jsonOutput.forEach((lint: any) => { | |
const newLintResult = new LintResult(lint) | |
let message = `${newLintResult.type}: ${newLintResult.reason}` | |
let fileComponents = newLintResult.file.split(`jenkins-job-name/`) | |
var file: string = fileComponents[0] | |
if (fileComponents.length >= 2) { | |
file = fileComponents[1] | |
} | |
let line = newLintResult.line | |
if (newLintResult.severity.toLowerCase() === "error") { | |
fail(message, file, line) | |
} else { | |
warn(message, file, line) | |
} | |
}); | |
}) | |
swiftFiles.forEach(filePath => { | |
var fileText = readFileSync(filePath, 'utf8'); | |
if (stringContains(fileText, "UINavigationController(rootViewController:")) { | |
warn(`${fileNameFrom(filePath)} is using a default UINavigationController. Please use ABCNavigationController instead.`); | |
} | |
if (stringContains(filePath, "ViewController.swift") && !stringContains(fileText, "supportedInterfaceOrientations")) { | |
warn(`${fileNameFrom(filePath)} is not defining its supportedInterfaceOrientations. Please do so to ensure orientation is properly handled.`); | |
} | |
}) | |
// ** Helpers ** | |
function fileNameFrom(filePath: string) { | |
return filePath.replace(/^.*(\\|\/|\:)/, ''); | |
} | |
function stringContains(first: string, second: string) { | |
return first.indexOf(second) !== -1 | |
} | |
function stringContainsAny(first: string, any: string[]) { | |
let contains = any.find( tester => | |
stringContains(first, tester) | |
) | |
return contains !== undefined | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey @mikenikles, thanks! I really like danger's ability to do positive feedback too. I took a look and your dangerfile looks great! I'm inspired by your wording and think I'll try to make ours a bit friendlier.
Good tip on the
requested_reviewers
, I took a look! I'm seeing that it's defined asrequested_reviewers: GitHubUser[]
so it looks like an array and the length check is working, from https://github.com/danger/danger-js/blob/3c641236595774c1e4202fad43217432fe9c780b/source/dsl/GitHubDSL.ts#L18.