├── .github └── workflows │ ├── pr_flow.yaml │ └── verify_compatibility.yaml ├── .gitignore ├── .vscode ├── launch.json ├── model.code-snippets ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── analysis_options.yaml ├── dangerfile.dart ├── docs ├── DEBUGGING.MD ├── images │ ├── intellij_1.png │ ├── intellij_2.png │ ├── intellij_3.png │ ├── intellij_4.png │ ├── intellij_5.png │ └── vscode_1.png └── usage │ └── bitbucket_cloud.html.md ├── example ├── dart2 │ ├── dangerfile.dart │ └── pubspec.yaml ├── dart3 │ ├── dangerfile.dart │ └── pubspec.yaml └── with_plugin │ ├── danger_plugin_example │ ├── lib │ │ ├── danger_plugin_example.dart │ │ └── src │ │ │ └── random_generate_code.dart │ └── pubspec.yaml │ ├── dangerfile.dart │ └── pubspec.yaml ├── packages ├── danger_core │ ├── .gitignore │ ├── .vscode │ │ └── settings.json │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── build.yaml │ ├── lib │ │ ├── danger_core.dart │ │ └── src │ │ │ ├── danger_executor.dart │ │ │ ├── danger_utils.dart │ │ │ ├── mock_json_annotation.dart │ │ │ ├── models │ │ │ ├── bitbucket_cloud.dart │ │ │ ├── bitbucket_cloud.g.dart │ │ │ ├── danger_core_constants.dart │ │ │ ├── danger_dsl.dart │ │ │ ├── danger_dsl.g.dart │ │ │ ├── danger_results.dart │ │ │ ├── danger_results.g.dart │ │ │ ├── git_diff.dart │ │ │ ├── git_dsl.dart │ │ │ ├── git_dsl.g.dart │ │ │ ├── github_dsl.dart │ │ │ ├── github_dsl.g.dart │ │ │ ├── gitlab_dsl.dart │ │ │ ├── gitlab_dsl.g.dart │ │ │ ├── settings_github.dart │ │ │ ├── settings_github.g.dart │ │ │ ├── violation.dart │ │ │ └── violation.g.dart │ │ │ └── utils │ │ │ ├── danger_isolate_receiver.dart │ │ │ ├── danger_isolate_sender.dart │ │ │ ├── danger_isolate_sender_impl.dart │ │ │ ├── danger_isolate_sender_mock.dart │ │ │ └── git_diff_parser.dart │ ├── pubspec.yaml │ └── test │ │ ├── danger_cross_isolate_test.dart │ │ ├── danger_isolate_receiver_test.dart │ │ ├── danger_isolate_sender_test.dart │ │ ├── fixtures │ │ ├── bbc-dsl-input.json │ │ ├── diff │ │ │ ├── add_only.diff │ │ │ ├── mix.diff │ │ │ ├── multiple_chunk.diff │ │ │ ├── multiple_files.diff │ │ │ ├── remove_only.diff │ │ │ └── rename_only.diff │ │ ├── github-dsl.json │ │ ├── github-with-some-nulls-attribute.json │ │ └── gitlab-dsl-input.json │ │ └── parser │ │ ├── bitbucket_cloud_dsl_test.dart │ │ ├── git_diff_test.dart │ │ ├── gitlab_dsl_test.dart │ │ └── gtihub_dsl_test.dart ├── danger_dart │ ├── .gitignore │ ├── .vscode │ │ └── settings.json │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── bin │ │ └── danger_dart.dart │ ├── lib │ │ ├── commands │ │ │ ├── base │ │ │ │ └── danger_wrapper_command.dart │ │ │ ├── ci_command.dart │ │ │ ├── local_command.dart │ │ │ ├── pr_command.dart │ │ │ └── process_command.dart │ │ ├── danger_dart.dart │ │ └── danger_util.dart │ ├── pubspec.yaml │ └── test │ │ ├── base │ │ └── test_command_runner.dart │ │ ├── commands │ │ ├── ci_command_test.dart │ │ ├── local_command_test.dart │ │ ├── pr_command_test.dart │ │ └── process_command_test.dart │ │ ├── danger_dart_test.dart │ │ ├── danger_util_test.dart │ │ ├── fixtures │ │ ├── bbc-dsl-input.json │ │ ├── mock_dangerjs.sh │ │ └── mock_dangeruby.sh │ │ ├── mock_util.dart │ │ └── mock_util.mocks.dart ├── danger_plugin_dart_test │ ├── .vscode │ │ └── settings.json │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── lib │ │ ├── danger_plugin_dart_test.dart │ │ └── src │ │ │ ├── danger_dart_test_reporter.dart │ │ │ ├── danger_plugin_dart_test.dart │ │ │ ├── models │ │ │ ├── danger_dart_error_case.dart │ │ │ └── dart_test_result.dart │ │ │ └── reporters │ │ │ ├── bitbucket_cloud_inline_test_reporter.dart │ │ │ ├── bitbucket_cloud_test_reporter.dart │ │ │ ├── default_inline_test_reporter.dart │ │ │ └── default_test_reporter.dart │ ├── pubspec.yaml │ └── test │ │ ├── danger_plugin_dart_test_test.dart │ │ └── fixtures │ │ ├── error_golden_test.json │ │ ├── error_results.json │ │ ├── fail_results.json │ │ └── success_results.json └── danger_plugin_golden_reporter │ ├── .gitignore │ ├── .vscode │ └── settings.json │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ ├── danger_plugin_golden_reporter.dart │ └── src │ │ ├── danger_plugin_golden_reporter.dart │ │ ├── golden_reporter.dart │ │ └── impl │ │ └── github_golden_reporter.dart │ ├── pubspec.yaml │ └── test │ ├── danger_plugin_golden_reporter_test.dart │ ├── mock_utils.dart │ ├── mock_utils.mocks.dart │ └── src │ └── impl │ └── github_golden_reporter_test.dart ├── pubspec.yaml └── tools ├── diff_parser.dart ├── pre_publish.dart └── test_all.sh /.github/workflows/pr_flow.yaml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: Danger on PR 7 | 8 | on: pull_request 9 | 10 | jobs: 11 | build: 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - uses: actions/setup-node@v1 18 | 19 | - uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603 20 | 21 | - name: Install Danger-js 22 | run: npm install -g danger 23 | 24 | - name: Activate command 25 | run: dart pub global activate --source path packages/danger_dart/ 26 | 27 | - name: Install danger_core dependencies 28 | run: dart pub get 29 | working-directory: packages/danger_core/ 30 | 31 | - name: Test danger_core 32 | run: dart test --reporter json > ../../danger_core_report.json 33 | continue-on-error: true 34 | working-directory: packages/danger_core/ 35 | 36 | - name: Install danger_dart dependencies 37 | run: dart pub get 38 | working-directory: packages/danger_dart/ 39 | 40 | - name: Test danger_dart 41 | run: dart test --reporter json > ../../danger_dart_report.json 42 | continue-on-error: true 43 | working-directory: packages/danger_dart/ 44 | 45 | - name: Install danger_plugin_dart_test dependencies 46 | run: dart pub get 47 | working-directory: packages/danger_plugin_dart_test/ 48 | 49 | - name: Test danger_plugin_dart_test 50 | run: dart test --reporter json > ../../danger_plugin_dart_test_report.json 51 | continue-on-error: true 52 | working-directory: packages/danger_plugin_dart_test/ 53 | 54 | - name: Install danger_plugin_golden_reporter dependencies 55 | run: dart pub get 56 | working-directory: packages/danger_plugin_golden_reporter/ 57 | 58 | - name: Test danger_plugin_golden_reporter 59 | run: dart test --reporter json > ../../danger_plugin_golden_reporter.json 60 | continue-on-error: true 61 | working-directory: packages/danger_plugin_golden_reporter/ 62 | 63 | - name: Install app dependencies 64 | run: dart pub get 65 | 66 | - name: Run danger ci 67 | run: danger_dart ci --failOnErrors 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | -------------------------------------------------------------------------------- /.github/workflows/verify_compatibility.yaml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: Danger compatibility 7 | 8 | on: pull_request 9 | 10 | jobs: 11 | build: 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | ref: ${{ github.event.pull_request.head.sha }} 19 | 20 | - name: Fetch master 21 | run: git fetch origin master:master 22 | 23 | - uses: actions/setup-node@v1 24 | 25 | - uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603 26 | 27 | - name: Install Danger-js 28 | run: npm install -g danger 29 | 30 | - name: Activate command 31 | run: dart pub global activate --source path packages/danger_dart/ 32 | 33 | - name: Install danger_core dependencies 34 | run: dart pub get 35 | working-directory: packages/danger_core/ 36 | 37 | - name: Install danger_dart dependencies 38 | run: dart pub get 39 | working-directory: packages/danger_dart/ 40 | 41 | - name: Install plugin dependencies 42 | run: dart pub get 43 | working-directory: example/with_plugin/danger_plugin_example/ 44 | 45 | - name: Install plugin example dependencies 46 | run: dart pub get 47 | working-directory: example/with_plugin/ 48 | 49 | - name: Run danger local (with plugin) 50 | run: danger_dart local 51 | working-directory: example/with_plugin/ 52 | 53 | - name: Install app dependencies (Dart 2) 54 | run: dart pub get 55 | working-directory: example/dart2/ 56 | 57 | - name: Run danger local (Dart 2) 58 | run: danger_dart local 59 | working-directory: example/dart2/ 60 | 61 | - name: Install app dependencies (Dart 3) 62 | run: dart pub get 63 | working-directory: example/dart3/ 64 | 65 | - name: Run danger local (Dart 3) 66 | run: danger_dart local 67 | working-directory: example/dart3/ 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | .DS_Store 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | # If you're building an application, you may want to check-in your pubspec.lock 8 | pubspec.lock 9 | 10 | # Directory created by dartdoc 11 | # If you don't generate documentation locally you can remove this line. 12 | doc/api/ 13 | 14 | # Avoid committing generated Javascript files: 15 | *.dart.js 16 | *.info.json # Produced by the --dump-info flag. 17 | *.js # When generated by dart2js. Don't specify *.js if your 18 | # project includes source files written in JavaScript. 19 | *.js_ 20 | *.js.deps 21 | *.js.map 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Dart", 9 | "type": "dart", 10 | "request": "launch", 11 | "program": "bin/main.dart" 12 | }, 13 | { 14 | "name": "Dart: Attach to Process", 15 | "type": "dart", 16 | "request": "attach" 17 | }, 18 | { 19 | "name": "Danger Attach", 20 | "type": "dart", 21 | "request": "attach", 22 | "program": "tool/dangerfile.dart" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /.vscode/model.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "model": { 3 | "scope": "dart", 4 | "prefix": "model", 5 | "body": [ 6 | "@JsonSerializable()", 7 | "class $1 {", 8 | " final String id;", 9 | "", 10 | " factory $1.fromJson(Map json) => _$$1FromJson(json);", 11 | " Map toJson() => _$$1ToJson(this);", 12 | "}" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "presentation": { 6 | "echo": true, 7 | "focus": false, 8 | "panel": "shared", 9 | "showReuseMessage": false, 10 | "clear": true 11 | }, 12 | "tasks": [ 13 | { 14 | "label": "Generate Code", 15 | "type": "shell", 16 | "options": { 17 | "cwd": "packages/danger_core" 18 | }, 19 | "command": "pub run build_runner build --delete-conflicting-outputs", 20 | "problemMatcher": [] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2019 Danger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Danger.dart 2 | 3 | Supports GitHub, GitLab, and Bitbucket Cloud. 4 | 5 | ### Getting Started 6 | 7 | https://medium.com/p/8c61e402cd4e 8 | 9 | ### Using Danger Dart 10 | 11 | - Install Danger JS 12 | 13 | ```bash 14 | $ npm install -g danger 15 | ``` 16 | 17 | - Activate Danger Dart 18 | 19 | ```bash 20 | $ pub global activate danger_dart 21 | ``` 22 | 23 | - Adding `danger_core` to `dev_dependencies` 24 | 25 | ```yaml 26 | dev_dependencies: 27 | danger_core: 28 | ``` 29 | 30 | - Create `dangerfile.dart` 31 | 32 | ```dart 33 | import 'package:danger_core/danger_core.dart'; 34 | 35 | void main() { 36 | if (danger.github.pr.title.contains('WIP')) { 37 | warn('PR is considered WIP'); 38 | } 39 | } 40 | ``` 41 | 42 | ### Preparing Environment Variables 43 | 44 | For GitHub, you need `DANGER_GITHUB_API_TOKEN` in your environment variable, can be created [here](https://github.com/settings/tokens/new). 45 | 46 | For Bitbucket Cloud, please refer to https://danger.systems/js/usage/bitbucket_cloud.html 47 | 48 | For GitLab, please refer to https://danger.systems/js/usage/gitlab.html 49 | 50 | 51 | ### Commands 52 | 53 | - `danger_dart ci` - Use this on CI 54 | - `danger_dart pr https://github.com/Moya/Harvey/pull/23` - Use this to build your Dangerfile 55 | - `danger_dart local` - Use this to run danger against your local changes from master 56 | 57 | ### Notes 58 | 59 | For GithubAction, you need to set GITHUB_TOKEN as environment [example](https://github.com/danger/dart/blob/master/.github/workflows/pr_flow.yaml) 60 | 61 | ```yaml 62 | - name: Run danger ci 63 | run: danger_dart ci 64 | env: 65 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | ``` 67 | 68 | ### Debugging `dangerfile.dart` 69 | 70 | Check the [Debugging doc](https://github.com/danger/dart/blob/master/docs/DEBUGGING.MD). 71 | 72 | ### Development 73 | 74 | We can use `pub global activate` to enable command `danger_dart`. 75 | 76 | ```bash 77 | $ pub global activate --source path packages/danger_dart/ 78 | ``` 79 | 80 | Or using `dart` to run directly. 81 | 82 | ```bash 83 | $ dart packages/danger_dart/bin/danger_dart.dart ci 84 | $ dart packages/danger_dart/bin/danger_dart.dart pr https://github.com/Moya/Harvey/pull/23 85 | $ dart packages/danger_dart/bin/danger_dart.dart local 86 | ``` 87 | 88 | ### Plugins 89 | 90 | You can create your own plugin using command 91 | 92 | ```bash 93 | $ dart create -t package-simple 94 | ``` 95 | 96 | In `pubspec.yaml` put `danger_core` in `dependences` 97 | 98 | ```yaml 99 | dependencies: 100 | danger_core: 101 | ``` 102 | 103 | For more information, see the example https://github.com/danger/dart/tree/master/packages/danger_plugin_dart_test 104 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | include: package:lints/recommended.yaml 4 | 5 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 6 | # Uncomment to specify additional rules. 7 | # linter: 8 | # rules: 9 | # - camel_case_types 10 | 11 | analyzer: 12 | # exclude: 13 | # - path/to/excluded/files/** 14 | -------------------------------------------------------------------------------- /dangerfile.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' show join, current; 4 | import 'package:danger_core/danger_core.dart'; 5 | import 'package:danger_plugin_dart_test/danger_plugin_dart_test.dart'; 6 | 7 | void main() async { 8 | await DangerUtils.gitFetchBranch(); 9 | final fullDiff = await DangerUtils.getFullDiff( 10 | targetBranch: 'origin/${DangerUtils.getTargetBranch()}'); 11 | 12 | message('There are ${fullDiff.length} changed files'); 13 | 14 | if (danger.isGitHub) { 15 | if (danger.github.pr.title.contains('WIP') == true) { 16 | warn('PR is considered WIP'); 17 | } 18 | 19 | DangerPluginDartTest.processFile( 20 | File(join(current, 'danger_core_report.json'))); 21 | DangerPluginDartTest.processFile( 22 | File(join(current, 'danger_dart_report.json'))); 23 | DangerPluginDartTest.processFile( 24 | File(join(current, 'danger_plugin_dart_test_report.json'))); 25 | DangerPluginDartTest.processFile( 26 | File(join(current, 'danger_plugin_golden_reporter.json'))); 27 | } else { 28 | message('Welcome to danger local'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/DEBUGGING.MD: -------------------------------------------------------------------------------- 1 | # Debugging dangerfile.dart 2 | 3 | 1. You need to add `--debug` to any command you wanted to run. 4 | 2. Waiting for the text `Observatory listening on http://127.0.0.1:8181/xxxxxxx=/` 5 | 3. **Don't forget** to put breakpoints in your `dangerfile.dart` 6 | 7 | ## On your editor 8 | 9 | ### VSCode 10 | 11 | 1. Open `.vscode/launch.json` or create one if you don't have it. 12 | 13 | 2. Add following configuration 14 | 15 | ```json 16 | { 17 | "name": "Danger Attach", 18 | "type": "dart", 19 | "request": "attach", 20 | "program": "tool/dangerfile.dart" 21 | } 22 | ``` 23 | 24 | **Note:** It doesn't have to point to your `dangerfile.dart` , any dart file inside folder `bin` or `tool` in your workspace should be fine. [More detail](https://github.com/Dart-Code/Dart-Code/blob/9e400c826bc73f7ccd64e54e365af97859e98e2f/src/extension/providers/debug_config_provider.ts#L150) 25 | 26 | 3. Press `Run` on `Danger Attach` in `Run and Debug` tab 27 | 28 | 4. VSCode will ask for `VM Service URI` 29 | 30 | ![Image of VSCode Step 1](/docs/images/vscode_1.png) 31 | 32 | 5. It will start at `yourdangerfile.dart.g.dart`, you can skip it 33 | 34 | ### Intellij or Android Studio 35 | 36 | 1. Go to `Run` > `Edit Configurations...` 37 | 38 | ![Image of Intellij Step 1](/docs/images/intellij_1.png) 39 | 40 | 2. Press `+` button and select `Dart Remote Debug` 41 | 42 | ![Image of Intellij Step 2](/docs/images/intellij_2.png) 43 | 44 | 3. Put 'Debug Danger' into name field, and press `OK` 45 | 46 | ![Image of Intellij Step 3](/docs/images/intellij_3.png) 47 | 48 | 4. On the main window, select `Debug Danger` and press `Debug` 49 | 50 | ![Image of Intellij Step 4](/docs/images/intellij_4.png) 51 | 52 | 5. It will ask for `VM Service URI` 53 | 54 | ![Image of Intellij Step 5](/docs/images/intellij_5.png) 55 | 56 | 6. It will start at `yourdangerfile.dart.g.dart`, you can skip it 57 | -------------------------------------------------------------------------------- /docs/images/intellij_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danger/dart/da1c4eaf18b20f9e494c71f32ffb37290d87702a/docs/images/intellij_1.png -------------------------------------------------------------------------------- /docs/images/intellij_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danger/dart/da1c4eaf18b20f9e494c71f32ffb37290d87702a/docs/images/intellij_2.png -------------------------------------------------------------------------------- /docs/images/intellij_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danger/dart/da1c4eaf18b20f9e494c71f32ffb37290d87702a/docs/images/intellij_3.png -------------------------------------------------------------------------------- /docs/images/intellij_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danger/dart/da1c4eaf18b20f9e494c71f32ffb37290d87702a/docs/images/intellij_4.png -------------------------------------------------------------------------------- /docs/images/intellij_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danger/dart/da1c4eaf18b20f9e494c71f32ffb37290d87702a/docs/images/intellij_5.png -------------------------------------------------------------------------------- /docs/images/vscode_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danger/dart/da1c4eaf18b20f9e494c71f32ffb37290d87702a/docs/images/vscode_1.png -------------------------------------------------------------------------------- /docs/usage/bitbucket_cloud.html.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Danger + BitBucket Cloud 3 | subtitle: Dangerous bits 4 | layout: guide_dart 5 | order: 4 6 | blurb: An overview of using Danger with BitBucket Cloud, and some examples 7 | --- 8 | 9 | To use Danger Dart with BitBucket Cloud: you'll need to create a new account for Danger to use, then set the following 10 | environment variables on your CI: 11 | 12 | You could use either username with password or OAuth key with OAuth secret. 13 | 14 | For username and password, you need to set. 15 | 16 | - `DANGER_BITBUCKETCLOUD_USERNAME` = The username for the account used to comment, as shown on 17 | https://bitbucket.org/account/ 18 | - `DANGER_BITBUCKETCLOUD_PASSWORD` = The password for the account used to comment, you could use 19 | [App passwords](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html#Apppasswords-Aboutapppasswords) 20 | with Read Pull Requests and Read Account Permissions. 21 | 22 | For OAuth key and OAuth secret, you can get them from. 23 | 24 | - Open [BitBucket Cloud Website](https://bitbucket.org) 25 | - Navigate to Settings > OAuth > Add consumer 26 | - Put `https://bitbucket.org/site/oauth2/authorize` for `Callback URL`, and enable Read Pull requests, and Read Account 27 | Permission. 28 | 29 | - `DANGER_BITBUCKETCLOUD_OAUTH_KEY` = The consumer key for the account used to comment, as show as `Key` on the website. 30 | - `DANGER_BITBUCKETCLOUD_OAUTH_SECRET` = The consumer secret for the account used to comment, as show as `Secret` on the 31 | website. 32 | 33 | You need to put `danger_core` into `dev_dependencies` inside `pubspec.yaml` 34 | 35 | ```yaml 36 | dev_dependencies: 37 | danger_core: 38 | ``` 39 | 40 | Then in your Dangerfiles you will have a fully fleshed out `danger.bitbucket_cloud` object to work with. For example: 41 | 42 | ```dart 43 | import 'package:danger_core/danger_core.dart'; 44 | 45 | void main() { 46 | if (danger.bitbucketCloud.pr.title.contains('WIP')) { 47 | warn('PR is considered WIP'); 48 | } 49 | } 50 | ``` 51 | 52 | The DSL is expansive, you can see all the details inside the [Danger Dart Reference][ref], but the TLDR is: 53 | 54 | ```dart 55 | danger.bitbucketCloud. 56 | 57 | /// The pull request and repository metadata 58 | final RepoMetaData metadata; 59 | 60 | /// The PR metadata 61 | final BitBucketCloudPRDSL pr; 62 | 63 | /// The commits associated with the pull request 64 | final List commits; 65 | 66 | /// The comments on the pull request 67 | final List comments; 68 | 69 | /// The activities such as OPENING, CLOSING, MERGING or UPDATING a pull request 70 | final List activities; 71 | ``` 72 | -------------------------------------------------------------------------------- /example/dart2/dangerfile.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | 3 | void main() { 4 | message('hello from nullsafety'); 5 | } 6 | -------------------------------------------------------------------------------- /example/dart2/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart2 2 | description: A simple command-line application. 3 | # version: 1.0.0 4 | # homepage: https://www.example.com 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dev_dependencies: 10 | lints: ^1.0.1 11 | path: ^1.8.0 12 | danger_core: 13 | path: ../../packages/danger_core 14 | -------------------------------------------------------------------------------- /example/dart3/dangerfile.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | 3 | void main() { 4 | message('hello from Dart 3'); 5 | } 6 | -------------------------------------------------------------------------------- /example/dart3/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_test_target_null_safety 2 | description: A simple command-line application. 3 | # version: 1.0.0 4 | # homepage: https://www.example.com 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dev_dependencies: 10 | lints: ^1.0.1 11 | path: ^1.8.3 12 | danger_core: 13 | path: ../../packages/danger_core 14 | -------------------------------------------------------------------------------- /example/with_plugin/danger_plugin_example/lib/danger_plugin_example.dart: -------------------------------------------------------------------------------- 1 | /// Support for doing something awesome. 2 | /// 3 | /// More dartdocs go here. 4 | library danger_plugin_example; 5 | 6 | export 'src/random_generate_code.dart'; 7 | -------------------------------------------------------------------------------- /example/with_plugin/danger_plugin_example/lib/src/random_generate_code.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:uuid/uuid.dart'; 3 | 4 | void dangerRandomGenerateCode() { 5 | final uuid = Uuid(); 6 | message('Hello From Plugin [${uuid.v4()}]'); 7 | } 8 | -------------------------------------------------------------------------------- /example/with_plugin/danger_plugin_example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_plugin_example 2 | description: A simple command-line application. 3 | # version: 1.0.0 4 | # homepage: https://www.example.com 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dependencies: 10 | uuid: ^3.0.1 11 | 12 | dev_dependencies: 13 | lints: ^1.0.1 14 | path: ^1.8.0 15 | danger_core: 16 | path: ../../../packages/danger_core 17 | -------------------------------------------------------------------------------- /example/with_plugin/dangerfile.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_plugin_example/danger_plugin_example.dart'; 3 | 4 | void main() { 5 | dangerRandomGenerateCode(); 6 | 7 | message('Hello World'); 8 | } 9 | -------------------------------------------------------------------------------- /example/with_plugin/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_test_with_plugin 2 | description: A simple command-line application. 3 | # version: 1.0.0 4 | # homepage: https://www.example.com 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dev_dependencies: 10 | lints: ^1.0.1 11 | path: ^1.8.0 12 | danger_core: 13 | path: ../../packages/danger_core 14 | danger_plugin_example: 15 | path: ./danger_plugin_example 16 | -------------------------------------------------------------------------------- /packages/danger_core/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | # Omit commiting pubspec.lock for library packages: 6 | # https://dart.dev/guides/libraries/private-files#pubspeclock 7 | pubspec.lock 8 | 9 | # Conventional directory for build outputs 10 | build/ 11 | 12 | # Directory created by dartdoc 13 | doc/api/ 14 | -------------------------------------------------------------------------------- /packages/danger_core/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /packages/danger_core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | - Provides API to get GitDiff (DangerUtils.getFullDiff) 4 | - Migrate to Dart 3 5 | 6 | ## 1.0.1 7 | 8 | - Fixed GitLabDSL 9 | 10 | ## 1.0.0 11 | 12 | - Supports Null Safety 13 | - Supports GitLab 14 | 15 | ## 0.0.6 16 | - Make cliArgs dynamic 17 | 18 | ## 0.0.5 19 | 20 | - Expose settings on DangerJSONDSL 21 | 22 | ## 0.0.4 23 | 24 | - Expose settings on DangerJSONDSL 25 | 26 | ## 0.0.3 27 | 28 | - Add DangetSettingsGithub to expose Github Access Token 29 | 30 | ## 0.0.2 31 | 32 | - Fix Unhandled Github PR Review State 33 | 34 | ## 0.0.1 35 | 36 | - Initial version, created by Stagehand 37 | -------------------------------------------------------------------------------- /packages/danger_core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2019 Danger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/danger_core/README.md: -------------------------------------------------------------------------------- 1 | # Danger Core 2 | 3 | [![Pub version](https://img.shields.io/pub/v/danger_core.svg)](https://pub.dev/packages/danger_core) 4 | 5 | This is Core of Danger Dart 6 | 7 | ### Installation 8 | 9 | Adding `danger_core` to `dev_dependencies` in `pubspec.yaml` 10 | 11 | ```yaml 12 | dev_dependencies: 13 | danger_core: 14 | ``` 15 | 16 | For more information, please refer to https://github.com/danger/dart 17 | 18 | ### Publishing Note 19 | 20 | Before publishing, need to replace. 21 | 22 | ```dart 23 | import 'package:json_annotation/json_annotation.dart' 24 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 25 | ``` 26 | 27 | with 28 | 29 | ```dart 30 | import 'package:danger_core/src/mock_json_annotation.dart'; 31 | ``` 32 | -------------------------------------------------------------------------------- /packages/danger_core/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | include: package:lints/recommended.yaml 4 | 5 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 6 | # Uncomment to specify additional rules. 7 | # linter: 8 | # rules: 9 | # - camel_case_types 10 | 11 | analyzer: 12 | # exclude: 13 | # - path/to/excluded/files/** 14 | -------------------------------------------------------------------------------- /packages/danger_core/build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | json_serializable: 5 | options: 6 | explicit_to_json: true 7 | -------------------------------------------------------------------------------- /packages/danger_core/lib/danger_core.dart: -------------------------------------------------------------------------------- 1 | /// Support for doing something awesome. 2 | /// 3 | /// More dartdocs go here. 4 | library danger_core; 5 | 6 | export 'src/danger_executor.dart'; 7 | export 'src/danger_utils.dart'; 8 | export 'src/models/danger_dsl.dart'; 9 | export 'src/models/bitbucket_cloud.dart'; 10 | export 'src/models/git_dsl.dart'; 11 | export 'src/models/github_dsl.dart'; 12 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/danger_executor.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_core/src/models/danger_dsl.dart'; 3 | import 'package:danger_core/src/models/violation.dart'; 4 | import 'package:danger_core/src/utils/danger_isolate_sender.dart'; 5 | import 'package:danger_core/src/utils/danger_isolate_sender_impl.dart'; 6 | import 'package:danger_core/src/utils/danger_isolate_sender_mock.dart'; 7 | 8 | class Danger { 9 | static void setup(dynamic data) { 10 | _sender = DangerIsolateSenderImpl(data); 11 | } 12 | 13 | static DangerIsolateSenderMock setupWithMock() { 14 | final sender = DangerIsolateSenderMock(); 15 | _sender = sender; 16 | return sender; 17 | } 18 | } 19 | 20 | late DangerIsolateSender _sender; 21 | DangerJSONDSL get danger => _sender.dangerJSONDSL; 22 | 23 | void message(String message, {String? file, int? line, String? icon}) { 24 | final violation = 25 | Violation(message: message, file: file, line: line, icon: icon); 26 | _sender.message(violation); 27 | } 28 | 29 | void warn(String message, {String? file, int? line, String? icon}) { 30 | final violation = 31 | Violation(message: message, file: file, line: line, icon: icon); 32 | _sender.warn(violation); 33 | } 34 | 35 | void fail(String message, {String? file, int? line, String? icon}) { 36 | final violation = 37 | Violation(message: message, file: file, line: line, icon: icon); 38 | _sender.fail(violation); 39 | } 40 | 41 | void markdown(String message, {String? file, int? line, String? icon}) { 42 | final violation = 43 | Violation(message: message, file: file, line: line, icon: icon); 44 | _sender.markdown(violation); 45 | } 46 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/danger_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_core/danger_core.dart'; 4 | import 'package:danger_core/src/models/git_diff.dart'; 5 | import 'package:danger_core/src/utils/git_diff_parser.dart'; 6 | 7 | class DangerUtils { 8 | DangerUtils._(); 9 | 10 | static Future spawn(String command, 11 | {List arguments = const []}) async { 12 | final result = await Process.run(command, arguments, runInShell: true); 13 | return result.stdout.toString().trim(); 14 | } 15 | 16 | static Future gitFetchBranch({String? targetBranch}) async { 17 | var base = targetBranch ?? ''; 18 | if (base.isEmpty) { 19 | base = getTargetBranch(); 20 | } 21 | 22 | await DangerUtils.spawn('git', arguments: ['fetch', 'origin', base]); 23 | } 24 | 25 | /// Get PR target branch based on git provider 26 | static String getTargetBranch() { 27 | var target = ''; 28 | 29 | if (danger.isGitHub) { 30 | target = danger.github.pr.base.ref; 31 | } else if (danger.isBitbucketCloud) { 32 | target = danger.bitbucketCloud.pr.destination.branch.name; 33 | } else if (danger.isGitLab) { 34 | target = danger.gitLab.mergeRequest.targetBranch; 35 | } else { 36 | target = danger.settings.cliArgs?['base'] ?? ''; 37 | } 38 | 39 | if (target.isEmpty) { 40 | throw 'Cannot find base branch'; 41 | } 42 | 43 | return target; 44 | } 45 | 46 | /// Get Git full diff. 47 | /// The default targetBranch will be selected based on current environment. 48 | /// 49 | /// This function needs Git history on the machine. 50 | static Future> getFullDiff( 51 | {String sourceBranch = "HEAD", String? targetBranch}) async { 52 | var base = targetBranch ?? ''; 53 | if (base.isEmpty) { 54 | base = getTargetBranch(); 55 | } 56 | 57 | final data = await DangerUtils.spawn('git', arguments: ['diff', base]); 58 | return GitDiffParser.parse(data); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/mock_json_annotation.dart: -------------------------------------------------------------------------------- 1 | enum FieldRename { none, kebab, snake, pascal } 2 | 3 | class JsonSerializable { 4 | final bool? anyMap; 5 | final bool? checked; 6 | final bool? createFactory; 7 | final bool? createToJson; 8 | final bool? disallowUnrecognizedKeys; 9 | final bool? explicitToJson; 10 | final FieldRename? fieldRename; 11 | final bool? genericArgumentFactories; 12 | final bool? ignoreUnannotated; 13 | final bool? includeIfNull; 14 | final bool? nullable; 15 | 16 | const JsonSerializable({ 17 | this.anyMap, 18 | this.checked, 19 | this.createFactory, 20 | this.createToJson, 21 | this.disallowUnrecognizedKeys, 22 | this.explicitToJson, 23 | this.fieldRename, 24 | this.ignoreUnannotated, 25 | this.includeIfNull, 26 | this.nullable, 27 | this.genericArgumentFactories, 28 | }); 29 | } 30 | 31 | class JsonKey { 32 | final Object? defaultValue; 33 | final bool? disallowNullValue; 34 | final Function? fromJson; 35 | final bool? ignore; 36 | final bool? includeIfNull; 37 | final String? name; 38 | final bool? nullable; 39 | final bool? required; 40 | final Function? toJson; 41 | final Object? unknownEnumValue; 42 | 43 | const JsonKey({ 44 | this.defaultValue, 45 | this.disallowNullValue, 46 | this.fromJson, 47 | this.ignore, 48 | this.includeIfNull, 49 | this.name, 50 | this.nullable, 51 | this.required, 52 | this.toJson, 53 | this.unknownEnumValue, 54 | }); 55 | static const Enum nullForUndefinedEnumValue = _NullAsDefault.value; 56 | } 57 | 58 | enum _NullAsDefault { value } 59 | 60 | class JsonValue { 61 | final dynamic value; 62 | const JsonValue(this.value); 63 | } 64 | 65 | /// Returns the key associated with value [source] from [enumValues], if one 66 | /// exists. 67 | /// 68 | /// If [unknownValue] is not `null` and [source] is not a value in [enumValues], 69 | /// [unknownValue] is returned. Otherwise, an [ArgumentError] is thrown. 70 | /// 71 | /// If [source] is `null`, `null` is returned. 72 | /// 73 | /// Exposed only for code generated by `package:json_serializable`. 74 | /// Not meant to be used directly by user code. 75 | K? $enumDecodeNullable( 76 | Map enumValues, 77 | Object? source, { 78 | Enum? unknownValue, 79 | }) { 80 | if (source == null) { 81 | return null; 82 | } 83 | 84 | for (var entry in enumValues.entries) { 85 | if (entry.value == source) { 86 | return entry.key; 87 | } 88 | } 89 | 90 | if (unknownValue == JsonKey.nullForUndefinedEnumValue) { 91 | return null; 92 | } 93 | 94 | if (unknownValue == null) { 95 | throw ArgumentError( 96 | '`$source` is not one of the supported values: ' 97 | '${enumValues.values.join(', ')}', 98 | ); 99 | } 100 | 101 | if (unknownValue is! K) { 102 | throw ArgumentError.value( 103 | unknownValue, 104 | 'unknownValue', 105 | 'Must by of type `$K` or `JsonKey.nullForUndefinedEnumValue`.', 106 | ); 107 | } 108 | 109 | return unknownValue; 110 | } 111 | 112 | /// Returns the key associated with value [source] from [enumValues], if one 113 | /// exists. 114 | /// 115 | /// If [unknownValue] is not `null` and [source] is not a value in [enumValues], 116 | /// [unknownValue] is returned. Otherwise, an [ArgumentError] is thrown. 117 | /// 118 | /// If [source] is `null`, an [ArgumentError] is thrown. 119 | /// 120 | /// Exposed only for code generated by `package:json_serializable`. 121 | /// Not meant to be used directly by user code. 122 | K $enumDecode( 123 | Map enumValues, 124 | Object? source, { 125 | K? unknownValue, 126 | }) { 127 | if (source == null) { 128 | throw ArgumentError( 129 | 'A value must be provided. Supported values: ' 130 | '${enumValues.values.join(', ')}', 131 | ); 132 | } 133 | 134 | for (var entry in enumValues.entries) { 135 | if (entry.value == source) { 136 | return entry.key; 137 | } 138 | } 139 | 140 | if (unknownValue == null) { 141 | throw ArgumentError( 142 | '`$source` is not one of the supported values: ' 143 | '${enumValues.values.join(', ')}', 144 | ); 145 | } 146 | 147 | return unknownValue; 148 | } 149 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/danger_core_constants.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names 2 | 3 | const DANGER_SEND_PORT_MESSAGE_KEY = 'port'; 4 | const DANGER_DSL_MESSAGE_KEY = 'dsl'; 5 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/danger_dsl.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/src/models/bitbucket_cloud.dart'; 2 | import 'package:danger_core/src/models/git_dsl.dart'; 3 | import 'package:danger_core/src/models/github_dsl.dart'; 4 | import 'package:danger_core/src/models/gitlab_dsl.dart'; 5 | import 'package:danger_core/src/models/settings_github.dart'; 6 | 7 | import 'package:json_annotation/json_annotation.dart' 8 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 9 | 10 | part 'danger_dsl.g.dart'; 11 | 12 | class DangerJSONDSL { 13 | /// The data only version of Git DSL 14 | GitJSONDSL get git => rawJSONDSL.git; 15 | 16 | /// The data only version of BitBucket Cloud DSL 17 | BitBucketCloudJSONDSL get bitbucketCloud => rawJSONDSL.bitbucketCloud!; 18 | 19 | /// The data only version of GitHub 20 | GitHubDSL get github => rawJSONDSL.github!; 21 | 22 | /// The data only version of GitLab 23 | GitLabDSL get gitLab => rawJSONDSL.gitlab!; 24 | 25 | DangerJSONSettings get settings => rawJSONDSL.settings!; 26 | 27 | final DangerRawJSONDSL rawJSONDSL; 28 | 29 | DangerJSONDSL(this.rawJSONDSL); 30 | 31 | bool get isGitHub => rawJSONDSL.github != null; 32 | bool get isBitbucketCloud => rawJSONDSL.bitbucketCloud != null; 33 | bool get isGitLab => rawJSONDSL.gitlab != null; 34 | } 35 | 36 | @JsonSerializable() 37 | class DangerJSON { 38 | final DangerRawJSONDSL danger; 39 | 40 | factory DangerJSON.fromJson(Map json) => 41 | _$DangerJSONFromJson(json); 42 | 43 | DangerJSON({required this.danger}); 44 | 45 | Map toJson() => _$DangerJSONToJson(this); 46 | } 47 | 48 | @JsonSerializable() 49 | class DangerRawJSONDSL { 50 | /// The data only version of Git DSL 51 | final GitJSONDSL git; 52 | 53 | /// The data only version of BitBucket Cloud DSL 54 | @JsonKey(name: 'bitbucket_cloud') 55 | final BitBucketCloudJSONDSL? bitbucketCloud; 56 | 57 | final GitHubDSL? github; 58 | 59 | final GitLabDSL? gitlab; 60 | 61 | final DangerJSONSettings? settings; 62 | 63 | factory DangerRawJSONDSL.fromJson(Map json) => 64 | _$DangerRawJSONDSLFromJson(json); 65 | 66 | DangerRawJSONDSL( 67 | {required this.git, 68 | this.bitbucketCloud, 69 | this.github, 70 | this.settings, 71 | this.gitlab}); 72 | Map toJson() => _$DangerRawJSONDSLToJson(this); 73 | } 74 | 75 | @JsonSerializable() 76 | class DangerJSONSettings { 77 | final Map? cliArgs; 78 | final DangetSettingsGithub? github; 79 | 80 | factory DangerJSONSettings.fromJson(Map json) => 81 | _$DangerJSONSettingsFromJson(json); 82 | 83 | DangerJSONSettings({this.cliArgs, this.github}); 84 | Map toJson() => _$DangerJSONSettingsToJson(this); 85 | } 86 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/danger_dsl.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'danger_dsl.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | DangerJSON _$DangerJSONFromJson(Map json) => DangerJSON( 10 | danger: DangerRawJSONDSL.fromJson(json['danger'] as Map), 11 | ); 12 | 13 | Map _$DangerJSONToJson(DangerJSON instance) => 14 | { 15 | 'danger': instance.danger.toJson(), 16 | }; 17 | 18 | DangerRawJSONDSL _$DangerRawJSONDSLFromJson(Map json) => 19 | DangerRawJSONDSL( 20 | git: GitJSONDSL.fromJson(json['git'] as Map), 21 | bitbucketCloud: json['bitbucket_cloud'] == null 22 | ? null 23 | : BitBucketCloudJSONDSL.fromJson( 24 | json['bitbucket_cloud'] as Map), 25 | github: json['github'] == null 26 | ? null 27 | : GitHubDSL.fromJson(json['github'] as Map), 28 | settings: json['settings'] == null 29 | ? null 30 | : DangerJSONSettings.fromJson( 31 | json['settings'] as Map), 32 | gitlab: json['gitlab'] == null 33 | ? null 34 | : GitLabDSL.fromJson(json['gitlab'] as Map), 35 | ); 36 | 37 | Map _$DangerRawJSONDSLToJson(DangerRawJSONDSL instance) => 38 | { 39 | 'git': instance.git.toJson(), 40 | 'bitbucket_cloud': instance.bitbucketCloud?.toJson(), 41 | 'github': instance.github?.toJson(), 42 | 'gitlab': instance.gitlab?.toJson(), 43 | 'settings': instance.settings?.toJson(), 44 | }; 45 | 46 | DangerJSONSettings _$DangerJSONSettingsFromJson(Map json) => 47 | DangerJSONSettings( 48 | cliArgs: json['cliArgs'] as Map?, 49 | github: json['github'] == null 50 | ? null 51 | : DangetSettingsGithub.fromJson( 52 | json['github'] as Map), 53 | ); 54 | 55 | Map _$DangerJSONSettingsToJson(DangerJSONSettings instance) => 56 | { 57 | 'cliArgs': instance.cliArgs, 58 | 'github': instance.github?.toJson(), 59 | }; 60 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/danger_results.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/src/models/violation.dart'; 2 | import 'package:json_annotation/json_annotation.dart' 3 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 4 | 5 | part 'danger_results.g.dart'; 6 | 7 | @JsonSerializable() 8 | class DangerResults { 9 | final List fails; 10 | 11 | final List warnings; 12 | 13 | final List messages; 14 | 15 | final List markdowns; 16 | 17 | final DangerResultMetaData meta; 18 | 19 | DangerResults( 20 | {required this.fails, 21 | required this.warnings, 22 | required this.messages, 23 | required this.markdowns, 24 | this.meta = const DangerResultMetaData()}); 25 | 26 | factory DangerResults.fromJson(Map json) => 27 | _$DangerResultsFromJson(json); 28 | Map toJson() => _$DangerResultsToJson(this); 29 | } 30 | 31 | @JsonSerializable() 32 | class DangerResultMetaData { 33 | final String runtimeName; 34 | final String runtimeHref; 35 | 36 | const DangerResultMetaData( 37 | {this.runtimeName = 'Danger Dart', 38 | this.runtimeHref = 'https://danger.systems/dart'}); 39 | 40 | factory DangerResultMetaData.fromJson(Map json) => 41 | _$DangerResultMetaDataFromJson(json); 42 | Map toJson() => _$DangerResultMetaDataToJson(this); 43 | } 44 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/danger_results.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'danger_results.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | DangerResults _$DangerResultsFromJson(Map json) => 10 | DangerResults( 11 | fails: (json['fails'] as List) 12 | .map((e) => Violation.fromJson(e as Map)) 13 | .toList(), 14 | warnings: (json['warnings'] as List) 15 | .map((e) => Violation.fromJson(e as Map)) 16 | .toList(), 17 | messages: (json['messages'] as List) 18 | .map((e) => Violation.fromJson(e as Map)) 19 | .toList(), 20 | markdowns: (json['markdowns'] as List) 21 | .map((e) => Violation.fromJson(e as Map)) 22 | .toList(), 23 | meta: json['meta'] == null 24 | ? const DangerResultMetaData() 25 | : DangerResultMetaData.fromJson(json['meta'] as Map), 26 | ); 27 | 28 | Map _$DangerResultsToJson(DangerResults instance) => 29 | { 30 | 'fails': instance.fails.map((e) => e.toJson()).toList(), 31 | 'warnings': instance.warnings.map((e) => e.toJson()).toList(), 32 | 'messages': instance.messages.map((e) => e.toJson()).toList(), 33 | 'markdowns': instance.markdowns.map((e) => e.toJson()).toList(), 34 | 'meta': instance.meta.toJson(), 35 | }; 36 | 37 | DangerResultMetaData _$DangerResultMetaDataFromJson( 38 | Map json) => 39 | DangerResultMetaData( 40 | runtimeName: json['runtimeName'] as String? ?? 'Danger Dart', 41 | runtimeHref: 42 | json['runtimeHref'] as String? ?? 'https://danger.systems/dart', 43 | ); 44 | 45 | Map _$DangerResultMetaDataToJson( 46 | DangerResultMetaData instance) => 47 | { 48 | 'runtimeName': instance.runtimeName, 49 | 'runtimeHref': instance.runtimeHref, 50 | }; 51 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/git_diff.dart: -------------------------------------------------------------------------------- 1 | class GitDiff { 2 | final String fromFile; 3 | final String toFile; 4 | final List diffBlocks; 5 | 6 | GitDiff( 7 | {required this.fromFile, required this.toFile, required this.diffBlocks}); 8 | } 9 | 10 | class DiffBlock { 11 | final int fromStart; 12 | final int fromEnd; 13 | final int toStart; 14 | final int toEnd; 15 | 16 | final List addedLines; 17 | final List removedLines; 18 | final List unchangedLines; 19 | 20 | DiffBlock( 21 | {required this.fromStart, 22 | required this.fromEnd, 23 | required this.toStart, 24 | required this.toEnd, 25 | required this.addedLines, 26 | required this.removedLines, 27 | required this.unchangedLines}); 28 | } 29 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/git_dsl.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart' 2 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 3 | 4 | part 'git_dsl.g.dart'; 5 | 6 | @JsonSerializable() 7 | class GitJSONDSL { 8 | /// Filepaths with changes relative to the git root 9 | @JsonKey(name: 'modified_files') 10 | final List modifiedFiles; 11 | 12 | ///Newly created filepaths relative to the git root 13 | @JsonKey(name: 'created_files') 14 | final List createdFiles; 15 | 16 | /// Removed filepaths relative to the git root 17 | @JsonKey(name: 'deleted_files') 18 | final List deletedFiles; 19 | 20 | /// The Git commit metadata 21 | final List commits; 22 | 23 | factory GitJSONDSL.fromJson(Map json) => 24 | _$GitJSONDSLFromJson(json); 25 | 26 | GitJSONDSL( 27 | {required this.modifiedFiles, 28 | required this.createdFiles, 29 | required this.deletedFiles, 30 | required this.commits}); 31 | 32 | Map toJson() => _$GitJSONDSLToJson(this); 33 | } 34 | 35 | @JsonSerializable() 36 | class GitCommit { 37 | /// The SHA for the commit 38 | final String? sha; 39 | 40 | /// Who wrote the commit 41 | final GitCommitAuthor author; 42 | 43 | /// Who deployed the commit 44 | final GitCommitAuthor committer; 45 | 46 | /// The commit message 47 | final String message; 48 | 49 | /// Potential parent commits, and other assorted metadata 50 | final dynamic tree; 51 | 52 | /// SHAs for the commit's parents 53 | final List? parents; 54 | 55 | /// Link to the commit 56 | final String? url; 57 | 58 | factory GitCommit.fromJson(Map json) => 59 | _$GitCommitFromJson(json); 60 | 61 | GitCommit( 62 | {this.sha, 63 | required this.author, 64 | required this.committer, 65 | required this.message, 66 | this.tree, 67 | this.parents, 68 | this.url}); 69 | Map toJson() => _$GitCommitToJson(this); 70 | } 71 | 72 | @JsonSerializable() 73 | class GitCommitAuthor { 74 | /// The display name for the author 75 | final String name; 76 | 77 | /// The authors email 78 | final String email; 79 | 80 | /// ISO6801 date string 81 | final String date; 82 | 83 | factory GitCommitAuthor.fromJson(Map json) => 84 | _$GitCommitAuthorFromJson(json); 85 | 86 | GitCommitAuthor( 87 | {required this.name, required this.email, required this.date}); 88 | Map toJson() => _$GitCommitAuthorToJson(this); 89 | } 90 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/git_dsl.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'git_dsl.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | GitJSONDSL _$GitJSONDSLFromJson(Map json) => GitJSONDSL( 10 | modifiedFiles: (json['modified_files'] as List) 11 | .map((e) => e as String) 12 | .toList(), 13 | createdFiles: (json['created_files'] as List) 14 | .map((e) => e as String) 15 | .toList(), 16 | deletedFiles: (json['deleted_files'] as List) 17 | .map((e) => e as String) 18 | .toList(), 19 | commits: (json['commits'] as List) 20 | .map((e) => GitCommit.fromJson(e as Map)) 21 | .toList(), 22 | ); 23 | 24 | Map _$GitJSONDSLToJson(GitJSONDSL instance) => 25 | { 26 | 'modified_files': instance.modifiedFiles, 27 | 'created_files': instance.createdFiles, 28 | 'deleted_files': instance.deletedFiles, 29 | 'commits': instance.commits.map((e) => e.toJson()).toList(), 30 | }; 31 | 32 | GitCommit _$GitCommitFromJson(Map json) => GitCommit( 33 | sha: json['sha'] as String?, 34 | author: GitCommitAuthor.fromJson(json['author'] as Map), 35 | committer: 36 | GitCommitAuthor.fromJson(json['committer'] as Map), 37 | message: json['message'] as String, 38 | tree: json['tree'], 39 | parents: 40 | (json['parents'] as List?)?.map((e) => e as String).toList(), 41 | url: json['url'] as String?, 42 | ); 43 | 44 | Map _$GitCommitToJson(GitCommit instance) => { 45 | 'sha': instance.sha, 46 | 'author': instance.author.toJson(), 47 | 'committer': instance.committer.toJson(), 48 | 'message': instance.message, 49 | 'tree': instance.tree, 50 | 'parents': instance.parents, 51 | 'url': instance.url, 52 | }; 53 | 54 | GitCommitAuthor _$GitCommitAuthorFromJson(Map json) => 55 | GitCommitAuthor( 56 | name: json['name'] as String, 57 | email: json['email'] as String, 58 | date: json['date'] as String, 59 | ); 60 | 61 | Map _$GitCommitAuthorToJson(GitCommitAuthor instance) => 62 | { 63 | 'name': instance.name, 64 | 'email': instance.email, 65 | 'date': instance.date, 66 | }; 67 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/gitlab_dsl.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart' 2 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 3 | 4 | part 'gitlab_dsl.g.dart'; 5 | 6 | @JsonSerializable() 7 | class GitLabDSL { 8 | @JsonKey(name: 'mr') 9 | final GitLabMergeRequest mergeRequest; 10 | 11 | final GitLabMetadata metadata; 12 | 13 | GitLabDSL({required this.mergeRequest, required this.metadata}); 14 | 15 | factory GitLabDSL.fromJson(Map json) => 16 | _$GitLabDSLFromJson(json); 17 | Map toJson() => _$GitLabDSLToJson(this); 18 | } 19 | 20 | @JsonSerializable() 21 | class GitLabDiffRefs { 22 | @JsonKey(name: 'base_sha') 23 | final String baseSha; 24 | 25 | @JsonKey(name: 'head_sha') 26 | final String headSha; 27 | 28 | @JsonKey(name: 'start_sha') 29 | final String startSha; 30 | 31 | GitLabDiffRefs( 32 | {required this.baseSha, required this.headSha, required this.startSha}); 33 | 34 | factory GitLabDiffRefs.fromJson(Map json) => 35 | _$GitLabDiffRefsFromJson(json); 36 | Map toJson() => _$GitLabDiffRefsToJson(this); 37 | } 38 | 39 | @JsonSerializable() 40 | class GitLabUserMergeData { 41 | @JsonKey(name: 'can_merge') 42 | final bool canMerge; 43 | 44 | GitLabUserMergeData({required this.canMerge}); 45 | 46 | factory GitLabUserMergeData.fromJson(Map json) => 47 | _$GitLabUserMergeDataFromJson(json); 48 | Map toJson() => _$GitLabUserMergeDataToJson(this); 49 | } 50 | 51 | @JsonSerializable() 52 | class GitLabMergeRequest { 53 | @JsonKey(name: 'allow_collaboration') 54 | final bool? allowCollaboration; 55 | 56 | @JsonKey(name: 'allow_maintainer_to_push') 57 | final bool? allowMaintainerToPush; 58 | 59 | @JsonKey(name: 'approvals_before_merge') 60 | final int? approvalsBeforeMerge; 61 | 62 | final GitLabUser? assignee; 63 | 64 | final GitLabUser author; 65 | 66 | @JsonKey(name: 'changes_count') 67 | final String changesCount; 68 | 69 | @JsonKey(name: 'closed_at') 70 | final DateTime? closedAt; 71 | 72 | @JsonKey(name: 'closed_by') 73 | final GitLabUser? closedBy; 74 | 75 | final String description; 76 | 77 | @JsonKey(name: 'diff_refs') 78 | final GitLabDiffRefs diffRefs; 79 | 80 | final int downvotes; 81 | 82 | @JsonKey(name: 'first_deployed_to_production_at') 83 | final DateTime? firstDeployedToProductionAt; 84 | 85 | @JsonKey(name: 'force_remove_source_branch') 86 | final bool? forceRemoveSourceBranch; 87 | 88 | final int id; 89 | 90 | final int iid; 91 | 92 | @JsonKey(name: 'latest_build_finished_at') 93 | final DateTime? latestBuildFinishedAt; 94 | 95 | @JsonKey(name: 'latest_build_started_at') 96 | final DateTime? latestBuildStartedAt; 97 | 98 | final List labels; 99 | 100 | @JsonKey(name: 'merge_commit_sha') 101 | final String? mergeCommitSha; 102 | 103 | @JsonKey(name: 'merged_at') 104 | final DateTime? mergedAt; 105 | 106 | @JsonKey(name: 'merged_by') 107 | final GitLabUser? mergedBy; 108 | 109 | @JsonKey(name: 'merge_when_pipeline_succeeds') 110 | final bool mergeOnPipelineSuccess; 111 | 112 | final GitLabMilestone? milestone; 113 | 114 | final GitLabPipeline? pipeline; 115 | 116 | @JsonKey(name: 'project_id') 117 | final int projectId; 118 | 119 | final String sha; 120 | 121 | @JsonKey(name: 'should_remove_source_branch') 122 | final bool? shouldRemoveSourceBranch; 123 | 124 | @JsonKey(name: 'source_branch') 125 | final String sourceBranch; 126 | 127 | @JsonKey(name: 'source_project_id') 128 | final int sourceProjectId; 129 | 130 | final GitLabMergeRequestState state; 131 | 132 | final bool subscribed; 133 | 134 | @JsonKey(name: 'target_branch') 135 | final String targetBranch; 136 | 137 | @JsonKey(name: 'target_project_id') 138 | final int targetProjectId; 139 | 140 | final GitLabMergeRequestTimeStats? timeStats; 141 | 142 | final String title; 143 | 144 | final int upvotes; 145 | 146 | @JsonKey(name: 'user') 147 | final GitLabUserMergeData userMergeData; 148 | 149 | @JsonKey(name: 'user_notes_count') 150 | final int userNotesCount; 151 | 152 | @JsonKey(name: 'web_url') 153 | final String webUrl; 154 | 155 | @JsonKey(name: 'work_in_progress') 156 | final bool workInProgress; 157 | 158 | GitLabMergeRequest( 159 | {this.allowCollaboration, 160 | this.allowMaintainerToPush, 161 | this.approvalsBeforeMerge, 162 | this.assignee, 163 | required this.author, 164 | required this.changesCount, 165 | this.closedAt, 166 | this.closedBy, 167 | required this.description, 168 | required this.diffRefs, 169 | required this.downvotes, 170 | this.firstDeployedToProductionAt, 171 | this.forceRemoveSourceBranch, 172 | required this.id, 173 | required this.iid, 174 | this.latestBuildFinishedAt, 175 | this.latestBuildStartedAt, 176 | required this.labels, 177 | this.mergeCommitSha, 178 | this.mergedAt, 179 | this.mergedBy, 180 | required this.mergeOnPipelineSuccess, 181 | this.milestone, 182 | this.pipeline, 183 | required this.projectId, 184 | required this.sha, 185 | this.shouldRemoveSourceBranch, 186 | required this.sourceBranch, 187 | required this.sourceProjectId, 188 | required this.state, 189 | required this.subscribed, 190 | required this.targetBranch, 191 | required this.targetProjectId, 192 | required this.timeStats, 193 | required this.title, 194 | required this.upvotes, 195 | required this.userMergeData, 196 | required this.userNotesCount, 197 | required this.webUrl, 198 | required this.workInProgress}); 199 | 200 | factory GitLabMergeRequest.fromJson(Map json) => 201 | _$GitLabMergeRequestFromJson(json); 202 | Map toJson() => _$GitLabMergeRequestToJson(this); 203 | } 204 | 205 | @JsonSerializable() 206 | class GitLabMergeRequestTimeStats { 207 | @JsonKey(name: 'human_time_estimate') 208 | final int? humanTimeEstimate; 209 | 210 | @JsonKey(name: 'human_time_spent') 211 | final int? humanTimeSpent; 212 | 213 | @JsonKey(name: 'time_estimate') 214 | final int timeEstimate; 215 | 216 | @JsonKey(name: 'total_time_spent') 217 | final int totalTimeSpent; 218 | 219 | GitLabMergeRequestTimeStats( 220 | {this.humanTimeEstimate, 221 | this.humanTimeSpent, 222 | required this.timeEstimate, 223 | required this.totalTimeSpent}); 224 | 225 | factory GitLabMergeRequestTimeStats.fromJson(Map json) => 226 | _$GitLabMergeRequestTimeStatsFromJson(json); 227 | Map toJson() => _$GitLabMergeRequestTimeStatsToJson(this); 228 | } 229 | 230 | @JsonSerializable() 231 | class GitLabMetadata { 232 | final String pullRequestID; 233 | final String repoSlug; 234 | 235 | GitLabMetadata({required this.pullRequestID, required this.repoSlug}); 236 | 237 | factory GitLabMetadata.fromJson(Map json) => 238 | _$GitLabMetadataFromJson(json); 239 | Map toJson() => _$GitLabMetadataToJson(this); 240 | } 241 | 242 | enum GitLabMergeRequestState { 243 | @JsonValue('closed') 244 | closed, 245 | 246 | @JsonValue('locked') 247 | locked, 248 | 249 | @JsonValue('merged') 250 | merged, 251 | 252 | @JsonValue('opened') 253 | opened 254 | } 255 | 256 | @JsonSerializable() 257 | class GitLabMilestone { 258 | @JsonKey(name: 'created_at') 259 | final DateTime createdAt; 260 | 261 | final String description; 262 | 263 | @JsonKey(name: 'due_date') 264 | final DateTime? dueDate; 265 | 266 | final int id; 267 | 268 | final int iid; 269 | 270 | @JsonKey(name: 'project_id') 271 | final int projectID; 272 | 273 | @JsonKey(name: 'start_date') 274 | final DateTime? startDate; 275 | 276 | final GitLabMilestoneState state; 277 | 278 | final String title; 279 | 280 | @JsonKey(name: 'updated_at') 281 | final DateTime updatedAt; 282 | 283 | @JsonKey(name: 'web_url') 284 | final String webUrl; 285 | 286 | GitLabMilestone( 287 | {required this.createdAt, 288 | required this.description, 289 | this.dueDate, 290 | required this.id, 291 | required this.iid, 292 | required this.projectID, 293 | this.startDate, 294 | required this.state, 295 | required this.title, 296 | required this.updatedAt, 297 | required this.webUrl}); 298 | 299 | factory GitLabMilestone.fromJson(Map json) => 300 | _$GitLabMilestoneFromJson(json); 301 | Map toJson() => _$GitLabMilestoneToJson(this); 302 | } 303 | 304 | enum GitLabMilestoneState { 305 | @JsonValue('active') 306 | active, 307 | 308 | @JsonValue('closed') 309 | closed 310 | } 311 | 312 | @JsonSerializable() 313 | class GitLabPipeline { 314 | final int id; 315 | 316 | final String ref; 317 | 318 | final String sha; 319 | 320 | final GitLabPipelineStatus status; 321 | 322 | @JsonKey(name: 'web_url') 323 | final String webUrl; 324 | 325 | GitLabPipeline( 326 | {required this.id, 327 | required this.ref, 328 | required this.sha, 329 | required this.status, 330 | required this.webUrl}); 331 | 332 | factory GitLabPipeline.fromJson(Map json) => 333 | _$GitLabPipelineFromJson(json); 334 | Map toJson() => _$GitLabPipelineToJson(this); 335 | } 336 | 337 | enum GitLabPipelineStatus { 338 | @JsonValue('cancelled') 339 | cancelled, 340 | 341 | @JsonValue('failed') 342 | failed, 343 | 344 | @JsonValue('pending') 345 | pending, 346 | 347 | @JsonValue('running') 348 | running, 349 | 350 | @JsonValue('skipped') 351 | skipped, 352 | 353 | @JsonValue('success') 354 | success 355 | } 356 | 357 | @JsonSerializable() 358 | class GitLabUser { 359 | @JsonKey(name: 'avatar_url') 360 | final String? avatarUrl; 361 | 362 | final int id; 363 | 364 | final String name; 365 | 366 | final GitLabUserState state; 367 | 368 | final String username; 369 | 370 | @JsonKey(name: 'web_url') 371 | final String webUrl; 372 | 373 | GitLabUser( 374 | {this.avatarUrl, 375 | required this.id, 376 | required this.name, 377 | required this.state, 378 | required this.username, 379 | required this.webUrl}); 380 | 381 | factory GitLabUser.fromJson(Map json) => 382 | _$GitLabUserFromJson(json); 383 | Map toJson() => _$GitLabUserToJson(this); 384 | } 385 | 386 | enum GitLabUserState { 387 | @JsonValue('active') 388 | active, 389 | 390 | @JsonValue('blocked') 391 | blocked, 392 | } 393 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/settings_github.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart' 2 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 3 | 4 | part 'settings_github.g.dart'; 5 | 6 | @JsonSerializable() 7 | class DangetSettingsGithub { 8 | final String accessToken; 9 | final Map? additionalHeaders; 10 | 11 | factory DangetSettingsGithub.fromJson(Map json) => 12 | _$DangetSettingsGithubFromJson(json); 13 | 14 | DangetSettingsGithub({this.additionalHeaders, required this.accessToken}); 15 | Map toJson() => _$DangetSettingsGithubToJson(this); 16 | } 17 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/settings_github.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'settings_github.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | DangetSettingsGithub _$DangetSettingsGithubFromJson( 10 | Map json) => 11 | DangetSettingsGithub( 12 | additionalHeaders: json['additionalHeaders'] as Map?, 13 | accessToken: json['accessToken'] as String, 14 | ); 15 | 16 | Map _$DangetSettingsGithubToJson( 17 | DangetSettingsGithub instance) => 18 | { 19 | 'accessToken': instance.accessToken, 20 | 'additionalHeaders': instance.additionalHeaders, 21 | }; 22 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/violation.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart' 2 | if (dart.library.isolate) 'package:danger_core/src/mock_json_annotation.dart'; 3 | 4 | part 'violation.g.dart'; 5 | 6 | enum ViolationType { 7 | @JsonValue('message') 8 | message, 9 | @JsonValue('warn') 10 | warn, 11 | 12 | @JsonValue('fail') 13 | fail, 14 | 15 | @JsonValue('markdown') 16 | markdown, 17 | } 18 | 19 | @JsonSerializable() 20 | class Violation { 21 | /// The string representation 22 | final String message; 23 | 24 | /// Optional path to the file 25 | @JsonKey(includeIfNull: false) 26 | final String? file; 27 | 28 | /// Optional line in the file 29 | @JsonKey(includeIfNull: false) 30 | final int? line; 31 | 32 | /// Optional icon for table (Only valid for messages) 33 | @JsonKey(includeIfNull: false) 34 | final String? icon; 35 | 36 | factory Violation.fromJson(Map json) => 37 | _$ViolationFromJson(json); 38 | 39 | Violation({required this.message, this.file, this.line, this.icon}); 40 | Map toJson() => _$ViolationToJson(this); 41 | } 42 | 43 | @JsonSerializable() 44 | class WrappedViolation { 45 | final ViolationType type; 46 | final Violation violation; 47 | 48 | WrappedViolation({required this.type,required this.violation}); 49 | 50 | factory WrappedViolation.fromJson(Map json) => 51 | _$WrappedViolationFromJson(json); 52 | Map toJson() => _$WrappedViolationToJson(this); 53 | } 54 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/models/violation.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'violation.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Violation _$ViolationFromJson(Map json) => Violation( 10 | message: json['message'] as String, 11 | file: json['file'] as String?, 12 | line: json['line'] as int?, 13 | icon: json['icon'] as String?, 14 | ); 15 | 16 | Map _$ViolationToJson(Violation instance) { 17 | final val = { 18 | 'message': instance.message, 19 | }; 20 | 21 | void writeNotNull(String key, dynamic value) { 22 | if (value != null) { 23 | val[key] = value; 24 | } 25 | } 26 | 27 | writeNotNull('file', instance.file); 28 | writeNotNull('line', instance.line); 29 | writeNotNull('icon', instance.icon); 30 | return val; 31 | } 32 | 33 | WrappedViolation _$WrappedViolationFromJson(Map json) => 34 | WrappedViolation( 35 | type: $enumDecode(_$ViolationTypeEnumMap, json['type']), 36 | violation: Violation.fromJson(json['violation'] as Map), 37 | ); 38 | 39 | Map _$WrappedViolationToJson(WrappedViolation instance) => 40 | { 41 | 'type': _$ViolationTypeEnumMap[instance.type], 42 | 'violation': instance.violation.toJson(), 43 | }; 44 | 45 | const _$ViolationTypeEnumMap = { 46 | ViolationType.message: 'message', 47 | ViolationType.warn: 'warn', 48 | ViolationType.fail: 'fail', 49 | ViolationType.markdown: 'markdown', 50 | }; 51 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/utils/danger_isolate_receiver.dart: -------------------------------------------------------------------------------- 1 | import 'dart:isolate'; 2 | 3 | import 'package:danger_core/src/models/danger_core_constants.dart'; 4 | import 'package:danger_core/src/models/danger_results.dart'; 5 | import 'package:danger_core/src/models/violation.dart'; 6 | 7 | class DangerIsolateReceiver { 8 | final ReceivePort receivePort; 9 | final dynamic json; 10 | final DangerResults dangerResults; 11 | 12 | DangerIsolateReceiver(this.json) 13 | : receivePort = ReceivePort(), 14 | dangerResults = DangerResults( 15 | warnings: [], messages: [], markdowns: [], fails: []) { 16 | _initialize(); 17 | } 18 | 19 | void _initialize() { 20 | receivePort.listen((message) { 21 | if (message is Map) { 22 | try { 23 | final wrappedViolation = WrappedViolation.fromJson(message); 24 | switch (wrappedViolation.type) { 25 | case ViolationType.message: 26 | dangerResults.messages.add(wrappedViolation.violation); 27 | break; 28 | case ViolationType.warn: 29 | dangerResults.warnings.add(wrappedViolation.violation); 30 | break; 31 | case ViolationType.fail: 32 | dangerResults.fails.add(wrappedViolation.violation); 33 | break; 34 | case ViolationType.markdown: 35 | dangerResults.markdowns.add(wrappedViolation.violation); 36 | break; 37 | } 38 | } catch (e) { 39 | //do nothing 40 | } 41 | } 42 | }); 43 | } 44 | 45 | dynamic toMessage() { 46 | return { 47 | DANGER_DSL_MESSAGE_KEY: json['danger'], 48 | DANGER_SEND_PORT_MESSAGE_KEY: receivePort.sendPort, 49 | }; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/utils/danger_isolate_sender.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/src/models/danger_dsl.dart'; 2 | import 'package:danger_core/src/models/violation.dart'; 3 | 4 | abstract class DangerIsolateSender { 5 | DangerJSONDSL get dangerJSONDSL; 6 | 7 | void message(Violation violation); 8 | void warn(Violation violation); 9 | void fail(Violation violation); 10 | void markdown(Violation violation); 11 | } 12 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/utils/danger_isolate_sender_impl.dart: -------------------------------------------------------------------------------- 1 | import 'dart:isolate'; 2 | 3 | import 'package:danger_core/danger_core.dart'; 4 | import 'package:danger_core/src/models/danger_core_constants.dart'; 5 | import 'package:danger_core/src/models/violation.dart'; 6 | import 'package:danger_core/src/utils/danger_isolate_sender.dart'; 7 | 8 | typedef DangerJSONDSLMessageConverter = DangerRawJSONDSL Function( 9 | dynamic message); 10 | 11 | DangerRawJSONDSL _defaultDangerJSONDSLMessageConverter(dynamic message) { 12 | return DangerRawJSONDSL.fromJson(message); 13 | } 14 | 15 | class DangerIsolateSenderImpl extends DangerIsolateSender { 16 | final SendPort sendPort; 17 | 18 | DangerIsolateSenderImpl(dynamic message, 19 | {DangerJSONDSLMessageConverter? converter}) 20 | : sendPort = message[DANGER_SEND_PORT_MESSAGE_KEY], 21 | dangerJSONDSL = DangerJSONDSL( 22 | (converter ?? _defaultDangerJSONDSLMessageConverter)( 23 | message[DANGER_DSL_MESSAGE_KEY])); 24 | 25 | @override 26 | final DangerJSONDSL dangerJSONDSL; 27 | 28 | @override 29 | void message(Violation violation) { 30 | final wrapped = 31 | WrappedViolation(type: ViolationType.message, violation: violation); 32 | sendPort.send(wrapped.toJson()); 33 | } 34 | 35 | @override 36 | void warn(Violation violation) { 37 | final wrapped = 38 | WrappedViolation(type: ViolationType.warn, violation: violation); 39 | sendPort.send(wrapped.toJson()); 40 | } 41 | 42 | @override 43 | void fail(Violation violation) { 44 | final wrapped = 45 | WrappedViolation(type: ViolationType.fail, violation: violation); 46 | sendPort.send(wrapped.toJson()); 47 | } 48 | 49 | @override 50 | void markdown(Violation violation) { 51 | final wrapped = 52 | WrappedViolation(type: ViolationType.markdown, violation: violation); 53 | sendPort.send(wrapped.toJson()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/utils/danger_isolate_sender_mock.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/src/models/violation.dart'; 2 | import 'package:danger_core/src/models/danger_dsl.dart'; 3 | import 'package:danger_core/src/utils/danger_isolate_sender.dart'; 4 | 5 | class DangerIsolateSenderMock extends DangerIsolateSender { 6 | @override 7 | late DangerJSONDSL dangerJSONDSL; 8 | 9 | final failList = []; 10 | final markdownList = []; 11 | final warningList = []; 12 | final messageList = []; 13 | 14 | @override 15 | void fail(Violation violation) { 16 | failList.add(violation); 17 | } 18 | 19 | @override 20 | void markdown(Violation violation) { 21 | markdownList.add(violation); 22 | } 23 | 24 | @override 25 | void message(Violation violation) { 26 | messageList.add(violation); 27 | } 28 | 29 | @override 30 | void warn(Violation violation) { 31 | warningList.add(violation); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/danger_core/lib/src/utils/git_diff_parser.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/src/models/git_diff.dart'; 2 | 3 | class GitDiffParser { 4 | GitDiffParser._(); 5 | 6 | static List parse(String diffData) { 7 | List diffs = []; 8 | List lines = diffData.split('\n'); 9 | GitDiff? currentDiff; 10 | DiffBlock? currentBlock; 11 | 12 | for (var line in lines) { 13 | if (line.startsWith('diff --git')) { 14 | final fromFile = line.split(' ')[2].substring(2); 15 | final toFile = line.split(' ')[3].substring(2); 16 | currentDiff = 17 | GitDiff(fromFile: fromFile, toFile: toFile, diffBlocks: []); 18 | diffs.add(currentDiff); 19 | continue; 20 | } 21 | 22 | if (line.startsWith('@@')) { 23 | String header = line.substring(3); 24 | List parts = header.split(' '); 25 | List fromRange = parts[0].split(','); 26 | List toRange = parts[1].split(','); 27 | 28 | final fromStart = int.parse(fromRange[0].substring(1)); 29 | final fromEnd = fromStart + 30 | (fromRange.length > 1 ? int.parse(fromRange[1]) : 1) - 31 | 1; 32 | final toStart = int.parse(toRange[0].substring(1)); 33 | final toEnd = 34 | toStart + (toRange.length > 1 ? int.parse(toRange[1]) : 1) - 1; 35 | 36 | currentBlock = DiffBlock( 37 | fromStart: fromStart, 38 | fromEnd: fromEnd, 39 | toStart: toStart, 40 | toEnd: toEnd, 41 | addedLines: [], 42 | removedLines: [], 43 | unchangedLines: []); 44 | currentDiff?.diffBlocks.add(currentBlock); 45 | } 46 | 47 | if (line.startsWith('+')) { 48 | currentBlock?.addedLines.add(line.substring(1)); 49 | } else if (line.startsWith('-')) { 50 | currentBlock?.removedLines.add(line.substring(1)); 51 | } else if (line.startsWith(' ')) { 52 | currentBlock?.unchangedLines.add(line.substring(1)); 53 | } 54 | } 55 | 56 | return diffs; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/danger_core/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_core 2 | description: Core of Danger Dart, tool to help you reviewing the code. 3 | version: 2.0.0 4 | homepage: https://github.com/danger/dart 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dev_dependencies: 10 | lints: ^2.1.1 11 | json_annotation: ^4.8.1 12 | test: ^1.24.7 13 | json_serializable: ^6.7.1 14 | build_runner: ^2.4.6 15 | mockito: ^5.4.2 16 | isolate: ^2.1.1 17 | path: ^1.8.3 18 | -------------------------------------------------------------------------------- /packages/danger_core/test/danger_cross_isolate_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:danger_core/danger_core.dart' as danger_dart; 4 | import 'package:danger_core/src/utils/danger_isolate_receiver.dart'; 5 | import 'package:isolate/isolate.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | void main() { 9 | group('Cross isolate', () { 10 | late DangerIsolateReceiver receiver; 11 | setUp(() { 12 | receiver = DangerIsolateReceiver({ 13 | 'danger': { 14 | 'git': { 15 | 'modified_files': ['README.md'], 16 | 'created_files': [], 17 | 'deleted_files': [], 18 | 'commits': [] 19 | } 20 | } 21 | }); 22 | }); 23 | 24 | test('should pass message correctly', () async { 25 | final runner = await IsolateRunner.spawn(); 26 | 27 | await runner.run(testMessage, receiver.toMessage()); 28 | await runner.close(); 29 | 30 | expect( 31 | receiver.dangerResults.messages.first.message, equals('README.md')); 32 | }); 33 | 34 | test('should pass warning correctly', () async { 35 | final runner = await IsolateRunner.spawn(); 36 | 37 | await runner.run(testWarn, receiver.toMessage()); 38 | await runner.close(); 39 | 40 | expect( 41 | receiver.dangerResults.warnings.first.message, equals('README.md')); 42 | }); 43 | 44 | test('should pass failure correctly', () async { 45 | final runner = await IsolateRunner.spawn(); 46 | 47 | await runner.run(testFail, receiver.toMessage()); 48 | await runner.close(); 49 | 50 | expect(receiver.dangerResults.fails.first.message, equals('README.md')); 51 | }); 52 | 53 | test('should pass markdown correctly', () async { 54 | final runner = await IsolateRunner.spawn(); 55 | 56 | await runner.run(testMarkdown, receiver.toMessage()); 57 | await runner.close(); 58 | 59 | expect( 60 | receiver.dangerResults.markdowns.first.message, equals('README.md')); 61 | }); 62 | 63 | test('mix result', () async { 64 | final runner = await IsolateRunner.spawn(); 65 | 66 | await runner.run(testMixResult, receiver.toMessage()); 67 | await runner.close(); 68 | 69 | final expected = 70 | r'{"fails":[{"message":"Hello World fail","file":"helloworld.dart"}],"warnings":[{"message":"Hello World warn","line":10}],"messages":[{"message":"Hello World message"}],"markdowns":[],"meta":{"runtimeName":"Danger Dart","runtimeHref":"https://danger.systems/dart"}}'; 71 | final json = jsonEncode(receiver.dangerResults); 72 | expect(json, equals(expected)); 73 | }); 74 | }); 75 | } 76 | 77 | void testMessage(dynamic data) { 78 | danger_dart.Danger.setup(data); 79 | danger_dart.message(danger_dart.danger.git.modifiedFiles.first); 80 | } 81 | 82 | void testWarn(dynamic data) { 83 | danger_dart.Danger.setup(data); 84 | danger_dart.warn(danger_dart.danger.git.modifiedFiles.first); 85 | } 86 | 87 | void testFail(dynamic data) { 88 | danger_dart.Danger.setup(data); 89 | danger_dart.fail(danger_dart.danger.git.modifiedFiles.first); 90 | } 91 | 92 | void testMarkdown(dynamic data) { 93 | danger_dart.Danger.setup(data); 94 | danger_dart.markdown(danger_dart.danger.git.modifiedFiles.first); 95 | } 96 | 97 | void testMixResult(dynamic data) { 98 | danger_dart.Danger.setup(data); 99 | danger_dart.message('Hello World message'); 100 | danger_dart.warn('Hello World warn', line: 10); 101 | danger_dart.fail('Hello World fail', file: 'helloworld.dart'); 102 | } 103 | -------------------------------------------------------------------------------- /packages/danger_core/test/danger_isolate_receiver_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/src/models/danger_core_constants.dart'; 2 | import 'package:danger_core/src/models/violation.dart'; 3 | import 'package:danger_core/src/utils/danger_isolate_receiver.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('DangerIsolateReceiver', () { 8 | late DangerIsolateReceiver receiver; 9 | final onlyMessageViolation = Violation(message: 'hello'); 10 | final json = {'danger': 'JSON'}; 11 | 12 | setUp(() { 13 | receiver = DangerIsolateReceiver(json); 14 | }); 15 | 16 | test('toMessage() should return correctly', () { 17 | final message = receiver.toMessage(); 18 | expect(message[DANGER_DSL_MESSAGE_KEY], equals('JSON')); 19 | expect(message[DANGER_SEND_PORT_MESSAGE_KEY], 20 | equals(receiver.receivePort.sendPort)); 21 | }); 22 | 23 | test('should add message to dangerResults', () async { 24 | final wrappedViolation = WrappedViolation( 25 | type: ViolationType.message, violation: onlyMessageViolation); 26 | 27 | receiver.receivePort.sendPort.send(wrappedViolation.toJson()); 28 | await Future.delayed(Duration.zero); 29 | 30 | expect(receiver.dangerResults.messages.length, equals(1)); 31 | expect(receiver.dangerResults.messages.first.toJson(), 32 | equals(onlyMessageViolation.toJson())); 33 | }); 34 | 35 | test('should add warn to dangerResults', () async { 36 | final wrappedViolation = WrappedViolation( 37 | type: ViolationType.warn, violation: onlyMessageViolation); 38 | 39 | receiver.receivePort.sendPort.send(wrappedViolation.toJson()); 40 | await Future.delayed(Duration.zero); 41 | 42 | expect(receiver.dangerResults.warnings.length, equals(1)); 43 | expect(receiver.dangerResults.warnings.first.toJson(), 44 | equals(onlyMessageViolation.toJson())); 45 | }); 46 | 47 | test('should add fail to dangerResults', () async { 48 | final wrappedViolation = WrappedViolation( 49 | type: ViolationType.fail, violation: onlyMessageViolation); 50 | 51 | receiver.receivePort.sendPort.send(wrappedViolation.toJson()); 52 | await Future.delayed(Duration.zero); 53 | 54 | expect(receiver.dangerResults.fails.length, equals(1)); 55 | expect(receiver.dangerResults.fails.first.toJson(), 56 | equals(onlyMessageViolation.toJson())); 57 | }); 58 | 59 | test('should add markdown to dangerResults', () async { 60 | final wrappedViolation = WrappedViolation( 61 | type: ViolationType.markdown, violation: onlyMessageViolation); 62 | 63 | receiver.receivePort.sendPort.send(wrappedViolation.toJson()); 64 | await Future.delayed(Duration.zero); 65 | 66 | expect(receiver.dangerResults.markdowns.length, equals(1)); 67 | expect(receiver.dangerResults.markdowns.first.toJson(), 68 | equals(onlyMessageViolation.toJson())); 69 | }); 70 | }); 71 | } 72 | -------------------------------------------------------------------------------- /packages/danger_core/test/danger_isolate_sender_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:isolate'; 2 | 3 | import 'package:danger_core/danger_core.dart'; 4 | import 'package:danger_core/src/models/danger_core_constants.dart'; 5 | import 'package:danger_core/src/models/violation.dart'; 6 | import 'package:danger_core/src/utils/danger_isolate_sender_impl.dart'; 7 | import 'package:mockito/mockito.dart'; 8 | import 'package:test/test.dart'; 9 | 10 | class _MockGitJSONDSL extends Mock implements GitJSONDSL {} 11 | 12 | class _MockDangerRawJSONDSL extends Mock implements DangerRawJSONDSL { 13 | final _mockGit = _MockGitJSONDSL(); 14 | 15 | @override 16 | GitJSONDSL get git => _mockGit; 17 | } 18 | 19 | void main() { 20 | group('DangerIsolateSender', () { 21 | late DangerIsolateSenderImpl isolateSender; 22 | late ReceivePort receivePort; 23 | late _MockDangerRawJSONDSL mockDangerJSONDSL; 24 | 25 | dynamic lastMessage; 26 | final onlyMessageViolation = Violation(message: 'hello'); 27 | 28 | setUp(() { 29 | receivePort = ReceivePort(); 30 | mockDangerJSONDSL = _MockDangerRawJSONDSL(); 31 | 32 | isolateSender = DangerIsolateSenderImpl({ 33 | DANGER_SEND_PORT_MESSAGE_KEY: receivePort.sendPort, 34 | DANGER_DSL_MESSAGE_KEY: '{}', 35 | }, converter: (message) { 36 | lastMessage = message; 37 | return mockDangerJSONDSL; 38 | }); 39 | }); 40 | 41 | test('should initialize correctly', () { 42 | expect(isolateSender.sendPort, equals(receivePort.sendPort)); 43 | expect(lastMessage, equals('{}')); 44 | expect(isolateSender.dangerJSONDSL.rawJSONDSL, equals(mockDangerJSONDSL)); 45 | expect(isolateSender.dangerJSONDSL.git, equals(mockDangerJSONDSL.git)); 46 | }); 47 | 48 | test('should add message violation correctly', () async { 49 | isolateSender.message(onlyMessageViolation); 50 | final wrappedViolation = await receivePort.first; 51 | expect(wrappedViolation['type'], equals('message')); 52 | expect(wrappedViolation['violation'], onlyMessageViolation.toJson()); 53 | }); 54 | 55 | test('should add warn violation correctly', () async { 56 | isolateSender.warn(onlyMessageViolation); 57 | final wrappedViolation = await receivePort.first; 58 | expect(wrappedViolation['type'], equals('warn')); 59 | expect(wrappedViolation['violation'], onlyMessageViolation.toJson()); 60 | }); 61 | test('should add fail violation correctly', () async { 62 | isolateSender.fail(onlyMessageViolation); 63 | final wrappedViolation = await receivePort.first; 64 | expect(wrappedViolation['type'], equals('fail')); 65 | expect(wrappedViolation['violation'], onlyMessageViolation.toJson()); 66 | }); 67 | 68 | test('should add markdown violation correctly', () async { 69 | isolateSender.markdown(onlyMessageViolation); 70 | final wrappedViolation = await receivePort.first; 71 | expect(wrappedViolation['type'], equals('markdown')); 72 | expect(wrappedViolation['violation'], onlyMessageViolation.toJson()); 73 | }); 74 | 75 | test('should add multiple violations correctly', () async { 76 | isolateSender.markdown(onlyMessageViolation); 77 | isolateSender.fail(onlyMessageViolation); 78 | isolateSender.warn(onlyMessageViolation); 79 | isolateSender.message(onlyMessageViolation); 80 | 81 | final wrappedViolations = await receivePort.take(4).toList(); 82 | expect(wrappedViolations[0]['type'], equals('markdown')); 83 | expect(wrappedViolations[1]['type'], equals('fail')); 84 | expect(wrappedViolations[2]['type'], equals('warn')); 85 | expect(wrappedViolations[3]['type'], equals('message')); 86 | }); 87 | }); 88 | } 89 | -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/diff/add_only.diff: -------------------------------------------------------------------------------- 1 | diff --git a/.github/workflows/verify_compatibility.yaml b/.github/workflows/verify_compatibility.yaml 2 | index 507cacb..701dd94 100644 3 | --- a/.github/workflows/verify_compatibility.yaml 4 | +++ b/.github/workflows/verify_compatibility.yaml 5 | @@ -38,6 +38,22 @@ jobs: 6 | run: dart pub get 7 | working-directory: packages/danger_dart/ 8 | 9 | + - name: Install app (non nullsafety) dependencies 10 | + run: dart pub get 11 | + working-directory: example/pre_nullsafety/ 12 | + 13 | + - name: Run danger local (non nullsafety) 14 | + run: danger_dart local 15 | + working-directory: example/pre_nullsafety/ 16 | + 17 | + - name: Install app dependencies (nullsafety) 18 | + run: dart pub get 19 | + working-directory: example/target_nullsafety/ 20 | + 21 | + - name: Run danger local (nullsafety) 22 | + run: danger_dart local 23 | + working-directory: example/target_nullsafety/ 24 | + 25 | - name: Install plugin dependencies 26 | run: dart pub get 27 | working-directory: example/with_plugin/danger_plugin_example/ -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/diff/mix.diff: -------------------------------------------------------------------------------- 1 | diff --git a/example/dart3/pubspec.yaml b/example/pre_nullsafety/pubspec.yaml 2 | similarity index 64% 3 | rename from example/dart3/pubspec.yaml 4 | rename to example/pre_nullsafety/pubspec.yaml 5 | index 8aca558..9c93b1b 100644 6 | --- a/example/dart3/pubspec.yaml 7 | +++ b/example/pre_nullsafety/pubspec.yaml 8 | @@ -1,13 +1,16 @@ 9 | -name: danger_test_target_null_safety 10 | +name: danger_test_pre_nullsafety 11 | description: A simple command-line application. 12 | # version: 1.0.0 13 | # homepage: https://www.example.com 14 | 15 | environment: 16 | - sdk: ">=3.0.0 <4.0.0" 17 | + sdk: ">=2.7.0 <3.0.0" 18 | + 19 | +dependencies: 20 | + json_annotation: ^3.0.0 21 | 22 | dev_dependencies: 23 | lints: ^1.0.1 24 | - path: ^1.8.3 25 | + path: ^1.8.0 26 | danger_core: 27 | path: ../../packages/danger_core -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/diff/multiple_chunk.diff: -------------------------------------------------------------------------------- 1 | diff --git a/packages/danger_plugin_golden_reporter/pubspec.yaml b/packages/danger_plugin_golden_reporter/pubspec.yaml 2 | index eca2e35..a0d38bd 100644 3 | --- a/packages/danger_plugin_golden_reporter/pubspec.yaml 4 | +++ b/packages/danger_plugin_golden_reporter/pubspec.yaml 5 | @@ -1,10 +1,10 @@ 6 | name: danger_plugin_golden_reporter 7 | description: A Danger Dart plugin to display golden images on pull requests. 8 | -version: 2.0.0 9 | +version: 1.0.0 10 | homepage: https://github.com/danger/dart 11 | 12 | environment: 13 | - sdk: ">=3.0.0 <4.0.0" 14 | + sdk: ">=2.12.0 <3.0.0" 15 | 16 | dependencies: 17 | # danger_core: ">= 1.0.0 < 2.0.0" 18 | @@ -12,7 +12,7 @@ dependencies: 19 | path: ../danger_core 20 | 21 | dev_dependencies: 22 | - lints: ^2.1.1 23 | + lints: ^1.0.1 24 | test: ^1.20.2 25 | mockito: ^5.1.0 26 | build_runner: ^2.1.8 -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/diff/multiple_files.diff: -------------------------------------------------------------------------------- 1 | diff --git a/.github/workflows/verify_compatibility.yaml b/.github/workflows/verify_compatibility.yaml 2 | index 507cacb..701dd94 100644 3 | --- a/.github/workflows/verify_compatibility.yaml 4 | +++ b/.github/workflows/verify_compatibility.yaml 5 | @@ -38,6 +38,22 @@ jobs: 6 | run: dart pub get 7 | working-directory: packages/danger_dart/ 8 | 9 | + - name: Install app (non nullsafety) dependencies 10 | + run: dart pub get 11 | + working-directory: example/pre_nullsafety/ 12 | + 13 | + - name: Run danger local (non nullsafety) 14 | + run: danger_dart local 15 | + working-directory: example/pre_nullsafety/ 16 | + 17 | + - name: Install app dependencies (nullsafety) 18 | + run: dart pub get 19 | + working-directory: example/target_nullsafety/ 20 | + 21 | + - name: Run danger local (nullsafety) 22 | + run: danger_dart local 23 | + working-directory: example/target_nullsafety/ 24 | + 25 | - name: Install plugin dependencies 26 | run: dart pub get 27 | working-directory: example/with_plugin/danger_plugin_example/ 28 | @@ -50,18 +66,3 @@ jobs: 29 | run: danger_dart local 30 | working-directory: example/with_plugin/ 31 | 32 | - - name: Install app dependencies (Dart 2) 33 | - run: dart pub get 34 | - working-directory: example/dart2/ 35 | - 36 | - - name: Run danger local (Dart 2) 37 | - run: danger_dart local 38 | - working-directory: example/dart2/ 39 | - 40 | - - name: Install app dependencies (Dart 3) 41 | - run: dart pub get 42 | - working-directory: example/dart3/ 43 | - 44 | - - name: Run danger local (Dart 3) 45 | - run: danger_dart local 46 | - working-directory: example/dart3/ 47 | diff --git a/example/dart3/dangerfile.dart b/example/pre_nullsafety/dangerfile.dart 48 | similarity index 61% 49 | rename from example/dart3/dangerfile.dart 50 | rename to example/pre_nullsafety/dangerfile.dart 51 | index fb4ec51..5cf13f1 100644 52 | --- a/example/dart3/dangerfile.dart 53 | +++ b/example/pre_nullsafety/dangerfile.dart 54 | @@ -1,5 +1,5 @@ 55 | import 'package:danger_core/danger_core.dart'; 56 | 57 | void main() { 58 | - message('hello from Dart 3'); 59 | + message('hello from pre-nullsafety'); 60 | } 61 | diff --git a/example/dart3/pubspec.yaml b/example/pre_nullsafety/pubspec.yaml 62 | similarity index 64% 63 | rename from example/dart3/pubspec.yaml 64 | rename to example/pre_nullsafety/pubspec.yaml 65 | index 8aca558..9c93b1b 100644 66 | --- a/example/dart3/pubspec.yaml 67 | +++ b/example/pre_nullsafety/pubspec.yaml 68 | @@ -1,13 +1,16 @@ 69 | -name: danger_test_target_null_safety 70 | +name: danger_test_pre_nullsafety 71 | description: A simple command-line application. 72 | # version: 1.0.0 73 | # homepage: https://www.example.com 74 | 75 | environment: 76 | - sdk: ">=3.0.0 <4.0.0" 77 | + sdk: ">=2.7.0 <3.0.0" 78 | + 79 | +dependencies: 80 | + json_annotation: ^3.0.0 81 | 82 | dev_dependencies: 83 | lints: ^1.0.1 84 | - path: ^1.8.3 85 | + path: ^1.8.0 86 | danger_core: 87 | path: ../../packages/danger_core 88 | diff --git a/example/dart2/dangerfile.dart b/example/target_nullsafety/dangerfile.dart 89 | similarity index 100% 90 | rename from example/dart2/dangerfile.dart 91 | rename to example/target_nullsafety/dangerfile.dart 92 | diff --git a/example/dart2/pubspec.yaml b/example/target_nullsafety/pubspec.yaml 93 | similarity index 75% 94 | rename from example/dart2/pubspec.yaml 95 | rename to example/target_nullsafety/pubspec.yaml 96 | index 58e68a9..2971b33 100644 97 | --- a/example/dart2/pubspec.yaml 98 | +++ b/example/target_nullsafety/pubspec.yaml 99 | @@ -1,4 +1,4 @@ 100 | -name: dart2 101 | +name: danger_test_target_null_safety 102 | description: A simple command-line application. 103 | # version: 1.0.0 104 | # homepage: https://www.example.com 105 | @@ -6,6 +6,9 @@ description: A simple command-line application. 106 | environment: 107 | sdk: ">=2.12.0 <3.0.0" 108 | 109 | +dependencies: 110 | + json_annotation: ^3.0.0 111 | + 112 | dev_dependencies: 113 | lints: ^1.0.1 114 | path: ^1.8.0 115 | diff --git a/example/with_plugin/pubspec.yaml b/example/with_plugin/pubspec.yaml 116 | index 7980d4b..8fb2b3d 100644 117 | --- a/example/with_plugin/pubspec.yaml 118 | +++ b/example/with_plugin/pubspec.yaml 119 | @@ -6,6 +6,9 @@ description: A simple command-line application. 120 | environment: 121 | sdk: ">=2.12.0 <3.0.0" 122 | 123 | +dependencies: 124 | + json_annotation: ^3.0.0 125 | + 126 | dev_dependencies: 127 | lints: ^1.0.1 128 | path: ^1.8.0 129 | diff --git a/packages/danger_core/CHANGELOG.md b/packages/danger_core/CHANGELOG.md 130 | index 2470454..6a86da3 100644 131 | --- a/packages/danger_core/CHANGELOG.md 132 | +++ b/packages/danger_core/CHANGELOG.md 133 | @@ -1,7 +1,3 @@ 134 | -## 2.0.0 135 | - 136 | -- Migrate to Dart 3 137 | - 138 | ## 1.0.1 139 | 140 | - Fixed GitLabDSL 141 | diff --git a/packages/danger_core/pubspec.yaml b/packages/danger_core/pubspec.yaml 142 | index 4ba9480..c487bd1 100644 143 | --- a/packages/danger_core/pubspec.yaml 144 | +++ b/packages/danger_core/pubspec.yaml 145 | @@ -1,17 +1,17 @@ 146 | name: danger_core 147 | description: Core of Danger Dart, tool to help you reviewing the code. 148 | -version: 2.0.0 149 | +version: 1.0.1 150 | homepage: https://github.com/danger/dart 151 | 152 | environment: 153 | - sdk: ">=3.0.0 <4.0.0" 154 | + sdk: ">=2.12.0 <3.0.0" 155 | 156 | dev_dependencies: 157 | - lints: ^2.1.1 158 | - json_annotation: ^4.8.1 159 | - test: ^1.24.7 160 | - json_serializable: ^6.7.1 161 | - build_runner: ^2.4.6 162 | - mockito: ^5.4.2 163 | + lints: ^1.0.1 164 | + json_annotation: ^4.4.0 165 | + test: ^1.20.2 166 | + json_serializable: ^6.1.5 167 | + build_runner: ^2.1.8 168 | + mockito: ^5.1.0 169 | isolate: ^2.1.1 170 | - path: ^1.8.3 171 | + path: ^1.8.0 172 | diff --git a/packages/danger_dart/CHANGELOG.md b/packages/danger_dart/CHANGELOG.md 173 | index 10911ab..33d4244 100644 174 | --- a/packages/danger_dart/CHANGELOG.md 175 | +++ b/packages/danger_dart/CHANGELOG.md 176 | @@ -1,7 +1,3 @@ 177 | -## 2.0.0 178 | - 179 | -- Migrate to Dart 3 180 | - 181 | ## 1.0.1 182 | 183 | - Add argument `--failOnErrors` on every command 184 | diff --git a/packages/danger_dart/lib/danger_util.dart b/packages/danger_dart/lib/danger_util.dart 185 | index a6f1981..6332c40 100644 186 | --- a/packages/danger_dart/lib/danger_util.dart 187 | +++ b/packages/danger_dart/lib/danger_util.dart 188 | @@ -126,6 +126,7 @@ class DangerUtil { 189 | } 190 | tempFile.createSync(); 191 | tempFile.writeAsStringSync(''' 192 | +// @dart=2.7 193 | import 'dart:developer'; 194 | 195 | import 'package:danger_core/danger_core.dart'; 196 | diff --git a/packages/danger_dart/pubspec.yaml b/packages/danger_dart/pubspec.yaml 197 | index d1f5e3f..254c34d 100644 198 | --- a/packages/danger_dart/pubspec.yaml 199 | +++ b/packages/danger_dart/pubspec.yaml 200 | @@ -7,20 +7,20 @@ executables: 201 | danger_dart: 202 | 203 | environment: 204 | - sdk: ">=3.0.0 <4.0.0" 205 | + sdk: ">=2.12.0 <3.0.0" 206 | 207 | dependencies: 208 | - meta: ^1.10.0 209 | - args: ^2.4.2 210 | - process_run: ^0.13.1 211 | - fimber: ^0.7.0 212 | - path: ^1.8.3 213 | + meta: ^1.7.0 214 | + args: ^2.3.0 215 | + process_run: ^0.12.3+2 216 | + fimber: ^0.6.5 217 | + path: ^1.8.1 218 | # danger_core: ">= 1.0.0 < 2.0.0" 219 | danger_core: 220 | path: ../danger_core 221 | 222 | dev_dependencies: 223 | - lints: ^2.1.1 224 | - test: ^1.24.7 225 | - mockito: ^5.4.2 226 | - build_runner: ^2.4.6 227 | + lints: ^1.0.1 228 | + test: ^1.20.2 229 | + mockito: ^5.1.0 230 | + build_runner: ^2.1.8 231 | diff --git a/packages/danger_plugin_dart_test/CHANGELOG.md b/packages/danger_plugin_dart_test/CHANGELOG.md 232 | index 40d5f85..e2f6109 100644 233 | --- a/packages/danger_plugin_dart_test/CHANGELOG.md 234 | +++ b/packages/danger_plugin_dart_test/CHANGELOG.md 235 | @@ -1,7 +1,3 @@ 236 | -## 2.0.0 237 | - 238 | -- Migrate to Dart 3 239 | - 240 | ## 1.0.0 241 | 242 | - Supports Null Safety 243 | diff --git a/packages/danger_plugin_dart_test/pubspec.yaml b/packages/danger_plugin_dart_test/pubspec.yaml 244 | index 4721fff..9239b79 100644 245 | --- a/packages/danger_plugin_dart_test/pubspec.yaml 246 | +++ b/packages/danger_plugin_dart_test/pubspec.yaml 247 | @@ -1,17 +1,17 @@ 248 | name: danger_plugin_dart_test 249 | description: A Danger Dart plugin to process test result. 250 | -version: 2.0.0 251 | +version: 1.0.0 252 | homepage: https://github.com/danger/dart 253 | 254 | environment: 255 | - sdk: ">=3.0.0 <4.0.0" 256 | + sdk: ">=2.12.0 <3.0.0" 257 | 258 | dependencies: 259 | - path: ^1.8.3 260 | + path: ">= 1.8.0 < 2.0.0" 261 | # danger_core: ">= 1.0.0 < 2.0.0" 262 | danger_core: 263 | path: ../danger_core 264 | 265 | dev_dependencies: 266 | - lints: ^2.1.1 267 | - test: ^1.24.7 268 | + lints: ^1.0.1 269 | + test: ^1.20.2 270 | diff --git a/packages/danger_plugin_golden_reporter/CHANGELOG.md b/packages/danger_plugin_golden_reporter/CHANGELOG.md 271 | index fd53903..6fdf70e 100644 272 | --- a/packages/danger_plugin_golden_reporter/CHANGELOG.md 273 | +++ b/packages/danger_plugin_golden_reporter/CHANGELOG.md 274 | @@ -1,7 +1,3 @@ 275 | -## 2.0.0 276 | - 277 | -- Migrate to Dart 3 278 | - 279 | ## 1.0.0 280 | 281 | - Supports Null Safety 282 | diff --git a/packages/danger_plugin_golden_reporter/pubspec.yaml b/packages/danger_plugin_golden_reporter/pubspec.yaml 283 | index eca2e35..a0d38bd 100644 284 | --- a/packages/danger_plugin_golden_reporter/pubspec.yaml 285 | +++ b/packages/danger_plugin_golden_reporter/pubspec.yaml 286 | @@ -1,10 +1,10 @@ 287 | name: danger_plugin_golden_reporter 288 | description: A Danger Dart plugin to display golden images on pull requests. 289 | -version: 2.0.0 290 | +version: 1.0.0 291 | homepage: https://github.com/danger/dart 292 | 293 | environment: 294 | - sdk: ">=3.0.0 <4.0.0" 295 | + sdk: ">=2.12.0 <3.0.0" 296 | 297 | dependencies: 298 | # danger_core: ">= 1.0.0 < 2.0.0" 299 | @@ -12,7 +12,7 @@ dependencies: 300 | path: ../danger_core 301 | 302 | dev_dependencies: 303 | - lints: ^2.1.1 304 | + lints: ^1.0.1 305 | test: ^1.20.2 306 | mockito: ^5.1.0 307 | build_runner: ^2.1.8 308 | diff --git a/pubspec.yaml b/pubspec.yaml 309 | index c7730a5..6a91c44 100644 310 | --- a/pubspec.yaml 311 | +++ b/pubspec.yaml 312 | @@ -4,11 +4,11 @@ description: A simple command-line application. 313 | # homepage: https://www.example.com 314 | 315 | environment: 316 | - sdk: ">=3.0.0 <4.0.0" 317 | + sdk: ">=2.12.0 <3.0.0" 318 | 319 | dev_dependencies: 320 | - lints: ^2.1.1 321 | - path: ^1.8.3 322 | + lints: ^1.0.1 323 | + path: ^1.8.0 324 | danger_core: 325 | path: packages/danger_core 326 | danger_plugin_dart_test: -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/diff/remove_only.diff: -------------------------------------------------------------------------------- 1 | diff --git a/.github/workflows/verify_compatibility.yaml b/.github/workflows/verify_compatibility.yaml 2 | index 507cacb..701dd94 100644 3 | --- a/.github/workflows/verify_compatibility.yaml 4 | +++ b/.github/workflows/verify_compatibility.yaml 5 | @@ -50,18 +66,3 @@ jobs: 6 | run: danger_dart local 7 | working-directory: example/with_plugin/ 8 | 9 | - - name: Install app dependencies (Dart 2) 10 | - run: dart pub get 11 | - working-directory: example/dart2/ 12 | - 13 | - - name: Run danger local (Dart 2) 14 | - run: danger_dart local 15 | - working-directory: example/dart2/ 16 | - 17 | - - name: Install app dependencies (Dart 3) 18 | - run: dart pub get 19 | - working-directory: example/dart3/ 20 | - 21 | - - name: Run danger local (Dart 3) 22 | - run: danger_dart local 23 | - working-directory: example/dart3/ -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/diff/rename_only.diff: -------------------------------------------------------------------------------- 1 | diff --git a/example/dart2/dangerfile.dart b/example/target_nullsafety/dangerfile.dart 2 | similarity index 100% 3 | rename from example/dart2/dangerfile.dart 4 | rename to example/target_nullsafety/dangerfile.dart -------------------------------------------------------------------------------- /packages/danger_core/test/fixtures/gitlab-dsl-input.json: -------------------------------------------------------------------------------- 1 | { 2 | "danger": { 3 | "git": { 4 | "modified_files": [ 5 | "static/source/swift/guides/getting_started.html.slim" 6 | ], 7 | "created_files": [], 8 | "deleted_files": [], 9 | "commits": [ 10 | { 11 | "sha": "621bc3348549e51c5bd6ea9f094913e9e4667c7b", 12 | "author": { 13 | "name": "Franco Meloni", 14 | "email": "franco.meloni91@gmail.com", 15 | "date": "2019-04-10T21:56:43.000Z" 16 | }, 17 | "committer": { 18 | "name": "Franco Meloni", 19 | "email": "franco.meloni91@gmail.com", 20 | "date": "2019-04-10T21:56:43.000Z" 21 | }, 22 | "message": "Update getting_started.html.slim", 23 | "parents": [], 24 | "url": "https://gitlab.com/danger-systems/danger.systems/commit/621bc3348549e51c5bd6ea9f094913e9e4667c7b", 25 | "tree": null 26 | } 27 | ] 28 | }, 29 | "gitlab": { 30 | "metadata": { 31 | "pullRequestID": "182", 32 | "repoSlug": "danger-systems/danger.systems" 33 | }, 34 | "mr": { 35 | "id": 27469633, 36 | "iid": 182, 37 | "project_id": 1620437, 38 | "title": "Update getting_started.html.slim", 39 | "description": "Updating it to avoid problems like https://github.com/danger/swift/issues/221", 40 | "state": "merged", 41 | "created_at": "2019-04-10T21:57:45.346Z", 42 | "updated_at": "2019-04-11T00:37:22.460Z", 43 | "merged_by": { 44 | "id": 377669, 45 | "name": "Orta", 46 | "username": "orta", 47 | "state": "active", 48 | "avatar_url": "https://secure.gravatar.com/avatar/f116cb3be23153ec08b94e8bd4dbcfeb?s=80&d=identicon", 49 | "web_url": "https://gitlab.com/orta" 50 | }, 51 | "merged_at": "2019-04-11T00:37:22.492Z", 52 | "closed_by": null, 53 | "closed_at": null, 54 | "target_branch": "master", 55 | "source_branch": "patch-2", 56 | "user_notes_count": 0, 57 | "upvotes": 0, 58 | "downvotes": 0, 59 | "assignee": { 60 | "id": 377669, 61 | "name": "Orta", 62 | "username": "orta", 63 | "state": "active", 64 | "avatar_url": "https://secure.gravatar.com/avatar/f116cb3be23153ec08b94e8bd4dbcfeb?s=80&d=identicon", 65 | "web_url": "https://gitlab.com/orta" 66 | }, 67 | "author": { 68 | "id": 3331525, 69 | "name": "Franco Meloni", 70 | "username": "f-meloni", 71 | "state": "active", 72 | "avatar_url": "https://secure.gravatar.com/avatar/3d90e967de2beab6d44cfadbb4976b87?s=80&d=identicon", 73 | "web_url": "https://gitlab.com/f-meloni" 74 | }, 75 | "assignees": [], 76 | "source_project_id": 10132593, 77 | "target_project_id": 1620437, 78 | "labels": [], 79 | "work_in_progress": false, 80 | "milestone": { 81 | "id": 1, 82 | "iid": 2, 83 | "project_id": 1000, 84 | "title": "Test Milestone", 85 | "description": "Test Description", 86 | "state": "closed", 87 | "start_date": "2019-04-10T21:57:45.346Z", 88 | "created_at": "2019-04-10T21:57:45.346Z", 89 | "updated_at": "2019-04-10T21:57:45.346Z", 90 | "due_date": "2019-06-10T00:00:00.000Z", 91 | "web_url": "https://gitlab.com/milestone" 92 | }, 93 | "merge_when_pipeline_succeeds": false, 94 | "merge_status": "can_be_merged", 95 | "sha": "621bc3348549e51c5bd6ea9f094913e9e4667c7b", 96 | "merge_commit_sha": "377a24fb7a0f30364f089f7bca67752a8b61f477", 97 | "discussion_locked": null, 98 | "should_remove_source_branch": null, 99 | "force_remove_source_branch": true, 100 | "allow_collaboration": false, 101 | "allow_maintainer_to_push": false, 102 | "reference": "!182", 103 | "web_url": "https://gitlab.com/danger-systems/danger.systems/merge_requests/182", 104 | "time_stats": { 105 | "time_estimate": 0, 106 | "total_time_spent": 0, 107 | "human_time_estimate": null, 108 | "human_total_time_spent": null 109 | }, 110 | "squash": false, 111 | "subscribed": false, 112 | "changes_count": "1", 113 | "latest_build_started_at": "2021-04-30T14:35:00.103+02:00", 114 | "latest_build_finished_at": "2019-04-11T00:33:22.492Z", 115 | "first_deployed_to_production_at": "2019-04-11T00:30:22.492Z", 116 | "pipeline": { 117 | "id": 50, 118 | "sha": "621bc3348549e51c5bd6ea9f094913e9e4667c7b", 119 | "ref": "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f", 120 | "status": "success", 121 | "web_url": "https://gitlab.com/danger-systems/danger.systems/pipeline/621bc3348549e51c5bd6ea9f094913e9e4667c7b" 122 | }, 123 | "head_pipeline": null, 124 | "diff_refs": { 125 | "base_sha": "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f", 126 | "head_sha": "621bc3348549e51c5bd6ea9f094913e9e4667c7b", 127 | "start_sha": "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f" 128 | }, 129 | "merge_error": null, 130 | "user": { 131 | "can_merge": false 132 | }, 133 | "approvals_before_merge": 1 134 | }, 135 | "commits": [ 136 | { 137 | "id": "621bc3348549e51c5bd6ea9f094913e9e4667c7b", 138 | "short_id": "621bc334", 139 | "created_at": "2019-04-10T21:56:43.000Z", 140 | "parent_ids": [], 141 | "title": "Update getting_started.html.slim", 142 | "message": "Update getting_started.html.slim", 143 | "author_name": "Franco Meloni", 144 | "author_email": "franco.meloni91@gmail.com", 145 | "authored_date": "2019-04-10T21:56:43.000Z", 146 | "committer_name": "Franco Meloni", 147 | "committer_email": "franco.meloni91@gmail.com", 148 | "committed_date": "2019-04-10T21:56:43.000Z" 149 | } 150 | ] 151 | }, 152 | "settings": { 153 | "github": { 154 | "accessToken": "NO_T...", 155 | "additionalHeaders": {} 156 | }, 157 | "cliArgs": {} 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /packages/danger_core/test/parser/bitbucket_cloud_dsl_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:danger_core/src/models/bitbucket_cloud.dart'; 5 | import 'package:test/test.dart'; 6 | import 'package:path/path.dart' show join, current; 7 | 8 | void main() { 9 | group('bitbucket_cloud_dsl', () { 10 | test('should be able to parse correctly', () { 11 | final fixtureFile = 12 | File(join(current, 'test', 'fixtures', 'bbc-dsl-input.json')); 13 | final str = fixtureFile.readAsStringSync(); 14 | final json = jsonDecode(str); 15 | final bbcJSON = json['danger']['bitbucket_cloud']; 16 | 17 | final result = BitBucketCloudJSONDSL.fromJson(bbcJSON); 18 | 19 | expect( 20 | result.pr.title, equals("Custom suffix for tags and POM's version")); 21 | expect(result.pr.id, equals(80)); 22 | }); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /packages/danger_core/test/parser/git_diff_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_core/src/utils/git_diff_parser.dart'; 4 | import 'package:test/test.dart'; 5 | import 'package:path/path.dart' show join, current; 6 | 7 | void main() { 8 | group('git_diff_parser', () { 9 | test('should be able to parse add_only correctly', () { 10 | final fixtureFile = 11 | File(join(current, 'test', 'fixtures', 'diff', 'add_only.diff')); 12 | final str = fixtureFile.readAsStringSync(); 13 | final data = GitDiffParser.parse(str); 14 | expect(data.length, 1); 15 | expect( 16 | data.first.fromFile, '.github/workflows/verify_compatibility.yaml'); 17 | expect(data.first.toFile, '.github/workflows/verify_compatibility.yaml'); 18 | expect(data.first.diffBlocks.length, 1); 19 | expect(data.first.diffBlocks.first.addedLines.length, 16); 20 | expect(data.first.diffBlocks.first.removedLines, isEmpty); 21 | expect(data.first.diffBlocks.first.unchangedLines.length, 6); 22 | expect(data.first.diffBlocks.first.fromStart, 38); 23 | expect(data.first.diffBlocks.first.fromEnd, 43); 24 | expect(data.first.diffBlocks.first.toStart, 38); 25 | expect(data.first.diffBlocks.first.toEnd, 59); 26 | }); 27 | 28 | test('should be able to parse remove_only correctly', () { 29 | final fixtureFile = 30 | File(join(current, 'test', 'fixtures', 'diff', 'remove_only.diff')); 31 | final str = fixtureFile.readAsStringSync(); 32 | final data = GitDiffParser.parse(str); 33 | expect(data.length, 1); 34 | expect( 35 | data.first.fromFile, '.github/workflows/verify_compatibility.yaml'); 36 | expect(data.first.toFile, '.github/workflows/verify_compatibility.yaml'); 37 | expect(data.first.diffBlocks.length, 1); 38 | expect(data.first.diffBlocks.first.addedLines, isEmpty); 39 | expect(data.first.diffBlocks.first.removedLines.length, 15); 40 | expect(data.first.diffBlocks.first.unchangedLines.length, 3); 41 | expect(data.first.diffBlocks.first.fromStart, 50); 42 | expect(data.first.diffBlocks.first.fromEnd, 67); 43 | expect(data.first.diffBlocks.first.toStart, 66); 44 | expect(data.first.diffBlocks.first.toEnd, 68); 45 | }); 46 | 47 | test('should be able to parse rename_only correctly', () { 48 | final fixtureFile = 49 | File(join(current, 'test', 'fixtures', 'diff', 'rename_only.diff')); 50 | final str = fixtureFile.readAsStringSync(); 51 | final data = GitDiffParser.parse(str); 52 | expect(data.length, 1); 53 | expect(data.first.fromFile, 'example/dart2/dangerfile.dart'); 54 | expect(data.first.toFile, 'example/target_nullsafety/dangerfile.dart'); 55 | expect(data.first.diffBlocks.length, 0); 56 | }); 57 | 58 | test('should be able to parse mix correctly', () { 59 | final fixtureFile = 60 | File(join(current, 'test', 'fixtures', 'diff', 'mix.diff')); 61 | final str = fixtureFile.readAsStringSync(); 62 | final data = GitDiffParser.parse(str); 63 | expect(data.length, 1); 64 | expect(data.first.fromFile, 'example/dart3/pubspec.yaml'); 65 | expect(data.first.toFile, 'example/pre_nullsafety/pubspec.yaml'); 66 | expect(data.first.diffBlocks.length, 1); 67 | expect(data.first.diffBlocks.first.addedLines.length, 6); 68 | expect(data.first.diffBlocks.first.removedLines.length, 3); 69 | expect(data.first.diffBlocks.first.unchangedLines.length, 10); 70 | expect(data.first.diffBlocks.first.fromStart, 1); 71 | expect(data.first.diffBlocks.first.fromEnd, 13); 72 | expect(data.first.diffBlocks.first.toStart, 1); 73 | expect(data.first.diffBlocks.first.toEnd, 16); 74 | }); 75 | 76 | test('should be able to parse multiple_chunk correctly', () { 77 | final fixtureFile = File( 78 | join(current, 'test', 'fixtures', 'diff', 'multiple_chunk.diff')); 79 | final str = fixtureFile.readAsStringSync(); 80 | final data = GitDiffParser.parse(str); 81 | expect(data.length, 1); 82 | expect(data.first.fromFile, 83 | 'packages/danger_plugin_golden_reporter/pubspec.yaml'); 84 | expect(data.first.toFile, 85 | 'packages/danger_plugin_golden_reporter/pubspec.yaml'); 86 | expect(data.first.diffBlocks.length, 2); 87 | 88 | expect(data.first.diffBlocks.first.addedLines.length, 2); 89 | expect(data.first.diffBlocks.first.removedLines.length, 2); 90 | expect(data.first.diffBlocks.first.unchangedLines.length, 8); 91 | expect(data.first.diffBlocks.first.fromStart, 1); 92 | expect(data.first.diffBlocks.first.fromEnd, 10); 93 | expect(data.first.diffBlocks.first.toStart, 1); 94 | expect(data.first.diffBlocks.first.toEnd, 10); 95 | 96 | expect(data.first.diffBlocks[1].addedLines.length, 1); 97 | expect(data.first.diffBlocks[1].removedLines.length, 1); 98 | expect(data.first.diffBlocks[1].unchangedLines.length, 6); 99 | expect(data.first.diffBlocks[1].fromStart, 12); 100 | expect(data.first.diffBlocks[1].fromEnd, 18); 101 | expect(data.first.diffBlocks[1].toStart, 12); 102 | expect(data.first.diffBlocks[1].toEnd, 18); 103 | }); 104 | 105 | test('should be able to parse multiple_files', () { 106 | final fixtureFile = File( 107 | join(current, 'test', 'fixtures', 'diff', 'multiple_files.diff')); 108 | final str = fixtureFile.readAsStringSync(); 109 | final data = GitDiffParser.parse(str); 110 | expect(data.length, 16); 111 | expect( 112 | data.first.fromFile, '.github/workflows/verify_compatibility.yaml'); 113 | expect(data.first.toFile, '.github/workflows/verify_compatibility.yaml'); 114 | 115 | expect(data.last.fromFile, 'pubspec.yaml'); 116 | expect(data.last.toFile, 'pubspec.yaml'); 117 | }); 118 | }); 119 | } 120 | -------------------------------------------------------------------------------- /packages/danger_core/test/parser/gitlab_dsl_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:danger_core/src/models/gitlab_dsl.dart'; 5 | import 'package:test/test.dart'; 6 | import 'package:path/path.dart' show join, current; 7 | 8 | void main() { 9 | group('github_dsl', () { 10 | test('should be able to parse correctly', () { 11 | final fixtureFile = 12 | File(join(current, 'test', 'fixtures', 'gitlab-dsl-input.json')); 13 | final str = fixtureFile.readAsStringSync(); 14 | final json = jsonDecode(str); 15 | final gitLabJSON = json['danger']['gitlab']; 16 | 17 | final result = GitLabDSL.fromJson(gitLabJSON); 18 | 19 | expect(result.mergeRequest.title, 20 | equals('Update getting_started.html.slim')); 21 | expect(result.mergeRequest.id, equals(27469633)); 22 | expect(result.mergeRequest.iid, equals(182)); 23 | }); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /packages/danger_core/test/parser/gtihub_dsl_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:danger_core/src/models/github_dsl.dart'; 5 | import 'package:test/test.dart'; 6 | import 'package:path/path.dart' show join, current; 7 | 8 | void main() { 9 | group('github_dsl', () { 10 | test('should be able to parse correctly', () { 11 | final fixtureFile = 12 | File(join(current, 'test', 'fixtures', 'github-dsl.json')); 13 | final str = fixtureFile.readAsStringSync(); 14 | final json = jsonDecode(str); 15 | final githubJSON = json['danger']['github']; 16 | 17 | final result = GitHubDSL.fromJson(githubJSON); 18 | 19 | expect(result.pr.title, equals('Xcode updates')); 20 | expect(result.pr.number, equals(609)); 21 | }); 22 | 23 | test( 24 | 'should be able to parse github with some nulls atrribute dsl correctly', 25 | () { 26 | final fixtureFile = File(join(current, 'test', 'fixtures', 27 | 'github-with-some-nulls-attribute.json')); 28 | final str = fixtureFile.readAsStringSync(); 29 | final json = jsonDecode(str); 30 | final githubJSON = json['danger']['github']; 31 | 32 | final result = GitHubDSL.fromJson(githubJSON); 33 | 34 | expect(result.pr.title, equals('Xcode updates')); 35 | expect(result.pr.number, equals(609)); 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /packages/danger_dart/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | # Conventional directory for build outputs 6 | build/ 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /packages/danger_dart/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /packages/danger_dart/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | - Migrate to Dart 3 4 | 5 | ## 1.0.1 6 | 7 | - Add argument `--failOnErrors` on every command 8 | 9 | ## 1.0.0 10 | 11 | - Supports Null Safety 12 | - Supports GitLab 13 | 14 | ## 0.0.7 15 | 16 | - Order results to support Bitbucket Comment 17 | 18 | ## 0.0.6 19 | 20 | - Breaking Changes: Remove boilerplate on dangerfile.dart 21 | 22 | ## 0.0.5 23 | 24 | - Use passURLForDSL for local command 25 | 26 | ## 0.0.4 27 | 28 | - Use passURLForDSL instead 29 | 30 | ## 0.0.3 31 | 32 | - Close receive port before exit 33 | 34 | ## 0.0.2 35 | 36 | - Fix Danger Process finished before writing all results 37 | 38 | ## 0.0.1 39 | 40 | - Initial version, created by Stagehand 41 | -------------------------------------------------------------------------------- /packages/danger_dart/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2019 Danger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/danger_dart/README.md: -------------------------------------------------------------------------------- 1 | # Danger Dart 2 | 3 | [![Pub version](https://img.shields.io/pub/v/danger_dart.svg)](https://pub.dev/packages/danger_dart) 4 | 5 | This is Danger Dart runner 6 | 7 | ### Installation 8 | 9 | Use pub global to activate this command. 10 | 11 | ```bash 12 | $pub global activate danger_dart 13 | ``` 14 | 15 | For more information, please refer to https://github.com/danger/dart 16 | -------------------------------------------------------------------------------- /packages/danger_dart/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | include: package:lints/recommended.yaml 4 | 5 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 6 | # Uncomment to specify additional rules. 7 | # linter: 8 | # rules: 9 | # - camel_case_types 10 | 11 | analyzer: 12 | # exclude: 13 | # - path/to/excluded/files/** 14 | -------------------------------------------------------------------------------- /packages/danger_dart/bin/danger_dart.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_dart/danger_dart.dart' as danger_dart; 2 | 3 | // ignore: non_constant_identifier_names 4 | final LONG_ARS_REGEX = RegExp(r'^dart .* process --dangerfile ".*"$'); 5 | 6 | void main(List arguments) async { 7 | if (arguments.isEmpty) { 8 | await danger_dart.main(['--help']); 9 | } 10 | 11 | final runnerIndex = arguments.indexOf('runner'); 12 | if (runnerIndex != -1) { 13 | var newArgs = [...arguments]; 14 | newArgs.removeRange(runnerIndex, newArgs.length); 15 | 16 | await danger_dart.main(newArgs); 17 | } else { 18 | await danger_dart.main(arguments); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/commands/base/danger_wrapper_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:fimber/fimber.dart'; 5 | import 'package:danger_dart/danger_util.dart'; 6 | 7 | abstract class DangerWrapperCommand extends Command { 8 | final DangerUtil dangerUtil; 9 | 10 | DangerWrapperCommand(this.dangerUtil) { 11 | argParser.addOption('dangerfile', 12 | defaultsTo: 'dangerfile.dart', help: 'Location of dangerfile'); 13 | 14 | argParser.addOption('danger-js-path', help: 'Path to dangerJS'); 15 | argParser.addFlag('failOnErrors', 16 | defaultsTo: false, 17 | negatable: false, 18 | help: 'Fail if there are fails in the danger report'); 19 | argParser.addFlag('debug', defaultsTo: false, negatable: false); 20 | argParser.addFlag('verbose', defaultsTo: false, negatable: false); 21 | } 22 | 23 | final _logger = FimberLog('DangerWrapperCommand'); 24 | 25 | @override 26 | Future run() async { 27 | final args = argResults!; 28 | var url = ''; 29 | 30 | if (name == 'pr') { 31 | if (args.rest.isEmpty) { 32 | throw 'Please provide pull request url'; 33 | } else { 34 | url = args.rest[0]; 35 | } 36 | } 37 | 38 | final isDebug = args.wasParsed('debug'); 39 | final isVerbose = args.wasParsed('verbose'); 40 | final isFailOnErrors = args.wasParsed('failOnErrors'); 41 | 42 | final useColors = (Platform.environment['TERM'] ?? '').contains('xterm'); 43 | if (isVerbose) { 44 | Fimber.plantTree(DebugTree(useColors: useColors)); 45 | } else { 46 | Fimber.plantTree( 47 | DebugTree(useColors: useColors, logLevels: ['I', 'W', 'E'])); 48 | } 49 | 50 | final dangerFilePath = dangerUtil.getDangerFile(args); 51 | final metaData = await dangerUtil.getDangerJSMetaData(args); 52 | final dangerProcessCommand = [ 53 | 'dart', 54 | 'run', 55 | ...isDebug 56 | ? [ 57 | '--observe=8181', 58 | '--no-pause-isolates-on-exit', 59 | ] 60 | : [], 61 | (dangerUtil.getScriptFilePath()), 62 | 'process', 63 | '--dangerfile', 64 | dangerFilePath, 65 | ...isDebug ? ['--debug'] : [], 66 | ].join(' '); 67 | 68 | final dangerJSCommand = [ 69 | metaData.executable, 70 | name, 71 | ...(url.isNotEmpty ? [url] : []), 72 | if (isFailOnErrors) '--failOnErrors', 73 | '--dangerfile', 74 | args['dangerfile'], 75 | '--passURLForDSL', 76 | '--process', 77 | "'$dangerProcessCommand'" 78 | ].join(' '); 79 | 80 | try { 81 | _logger.d('Arguments [$dangerJSCommand]'); 82 | _logger.d('Run shell'); 83 | 84 | final result = await dangerUtil.execShellCommand(dangerJSCommand, 85 | isVerbose: isVerbose); 86 | 87 | _logger.d('Run Completed'); 88 | exitCode = result.last.exitCode; 89 | } catch (e) { 90 | if (e is Error) { 91 | _logger.e(e.toString(), ex: e, stacktrace: e.stackTrace); 92 | } else { 93 | _logger.e(e.toString(), ex: e); 94 | } 95 | exitCode = 1; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/commands/ci_command.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_dart/commands/base/danger_wrapper_command.dart'; 2 | import 'package:danger_dart/danger_util.dart'; 3 | 4 | class CICommand extends DangerWrapperCommand { 5 | CICommand(DangerUtil dangerUtil) : super(dangerUtil); 6 | 7 | @override 8 | String get description => 'Runs Danger on CI'; 9 | 10 | @override 11 | String get name => 'ci'; 12 | } 13 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/commands/local_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:danger_dart/danger_util.dart'; 5 | import 'package:fimber/fimber.dart'; 6 | 7 | class LocalCommand extends Command { 8 | final DangerUtil dangerUtil; 9 | final _logger = FimberLog('LocalCommand'); 10 | 11 | LocalCommand(this.dangerUtil) { 12 | argParser.addOption('dangerfile', 13 | defaultsTo: 'dangerfile.dart', help: 'Location of dangerfile'); 14 | 15 | argParser.addOption('danger-js-path', help: 'Path to dangerJS'); 16 | argParser.addOption('base', 17 | help: 'Use a different base branch', valueHelp: 'branch_name'); 18 | argParser.addFlag('failOnErrors', 19 | defaultsTo: false, 20 | negatable: false, 21 | help: 'Fail if there are fails in the danger report'); 22 | argParser.addFlag('staging', 23 | defaultsTo: false, negatable: false, help: 'Just use staged changes.'); 24 | argParser.addFlag('debug', defaultsTo: false, negatable: false); 25 | argParser.addFlag('verbose', defaultsTo: false, negatable: false); 26 | } 27 | 28 | @override 29 | String get description => 30 | 'Runs danger standalone on a repo, useful for git hooks'; 31 | 32 | @override 33 | String get name => 'local'; 34 | 35 | @override 36 | Future run() async { 37 | final args = argResults!; 38 | final isDebug = args.wasParsed('debug'); 39 | final isVerbose = args.wasParsed('verbose'); 40 | final isFailOnErrors = args.wasParsed('failOnErrors'); 41 | 42 | final useColors = (Platform.environment['TERM'] ?? '').contains('xterm'); 43 | if (isVerbose) { 44 | Fimber.plantTree(DebugTree(useColors: useColors)); 45 | } else { 46 | Fimber.plantTree( 47 | DebugTree(useColors: useColors, logLevels: ['I', 'W', 'E'])); 48 | } 49 | 50 | final dangerFilePath = dangerUtil.getDangerFile(args); 51 | final metaData = await dangerUtil.getDangerJSMetaData(args); 52 | final dangerProcessCommand = [ 53 | 'dart', 54 | 'run', 55 | ...isDebug ? ['--observe=8181', '--no-pause-isolates-on-exit'] : [], 56 | (dangerUtil.getScriptFilePath()), 57 | 'process', 58 | '--dangerfile', 59 | dangerFilePath, 60 | ...isDebug ? ['--debug'] : [], 61 | ].join(' '); 62 | 63 | final dangerJSCommand = [ 64 | metaData.executable, 65 | name, 66 | '--dangerfile', 67 | args['dangerfile'], 68 | '--passURLForDSL', 69 | if (isFailOnErrors) '--failOnErrors', 70 | '--process', 71 | '"$dangerProcessCommand"', 72 | ...(args['base'] != null ? ['--base', args['base']] : []), 73 | ...(args['staging'] ? ['--staging'] : []), 74 | ].join(' '); 75 | 76 | try { 77 | _logger.d('Arguments [$dangerJSCommand]'); 78 | _logger.d('Run shell'); 79 | 80 | final result = await dangerUtil.execShellCommand(dangerJSCommand, 81 | isVerbose: isVerbose); 82 | 83 | _logger.d('Run Completed'); 84 | exitCode = result.last.exitCode; 85 | } catch (e) { 86 | _logger.e(e.toString()); 87 | exitCode = 1; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/commands/pr_command.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_dart/commands/base/danger_wrapper_command.dart'; 2 | import 'package:danger_dart/danger_util.dart'; 3 | 4 | class PRCommand extends DangerWrapperCommand { 5 | PRCommand(DangerUtil dangerUtil) : super(dangerUtil); 6 | 7 | @override 8 | String get description => 9 | 'Runs your local Dangerfile against an existing GitHub PR. Will not post on the PR'; 10 | 11 | @override 12 | String get name => 'pr'; 13 | } 14 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/commands/process_command.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | 5 | import 'package:args/command_runner.dart'; 6 | import 'package:danger_dart/danger_util.dart'; 7 | import 'package:fimber/fimber.dart'; 8 | 9 | import 'package:danger_core/danger_core.dart'; 10 | // ignore: implementation_imports 11 | import 'package:danger_core/src/models/danger_dsl.dart' show DangerJSON; 12 | // ignore: implementation_imports 13 | import 'package:danger_core/src/utils/danger_isolate_receiver.dart' 14 | show DangerIsolateReceiver; 15 | import 'package:path/path.dart' show current, join; 16 | 17 | class ProcessCommand extends Command { 18 | final DangerUtil _dangerUtil; 19 | final Stdin _stdin; 20 | final Stdout _stdout; 21 | 22 | ProcessCommand(this._dangerUtil, this._stdin, this._stdout) { 23 | argParser.addOption( 24 | 'dangerfile', 25 | help: 'Location of dangerfile', 26 | ); 27 | argParser.addFlag('debug', defaultsTo: false, negatable: false); 28 | argParser.addFlag('verbose', defaultsTo: false, negatable: false); 29 | } 30 | 31 | @override 32 | String get description => 'Process Dangerfile'; 33 | 34 | @override 35 | String get name => 'process'; 36 | 37 | @override 38 | bool get hidden => true; 39 | 40 | final _logger = FimberLog('ProcessCommand'); 41 | 42 | @override 43 | Future run() async { 44 | final args = argResults!; 45 | 46 | var inputStr = (await _stdin.transform(utf8.decoder).toList()).join(''); 47 | 48 | final isDebug = args.wasParsed('debug'); 49 | final isVerbose = args.wasParsed('verbose'); 50 | final useColors = (Platform.environment['TERM'] ?? '').contains('xterm'); 51 | if (isVerbose) { 52 | Fimber.plantTree(DebugTree(useColors: useColors)); 53 | } else { 54 | Fimber.plantTree( 55 | DebugTree(useColors: useColors, logLevels: ['I', 'W', 'E'])); 56 | } 57 | 58 | if (inputStr.isEmpty) { 59 | _stdout.write('danger://send-dsl'); 60 | inputStr = (await _stdin.transform(utf8.decoder).toList()).join(''); 61 | } 62 | 63 | if (inputStr.isEmpty) { 64 | throw 'STDIN Error get empty input'; 65 | } 66 | 67 | if (!inputStr.startsWith(r'danger://dsl/')) { 68 | throw 'STDIN Error expect input [danger://dsl/] but got [$inputStr]'; 69 | } 70 | 71 | final inputFilePath = inputStr.substring('danger://dsl/'.length); 72 | final inputFile = File(inputFilePath); 73 | 74 | if (!inputFile.existsSync()) { 75 | throw 'File not found [$inputFilePath]'; 76 | } 77 | 78 | final str = inputFile.readAsStringSync(); 79 | 80 | final dangerFileName = args['dangerfile'] as String?; 81 | if (dangerFileName == null) { 82 | throw 'Dangerfile not found'; 83 | } 84 | 85 | final dangerFile = File(join(current, dangerFileName)); 86 | if (dangerFile.existsSync() == false) { 87 | throw 'Dangerfile at [${dangerFile.uri}] not found'; 88 | } 89 | 90 | DangerIsolateReceiver? isolateReceiver; 91 | 92 | try { 93 | final json = jsonDecode(str); 94 | final _ = DangerJSON.fromJson(json); 95 | 96 | isolateReceiver = DangerIsolateReceiver(json); 97 | 98 | await _dangerUtil.spawnFile( 99 | dangerFile, isolateReceiver.toMessage(), isDebug); 100 | 101 | _dangerUtil.sortDangerResult(isolateReceiver.dangerResults); 102 | 103 | final resultStr = jsonEncode(isolateReceiver.dangerResults); 104 | final tempDir = Directory.systemTemp; 105 | final tempFile = File(join(tempDir.path, 'danger-results.json')); 106 | if (tempFile.existsSync()) { 107 | tempFile.deleteSync(); 108 | } 109 | tempFile.createSync(); 110 | tempFile.writeAsStringSync(resultStr); 111 | 112 | _stdout.write('danger-results:/${tempFile.path}'); 113 | await _stdout.flush(); 114 | } catch (e) { 115 | if (e is Error) { 116 | _logger.e(e.toString(), ex: e, stacktrace: e.stackTrace); 117 | } else { 118 | _logger.e(e.toString(), ex: e); 119 | } 120 | } finally { 121 | isolateReceiver?.receivePort.close(); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/danger_dart.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:args/command_runner.dart'; 4 | import 'package:danger_dart/danger_util.dart'; 5 | 6 | import 'package:fimber/fimber.dart'; 7 | import 'package:danger_dart/commands/pr_command.dart'; 8 | import 'package:danger_dart/commands/ci_command.dart'; 9 | import 'package:danger_dart/commands/local_command.dart'; 10 | import 'package:danger_dart/commands/process_command.dart'; 11 | 12 | final logger = FimberLog('Danger.Dart'); 13 | 14 | Future main(List arguments) async { 15 | final runner = CommandRunner('danger_dart', 'Danger Dart.'); 16 | final dangerUtil = DangerUtil(); 17 | 18 | runner.addCommand(PRCommand(dangerUtil)); 19 | runner.addCommand(ProcessCommand(dangerUtil, stdin, stdout)); 20 | runner.addCommand(CICommand(dangerUtil)); 21 | runner.addCommand(LocalCommand(dangerUtil)); 22 | 23 | await runner.run(arguments); 24 | } 25 | -------------------------------------------------------------------------------- /packages/danger_dart/lib/danger_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'dart:isolate'; 4 | import 'package:args/args.dart'; 5 | import 'package:fimber/fimber.dart'; 6 | import 'package:process_run/shell.dart'; 7 | import 'package:path/path.dart' show current, join; 8 | // ignore: implementation_imports 9 | import 'package:danger_core/src/models/danger_results.dart' show DangerResults; 10 | // ignore: implementation_imports 11 | import 'package:danger_core/src/models/violation.dart' show Violation; 12 | 13 | final logger = FimberLog('DangerUtil'); 14 | 15 | class DangerJSMetadata { 16 | final String executable; 17 | 18 | DangerJSMetadata({required this.executable}); 19 | } 20 | 21 | class DangerUtil { 22 | const DangerUtil(); 23 | 24 | String getScriptFilePath() { 25 | return Platform.script.toFilePath(); 26 | } 27 | 28 | String getDangerFile(ArgResults args) { 29 | if (File(args['dangerfile']).existsSync()) { 30 | return args['dangerfile']; 31 | } else if (File(join(current, args['dangerfile'])).existsSync()) { 32 | return join(current, args['dangerfile']); 33 | } 34 | throw 'dangerfile not found'; 35 | } 36 | 37 | Future> execShellCommand(String command, 38 | {Shell? shell, required bool isVerbose}) async { 39 | final _shell = shell ?? 40 | Shell( 41 | verbose: true, 42 | environment: {'DEBUG': isVerbose ? '*' : ''}, 43 | runInShell: true, 44 | includeParentEnvironment: true); 45 | return await _shell.run(command); 46 | } 47 | 48 | Future getDangerJSMetaData(ArgResults args, 49 | {Shell? shell}) async { 50 | var dangerJSExecutable = ''; 51 | 52 | if (args['danger-js-path'] != null) { 53 | logger.i('Finind out danger from --danger-js-path'); 54 | final path = args['danger-js-path']; 55 | final file = File(path); 56 | if (file.existsSync()) { 57 | dangerJSExecutable = path; 58 | } else { 59 | throw 'please provide the corrent path for --danger-js-path'; 60 | } 61 | } else { 62 | logger.i('Finding out where the danger executable is'); 63 | 64 | final dangerJS = whichSync('danger'); 65 | if (dangerJS != null) { 66 | dangerJSExecutable = dangerJS; 67 | } else { 68 | throw 'danger-js not found, please install danger-js, or run with --danger-js-path'; 69 | } 70 | } 71 | 72 | final _shell = shell ?? Shell(verbose: false); 73 | final dangerJSHelpResult = 74 | await _shell.runExecutableArguments(dangerJSExecutable, ['--help']); 75 | 76 | final helpResult = dangerJSHelpResult.stdout.toString().trim(); 77 | if (!helpResult.contains(r'danger.systems/js')) { 78 | throw 'Your danger is not JS version, You need to uninstall danger ruby, or using --danger-js-path instead'; 79 | } 80 | 81 | return DangerJSMetadata(executable: dangerJSExecutable); 82 | } 83 | 84 | Future spawnFile(File dangerFile, dynamic message, bool isDebug) async { 85 | final exitPort = ReceivePort(); 86 | final errorPort = ReceivePort(); 87 | 88 | final isolateExitCompleter = Completer(); 89 | final isolateErrorCompleter = Completer(); 90 | 91 | exitPort.listen((message) { 92 | isolateExitCompleter.complete(); 93 | }); 94 | 95 | errorPort.listen((message) { 96 | isolateErrorCompleter.completeError(message); 97 | }); 98 | 99 | final tempDangerFile = _createTempDangerFile(dangerFile, isDebug); 100 | 101 | final currentIsolate = await Isolate.spawnUri( 102 | tempDangerFile.uri, [], message, 103 | automaticPackageResolution: true, 104 | paused: true, 105 | onExit: exitPort.sendPort); 106 | if (currentIsolate.pauseCapability != null) { 107 | currentIsolate.resume(currentIsolate.pauseCapability!); 108 | } 109 | return Future.any( 110 | [isolateExitCompleter.future, isolateErrorCompleter.future]) 111 | .whenComplete(() { 112 | exitPort.close(); 113 | errorPort.close(); 114 | currentIsolate.kill(priority: Isolate.immediate); 115 | if (tempDangerFile.existsSync()) { 116 | tempDangerFile.deleteSync(); 117 | } 118 | }); 119 | } 120 | 121 | File _createTempDangerFile(File dangerFile, bool isDebug) { 122 | final tempFilePath = '${dangerFile.path}.g.dart'; 123 | final tempFile = File(tempFilePath); 124 | if (tempFile.existsSync()) { 125 | tempFile.deleteSync(); 126 | } 127 | tempFile.createSync(); 128 | tempFile.writeAsStringSync(''' 129 | import 'dart:developer'; 130 | 131 | import 'package:danger_core/danger_core.dart'; 132 | import './${dangerFile.path}' as danger_file; 133 | 134 | void main(List args, dynamic data) { 135 | Danger.setup(data); 136 | ${isDebug ? ' debugger();' : ''} 137 | 138 | danger_file.main(); 139 | } 140 | '''); 141 | return tempFile; 142 | } 143 | 144 | void sortDangerResult(DangerResults results) { 145 | results.fails.sort(_sortViolation); 146 | results.warnings.sort(_sortViolation); 147 | results.messages.sort(_sortViolation); 148 | results.markdowns.sort(_sortViolation); 149 | } 150 | 151 | int _sortViolation(Violation left, Violation right) { 152 | if (left.file == null && right.file == null) { 153 | // Both null 154 | return 0; 155 | } else if (left.file == null) { 156 | // Left null 157 | return -1; 158 | } else if (right.file == null) { 159 | // Right null 160 | return 1; 161 | } 162 | 163 | // Not null 164 | if (left.file == right.file) { 165 | // Same file compare with line instead 166 | return left.line!.compareTo(right.line!); 167 | } else { 168 | // Not same file compare with filename 169 | return left.file!.compareTo(right.file!); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /packages/danger_dart/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_dart 2 | description: Danger Dart, tool to help you reviewing the code. 3 | version: 2.0.0 4 | homepage: https://github.com/danger/dart 5 | 6 | executables: 7 | danger_dart: 8 | 9 | environment: 10 | sdk: ">=3.0.0 <4.0.0" 11 | 12 | dependencies: 13 | meta: ^1.10.0 14 | args: ^2.4.2 15 | process_run: ^0.13.1 16 | fimber: ^0.7.0 17 | path: ^1.8.3 18 | # danger_core: ">= 1.0.0 < 2.0.0" 19 | danger_core: 20 | path: ../danger_core 21 | 22 | dev_dependencies: 23 | lints: ^2.1.1 24 | test: ^1.24.7 25 | mockito: ^5.4.2 26 | build_runner: ^2.4.6 27 | -------------------------------------------------------------------------------- /packages/danger_dart/test/base/test_command_runner.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/command_runner.dart'; 2 | 3 | class TestCommandRunner extends CommandRunner { 4 | TestCommandRunner(String executableName, String description) 5 | : super(executableName, description); 6 | 7 | factory TestCommandRunner.create(Command command) { 8 | final runner = TestCommandRunner('danger_dart', 'Danger Dart.'); 9 | runner.addCommand(command); 10 | return runner; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/danger_dart/test/commands/ci_command_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_dart/commands/ci_command.dart'; 4 | import 'package:danger_dart/danger_util.dart'; 5 | import 'package:mockito/mockito.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import '../base/test_command_runner.dart'; 9 | import '../mock_util.mocks.dart'; 10 | 11 | void main() { 12 | group('CICommand', () { 13 | late MockDangerUtil _mockDangerUtil; 14 | late CICommand _ciCommand; 15 | late TestCommandRunner _commandRunner; 16 | 17 | setUp(() { 18 | _mockDangerUtil = MockDangerUtil(); 19 | _ciCommand = CICommand(_mockDangerUtil); 20 | _commandRunner = TestCommandRunner.create(_ciCommand); 21 | 22 | when(_mockDangerUtil.getDangerJSMetaData(any, shell: anyNamed('shell'))) 23 | .thenAnswer((realInvocation) async { 24 | return DangerJSMetadata(executable: '/usr/local/danger-js'); 25 | }); 26 | 27 | when(_mockDangerUtil.execShellCommand(captureAny, 28 | isVerbose: captureAnyNamed('isVerbose'), 29 | shell: captureAnyNamed('shell'))) 30 | .thenAnswer((realInvocation) async { 31 | return [ProcessResult(pid, 0, stdout, stderr)]; 32 | }); 33 | 34 | when(_mockDangerUtil.getDangerFile(any)) 35 | .thenReturn('mock_danger_file.dart'); 36 | 37 | when(_mockDangerUtil.getScriptFilePath()) 38 | .thenReturn('danger/danger_dart.dart'); 39 | }); 40 | 41 | test('Should pass isVerbose', () async { 42 | await _commandRunner.run(['ci', '--verbose']); 43 | 44 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 45 | isVerbose: captureAnyNamed('isVerbose'), 46 | shell: captureAnyNamed('shell'))) 47 | .captured; 48 | 49 | expect(result[1], equals(true)); 50 | }); 51 | 52 | test('Should pass process to danger-js', () async { 53 | await _commandRunner.run(['ci']); 54 | 55 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 56 | isVerbose: captureAnyNamed('isVerbose'), 57 | shell: captureAnyNamed('shell'))) 58 | .captured; 59 | final processCommand = 60 | result.first.toString().split('--process').last.trim(); 61 | 62 | expect( 63 | processCommand, 64 | equals( 65 | "'dart run danger/danger_dart.dart process --dangerfile mock_danger_file.dart'")); 66 | }); 67 | 68 | test('Should pass failOnErrors to danger-js', () async { 69 | await _commandRunner.run(['ci', '--failOnErrors']); 70 | 71 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 72 | isVerbose: captureAnyNamed('isVerbose'), 73 | shell: captureAnyNamed('shell'))) 74 | .captured; 75 | final processCommand = 76 | result.first.toString().split('--process').first.trim(); 77 | 78 | expect(processCommand, contains("--failOnErrors")); 79 | }); 80 | }); 81 | } 82 | -------------------------------------------------------------------------------- /packages/danger_dart/test/commands/local_command_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_dart/commands/local_command.dart'; 4 | import 'package:danger_dart/danger_util.dart'; 5 | import 'package:mockito/mockito.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import '../base/test_command_runner.dart'; 9 | import '../mock_util.mocks.dart'; 10 | 11 | void main() { 12 | group('LocalCommand', () { 13 | late MockDangerUtil _mockDangerUtil; 14 | late LocalCommand _localCommand; 15 | late TestCommandRunner _commandRunner; 16 | 17 | setUp(() { 18 | _mockDangerUtil = MockDangerUtil(); 19 | _localCommand = LocalCommand(_mockDangerUtil); 20 | _commandRunner = TestCommandRunner.create(_localCommand); 21 | 22 | when(_mockDangerUtil.getDangerJSMetaData(any, shell: anyNamed('shell'))) 23 | .thenAnswer((realInvocation) async { 24 | return DangerJSMetadata(executable: '/usr/local/danger-js'); 25 | }); 26 | 27 | when(_mockDangerUtil.execShellCommand(captureAny, 28 | isVerbose: captureAnyNamed('isVerbose'), 29 | shell: captureAnyNamed('shell'))) 30 | .thenAnswer((realInvocation) async { 31 | return [ProcessResult(pid, 0, stdout, stderr)]; 32 | }); 33 | 34 | when(_mockDangerUtil.getDangerFile(any)) 35 | .thenReturn('mock_danger_file.dart'); 36 | 37 | when(_mockDangerUtil.getScriptFilePath()) 38 | .thenReturn('danger/danger_dart.dart'); 39 | }); 40 | 41 | test('Should pass isVerbose', () async { 42 | await _commandRunner.run([ 43 | 'local', 44 | '--verbose', 45 | ]); 46 | 47 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 48 | isVerbose: captureAnyNamed('isVerbose'), 49 | shell: captureAnyNamed('shell'))) 50 | .captured; 51 | 52 | expect(result[1], equals(true)); 53 | }); 54 | 55 | test('Should pass base to danger-js', () async { 56 | await _commandRunner.run(['local', '--base', 'master']); 57 | 58 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 59 | isVerbose: captureAnyNamed('isVerbose'), 60 | shell: captureAnyNamed('shell'))) 61 | .captured; 62 | 63 | expect(result[0], contains('--base master')); 64 | }); 65 | 66 | test('Should pass staging to danger-js', () async { 67 | await _commandRunner.run(['local', '--staging']); 68 | 69 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 70 | isVerbose: captureAnyNamed('isVerbose'), 71 | shell: captureAnyNamed('shell'))) 72 | .captured; 73 | 74 | expect(result[0], contains('--staging')); 75 | }); 76 | 77 | test('Should pass extra args on debug mode', () async { 78 | await _commandRunner.run(['local', '--debug']); 79 | 80 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 81 | isVerbose: captureAnyNamed('isVerbose'), 82 | shell: captureAnyNamed('shell'))) 83 | .captured; 84 | 85 | final processCommand = 86 | result.first.toString().split('--process').last.trim(); 87 | 88 | expect(processCommand, contains('--observe=8181')); 89 | expect(processCommand, contains('--no-pause-isolates-on-exit')); 90 | 91 | expect(processCommand, contains('--debug')); 92 | }); 93 | 94 | test('Should pass failOnErrors to danger-js', () async { 95 | await _commandRunner.run(['local', '--failOnErrors']); 96 | 97 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 98 | isVerbose: captureAnyNamed('isVerbose'), 99 | shell: captureAnyNamed('shell'))) 100 | .captured; 101 | final processCommand = 102 | result.first.toString().split('--process').first.trim(); 103 | 104 | expect(processCommand, contains("--failOnErrors")); 105 | }); 106 | }); 107 | } 108 | -------------------------------------------------------------------------------- /packages/danger_dart/test/commands/pr_command_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_dart/commands/pr_command.dart'; 4 | import 'package:danger_dart/danger_util.dart'; 5 | import 'package:mockito/mockito.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | import '../base/test_command_runner.dart'; 9 | import '../mock_util.mocks.dart'; 10 | 11 | void main() { 12 | group('PRCommand', () { 13 | late MockDangerUtil _mockDangerUtil; 14 | late PRCommand _prCommand; 15 | late TestCommandRunner _commandRunner; 16 | 17 | setUp(() { 18 | _mockDangerUtil = MockDangerUtil(); 19 | _prCommand = PRCommand(_mockDangerUtil); 20 | _commandRunner = TestCommandRunner.create(_prCommand); 21 | 22 | when(_mockDangerUtil.getDangerJSMetaData(any, shell: anyNamed('shell'))) 23 | .thenAnswer((realInvocation) async { 24 | return DangerJSMetadata(executable: '/usr/local/danger-js'); 25 | }); 26 | 27 | when(_mockDangerUtil.execShellCommand(captureAny, 28 | isVerbose: captureAnyNamed('isVerbose'), 29 | shell: captureAnyNamed('shell'))) 30 | .thenAnswer((realInvocation) async { 31 | return [ProcessResult(pid, 0, stdout, stderr)]; 32 | }); 33 | 34 | when(_mockDangerUtil.getDangerFile(any)) 35 | .thenReturn('mock_danger_file.dart'); 36 | 37 | when(_mockDangerUtil.getScriptFilePath()) 38 | .thenReturn('danger/danger_dart.dart'); 39 | }); 40 | 41 | test('Should pass url to danger-js', () async { 42 | await _commandRunner.run(['pr', 'https://www.github.com']); 43 | 44 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 45 | isVerbose: captureAnyNamed('isVerbose'), 46 | shell: captureAnyNamed('shell'))) 47 | .captured; 48 | 49 | expect(result.first, contains('https://www.github.com')); 50 | }); 51 | 52 | test('Should pass isVerbose', () async { 53 | await _commandRunner.run(['pr', '--verbose', 'https://www.github.com']); 54 | 55 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 56 | isVerbose: captureAnyNamed('isVerbose'), 57 | shell: captureAnyNamed('shell'))) 58 | .captured; 59 | 60 | expect(result[1], equals(true)); 61 | }); 62 | 63 | test('Should pass process to danger-js', () async { 64 | await _commandRunner.run(['pr', 'https://www.github.com']); 65 | 66 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 67 | isVerbose: captureAnyNamed('isVerbose'), 68 | shell: captureAnyNamed('shell'))) 69 | .captured; 70 | final processCommand = 71 | result.first.toString().split('--process').last.trim(); 72 | 73 | expect( 74 | processCommand, 75 | equals( 76 | "'dart run danger/danger_dart.dart process --dangerfile mock_danger_file.dart'")); 77 | }); 78 | 79 | test('Should pass extra args on debug mode', () async { 80 | await _commandRunner.run(['pr', '--debug', 'https://www.github.com']); 81 | 82 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 83 | isVerbose: captureAnyNamed('isVerbose'), 84 | shell: captureAnyNamed('shell'))) 85 | .captured; 86 | 87 | final processCommand = 88 | result.first.toString().split('--process').last.trim(); 89 | 90 | expect(processCommand, contains('--observe=8181')); 91 | expect(processCommand, contains('--no-pause-isolates-on-exit')); 92 | 93 | expect(processCommand, contains('--debug')); 94 | }); 95 | 96 | test('Should pass failOnErrors to danger-js', () async { 97 | await _commandRunner 98 | .run(['pr', 'https://www.github.com', '--failOnErrors']); 99 | 100 | final result = verify(_mockDangerUtil.execShellCommand(captureAny, 101 | isVerbose: captureAnyNamed('isVerbose'), 102 | shell: captureAnyNamed('shell'))) 103 | .captured; 104 | final processCommand = 105 | result.first.toString().split('--process').first.trim(); 106 | 107 | expect(processCommand, contains("--failOnErrors")); 108 | }); 109 | }); 110 | } 111 | -------------------------------------------------------------------------------- /packages/danger_dart/test/commands/process_command_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:isolate'; 3 | 4 | import 'package:danger_core/danger_core.dart'; 5 | import 'package:danger_dart/commands/process_command.dart'; 6 | import 'package:danger_dart/danger_util.dart'; 7 | import 'package:mockito/mockito.dart'; 8 | import 'package:test/test.dart'; 9 | import 'package:path/path.dart' show join, current; 10 | import 'package:danger_core/src/models/danger_core_constants.dart'; 11 | 12 | import '../base/test_command_runner.dart'; 13 | import '../mock_util.mocks.dart'; 14 | 15 | void main() { 16 | group('ProcessCommand', () { 17 | late MockDangerUtil _mockDangerUtil; 18 | late MockStdin _mockStdin; 19 | late MockStdout _mockStdout; 20 | late ProcessCommand _processCommand; 21 | late TestCommandRunner _commandRunner; 22 | 23 | setUp(() { 24 | _mockDangerUtil = MockDangerUtil(); 25 | _mockStdin = MockStdin(); 26 | _mockStdout = MockStdout(); 27 | _processCommand = 28 | ProcessCommand(_mockDangerUtil, _mockStdin, _mockStdout); 29 | _commandRunner = TestCommandRunner.create(_processCommand); 30 | 31 | when(_mockDangerUtil.getDangerJSMetaData(any, shell: anyNamed('shell'))) 32 | .thenAnswer((realInvocation) async { 33 | return DangerJSMetadata(executable: '/usr/local/danger-js'); 34 | }); 35 | 36 | when(_mockDangerUtil.spawnFile(captureAny, captureAny, captureAny)) 37 | .thenAnswer((realInvocation) async {}); 38 | 39 | when(_mockDangerUtil.getDangerFile(any)) 40 | .thenReturn('mock_danger_file.dart'); 41 | 42 | when(_mockDangerUtil.getScriptFilePath()) 43 | .thenReturn('danger/danger_dart.dart'); 44 | 45 | when(_mockStdin.transform(any)).thenAnswer((realInvocation) { 46 | final fixtureFile = 47 | File(join(current, 'test', 'fixtures', 'bbc-dsl-input.json')); 48 | 49 | return Stream.value('danger://dsl/${fixtureFile.path}'); 50 | }); 51 | 52 | when(_mockStdout.flush()).thenAnswer((realInvocation) async {}); 53 | }); 54 | 55 | test('Should pass dangerfile', () async { 56 | await _commandRunner.run( 57 | ['process', '--dangerfile', 'bin/danger_dart.dart', '--verbose']); 58 | 59 | final result = 60 | verify(_mockDangerUtil.spawnFile(captureAny, captureAny, captureAny)) 61 | .captured; 62 | final url = result[0]; 63 | expect(url.path.toString(), endsWith('/bin/danger_dart.dart')); 64 | }); 65 | 66 | test('Should pass sendPort in message key DANGER_SEND_PORT_MESSAGE_KEY', 67 | () async { 68 | await _commandRunner.run( 69 | ['process', '--dangerfile', 'bin/danger_dart.dart', '--verbose']); 70 | 71 | final result = 72 | verify(_mockDangerUtil.spawnFile(captureAny, captureAny, captureAny)) 73 | .captured; 74 | final message = result[1]; 75 | 76 | final sendPort = message[DANGER_SEND_PORT_MESSAGE_KEY]; 77 | expect(sendPort, TypeMatcher()); 78 | }); 79 | 80 | test('Should pass DSL in message key DANGER_DSL_MESSAGE_KEY', () async { 81 | await _commandRunner.run( 82 | ['process', '--dangerfile', 'bin/danger_dart.dart', '--verbose']); 83 | 84 | final result = 85 | verify(_mockDangerUtil.spawnFile(captureAny, captureAny, captureAny)) 86 | .captured; 87 | final message = result[1]; 88 | 89 | final dslJSON = message[DANGER_DSL_MESSAGE_KEY]; 90 | expect(dslJSON, isNotNull); 91 | 92 | final dsl = DangerRawJSONDSL.fromJson(dslJSON); 93 | 94 | /// check this according to fixture 95 | expect(dsl, isNotNull); 96 | expect(dsl.github, isNull); 97 | expect(dsl.bitbucketCloud, isNotNull); 98 | }); 99 | 100 | test('Should write and flush stdout after running dangerfile', () async { 101 | await _commandRunner.run( 102 | ['process', '--dangerfile', 'bin/danger_dart.dart', '--verbose']); 103 | 104 | verify(_mockStdout.flush()).called(1); 105 | 106 | final result = verify(_mockStdout.write(captureAny)).captured; 107 | final urlResult = result[0]; 108 | final fileResult = 109 | File(urlResult.toString().substring('danger-results:/'.length)); 110 | final str = fileResult.readAsStringSync(); 111 | expect( 112 | str, 113 | equals( 114 | '{"fails":[],"warnings":[],"messages":[],"markdowns":[],"meta":{"runtimeName":"Danger Dart","runtimeHref":"https://danger.systems/dart"}}')); 115 | }); 116 | }); 117 | } 118 | -------------------------------------------------------------------------------- /packages/danger_dart/test/danger_dart_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | void main() { 4 | group('danger_dart_test', () { 5 | test('This should be fail', () { 6 | expect(true, equals(false)); 7 | }, skip: true); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /packages/danger_dart/test/danger_util_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/args.dart'; 2 | import 'package:args/src/arg_results.dart'; 3 | import 'package:danger_dart/danger_util.dart'; 4 | import 'package:test/test.dart'; 5 | import 'package:danger_core/src/models/danger_results.dart'; 6 | import 'package:danger_core/src/models/violation.dart'; 7 | 8 | import 'package:path/path.dart' show current, join; 9 | 10 | ArgResults _createArgsResult(Map args) { 11 | final argParser = ArgParser(); 12 | argParser.addOption('dangerfile'); 13 | argParser.addOption('danger-js-path'); 14 | return newArgResults(argParser, args, null, null, [], []); 15 | } 16 | 17 | void main() { 18 | late DangerUtil dangerUtil; 19 | 20 | setUp(() { 21 | dangerUtil = DangerUtil(); 22 | }); 23 | 24 | group('getDangerJSMetaData', () { 25 | test('should find danger-js from args danger-js-path (relative path)', 26 | () async { 27 | final metaData = await dangerUtil.getDangerJSMetaData(_createArgsResult( 28 | {'danger-js-path': 'test/fixtures/mock_dangerjs.sh'})); 29 | 30 | expect(metaData.executable, equals('test/fixtures/mock_dangerjs.sh')); 31 | }); 32 | 33 | test('should find danger-js from args danger-js-path (absolute path)', 34 | () async { 35 | final metaData = await dangerUtil.getDangerJSMetaData(_createArgsResult({ 36 | 'danger-js-path': join(current, 'test', 'fixtures', 'mock_dangerjs.sh') 37 | })); 38 | 39 | expect(metaData.executable, 40 | equals(join(current, 'test', 'fixtures', 'mock_dangerjs.sh'))); 41 | }); 42 | 43 | test( 44 | 'should throw an error when cannot find danger-js from args danger-js-path', 45 | () { 46 | expectLater( 47 | dangerUtil.getDangerJSMetaData(_createArgsResult( 48 | {'danger-js-path': 'this_is_not_danger_js.sh'})), 49 | throwsA( 50 | equals('please provide the corrent path for --danger-js-path'))); 51 | }); 52 | 53 | test('should find default danger-js from env', () { 54 | // TODO: Cannot find the way to override env (maybe need to decouple whichSync) 55 | // Skip this for now. 56 | }, skip: true); 57 | 58 | test('should throw an error when found danger ruby instead of danger-js', 59 | () { 60 | expectLater( 61 | dangerUtil.getDangerJSMetaData(_createArgsResult( 62 | {'danger-js-path': 'test/fixtures/mock_dangeruby.sh'})), 63 | throwsA(equals( 64 | 'Your danger is not JS version, You need to uninstall danger ruby, or using --danger-js-path instead'))); 65 | }); 66 | }); 67 | 68 | group('getDangerFile', () { 69 | test('should be able to get dangerfile from args (relative path)', () { 70 | final result = dangerUtil.getDangerFile( 71 | _createArgsResult({'dangerfile': 'bin/danger_dart.dart'})); 72 | expect(result, 'bin/danger_dart.dart'); 73 | }); 74 | test('should be able to get dangerfile from args (absolute path)', () { 75 | final result = dangerUtil.getDangerFile(_createArgsResult( 76 | {'dangerfile': join(current, 'bin', 'danger_dart.dart')})); 77 | expect(result, join(current, 'bin', 'danger_dart.dart')); 78 | }); 79 | test('should throw error when cannot find dangerfile', () { 80 | expectLater( 81 | () => dangerUtil.getDangerFile( 82 | _createArgsResult({'dangerfile': 'not_a_dangerfile.dart'})), 83 | throwsA(equals('dangerfile not found'))); 84 | }); 85 | }); 86 | 87 | group('sortDangerResult', () { 88 | late DangerResults _result; 89 | 90 | setUp(() { 91 | _result = DangerResults(fails: [ 92 | Violation(message: 'fail on test 1 line 10', file: 'test1', line: 10), 93 | Violation(message: 'fail on test 2 line 5', file: 'test2', line: 5), 94 | Violation(message: 'fail on test 1 line 15', file: 'test1', line: 15), 95 | Violation(message: 'summary message'), 96 | ], messages: [ 97 | Violation( 98 | message: 'message on test 1 line 20', file: 'test1', line: 20), 99 | Violation(message: 'message on test 2 line 5', file: 'test2', line: 5), 100 | Violation( 101 | message: 'message on test 1 line 15', file: 'test1', line: 15), 102 | Violation(message: 'summary message'), 103 | ], warnings: [ 104 | Violation( 105 | message: 'warning on test 1 line 20', file: 'test1', line: 20), 106 | Violation( 107 | message: 'warning on test 2 line 10', file: 'test2', line: 10), 108 | Violation(message: 'summary message'), 109 | Violation( 110 | message: 'warning on test 2 line 15', file: 'test2', line: 15), 111 | ], markdowns: [ 112 | Violation( 113 | message: 'markdown on test 1 line 20', file: 'test1', line: 20), 114 | Violation(message: 'summary message 2'), 115 | Violation(message: 'summary message'), 116 | Violation( 117 | message: 'markdown on test 2 line 15', file: 'test2', line: 15), 118 | ]); 119 | }); 120 | 121 | test('should sort failures correctly', () { 122 | dangerUtil.sortDangerResult(_result); 123 | 124 | expect(_result.fails[0].message, 'summary message'); 125 | expect(_result.fails[1].message, 'fail on test 1 line 10'); 126 | expect(_result.fails[2].message, 'fail on test 1 line 15'); 127 | expect(_result.fails[3].message, 'fail on test 2 line 5'); 128 | }); 129 | 130 | test('should sort messages correctly', () { 131 | dangerUtil.sortDangerResult(_result); 132 | 133 | expect(_result.messages[0].message, 'summary message'); 134 | expect(_result.messages[1].message, 'message on test 1 line 15'); 135 | expect(_result.messages[2].message, 'message on test 1 line 20'); 136 | expect(_result.messages[3].message, 'message on test 2 line 5'); 137 | }); 138 | 139 | test('should sort warning correctly', () { 140 | dangerUtil.sortDangerResult(_result); 141 | 142 | expect(_result.warnings[0].message, 'summary message'); 143 | expect(_result.warnings[1].message, 'warning on test 1 line 20'); 144 | expect(_result.warnings[2].message, 'warning on test 2 line 10'); 145 | expect(_result.warnings[3].message, 'warning on test 2 line 15'); 146 | }); 147 | 148 | test('should sort markdown correctly', () { 149 | dangerUtil.sortDangerResult(_result); 150 | 151 | expect(_result.markdowns[0].message, 'summary message 2'); 152 | expect(_result.markdowns[1].message, 'summary message'); 153 | expect(_result.markdowns[2].message, 'markdown on test 1 line 20'); 154 | expect(_result.markdowns[3].message, 'markdown on test 2 line 15'); 155 | }); 156 | }); 157 | } 158 | -------------------------------------------------------------------------------- /packages/danger_dart/test/fixtures/mock_dangerjs.sh: -------------------------------------------------------------------------------- 1 | echo "http://danger.systems/js/reference.html" -------------------------------------------------------------------------------- /packages/danger_dart/test/fixtures/mock_dangeruby.sh: -------------------------------------------------------------------------------- 1 | echo "10.6.4" -------------------------------------------------------------------------------- /packages/danger_dart/test/mock_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_dart/danger_util.dart'; 4 | import 'package:mockito/annotations.dart'; 5 | 6 | @GenerateMocks([ 7 | DangerUtil, 8 | Stdin, 9 | Stdout, 10 | ]) 11 | class MockUtil {} 12 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | - Migrate to Dart 3 4 | 5 | ## 1.0.0 6 | 7 | - Supports Null Safety 8 | 9 | ## 0.0.6 10 | 11 | - Handle failure cases 12 | 13 | ## 0.0.5 14 | 15 | - Revarmp architecture 16 | 17 | ## 0.0.4 18 | 19 | - Make `limitMessageCharsPerLine` default at null. 20 | 21 | ## 0.0.3 22 | 23 | - Add parameter `limitMessageCharsPerLine` and default at 1000. 24 | 25 | ## 0.0.2 26 | 27 | - Fix test report case error and golden test error. 28 | 29 | ## 0.0.1 30 | 31 | - Initial version, created by Stagehand 32 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2019 Danger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/README.md: -------------------------------------------------------------------------------- 1 | # Danger Plugin: Dart Test 2 | 3 | [![Pub version](https://img.shields.io/pub/v/danger_plugin_dart_test.svg)](https://pub.dev/packages/danger_plugin_dart_test) 4 | 5 | This plugin will parse the test results, and notify the failure cases. 6 | 7 | ## Usage 8 | 9 | First, you need to prepare test result in json format. 10 | You may either: 11 | 12 | ```bash 13 | $ dart test --reporter json > your_test_results.json 14 | $ flutter test --reporter json > your_test_results.json 15 | ``` 16 | 17 | Adding this plugin to `pubspec.yaml` 18 | 19 | ```yaml 20 | dev_dependencies: 21 | danger_core: 22 | danger_plugin_dart_test: 23 | ``` 24 | 25 | In `dangerfile.dart`, you need to import this, and call `DangerPluginDartTest.processFile` with test result file. 26 | 27 | ```dart 28 | import 'dart:io'; 29 | 30 | import 'package:danger_core/danger_core.dart'; 31 | import 'package:danger_plugin_dart_test/danger_plugin_dart_test.dart'; 32 | 33 | void main() { 34 | final testResultFile = File('your_test_results.json'); 35 | DangerPluginDartTest.processFile(testResultFile); 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/danger_plugin_dart_test.dart: -------------------------------------------------------------------------------- 1 | library danger_plugin_dart_test; 2 | 3 | export './src/danger_plugin_dart_test.dart'; 4 | export './src/models/dart_test_result.dart'; 5 | export './src/reporters/default_inline_test_reporter.dart'; 6 | export './src/reporters/default_test_reporter.dart'; 7 | export './src/reporters/bitbucket_cloud_test_reporter.dart'; 8 | export './src/reporters/bitbucket_cloud_inline_test_reporter.dart'; -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/danger_dart_test_reporter.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 2 | 3 | abstract class DangerDartTestReporter { 4 | void reportToDanger(List errorCases); 5 | } -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/danger_plugin_dart_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_core/danger_core.dart'; 4 | import 'package:danger_plugin_dart_test/src/danger_dart_test_reporter.dart'; 5 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 6 | import 'package:danger_plugin_dart_test/src/models/dart_test_result.dart'; 7 | import 'package:danger_plugin_dart_test/src/reporters/default_test_reporter.dart'; 8 | 9 | import 'package:path/path.dart' show current; 10 | 11 | class DangerPluginDartTest { 12 | /// Reporter could be `DefaultTestReporter`, `DefaultInlineTestReporter`, `BitbucketCloudTestReporter`, or any class extends `DangerDartTestReporter` 13 | static Future processFile(File file, 14 | {String? workingDirectoryPath, 15 | int? limitMessageCharsPerLine, 16 | DangerDartTestReporter? reporter}) async { 17 | if (!file.existsSync()) { 18 | fail('Test report not found, path [${file.path}]'); 19 | return; 20 | } 21 | 22 | final workingPath = workingDirectoryPath ?? current; 23 | 24 | final line = file.readAsLinesSync(); 25 | final results = line 26 | .map((e) => DartTestEvent.fromJsonString(e)) 27 | .whereType(); 28 | 29 | final testSuiteMetaDataByID = {}; 30 | final testMetaDataByID = {}; 31 | final printMessageByID = >{}; 32 | 33 | void addMessageToPrintMessage(String message, int testId) { 34 | if (message.isEmpty) { 35 | return; 36 | } 37 | 38 | String msg; 39 | if (limitMessageCharsPerLine == null) { 40 | msg = message; 41 | } else if (message.length > limitMessageCharsPerLine) { 42 | msg = message.substring(0, limitMessageCharsPerLine) + '...'; 43 | } else { 44 | msg = message; 45 | } 46 | 47 | if (printMessageByID[testId] == null) { 48 | printMessageByID[testId] = [msg]; 49 | } else { 50 | printMessageByID[testId]!.add(msg); 51 | } 52 | } 53 | 54 | for (var result in results) { 55 | if (result is DartTestTestStartEvent) { 56 | testMetaDataByID[result.test.id] = result.test; 57 | } else if (result is DartTestSuiteEvent) { 58 | testSuiteMetaDataByID[result.suite.id] = result.suite; 59 | } else if (result is DartTestMessageEvent) { 60 | if (result.messageType == 'print') { 61 | addMessageToPrintMessage(result.message, result.testID); 62 | } 63 | } else if (result is DartTestErrorEvent) { 64 | addMessageToPrintMessage(result.error, result.testID); 65 | addMessageToPrintMessage(result.stackTrace, result.testID); 66 | } 67 | } 68 | 69 | // EnumValues({"error": Result.ERROR, "failure": Result.FAILURE, "success": Result.SUCCESS}); 70 | 71 | final failureList = results 72 | .whereType() 73 | .where((result) => (result.result != 'success')) 74 | .map((result) { 75 | final testMetaData = testMetaDataByID[result.testID]; 76 | final printMessage = printMessageByID[result.testID] ?? []; 77 | 78 | String? fileName; 79 | int? lineNo; 80 | String? testName; 81 | 82 | if (testMetaData != null) { 83 | final url = testMetaData.url; 84 | if (url != null && !url.startsWith('package:')) { 85 | fileName = url; 86 | lineNo = testMetaData.line ?? 0; 87 | } else if (testMetaData.rootUrl != null) { 88 | fileName = testMetaData.rootUrl!; 89 | lineNo = testMetaData.rootLine ?? 0; 90 | } else { 91 | final suiteMetaData = testSuiteMetaDataByID[testMetaData.suiteID]; 92 | if (suiteMetaData != null && suiteMetaData.path != null) { 93 | fileName = suiteMetaData.path!; 94 | lineNo = 0; 95 | } 96 | } 97 | 98 | if (fileName != null) { 99 | fileName = fileName.replaceFirst('file://', ''); 100 | 101 | if (fileName.startsWith(workingPath)) { 102 | fileName = fileName.substring(workingPath.length + 1); 103 | } 104 | } 105 | 106 | testName = testMetaData.name; 107 | } 108 | 109 | if (fileName == null || lineNo == null || testName == null) { 110 | return null; 111 | } 112 | 113 | return DangerDartErrorCase( 114 | fileName: fileName, 115 | lineNo: lineNo, 116 | message: printMessage.join('\n\n'), 117 | testName: testName, 118 | ); 119 | }) 120 | .whereType() 121 | .toList(); 122 | 123 | if (failureList.isNotEmpty) { 124 | (reporter ?? DefaultTestReporter()).reportToDanger(failureList); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/models/danger_dart_error_case.dart: -------------------------------------------------------------------------------- 1 | class DangerDartErrorCase { 2 | final String fileName; 3 | final int lineNo; 4 | final String testName; 5 | final String message; 6 | 7 | DangerDartErrorCase( 8 | {required this.fileName, 9 | required this.lineNo, 10 | required this.testName, 11 | required this.message}); 12 | } 13 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/reporters/bitbucket_cloud_inline_test_reporter.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: unnecessary_string_escapes 2 | 3 | import 'package:danger_core/danger_core.dart'; 4 | import 'package:danger_plugin_dart_test/src/danger_dart_test_reporter.dart'; 5 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 6 | 7 | class BitbucketCloudInlineTestReporter extends DangerDartTestReporter { 8 | @override 9 | void reportToDanger(List errorCases) { 10 | fail( 11 | '${errorCases.length} Tests have failed, see below for more information.'); 12 | 13 | final modifiedFiles = 14 | (danger.git.modifiedFiles + danger.git.createdFiles).toSet(); 15 | 16 | final normalCases = errorCases 17 | .where((element) => (!modifiedFiles.contains(element.fileName))); 18 | final inlineCases = 19 | errorCases.where((element) => modifiedFiles.contains(element.fileName)); 20 | 21 | if (normalCases.isNotEmpty) { 22 | var testResultsTable = 23 | '\n→ \n\n \n\n\n \n\n\n#### ❗️\[danger_plugin_dart_test\] Error Messages ️❗️\n\n---\n\n'; 24 | 25 | for (var element in normalCases) { 26 | testResultsTable += 27 | '\n\n❌ Fail in \`${element.fileName}:${element.lineNo}\`'; 28 | 29 | testResultsTable += '\n\nName \`${element.testName}\`\n'; 30 | 31 | testResultsTable += 32 | '\n\n#### Message\n\n\`\`\`\n${element.message}\n\`\`\`\n\n'; 33 | 34 | testResultsTable += '\n\n---\n\n'; 35 | } 36 | 37 | markdown(testResultsTable); 38 | } 39 | 40 | for (var element in inlineCases) { 41 | fail('''Test Failed 42 | > Name: `${element.testName}` 43 | #### Message 44 | ``` 45 | ${element.message} 46 | ``` 47 | ''', file: element.fileName, line: element.lineNo); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/reporters/bitbucket_cloud_test_reporter.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: unnecessary_string_escapes 2 | 3 | import 'package:danger_core/danger_core.dart'; 4 | import 'package:danger_plugin_dart_test/src/danger_dart_test_reporter.dart'; 5 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 6 | 7 | class BitbucketCloudTestReporter extends DangerDartTestReporter { 8 | @override 9 | void reportToDanger(List errorCases) { 10 | fail( 11 | '${errorCases.length} Tests have failed, see below for more information.'); 12 | 13 | var testResultsTable = 14 | '\n→ \n\n \n\n\n \n\n\n#### ❗️\[danger_plugin_dart_test\] Error Messages ️❗️\n\n---\n\n'; 15 | 16 | for (var element in errorCases) { 17 | testResultsTable += 18 | '\n\n❌ Fail in \`${element.fileName}:${element.lineNo}\`'; 19 | 20 | testResultsTable += '\n\nName \`${element.testName}\`\n'; 21 | 22 | testResultsTable += 23 | '\n\n#### Message\n\n\`\`\`\n${element.message}\n\`\`\`\n\n'; 24 | 25 | testResultsTable += '\n\n---\n\n'; 26 | } 27 | 28 | markdown(testResultsTable); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/reporters/default_inline_test_reporter.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_plugin_dart_test/src/danger_dart_test_reporter.dart'; 3 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 4 | 5 | class DefaultInlineTestReporter extends DangerDartTestReporter { 6 | @override 7 | void reportToDanger(List errorCases) { 8 | fail('Found ${errorCases.length} failure cases.'); 9 | for (var element in errorCases) { 10 | fail('''${element.fileName}#L${element.lineNo} 11 | Name: ${element.testName} 12 | ``` 13 | ${element.message} 14 | ``` 15 | ''', file: element.fileName, line: element.lineNo); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/lib/src/reporters/default_test_reporter.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_plugin_dart_test/src/danger_dart_test_reporter.dart'; 3 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 4 | 5 | class DefaultTestReporter extends DangerDartTestReporter { 6 | DefaultTestReporter(); 7 | 8 | @override 9 | void reportToDanger(List errorCases) { 10 | for (var element in errorCases) { 11 | fail('''${element.fileName}#L${element.lineNo} 12 | Name: ${element.testName} 13 | ``` 14 | ${element.message} 15 | ``` 16 | '''); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_plugin_dart_test 2 | description: A Danger Dart plugin to process test result. 3 | version: 2.0.0 4 | homepage: https://github.com/danger/dart 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | path: ^1.8.3 11 | # danger_core: ">= 1.0.0 < 2.0.0" 12 | danger_core: 13 | path: ../danger_core 14 | 15 | dev_dependencies: 16 | lints: ^2.1.1 17 | test: ^1.24.7 18 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/test/danger_plugin_dart_test_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:danger_plugin_dart_test/danger_plugin_dart_test.dart'; 4 | import 'package:danger_plugin_dart_test/src/danger_dart_test_reporter.dart'; 5 | import 'package:danger_plugin_dart_test/src/models/danger_dart_error_case.dart'; 6 | import 'package:test/test.dart'; 7 | import 'package:path/path.dart' show join, current; 8 | 9 | class _MockDangerDartTestReporter extends DangerDartTestReporter { 10 | List errorCases = []; 11 | @override 12 | void reportToDanger(List errorCases) { 13 | this.errorCases = errorCases; 14 | } 15 | } 16 | 17 | void main() { 18 | group('danger_plugin_dart_test', () { 19 | late _MockDangerDartTestReporter reporter; 20 | 21 | setUp(() { 22 | reporter = _MockDangerDartTestReporter(); 23 | }); 24 | 25 | test('should process success case correctly', () { 26 | final fixtureFile = 27 | File(join(current, 'test', 'fixtures', 'success_results.json')); 28 | 29 | DangerPluginDartTest.processFile(fixtureFile, 30 | reporter: reporter, 31 | workingDirectoryPath: 32 | '/Users/core/Documents/project/danger.dart/packages/danger_core'); 33 | 34 | expect(reporter.errorCases.length, equals(0)); 35 | }); 36 | 37 | test('should process failure case correctly', () { 38 | final fixtureFile = 39 | File(join(current, 'test', 'fixtures', 'fail_results.json')); 40 | 41 | DangerPluginDartTest.processFile(fixtureFile, 42 | reporter: reporter, 43 | workingDirectoryPath: 44 | '/Users/core/Documents/project/danger.dart/packages/danger_core'); 45 | 46 | expect(reporter.errorCases.length, equals(1)); 47 | 48 | final result = reporter.errorCases.first; 49 | expect( 50 | result.fileName, equals('test/parser/bitbucket_cloud_dsl_test.dart')); 51 | expect(result.lineNo, equals(10)); 52 | expect(result.message, equals('''Expected: <801> 53 | Actual: <80> 54 | 55 | 56 | package:test_api expect 57 | test/parser/bitbucket_cloud_dsl_test.dart 21:7 main.. 58 | ''')); 59 | }); 60 | 61 | test('should process error case correctly', () { 62 | final fixtureFile = 63 | File(join(current, 'test', 'fixtures', 'error_results.json')); 64 | 65 | DangerPluginDartTest.processFile(fixtureFile, 66 | reporter: reporter, 67 | workingDirectoryPath: 68 | '/Users/core/Documents/project/danger.dart/packages/danger_core'); 69 | 70 | expect(reporter.errorCases.length, equals(1)); 71 | 72 | final result = reporter.errorCases.first; 73 | expect( 74 | result.fileName, equals('test/parser/bitbucket_cloud_dsl_test.dart')); 75 | expect(result.lineNo, equals(10)); 76 | expect( 77 | result.message, 78 | startsWith( 79 | '''Failed to load "/Users/core/Documents/work/hello/test/utils/period_time_test.dart": 80 | Compilation failed 81 | Test: /Users/core/Documents/work/hello/test/utils/period_time_test.dart 82 | Shell: /Users/core/fvm/versions/2.0.4/bin/cache/artifacts/engine/darwin-x64/flutter_tester 83 | 84 | ''')); 85 | }); 86 | 87 | test('should process error from golden testcase correctly', () { 88 | final fixtureFile = 89 | File(join(current, 'test', 'fixtures', 'error_golden_test.json')); 90 | 91 | DangerPluginDartTest.processFile(fixtureFile, 92 | reporter: reporter, 93 | workingDirectoryPath: 94 | '/Users/core/Documents/project/danger.dart/packages/danger_core'); 95 | 96 | expect(reporter.errorCases.length, equals(1)); 97 | 98 | final result = reporter.errorCases.first; 99 | expect( 100 | result.fileName, equals('test/parser/bitbucket_cloud_dsl_test.dart')); 101 | expect(result.lineNo, equals(10)); 102 | expect( 103 | result.message, 104 | startsWith( 105 | '''══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ 106 | The following assertion was thrown while running async test code: 107 | Golden "goldens/test/default.iphone11.png": Pixel test failed, 12.38% diff detected. 108 | Failure feedback can be found at 109 | /Users/core/Documents/work/hello/test/goldens/pages/failures 110 | ''')); 111 | }); 112 | }); 113 | } 114 | -------------------------------------------------------------------------------- /packages/danger_plugin_dart_test/test/fixtures/success_results.json: -------------------------------------------------------------------------------- 1 | {"protocolVersion":"0.1.1","runnerVersion":"1.16.5","pid":14872,"type":"start","time":0} 2 | {"suite":{"id":0,"platform":"vm","path":"test/danger_isolate_receiver_test.dart"},"type":"suite","time":0} 3 | {"test":{"id":1,"name":"loading test/danger_isolate_receiver_test.dart","suiteID":0,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":4} 4 | {"suite":{"id":2,"platform":"vm","path":"test/danger_cross_isolate_test.dart"},"type":"suite","time":16} 5 | {"test":{"id":3,"name":"loading test/danger_cross_isolate_test.dart","suiteID":2,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":16} 6 | {"suite":{"id":4,"platform":"vm","path":"test/danger_isolate_sender_test.dart"},"type":"suite","time":16} 7 | {"test":{"id":5,"name":"loading test/danger_isolate_sender_test.dart","suiteID":4,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":17} 8 | {"suite":{"id":6,"platform":"vm","path":"test/parser/bitbucket_cloud_dsl_test.dart"},"type":"suite","time":19} 9 | {"test":{"id":7,"name":"loading test/parser/bitbucket_cloud_dsl_test.dart","suiteID":6,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":19} 10 | {"count":4,"type":"allSuites","time":19} 11 | {"testID":7,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":3336} 12 | {"group":{"id":8,"suiteID":6,"parentID":null,"name":"","metadata":{"skip":false,"skipReason":null},"testCount":1,"line":null,"column":null,"url":null},"type":"group","time":3343} 13 | {"group":{"id":9,"suiteID":6,"parentID":8,"name":"bitbucket_cloud_dsl","metadata":{"skip":false,"skipReason":null},"testCount":1,"line":9,"column":3,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/parser/bitbucket_cloud_dsl_test.dart"},"type":"group","time":3343} 14 | {"test":{"id":10,"name":"bitbucket_cloud_dsl should be able to parse correctly","suiteID":6,"groupIDs":[8,9],"metadata":{"skip":false,"skipReason":null},"line":10,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/parser/bitbucket_cloud_dsl_test.dart"},"type":"testStart","time":3344} 15 | {"testID":1,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":3351} 16 | {"group":{"id":11,"suiteID":0,"parentID":null,"name":"","metadata":{"skip":false,"skipReason":null},"testCount":5,"line":null,"column":null,"url":null},"type":"group","time":3352} 17 | {"group":{"id":12,"suiteID":0,"parentID":11,"name":"DangerIsolateReceiver","metadata":{"skip":false,"skipReason":null},"testCount":5,"line":7,"column":3,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_receiver_test.dart"},"type":"group","time":3352} 18 | {"test":{"id":13,"name":"DangerIsolateReceiver toMessage() should return correctly","suiteID":0,"groupIDs":[11,12],"metadata":{"skip":false,"skipReason":null},"line":16,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_receiver_test.dart"},"type":"testStart","time":3353} 19 | {"testID":3,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":3359} 20 | {"group":{"id":14,"suiteID":2,"parentID":null,"name":"","metadata":{"skip":false,"skipReason":null},"testCount":5,"line":null,"column":null,"url":null},"type":"group","time":3360} 21 | {"group":{"id":15,"suiteID":2,"parentID":14,"name":"Cross isolate","metadata":{"skip":false,"skipReason":null},"testCount":5,"line":9,"column":3,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_cross_isolate_test.dart"},"type":"group","time":3360} 22 | {"test":{"id":16,"name":"Cross isolate should pass message correctly","suiteID":2,"groupIDs":[14,15],"metadata":{"skip":false,"skipReason":null},"line":21,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_cross_isolate_test.dart"},"type":"testStart","time":3360} 23 | {"testID":5,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":3368} 24 | {"group":{"id":17,"suiteID":4,"parentID":null,"name":"","metadata":{"skip":false,"skipReason":null},"testCount":6,"line":null,"column":null,"url":null},"type":"group","time":3369} 25 | {"group":{"id":18,"suiteID":4,"parentID":17,"name":"DangerIsolateSender","metadata":{"skip":false,"skipReason":null},"testCount":6,"line":13,"column":3,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"group","time":3369} 26 | {"test":{"id":19,"name":"DangerIsolateSender should initialize correctly","suiteID":4,"groupIDs":[17,18],"metadata":{"skip":false,"skipReason":null},"line":32,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"testStart","time":3369} 27 | {"testID":13,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3392} 28 | {"test":{"id":20,"name":"DangerIsolateReceiver should add message to dangerResults","suiteID":0,"groupIDs":[11,12],"metadata":{"skip":false,"skipReason":null},"line":23,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_receiver_test.dart"},"type":"testStart","time":3394} 29 | {"testID":20,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3401} 30 | {"test":{"id":21,"name":"DangerIsolateReceiver should add warn to dangerResults","suiteID":0,"groupIDs":[11,12],"metadata":{"skip":false,"skipReason":null},"line":35,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_receiver_test.dart"},"type":"testStart","time":3401} 31 | {"testID":19,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3402} 32 | {"test":{"id":22,"name":"DangerIsolateSender should add message violation correctly","suiteID":4,"groupIDs":[17,18],"metadata":{"skip":false,"skipReason":null},"line":38,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"testStart","time":3402} 33 | {"testID":21,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3403} 34 | {"test":{"id":23,"name":"DangerIsolateReceiver should add fail to dangerResults","suiteID":0,"groupIDs":[11,12],"metadata":{"skip":false,"skipReason":null},"line":47,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_receiver_test.dart"},"type":"testStart","time":3403} 35 | {"testID":23,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3405} 36 | {"test":{"id":24,"name":"DangerIsolateReceiver should add markdown to dangerResults","suiteID":0,"groupIDs":[11,12],"metadata":{"skip":false,"skipReason":null},"line":59,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_receiver_test.dart"},"type":"testStart","time":3405} 37 | {"testID":24,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3408} 38 | {"testID":22,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3416} 39 | {"test":{"id":25,"name":"DangerIsolateSender should add warn violation correctly","suiteID":4,"groupIDs":[17,18],"metadata":{"skip":false,"skipReason":null},"line":45,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"testStart","time":3416} 40 | {"testID":25,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3418} 41 | {"test":{"id":26,"name":"DangerIsolateSender should add fail violation correctly","suiteID":4,"groupIDs":[17,18],"metadata":{"skip":false,"skipReason":null},"line":51,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"testStart","time":3418} 42 | {"testID":26,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3420} 43 | {"test":{"id":27,"name":"DangerIsolateSender should add markdown violation correctly","suiteID":4,"groupIDs":[17,18],"metadata":{"skip":false,"skipReason":null},"line":58,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"testStart","time":3421} 44 | {"testID":27,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3422} 45 | {"test":{"id":28,"name":"DangerIsolateSender should add multiple violations correctly","suiteID":4,"groupIDs":[17,18],"metadata":{"skip":false,"skipReason":null},"line":65,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_isolate_sender_test.dart"},"type":"testStart","time":3423} 46 | {"testID":28,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3427} 47 | {"testID":10,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3430} 48 | {"testID":16,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3452} 49 | {"test":{"id":29,"name":"Cross isolate should pass warning correctly","suiteID":2,"groupIDs":[14,15],"metadata":{"skip":false,"skipReason":null},"line":31,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_cross_isolate_test.dart"},"type":"testStart","time":3452} 50 | {"testID":29,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3497} 51 | {"test":{"id":30,"name":"Cross isolate should pass failure correctly","suiteID":2,"groupIDs":[14,15],"metadata":{"skip":false,"skipReason":null},"line":41,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_cross_isolate_test.dart"},"type":"testStart","time":3498} 52 | {"testID":30,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3545} 53 | {"test":{"id":31,"name":"Cross isolate should pass markdown correctly","suiteID":2,"groupIDs":[14,15],"metadata":{"skip":false,"skipReason":null},"line":50,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_cross_isolate_test.dart"},"type":"testStart","time":3545} 54 | {"testID":31,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3592} 55 | {"test":{"id":32,"name":"Cross isolate mix result","suiteID":2,"groupIDs":[14,15],"metadata":{"skip":false,"skipReason":null},"line":60,"column":5,"url":"file:///Users/core/Documents/project/danger.dart/packages/danger_core/test/danger_cross_isolate_test.dart"},"type":"testStart","time":3592} 56 | {"testID":32,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":3642} 57 | {"success":true,"type":"done","time":3645} 58 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | # Omit commiting pubspec.lock for library packages: 6 | # https://dart.dev/guides/libraries/private-files#pubspeclock 7 | pubspec.lock 8 | 9 | # Conventional directory for build outputs 10 | build/ 11 | 12 | # Directory created by dartdoc 13 | doc/api/ 14 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | - Migrate to Dart 3 4 | 5 | ## 1.0.0 6 | 7 | - Supports Null Safety 8 | 9 | ## 0.0.1 10 | 11 | - Initial version, created by Stagehand 12 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2019 Danger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/README.md: -------------------------------------------------------------------------------- 1 | # Danger Plugin: Golden Reporter 2 | 3 | [![Pub version](https://img.shields.io/pub/v/danger_plugin_golden_reporter.svg)](https://pub.dev/packages/danger_plugin_golden_reporter) 4 | 5 | This plugin will report created and modified golden results. 6 | 7 | ## Usage 8 | 9 | Adding this plugin to `pubspec.yaml` 10 | 11 | ```yaml 12 | dev_dependencies: 13 | danger_core: 14 | danger_plugin_golden_reporter: 15 | ``` 16 | 17 | In `dangerfile.dart`, you need to import this, and call `DangerPluginGoldenReporter.report` with given golden result path. 18 | 19 | ```dart 20 | import 'dart:io'; 21 | 22 | import 'package:danger_core/danger_core.dart'; 23 | import 'package:danger_plugin_golden_reporter/danger_plugin_golden_reporter.dart'; 24 | 25 | void main() { 26 | DangerPluginGoldenReporter.report('test/goldens'); 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | include: package:lints/recommended.yaml 4 | 5 | linter: 6 | rules: 7 | - prefer_relative_imports 8 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/lib/danger_plugin_golden_reporter.dart: -------------------------------------------------------------------------------- 1 | /// Support for doing something awesome. 2 | /// 3 | /// More dartdocs go here. 4 | library danger_plugin_golden_reporter; 5 | 6 | export 'src/danger_plugin_golden_reporter.dart'; 7 | export 'src/golden_reporter.dart'; 8 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/lib/src/danger_plugin_golden_reporter.dart: -------------------------------------------------------------------------------- 1 | import 'impl/github_golden_reporter.dart'; 2 | import 'golden_reporter.dart'; 3 | import 'package:danger_core/danger_core.dart'; 4 | 5 | class DangerPluginGoldenReporter { 6 | DangerPluginGoldenReporter._(); 7 | 8 | static void report(String path, 9 | {GoldenReporter reporter = const GithubGoldenReporter()}) { 10 | final modifiedFileMessages = danger.git.modifiedFiles 11 | .where( 12 | (element) => element.startsWith(path) && element.endsWith('.png')) 13 | .map((e) => reporter.reportForModifiedFile(e)); 14 | 15 | final createdFileMessages = danger.git.createdFiles 16 | .where( 17 | (element) => element.startsWith(path) && element.endsWith('.png')) 18 | .map((e) => reporter.reportForCreatedFile(e)); 19 | 20 | if (modifiedFileMessages.isNotEmpty) { 21 | reporter.reportAllModifiedFiles(modifiedFileMessages.toList()); 22 | } 23 | 24 | if (createdFileMessages.isNotEmpty) { 25 | reporter.reportAllCreatedFiles(createdFileMessages.toList()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/lib/src/golden_reporter.dart: -------------------------------------------------------------------------------- 1 | abstract class GoldenReporter { 2 | String reportForModifiedFile(String filePath); 3 | String reportForCreatedFile(String filePath); 4 | 5 | void reportAllModifiedFiles(List messages); 6 | void reportAllCreatedFiles(List messages); 7 | } 8 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/lib/src/impl/github_golden_reporter.dart: -------------------------------------------------------------------------------- 1 | import '../golden_reporter.dart'; 2 | import 'package:danger_core/danger_core.dart'; 3 | 4 | class GithubGoldenReporter implements GoldenReporter { 5 | const GithubGoldenReporter(); 6 | 7 | @override 8 | String reportForCreatedFile(String filePath) { 9 | final headSHA = danger.github.pr.head.sha; 10 | final repoOwner = danger.github.thisPR.owner; 11 | final repoName = danger.github.thisPR.repo; 12 | return ''' 13 | 14 | $filePath 15 | 16 | 17 | 18 | 19 | 20 | 21 | '''; 22 | } 23 | 24 | @override 25 | String reportForModifiedFile(String filePath) { 26 | final baseSHA = danger.github.pr.base.sha; 27 | final headSHA = danger.github.pr.head.sha; 28 | final repoOwner = danger.github.thisPR.owner; 29 | final repoName = danger.github.thisPR.repo; 30 | 31 | return ''' 32 | 33 | $filePath 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | '''; 44 | } 45 | 46 | @override 47 | void reportAllCreatedFiles(List messages) { 48 | final message = messages.join('\n'); 49 | markdown('''#### Found ${messages.length} Created Golden Images 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | $message 58 | 59 |
New Image
'''); 60 | } 61 | 62 | @override 63 | void reportAllModifiedFiles(List messages) { 64 | final message = messages.join('\n'); 65 | markdown('''#### Found ${messages.length} Modified Golden Images 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | $message 75 | 76 |
Old ImageNew Image
'''); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_plugin_golden_reporter 2 | description: A Danger Dart plugin to display golden images on pull requests. 3 | version: 2.0.0 4 | homepage: https://github.com/danger/dart 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | # danger_core: ">= 1.0.0 < 2.0.0" 11 | danger_core: 12 | path: ../danger_core 13 | 14 | dev_dependencies: 15 | lints: ^2.1.1 16 | test: ^1.20.2 17 | mockito: ^5.1.0 18 | build_runner: ^2.1.8 19 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/test/danger_plugin_golden_reporter_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_core/src/utils/danger_isolate_sender_mock.dart'; 3 | import 'package:danger_plugin_golden_reporter/danger_plugin_golden_reporter.dart'; 4 | import 'package:mockito/mockito.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import 'mock_utils.mocks.dart'; 8 | 9 | void main() { 10 | late DangerIsolateSenderMock dangerIsolateSenderMock; 11 | late MockDangerJSONDSL mockDangerJSONDSL; 12 | late MockGitJSONDSL mockGitJSONDSL; 13 | late MockGoldenReporter mockReporter; 14 | 15 | setUp(() { 16 | mockReporter = MockGoldenReporter(); 17 | mockDangerJSONDSL = MockDangerJSONDSL(); 18 | mockGitJSONDSL = MockGitJSONDSL(); 19 | 20 | dangerIsolateSenderMock = Danger.setupWithMock(); 21 | dangerIsolateSenderMock.dangerJSONDSL = mockDangerJSONDSL; 22 | 23 | when(mockDangerJSONDSL.git).thenReturn(mockGitJSONDSL); 24 | when(mockGitJSONDSL.createdFiles).thenReturn([]); 25 | when(mockGitJSONDSL.modifiedFiles).thenReturn([]); 26 | 27 | when(mockReporter.reportForCreatedFile(any)) 28 | .thenReturn("reportForCreatedFile"); 29 | when(mockReporter.reportForModifiedFile(any)) 30 | .thenReturn("reportForModifiedFile"); 31 | }); 32 | 33 | group('path', () { 34 | group('createdFiles', () { 35 | test('should filter out files that is not png', () { 36 | when(mockGitJSONDSL.createdFiles) 37 | .thenReturn(['test/goldens/foo.png', 'test/goldens/bar.text']); 38 | DangerPluginGoldenReporter.report('test/goldens', 39 | reporter: mockReporter); 40 | 41 | final result = verify(mockReporter.reportForCreatedFile(captureAny)); 42 | result.called(1); 43 | 44 | expect(result.captured.single, 'test/goldens/foo.png'); 45 | }); 46 | 47 | test('should filter out files that is in different path', () { 48 | when(mockGitJSONDSL.createdFiles) 49 | .thenReturn(['test/goldens/foo.png', 'test/gold2ens/bar.png']); 50 | DangerPluginGoldenReporter.report('test/goldens', 51 | reporter: mockReporter); 52 | 53 | final result = verify(mockReporter.reportForCreatedFile(captureAny)); 54 | result.called(1); 55 | 56 | expect(result.captured.single, 'test/goldens/foo.png'); 57 | }); 58 | }); 59 | group('modifiedFiles', () { 60 | test('should filter out files that is not png', () { 61 | when(mockGitJSONDSL.modifiedFiles) 62 | .thenReturn(['test/goldens/foo.png', 'test/goldens/bar.text']); 63 | DangerPluginGoldenReporter.report('test/goldens', 64 | reporter: mockReporter); 65 | 66 | final result = verify(mockReporter.reportForModifiedFile(captureAny)); 67 | result.called(1); 68 | 69 | expect(result.captured.single, 'test/goldens/foo.png'); 70 | }); 71 | 72 | test('should filter out files that is in different path', () { 73 | when(mockGitJSONDSL.modifiedFiles) 74 | .thenReturn(['test/goldens/foo.png', 'test/gold2ens/bar.png']); 75 | DangerPluginGoldenReporter.report('test/goldens', 76 | reporter: mockReporter); 77 | 78 | final result = verify(mockReporter.reportForModifiedFile(captureAny)); 79 | result.called(1); 80 | 81 | expect(result.captured.single, 'test/goldens/foo.png'); 82 | }); 83 | }); 84 | }); 85 | 86 | group('createdFiles', () { 87 | test( 88 | 'should not call reportForCreatedFile, and reportAllCreatedFiles when there is no created file', 89 | () { 90 | DangerPluginGoldenReporter.report('.', reporter: mockReporter); 91 | 92 | verifyNever(mockReporter.reportForCreatedFile(any)); 93 | verifyNever(mockReporter.reportAllCreatedFiles(any)); 94 | }); 95 | 96 | test('should call reportForCreatedFile when there is created file', () { 97 | when(mockGitJSONDSL.createdFiles) 98 | .thenReturn(['test/goldens/foo.png', 'test/goldens/bar.png']); 99 | when(mockReporter.reportForCreatedFile(any)).thenReturn('MOCK_REPORT'); 100 | 101 | DangerPluginGoldenReporter.report('test/goldens', reporter: mockReporter); 102 | 103 | verify(mockReporter.reportForCreatedFile('test/goldens/foo.png')) 104 | .called(1); 105 | verify(mockReporter.reportForCreatedFile('test/goldens/bar.png')) 106 | .called(1); 107 | verify( 108 | mockReporter.reportAllCreatedFiles(['MOCK_REPORT', 'MOCK_REPORT'])); 109 | }); 110 | }); 111 | 112 | group('modifiedFiles', () { 113 | test( 114 | 'should not call reportForModifiedFile, and reportAllModifiedFiles when there is no created file', 115 | () { 116 | DangerPluginGoldenReporter.report('.', reporter: mockReporter); 117 | 118 | verifyNever(mockReporter.reportForModifiedFile(any)); 119 | verifyNever(mockReporter.reportAllModifiedFiles(any)); 120 | }); 121 | 122 | test('should call reportForModifiedFile when there is created file', () { 123 | when(mockGitJSONDSL.modifiedFiles) 124 | .thenReturn(['test/goldens/foo.png', 'test/goldens/bar.png']); 125 | when(mockReporter.reportForModifiedFile(any)).thenReturn('MOCK_REPORT'); 126 | 127 | DangerPluginGoldenReporter.report('test/goldens', reporter: mockReporter); 128 | 129 | verify(mockReporter.reportForModifiedFile('test/goldens/foo.png')) 130 | .called(1); 131 | verify(mockReporter.reportForModifiedFile('test/goldens/bar.png')) 132 | .called(1); 133 | verify( 134 | mockReporter.reportAllModifiedFiles(['MOCK_REPORT', 'MOCK_REPORT'])); 135 | }); 136 | }); 137 | } 138 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/test/mock_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_plugin_golden_reporter/src/golden_reporter.dart'; 3 | import 'package:mockito/annotations.dart'; 4 | 5 | @GenerateMocks([ 6 | GoldenReporter, 7 | DangerJSONDSL, 8 | GitJSONDSL, 9 | GitHubDSL, 10 | GitHubAPIPR, 11 | GitHubPRDSL, 12 | GitHubMergeRef, 13 | ]) 14 | class MockUtils {} 15 | -------------------------------------------------------------------------------- /packages/danger_plugin_golden_reporter/test/src/impl/github_golden_reporter_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:danger_core/danger_core.dart'; 2 | import 'package:danger_plugin_golden_reporter/src/impl/github_golden_reporter.dart'; 3 | import 'package:mockito/mockito.dart'; 4 | import 'package:test/test.dart'; 5 | import 'package:danger_core/src/utils/danger_isolate_sender_mock.dart'; 6 | 7 | import '../../mock_utils.mocks.dart'; 8 | 9 | void main() { 10 | late DangerIsolateSenderMock dangerIsolateSenderMock; 11 | late MockDangerJSONDSL mockDangerJSONDSL; 12 | late MockGitJSONDSL mockGitJSONDSL; 13 | late MockGitHubDSL mockGitHubDSL; 14 | late MockGitHubAPIPR mockGitHubAPIPR; 15 | late MockGitHubPRDSL gitHubPRDSL; 16 | 17 | late MockGitHubMergeRef head; 18 | late MockGitHubMergeRef base; 19 | 20 | final reporter = GithubGoldenReporter(); 21 | 22 | setUp(() { 23 | mockDangerJSONDSL = MockDangerJSONDSL(); 24 | mockGitJSONDSL = MockGitJSONDSL(); 25 | mockGitHubDSL = MockGitHubDSL(); 26 | mockGitHubAPIPR = MockGitHubAPIPR(); 27 | gitHubPRDSL = MockGitHubPRDSL(); 28 | head = MockGitHubMergeRef(); 29 | base = MockGitHubMergeRef(); 30 | 31 | dangerIsolateSenderMock = Danger.setupWithMock(); 32 | dangerIsolateSenderMock.dangerJSONDSL = mockDangerJSONDSL; 33 | 34 | when(mockDangerJSONDSL.git).thenReturn(mockGitJSONDSL); 35 | when(mockDangerJSONDSL.github).thenReturn(mockGitHubDSL); 36 | when(mockGitJSONDSL.createdFiles).thenReturn([]); 37 | when(mockGitJSONDSL.modifiedFiles).thenReturn([]); 38 | 39 | when(mockGitHubDSL.thisPR).thenReturn(mockGitHubAPIPR); 40 | when(mockGitHubAPIPR.owner).thenReturn('danger'); 41 | when(mockGitHubAPIPR.repo).thenReturn('dart'); 42 | when(mockGitHubDSL.pr).thenReturn(gitHubPRDSL); 43 | 44 | when(gitHubPRDSL.head).thenReturn(head); 45 | when(gitHubPRDSL.base).thenReturn(base); 46 | 47 | when(head.sha).thenReturn('MOCK_HEAD_SHA'); 48 | when(base.sha).thenReturn('MOCK_BASE_SHA'); 49 | }); 50 | 51 | test('reportForCreatedFile', () { 52 | final result = reporter.reportForCreatedFile('test/goldens/foo.png'); 53 | expect(result, ''' 54 | 55 | test/goldens/foo.png 56 | 57 | 58 | 59 | 60 | 61 | 62 | '''); 63 | }); 64 | 65 | test('reportForModifiedFile', () { 66 | final result = reporter.reportForModifiedFile('test/goldens/foo.png'); 67 | expect(result, ''' 68 | 69 | test/goldens/foo.png 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | '''); 80 | }); 81 | 82 | test('reportAllCreatedFiles', () { 83 | reporter.reportAllCreatedFiles(['MOCK_MESSAGE1', 'MOCK_MESSAGE2']); 84 | expect(dangerIsolateSenderMock.markdownList.first.message, 85 | '''#### Found 2 Created Golden Images 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | MOCK_MESSAGE1 94 | MOCK_MESSAGE2 95 | 96 |
New Image
'''); 97 | }); 98 | 99 | test('reportAllModifiedFiles', () { 100 | reporter.reportAllModifiedFiles(['MOCK_MESSAGE1', 'MOCK_MESSAGE2']); 101 | expect(dangerIsolateSenderMock.markdownList.first.message, 102 | '''#### Found 2 Modified Golden Images 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | MOCK_MESSAGE1 112 | MOCK_MESSAGE2 113 | 114 |
Old ImageNew Image
'''); 115 | }); 116 | } 117 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: danger_test 2 | description: A simple command-line application. 3 | # version: 1.0.0 4 | # homepage: https://www.example.com 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dev_dependencies: 10 | lints: ^2.1.1 11 | path: ^1.8.3 12 | danger_core: 13 | path: packages/danger_core 14 | danger_plugin_dart_test: 15 | path: packages/danger_plugin_dart_test 16 | -------------------------------------------------------------------------------- /tools/pre_publish.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: non_constant_identifier_names 2 | 3 | import 'dart:convert'; 4 | import 'dart:io'; 5 | import 'package:path/path.dart' show join; 6 | 7 | final JSON_ANNOTATION_REGEX = RegExp(r'json_annotation\.dart'); 8 | final JSON_VALUE_ANNOTATION_REGEX = RegExp(r'\@JsonValue'); 9 | final JSON_SERIALIZABLE_ANNOTATION_REGEX = RegExp(r'\@JsonSerializable'); 10 | final JSON_KEY_ANNOTATION_REGEX = RegExp(r'\@JsonKey'); 11 | 12 | bool notJsonAnnotationLine(String line) { 13 | return !JSON_ANNOTATION_REGEX.hasMatch(line) && 14 | !JSON_VALUE_ANNOTATION_REGEX.hasMatch(line) && 15 | !JSON_SERIALIZABLE_ANNOTATION_REGEX.hasMatch(line) && 16 | !JSON_KEY_ANNOTATION_REGEX.hasMatch(line); 17 | } 18 | 19 | void removeJSONAnnotaionFromFile(File file) async { 20 | final content = await file 21 | .openRead() 22 | .transform(utf8.decoder) 23 | .transform(LineSplitter()) 24 | .where(notJsonAnnotationLine) 25 | .toList(); 26 | 27 | final sink = file.openWrite(mode: FileMode.write); 28 | sink.writeln("import 'package:danger_core/src/mock_json_annotation.dart';"); 29 | sink.writeAll(content, '\n'); 30 | await sink.close(); 31 | } 32 | 33 | void main() { 34 | final modelDirPath = join(Directory.current.path, 'packages', 'danger_core', 35 | 'lib', 'src', 'models'); 36 | final modelDir = Directory(modelDirPath); 37 | if (!modelDir.existsSync()) { 38 | throw 'Couldn\'t find path $modelDirPath'; 39 | } 40 | final modelList = modelDir.listSync(); 41 | modelList 42 | .where((element) => !element.path.endsWith('.g.dart')) 43 | .map((e) => File.fromUri(e.uri)) 44 | .forEach(removeJSONAnnotaionFromFile); 45 | } 46 | -------------------------------------------------------------------------------- /tools/test_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" 3 | 4 | cd ../packages 5 | 6 | for sub_directory in */ ; do 7 | echo "[SCRIPT] Process directory: $sub_directory" 8 | cd $sub_directory 9 | 10 | echo "[SCRIPT] Run pub get" 11 | dart pub get 12 | 13 | if grep -q "build_runner" "pubspec.yaml"; then 14 | echo "[SCRIPT] Run build runner" 15 | dart pub run build_runner build --delete-conflicting-outputs 16 | fi 17 | 18 | echo "[SCRIPT] Run test" 19 | dart test 20 | 21 | cd .. 22 | done 23 | 24 | echo "[SCRIPT] Done" --------------------------------------------------------------------------------