Skip to content

Instantly share code, notes, and snippets.

@stevethomp
Last active August 8, 2018 16:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevethomp/62aa48393065bdbd5d6aa92c57f1685d to your computer and use it in GitHub Desktop.
Save stevethomp/62aa48393065bdbd5d6aa92c57f1685d to your computer and use it in GitHub Desktop.
Dangerfile
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
}
@mikenikles
Copy link

Hey @stevethomp,

Thanks for sharing your Danger file. I got inspired by // Congratulate PRs that simplify things and added a few positive feedback messages to our Danger file at work. (Side note, your tweet earlier today reminded me of Danger and pushed me to integrate Danger into our project. Hopefully my team will appreciate the positive feedback received in their PRs next week 😄)

I noticed if (danger.github.requested_reviewers.length == 0) (line 20) in your Danger file and wonder if that does what you expect. The reason I bring it up is because requested_reviewers in my case returns an object, not an array. See https://github.com/danger/danger-js/blob/7ae8beeb28d64b471bf089766d39ee89195f8e5f/source/platforms/github/GitHubAPI.ts#L318 where Danger calls the Github API, which returns an object as documented here.

@stevethomp
Copy link
Author

stevethomp commented Jul 5, 2018

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 as requested_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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment