Danger JS Documentation

repository·main·Indexed 26 days ago

https://github.com/danger/danger-js

Danger 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.

Tokens
10.2K
Snippets
27
Records
70
Agent score
90%

What's inside Danger JS

  1. Overview of Danger JS

    main
    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.
  2. Understand the Danger JS execution lifecycle

    main

    Danger JS operates through a multi-step evaluation process to run per-application rules based on Pull Request metadata:

    1. CI Detection: Danger uses environment variables to identify the CI provider and validate the pull request context.
    2. Platform Identification: It identifies the code review platform (e.g., GitHub, GitLab, BitBucket Server, or BitBucket Cloud).
    3. DSL Generation: A JSON-based Domain Specific Language (DSL) is generated. This allows danger ci to handle async code and enables sandboxing via tools like peril.
    4. DSL Conversion: The danger runner command reads the JSON DSL from STDIN and converts it into a functional DangerDSLType.
    5. Evaluation: An inline runner sets up a transpiled environment, strips import { ... } from 'danger' from your Dangerfile, and executes the code inline with DSL attributes in the global context.
    6. Results: The runner passes results back to the platform, which then performs actions like creating, deleting, or editing comments in the code review interface.
  3. Understand Peril (Hosted Danger)

    main
    Peril 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.
  4. Write a Dangerfile with TypeScript support

    main

    The Danger JS DSL is fully typed via TypeScript. When you import danger in 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.

  5. Develop Peril-compatible plugins

    main
    Plugins 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 the schedule pattern or synchronous methods).
  6. Run Danger locally with danger local

    main

    The danger local command 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 local derives its environment from the local git differences between your current commit and the master branch.

    Important Considerations:

    • Platform Objects: In a local context, danger.github and danger.bitbucket will 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 --base flag.
  7. Create a Danger plugin using the Yeoman generator

    main

    To move your Dangerfile rules into a reusable node module, use the generator-danger-plugin Yeoman generator. This creates a scaffolded project in either JavaScript or TypeScript.

    1. Navigate to your project folder.
    2. Install the Yeoman generator and the template globally: npm i -g yo generator-danger-plugin.
    3. 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-plugin
  8. Configure TypeScript to include/exclude the Dangerfile

    main

    If you use a src folder for your source code and place a dangerfile.ts at the root, it may interfere with your project's compilation. To prevent this while still maintaining correct inline error reporting in your IDE, add dangerfile.ts to both the include and exclude sections of your tsconfig.json.

    {
      "compilerOptions": {},
      "include": ["src/**/*.ts", "src/**/*.tsx", "dangerfile.ts"],
      "exclude": ["dangerfile.ts", "node_modules"]
    }
  9. Mock the 'danger' module for testing

    main

    The danger module 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 to import "danger" in code running outside of Danger, it will throw an exception. To test code that relies on danger, 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.")
      })
    })
  10. Handle Async operations in Peril Dangerfiles

    main

    Because Peril runs via inline execution of a JavaScript script, standard async behavior can be unpredictable. You have two primary patterns for managing this:

    1. 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.xSync instead of path.x).

    2. Use schedule: The Dangerfile DSL provides a schedule function that can handle Promises or functions with a callback. When using async/await, wrap your logic in schedule to 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)
    })