Skip to content

Commit

Permalink
Merge pull request #1436 from danger/init-improv
Browse files Browse the repository at this point in the history
Improve the init CLI
  • Loading branch information
orta committed Apr 16, 2024
2 parents 9d9bd6e + 8733b5d commit f9c165f
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 25 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -17,6 +17,12 @@
<!-- Your comment below this -->
<!-- Your comment above this -->


## 12.1.0

It's been 7 years since I looked at `danger init` and err, the world of CI has changed quite a bit since then. So, Danger JS's
`init` command now knows that GitHub Actions exists and will correctly offer some advice on how to set up a Dangerfile for it. - [@orta]

## 12.0.0

Bumping to 12.x because we've raised the minimum to node version from 14 to 18. This is due to some of our dependencies
Expand Down
45 changes: 25 additions & 20 deletions source/commands/danger-init.ts
Expand Up @@ -6,7 +6,7 @@ import program from "commander"
import * as fs from "fs"

import { generateDefaultDangerfile } from "./init/default-dangerfile"
import { travis, circle, unsure } from "./init/add-to-ci"
import { travis, circle, unsure, githubActions } from "./init/add-to-ci"
import { generateInitialState, createUI } from "./init/state-setup"
import { InitUI, InitState, highlight } from "./init/interfaces"

Expand Down Expand Up @@ -42,9 +42,15 @@ const go = async (app: App) => {
state.isAnOSSRepo = isOSS

await setupDangerfile(ui, state)
await setupGitHubAccount(ui, state)
await setupGHAccessToken(ui, state)
await addToCI(ui, state)

if (state.isAnOSSRepo) {
await setupGitHubAccount(ui, state)
await setupGHAccessToken(ui, state)
await addToCI(ui, state)
} else {
// We can use the private github workflow for private repos
await githubActions(ui, state)
}
await wrapItUp(ui, state)
await thanks(ui, state)
}
Expand All @@ -65,9 +71,9 @@ const showTodoState = async (ui: InitUI) => {
await ui.pause(0.6)
ui.say(` - [ ] Create a Dangerfile and add a few simple rules.`)
await ui.pause(0.6)
ui.say(` - [ ] Create a GitHub account for Danger to use, for messaging.`)
ui.say(` - [ ] Potentially create a GitHub account for Danger to use, for messaging.`)
await ui.pause(0.6)
ui.say(` - [ ] Set up an access token for Danger.`)
ui.say(` - [ ] Set up an access token for Danger to comment with.`)
await ui.pause(0.6)
ui.say(" - [ ] Set up Danger to run on your CI.\n")

Expand Down Expand Up @@ -202,21 +208,20 @@ const wrapItUp = async (ui: InitUI, _state: InitState) => {
await ui.pause(0.6)

const link = (name: string, url: string) => ui.say(" * " + ui.link(name, url))
link("artsy/Emission#dangerfile.ts", "https://github.com/artsy/emission/blob/master/dangerfile.ts")
link("artsy/eigen#dangerfile.ts", "https://github.com/artsy/eigen/blob/master/dangerfile.ts")
link(
"facebook/react-native#danger/dangerfile.js",
"https://github.com/facebook/react-native/blob/master/bots/dangerfile.js"
"facebook/react-native#main/packages/react-native-bots/dangerfile.js",
"https://github.com/facebook/react-native/blob/main/packages/react-native-bots/dangerfile.js"
)
link("mui/material-ui#dangerfile.ts", "https://github.com/mui/material-ui/blob/main/dangerfile.ts#L4")
link(
"apollographql/apollo-client#dangerfile.ts",
"https://github.com/apollographql/apollo-client/blob/master/config/dangerfile.ts"
"styleguidist/react-styleguidist#dangerfile.ts",
"https://github.com/styleguidist/react-styleguidist/blob/master/dangerfile.ts"
)
link(
"styleguidist/react-styleguidist#dangerfile.js",
"https://github.com/styleguidist/react-styleguidist/blob/master/dangerfile.js"
"storybooks/storybook#.ci/danger/dangerfile.ts",
"https://github.com/storybookjs/storybook/blob/master/.ci/danger/dangerfile.ts"
)
link("storybooks/storybook#dangerfle.js", "https://github.com/storybooks/storybook/blob/master/dangerfile.js")
link("ReactiveX/rxjs#dangerfle.js", "https://github.com/ReactiveX/rxjs/blob/master/dangerfile.js")

await ui.pause(1)
}
Expand All @@ -225,7 +230,9 @@ const addToCI = async (ui: InitUI, state: InitState) => {
ui.header("Add to CI")

await ui.pause(0.6)
if (state.ciType === "travis") {
if (state.ciType === "gh-actions") {
await githubActions(ui, state)
} else if (state.ciType === "travis") {
await travis(ui, state)
} else if (state.ciType === "circle") {
await circle(ui, state)
Expand All @@ -242,10 +249,8 @@ const thanks = async (ui: InitUI, _state: InitState) => {
ui.say("and every who has sent PRs.\n")
ui.say(
"If you like Danger, let others know. If you want to know more, follow " +
highlight("@orta") +
" and " +
highlight("@DangerSystems") +
" on Twitter."
highlight("@orta@webtoo.ls") +
" on Mastodon!"
)
ui.say("If you don't like something about Danger, help us improve the project - it's all done on volunteer time! xxx")
ui.say("Remember: it's nice to be nice.\n")
Expand Down
60 changes: 60 additions & 0 deletions source/commands/init/add-to-ci.ts
@@ -1,4 +1,64 @@
import { InitUI, InitState, highlight } from "./interfaces"
import chalk from "chalk"

export const githubActions = async (ui: InitUI, state: InitState) => {
if (!state.isAnOSSRepo) {
ui.say("For your closed-source project, we can use the default GitHub Auth token for posting.")
ui.say("So, you don't need to create a bot account.")
ui.pause(0.5)

ui.say("You will want to add a new step in an existing workflow yaml file.")
ui.pause(0.2)

ui.say("The step should look like this:")
ui.say("")
ui.say("```yaml")
ui.say(chalk.bold(" - name: Run Danger"))
ui.say(chalk.bold(" run: yarn danger ci"))
ui.say(chalk.bold(" env:"))
ui.say(chalk.bold(" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}`"))
ui.say("```")
ui.say("")
ui.pause(1)

ui.say("This will run Danger on every PR, press return when you have added this to one of your workflows.")
ui.waitForReturn()
return
}

const link = ui.link("issue #918.", "https://github.com/danger/danger-js/issues/918")
ui.say(
`For your OSS project, there are a few options you can find in ${link}. We will continue with using the new GitHub user account here.`
)
ui.pause(0.5)

ui.say("For your OSS project, you need to add a new secret to your workflow in a way that is slightly obfuscated.")
ui.say("This is because GitHub Actions doesn't allow you to use the default GITHUB_TOKEN to update its own comments.")
ui.pause(0.5)
ui.say("This would make Danger very spammy on a Pull Request.")

ui.pause(0.1)
ui.say("To get started, add a new step in an existing workflow file.")
ui.say("The step should look like this:")
ui.say("")
ui.say("```yaml")
ui.say(
chalk.bold(`)
- name: Run Danger
run: |
# Exposing this token is safe because the user of it has no other public repositories
# and has no permission to modify this repository.
TOKEN='ghp_On3bHOkcV2AmVY6'
TOKEN+='56186c3b09b4f86b1c65136769'
DANGER_GITHUB_API_TOKEN=$TOKEN yarn danger ci`)
)
ui.say("```")
ui.say("")
ui.pause(1)

ui.say("This will run Danger on every PR, press return when you have added this to one of your workflows.")
ui.waitForReturn()
}

export const travis = async (ui: InitUI, state: InitState) => {
// https://travis-ci.org/artsy/eigen/settings
Expand Down
10 changes: 7 additions & 3 deletions source/commands/init/default-dangerfile.ts
Expand Up @@ -34,17 +34,21 @@ export const generateDefaultDangerfile = (state: InitState) => {
${rules.join("\n")}
`
return formatDangerfile(dangerfile, dangerfileState)
return formatDangerfile(dangerfile, state, dangerfileState)
}

export const formatDangerfile = (dangerfile: string, dangerfileState: any) => {
export const formatDangerfile = (
dangerfile: string,
initState: InitState,
dangerfileState: ReturnType<typeof generateDangerfileState>
) => {
if (dangerfileState.hasPrettier) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { format } = require("prettier")
// Get package settings
const localPrettier = fs.existsSync("package.json") && JSON.parse(fs.readFileSync("package.json", "utf8")).prettier
// Always include this
const always = { editorconfig: true }
const always = { editorconfig: true, parser: "typescript", filepath: process.cwd() + " /" + initState.filename }
const settings = localPrettier ? { ...always, ...localPrettier } : always

return format(dangerfile, settings)
Expand Down
2 changes: 1 addition & 1 deletion source/commands/init/interfaces.ts
Expand Up @@ -17,7 +17,7 @@ export interface InitState {
hasSetUpAccountToken: boolean

repoSlug: string | null
ciType: "travis" | "circle" | "unknown"
ciType: "gh-actions" | "travis" | "circle" | "unknown"
isGitHub: boolean
}

Expand Down
4 changes: 3 additions & 1 deletion source/commands/init/state-setup.ts
Expand Up @@ -38,7 +38,9 @@ export const generateInitialState = (osProcess: NodeJS.Process): InitState => {
const isBabel = checkForBabel()
const hasTravis = fs.existsSync(".travis.yml")
const hasCircle = fs.existsSync("circle.yml")
const ciType = hasTravis ? "travis" : hasCircle ? "circle" : "unknown"
const hasGitHubActions = fs.existsSync(".github/") && fs.existsSync(".github/workflows")

const ciType = hasGitHubActions ? "gh-actions" : hasTravis ? "travis" : hasCircle ? "circle" : "unknown"
const repoSlug = getRepoSlug()
const isGitHub = !!repoSlug

Expand Down

0 comments on commit f9c165f

Please sign in to comment.