Danger JS Documentation
repository·main·Indexed 26 days ago
https://github.com/danger/danger-jsDanger JS is a tool that automates code review etiquette by running in CI pipelines to codify team norms, such as enforcing documentation updates or checking for JIRA links. It supports platforms like GitHub, BitBucket Server, and BitBucket Cloud, and integrates with CI providers including GitHub Actions, GitLab CI, Travis CI, Circle CI, and Jenkins. The documentation covers the execution lifecycle, Dangerfile configuration with TypeScript support, local testing via `danger pr` and `danger local`, and the use of Peril for hosted, real-time responses.
What's inside Danger JS
- Danger JS automates code review conventions by running after your CI. It allows you to codify team norms (like enforcing CHANGELOG updates, checking for JIRA links in PR bodies, or looking for anti-patterns) to reduce rote manual review tasks. It supports various code review platforms (GitHub, BitBucket Server, BitBucket Cloud) and a wide range of CI providers including GitHub Actions, GitLab CI, Travis CI, Circle CI, and Jenkins.
Understand the Danger JS execution lifecycle
mainDanger JS operates through a multi-step evaluation process to run per-application rules based on Pull Request metadata:
- CI Detection: Danger uses environment variables to identify the CI provider and validate the pull request context.
- Platform Identification: It identifies the code review platform (e.g., GitHub, GitLab, BitBucket Server, or BitBucket Cloud).
- DSL Generation: A JSON-based Domain Specific Language (DSL) is generated. This allows
danger cito handle async code and enables sandboxing via tools likeperil. - DSL Conversion: The
danger runnercommand reads the JSON DSL fromSTDINand converts it into a functionalDangerDSLType. - Evaluation: An inline runner sets up a transpiled environment, strips
import { ... } from 'danger'from yourDangerfile, and executes the code inline with DSL attributes in the global context. - Results: The runner passes results back to the platform, which then performs actions like creating, deleting, or editing comments in the code review interface.
Understand Peril (Hosted Danger)
mainPeril is a hosted instance of Danger that runs on a server rather than on CI. It responds to webhooks instantly, allowing it to respond to PR changes in real-time and operate on events other than just Pull Requests. Peril is currently self-hosted via Heroku.Publish and register a Danger plugin
mainTo make your plugin discoverable and highlighted on the Danger website:
- Update your
package.jsonwith your new version. - Include the tag
"danger-plugin"in yourpackage.json. - Import your module into your
Dangerfile.
Once published, the Danger website will display your plugin's README.
- Update your
Write a Dangerfile with TypeScript support
mainThe Danger JS DSL is fully typed via TypeScript. When you import
dangerin your Dangerfile, editors like Visual Studio Code provide inline documentation and auto-completion.If your project uses Babel, your Dangerfile will use the same transpilation settings. If you use TypeScript + Jest, it works out of the box. For other setups, refer to the transpilation guide.
Develop Peril-compatible plugins
mainPlugins running on Peril must account for the same async constraints as Dangerfiles. If your plugin uses asynchronous code, you must ensure it handles execution in a way that is compatible with Peril's inline execution model (e.g., using theschedulepattern or synchronous methods).Run Danger locally with danger local
mainThe
danger localcommand allows you to run your Dangerfile rules locally using git hooks. This provides immediate feedback on your code before it is pushed to a remote repository.Unlike
danger ci, which uses Pull Request data,danger localderives its environment from the local git differences between your current commit and themasterbranch.Important Considerations:
- Platform Objects: In a local context,
danger.githubanddanger.bitbucketwill be falsy. If you share a Dangerfile between CI and local, ensure you check for the existence of these objects before accessing them. - Branch Base: By default, it compares against
master. If your reference branch is different, use the--baseflag.
- Platform Objects: In a local context,
Create a Danger plugin using the Yeoman generator
mainTo move your Dangerfile rules into a reusable node module, use the
generator-danger-pluginYeoman generator. This creates a scaffolded project in either JavaScript or TypeScript.- Navigate to your project folder.
- Install the Yeoman generator and the template globally:
npm i -g yo generator-danger-plugin. - Run the generator:
yo danger-plugin.
It is recommended to choose the TypeScript option for a better editor experience (e.g., in VS Code).
npm i -g yo generator-danger-plugin yo danger-pluginDisable Danger transpilation
mainTo force Danger to skip transpiling your Dangerfile (bypassing the automatic detection of Babel or TypeScript), set the following environment variable to
"true":DANGER_DISABLE_TRANSPILATION="true"DANGER_DISABLE_TRANSPILATION="true"Configure TypeScript to include/exclude the Dangerfile
mainIf you use a
srcfolder for your source code and place adangerfile.tsat the root, it may interfere with your project's compilation. To prevent this while still maintaining correct inline error reporting in your IDE, adddangerfile.tsto both theincludeandexcludesections of yourtsconfig.json.{ "compilerOptions": {}, "include": ["src/**/*.ts", "src/**/*.tsx", "dangerfile.ts"], "exclude": ["dangerfile.ts", "node_modules"] }Mock the 'danger' module for testing
mainThe
dangermodule is not a real module that can be imported in external environments; its exports are injected into the global environment during evaluation. If you attempt toimport "danger"in code running outside of Danger, it will throw an exception. To test code that relies ondanger, use a mocking system like Jest to fake the module and manipulate the global object (e.g.,danger.github.pr).jest.mock("danger", () => jest.fn()) import * as danger from "danger" const dm = danger as any // Example: Mocking the PR body to test logic beforeEach(() => { dm.fail = jest.fn() }) it("fails when there's no PR body", () => { dm.danger = { github: { pr: { body: "" } } } return rfc5().then(() => { expect(dm.fail).toHaveBeenCalledWith("Please add a description to your PR.") }) })Handle Async operations in Peril Dangerfiles
mainBecause Peril runs via inline execution of a JavaScript script, standard async behavior can be unpredictable. You have two primary patterns for managing this:
Ignore Async: Since the Dangerfile is a script, you can ignore the non-blocking aspect of the Node API. Prefer synchronous methods where available (e.g., use
path.xSyncinstead ofpath.x).Use
schedule: The Dangerfile DSL provides aschedulefunction that can handle Promises or functions with a callback. When usingasync/await, wrap your logic inscheduleto ensure Danger waits for the tasks to complete before continuing.
import { schedule, danger } from "danger" /// [... a bunch of functions] schedule(async () => { const packageDiff = await danger.git.JSONDiffForFile("package.json") checkForRelease(packageDiff) checkForNewDependencies(packageDiff) checkForLockfileDiff(packageDiff) checkForTypesInDeps(packageDiff) })