├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ ├── danger.yml
│ ├── docker_manual.yml
│ ├── publish_release.yml
│ └── release_sdk.yml
├── .gitignore
├── CHANGELOG.md
├── CODEOWNERS
├── Dangerfile.df.kts
├── Dangerfile_ci.df.kts
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── action.yml
├── build.gradle
├── configurations.gradle
├── danger-kotlin-kts
├── build.gradle
├── src
│ └── main
│ │ └── kotlin
│ │ └── systems
│ │ └── danger
│ │ └── kts
│ │ └── DangerFileScriptDefinition.kt
└── version.gradle
├── danger-kotlin-library
├── build.gradle
├── dependencies.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── src
│ ├── main
│ │ └── kotlin
│ │ │ └── systems
│ │ │ └── danger
│ │ │ └── kotlin
│ │ │ ├── KtxBitBucketServer.kt
│ │ │ ├── KtxDangerDSL.kt
│ │ │ ├── KtxGit.kt
│ │ │ ├── KtxGitHub.kt
│ │ │ ├── KtxGitLab.kt
│ │ │ ├── MainDangerRunner.kt
│ │ │ ├── MainPlugins.kt
│ │ │ ├── MainScript.kt
│ │ │ ├── json
│ │ │ └── JsonParser.kt
│ │ │ ├── models
│ │ │ ├── bitbucket
│ │ │ │ ├── BitBucketCloud.kt
│ │ │ │ ├── BitBucketMetadata.kt
│ │ │ │ └── BitBucketServer.kt
│ │ │ ├── danger
│ │ │ │ ├── DangerDSL.kt
│ │ │ │ ├── DangerResults.kt
│ │ │ │ └── Utils.kt
│ │ │ ├── git
│ │ │ │ └── Git.kt
│ │ │ ├── github
│ │ │ │ └── GitHub.kt
│ │ │ ├── gitlab
│ │ │ │ └── GitLab.kt
│ │ │ └── serializers
│ │ │ │ ├── DateSerializer.kt
│ │ │ │ └── ViolationSerializer.kt
│ │ │ └── tools
│ │ │ └── shell
│ │ │ └── ShellExecutor.kt
│ └── test
│ │ ├── kotlin
│ │ └── systems
│ │ │ └── danger
│ │ │ └── kotlin
│ │ │ ├── KtxGitLabTest.kt
│ │ │ ├── KtxGitTest.kt
│ │ │ ├── UtilsTests.kt
│ │ │ ├── models
│ │ │ ├── bitbucket
│ │ │ │ ├── BitBucketCloudParsingTests.kt
│ │ │ │ └── BitBucketServerParsingTests.kt
│ │ │ ├── git
│ │ │ │ └── GitParsingTests.kt
│ │ │ ├── github
│ │ │ │ └── GitHubParsingTests.kt
│ │ │ └── gitlab
│ │ │ │ ├── GitLabParsingTests.kt
│ │ │ │ └── GitLabPipelineStatusTest.kt
│ │ │ └── utils
│ │ │ └── TestUtils.kt
│ │ └── resources
│ │ ├── bitbucketCloudDangerJSON.json
│ │ ├── bitbucketServerDangerJSON.json
│ │ ├── githubDangerJSON.json
│ │ ├── githubWithClosedMilestoneDangerJSON.json
│ │ ├── githubWithSomeNullsAttributeDangerJSON.json
│ │ ├── gitlabDangerJSON.json
│ │ └── gitlabWithCancelledPipelineDangerJSON.json
└── version.gradle
├── danger-kotlin-sample-plugin
├── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
│ └── main
│ └── kotlin
│ └── systems
│ └── danger
│ └── samples
│ └── plugin
│ └── SamplePlugin.kt
├── danger-kotlin-sdk
├── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── maven-publish.gradle
├── src
│ └── main
│ │ └── kotlin
│ │ └── systems
│ │ └── danger
│ │ └── kotlin
│ │ └── sdk
│ │ └── DangerKotlinAPI.kt
└── version.gradle
├── danger-kotlin
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── src
│ └── runnerMain
│ └── kotlin
│ ├── Main.kt
│ └── systems.danger
│ ├── DangerKotlin.kt
│ ├── Log.kt
│ └── cmd
│ ├── Cmd.kt
│ ├── Command.kt
│ ├── dangerfile
│ ├── DangerFile.kt
│ └── DangerFileBridge.kt
│ └── dangerjs
│ ├── DangerJS.kt
│ └── DangerJSBridge.kt
├── danger-plugin-installer
├── build.gradle
└── src
│ └── main
│ └── kotlin
│ └── systems
│ └── danger
│ └── kotlin
│ └── plugininstaller
│ └── PluginInstaller.kt
├── dependencyVersions.gradle
├── docs
├── guides
│ └── about_the_dangerfile.html.md
├── tutorials
│ ├── architecture.html.md
│ ├── fast_feedback.html.md
│ └── plugin_development.html.md
└── usage
│ ├── bitbucket.html.md
│ ├── culture.html.md
│ └── gitlab.html.md
├── github-action
├── Dockerfile
└── entrypoint.sh
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── scripts
├── install.sh
└── release_changelog.sh
├── secrets.gradle
├── settings.gradle
└── shadow.gradle
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [f-meloni, gianluz]
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: pull_request
4 |
5 | jobs:
6 | build:
7 | strategy:
8 | fail-fast: false
9 | matrix:
10 | os: [ubuntu-latest, macos-latest]
11 |
12 | runs-on: ${{ matrix.os }}
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - uses: sdkman/sdkman-action@master
18 | with:
19 | candidate: gradle
20 | version: 8.10.2
21 |
22 | - name: Install Kotlin
23 | run: |
24 | curl -o kotlin-compiler.zip -L https://github.com/JetBrains/kotlin/releases/download/v2.0.21/kotlin-compiler-2.0.21.zip
25 |
26 | if [[ "$OSTYPE" != "darwin"* ]]
27 | then
28 | sudo chmod -R a+rwx /usr/local/
29 |
30 | unzip -d /usr/local/bin kotlin-compiler.zip
31 | echo "/usr/local/bin/kotlinc/bin" >> $GITHUB_PATH
32 | rm -rf kotlin-compiler.zip
33 | fi
34 |
35 | - uses: actions/setup-node@v4
36 | with:
37 | node-version: '22.10.0'
38 |
39 | - name: Install Danger JS
40 | run: npm install -g danger
41 |
42 | - name: Install Danger Kotlin
43 | run: sudo make install
44 |
45 | - name: Run tests
46 | run: sudo ./gradlew danger-kotlin-library:test
47 |
48 | - name: Install Plugin Installer
49 | run: sudo ./gradlew danger-plugin-installer:publishToMavenLocal
50 |
51 | - name: Build and Install Sample Plugin
52 | working-directory: ./danger-kotlin-sample-plugin
53 | run: |
54 | sudo gradle wrapper
55 | sudo ./gradlew build
56 | sudo ./gradlew installDangerPlugin
57 |
58 | - name: Run Danger-Kotlin
59 | run: DEBUG='*' danger-kotlin ci --dangerfile Dangerfile_ci.df.kts
60 | env:
61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62 |
--------------------------------------------------------------------------------
/.github/workflows/danger.yml:
--------------------------------------------------------------------------------
1 | name: Danger Action
2 |
3 | on: [pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | name: "Run Danger"
9 | steps:
10 | - uses: actions/checkout@v4
11 | - name: Danger
12 | uses: danger/kotlin@master
13 | with:
14 | args: "--id DangerKotlinAction"
15 | env:
16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/docker_manual.yml:
--------------------------------------------------------------------------------
1 | name: Build Docker (Manual)
2 |
3 | on:
4 | workflow_dispatch :
5 | inputs:
6 | docker-version:
7 | description: "Docker Version"
8 | danger-js-version:
9 | description: "Danger JS release version"
10 | default: "12.3.3"
11 | danger-kotlin-version:
12 | description: "Danger Kotlin release version"
13 | kotlin-version:
14 | description: "Kotlin Version"
15 | default: "2.0.21"
16 |
17 | jobs:
18 | docker-build-push:
19 | name: Build and Push Docker image
20 | permissions:
21 | contents: read
22 | packages: write
23 | runs-on: ubuntu-latest
24 | steps:
25 | - uses: actions/checkout@v4
26 |
27 | - name: Docker Login
28 | run: echo $PACKAGES_WRITE_TOKEN | docker login ghcr.io -u $USERNAME --password-stdin
29 | env:
30 | PACKAGES_WRITE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31 | USERNAME: ${{ github.actor }}
32 |
33 | - name: Docker Build
34 | run: docker build -t ghcr.io/danger/danger-kotlin:$VERSION --build-arg="KOTLINC_VERSION=$KOTLINC_VERSION" --build-arg="DANGER_KOTLIN_VERSION=$DANGER_KOTLIN_VERSION" --build-arg="DANGER_JS_VERSION=$DANGER_JS_VERSION" .
35 | env:
36 | VERSION: ${{ github.event.inputs.docker-version }}
37 | KOTLINC_VERSION: ${{ github.event.inputs.kotlin-version }}
38 | DANGER_KOTLIN_VERSION: ${{ github.event.inputs.danger-kotlin-version }}
39 | DANGER_JS_VERSION: ${{ github.event.inputs.danger-js-version }}
40 |
41 | - name: Deploy
42 | run: docker push ghcr.io/danger/danger-kotlin:$VERSION
43 | env:
44 | VERSION: ${{ github.event.inputs.docker-version }}
45 |
--------------------------------------------------------------------------------
/.github/workflows/publish_release.yml:
--------------------------------------------------------------------------------
1 | name: Release distribution
2 |
3 | on:
4 | release:
5 | types: [ created ]
6 |
7 | jobs:
8 | dangerKotlinLibrary-shadowJar:
9 | name: Build Library
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v4
13 |
14 | - name: Set up JDK 23
15 | uses: actions/setup-java@v4
16 | with:
17 | distribution: "temurin"
18 | java-version: 23
19 | cache: gradle
20 | - name: danger-kotlin-library:shadowJar
21 | run: ./gradlew danger-kotlin-library:shadowJar
22 | - name: Upload Artifact lib
23 | uses: actions/upload-artifact@v4
24 | with:
25 | name: lib
26 | path: danger-kotlin-library/build/libs/danger-kotlin.jar
27 |
28 | dangerKotlin-build-and-distribute:
29 | name: Build and Attach binary to release
30 | needs: [ dangerKotlinLibrary-shadowJar ]
31 | strategy:
32 | fail-fast: false
33 | matrix:
34 | target: [ { os: ubuntu-latest, compiler: linuxX64 }, { os: macos-latest, compiler: macosX64 }, { os: macos-latest, compiler: macosArm64 } ]
35 |
36 | runs-on: ${{ matrix.target.os }}
37 |
38 | steps:
39 | - uses: actions/checkout@v4
40 | - name: Download Artifact lib
41 | uses: actions/download-artifact@v4
42 | with:
43 | name: lib
44 |
45 | - name: Set up JDK 23
46 | uses: actions/setup-java@v4
47 | with:
48 | distribution: "temurin"
49 | java-version: 23
50 | cache: gradle
51 | - name: danger-kotlin:build -PtargetOS="${{ matrix.target.compiler }}"
52 | run: ./gradlew danger-kotlin:build -PtargetOS="${{ matrix.target.compiler }}"
53 | - name: Prepare distribution package
54 | run: |
55 | mkdir -p lib/danger
56 | mkdir -p bin
57 | mv "danger-kotlin.jar" "lib/danger"
58 | mv "danger-kotlin/build/bin/runner/releaseExecutable/danger-kotlin.kexe" "bin/danger-kotlin"
59 | chmod +x bin/danger-kotlin
60 | - name: Tar files
61 | run: |
62 | tar -cvf danger-kotlin-${{ matrix.target.compiler }}.tar bin lib
63 | shasum -a 256 danger-kotlin-${{ matrix.target.compiler }}.tar
64 | - name: Get release information
65 | id: get_release
66 | uses: bruceadams/get-release@v1.3.2
67 | env:
68 | GITHUB_TOKEN: ${{ github.token }}
69 | - name: Upload artifacts to release
70 | uses: actions/upload-release-asset@v1.0.2
71 | env:
72 | GITHUB_TOKEN: ${{ github.token }}
73 | with:
74 | upload_url: ${{ steps.get_release.outputs.upload_url }}
75 | asset_path: ./danger-kotlin-${{ matrix.target.compiler }}.tar
76 | asset_name: danger-kotlin-${{ matrix.target.compiler }}.tar
77 | asset_content_type: application/x-tar
78 |
79 | docker-build-push:
80 | name: Build and Push Docker image
81 | permissions:
82 | contents: read
83 | packages: write
84 | runs-on: ubuntu-latest
85 | needs: [ dangerKotlin-build-and-distribute ]
86 | steps:
87 | - uses: actions/checkout@v4
88 |
89 | - name: Get release information
90 | id: get_release
91 | uses: bruceadams/get-release@v1.3.2
92 | env:
93 | GITHUB_TOKEN: ${{ github.token }}
94 |
95 | - name: Docker Login
96 | run: echo $PACKAGES_WRITE_TOKEN | docker login ghcr.io -u $USERNAME --password-stdin
97 | env:
98 | PACKAGES_WRITE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99 | USERNAME: ${{ github.actor }}
100 |
101 | - name: Docker Build
102 | run: docker build -t ghcr.io/danger/danger-kotlin:$VERSION .
103 | env:
104 | VERSION: ${{ steps.get_release.outputs.tag_name }}
105 |
106 | - name: Deploy
107 | run: docker push ghcr.io/danger/danger-kotlin:$VERSION
108 | env:
109 | VERSION: ${{ steps.get_release.outputs.tag_name }}
110 |
--------------------------------------------------------------------------------
/.github/workflows/release_sdk.yml:
--------------------------------------------------------------------------------
1 | name: Release SDK
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'sdk_*'
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Check out Git repository
13 | uses: actions/checkout@v4
14 | - name: Install Java and Maven
15 | uses: actions/setup-java@v4
16 | with:
17 | java-version: 1.8
18 | - name: Install GNUPG2 & Import Key
19 | env:
20 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
21 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
22 | run: |
23 | sudo apt-get install gnupg2 -y
24 | gpg2 --version
25 | echo "$GPG_PRIVATE_KEY" > secret.key
26 | echo "Importing GPG Key..."
27 | gpg2 --import --batch secret.key &> /dev/null
28 | echo "[ OK ] GPG Key imported."
29 | echo "Sending public key to the server..."
30 | gpg2 --keyserver hkps://keys.openpgp.org --send-keys $GPG_KEY_ID
31 | echo "[ OK ] Public key was sent to the server."
32 | rm secret.key
33 | - name: Deploy & Release
34 | env:
35 | SONATYPE_USER: ${{ secrets.SONATYPE_USER }}
36 | SONATYPE_PASS: ${{ secrets.SONATYPE_PASS }}
37 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
38 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
39 | run: |
40 | gradle wrapper
41 | ./gradlew :danger-kotlin-sdk:publish
42 | ./gradlew closeAndReleaseRepository
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Idea
2 | .idea/
3 | *.iml
4 | *.iws
5 | *.ipr
6 | /*/out
7 | local.properties
8 |
9 | #Gradle
10 | .gradle/
11 | build/
12 |
13 | #OSx
14 | .DS_Store
15 |
16 | # CMake
17 | cmake-build-debug/
18 | cmake-build-release/
19 |
20 | # JIRA plugin
21 | atlassian-ide-plugin.xml
22 |
23 | # Crashlytics plugin (for Android Studio and IntelliJ)
24 | com_crashlytics_export_strings.xml
25 | crashlytics.properties
26 | crashlytics-build.properties
27 | fabric.properties
28 |
29 | # Compiled class file
30 | *.class
31 |
32 | # Log file
33 | *.log
34 |
35 | # BlueJ files
36 | *.ctxt
37 |
38 | # Mobile Tools for Java (J2ME)
39 | .mtj.tmp/
40 |
41 | # Package Files #
42 | *.jar
43 | !gradle/wrapper/gradle-wrapper.jar
44 |
45 | *.war
46 | *.nar
47 | *.ear
48 | *.zip
49 | *.tar.gz
50 | *.rar
51 |
52 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
53 | hs_err_pid*
54 |
55 | # Danger Temporary Files #
56 | danger_out.json
57 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
13 | ## Master
14 | - Update README.md with guidance to enable auto-complete in Android Studio [@gianluz] - [#242](https://github.com/danger/kotlin/pull/242)
15 | - Update install script with Kotlin compiler 1.7.0 [@gianluz] - [#241](https://github.com/danger/kotlin/pull/241)
16 | - Add accessors for Danger reports [@417-72KI] - [#245](https://github.com/danger/kotlin/pull/245)
17 |
18 | # 1.2.0
19 | - Update `Kotlin` to `1.7.0` and added support for Apple Silicon Chipset [@gianluz] - [#231](https://github.com/danger/kotlin/pull/231)
20 | - Make user property nullable for cases when non BB user did a commit [@vchernyshov]
21 | - Make GitLab approvals_before_merge variable nullable [#227](https://github.com/danger/kotlin/pull/227)
22 |
23 | # 1.1.0
24 |
25 | - Add support of BitBucketCloud [@vchernyshov] - [#214](https://github.com/danger/kotlin/pull/214)
26 | - Make `force_remove_source_branch` nullable in GitLab Merge request entity [@davidbilik] - [#197](https://github.com/danger/kotlin/pull/197)
27 | - Make `lastReviewedCommit` nullable on BitBucket Server [@f-meloni] - [#211](https://github.com/danger/kotlin/pull/211)
28 | - Update `GitLabMergeRequest` model: add `squash` field [@sonulen] - [#212](https://github.com/danger/kotlin/pull/212)
29 | - Add Gitlab extensions for url's: to project, to file diff, to current version of file [@sonulen] - [#212](https://github.com/danger/kotlin/pull/212)
30 | - Upgrade action to use node14 [@eygraber] - [#215](https://github.com/danger/kotlin/pull/215)
31 |
32 | # 1.0.0-beta4, 1.0.0
33 |
34 | - Create the Danger main instance only once [@f-meloni] - [#185](https://github.com/danger/kotlin/pull/185)
35 |
36 | # 1.0.0-beta3
37 |
38 | - Coroutines compatibility [@gianluz] - [#177](https://github.com/danger/kotlin/pull/177)
39 | - Improving error message for when a DangerPlugin was not registered [@rojanthomas] - [#181](https://github.com/danger/kotlin/pull/181)
40 | - Fix body parameter in github models [@tegorov] - [#175](https://github.com/danger/kotlin/pull/175)
41 |
42 | # 1.0.0-beta2
43 |
44 | - Update kotlinx-datetime to 0.1.1 [@f-meloni] - [@gianluz] - [#167](https://github.com/danger/kotlin/pull/167)
45 | - Support GitLab different time zones on the JSON [@f-meloni] - [#169](https://github.com/danger/kotlin/pull/169)
46 | - Update Kotlin to 1.5.0 [@gianluz] - [#171](https://github.com/danger/kotlin/pull/171)
47 |
48 | # 1.0.0-beta
49 |
50 | - Support --help parameter [@f-meloni] - [#153](https://github.com/danger/kotlin/pull/155)
51 | - Update Kotlin to 1.4.10 [@gianluz] - [#140](https://github.com/danger/kotlin/pull/140)
52 | - Migrate from moshi to kotlinx serialization [@gianluz] - [#141](https://github.com/danger/kotlin/pull/141)
53 | - Fix incorrect url in install.sh script and in Dockerfile [@davidbilik] - [#144](https://github.com/danger/kotlin/pull/144)
54 | - Road to 1.0 - Refactor project structure [@gianluz] - [#142](https://github.com/danger/kotlin/pull/142)
55 | - Handle danger-js custom paths with parameter `--danger-js-path` [@f-meloni] - [#153](https://github.com/danger/kotlin/pull/153)
56 | - Update Kotlin to 1.4.20 [@gianluz] - [#148](https://github.com/danger/kotlin/pull/148)
57 | - Fix gitlab defaults following kotlinx serialisation [@gianluz] - [#146](https://github.com/danger/kotlin/pull/146)
58 | - Road to 1.0 - Migrate from java.util.Date to kotlinx.datetime [@gianluz] - [#147](https://github.com/danger/kotlin/pull/147)
59 | - Fix typo in Github Milestone serialization [@doodeec] - [#151](https://github.com/danger/kotlin/pull/151)
60 | - Use fixed commit of danger/kotlin repository in install.sh script [@davidbilik]- [#152](https://github.com/danger/kotlin/pull/152)
61 | - Update Kotlin to 1.4.31 [@gianluz] - [#160](https://github.com/danger/kotlin/pull/160)
62 | - Library resolver and plugin installer gradle plugin [@gianluz] - [#158](https://github.com/danger/kotlin/pull/158)
63 |
64 | # 0.7.1
65 |
66 | - Make milestone description optional [@f-meloni] - [#136](https://github.com/danger/kotlin/pull/136)
67 | - Optimise Dockerfile layers to make Danger-Kotlin faster when the image is pulled on CI [@f-meloni] - [#129](https://github.com/danger/kotlin/pull/129)
68 | - Add action.yml to make it possible to run locally through [act](https://github.com/nektos/act) [@mariusgreve] - [#135](https://github.com/danger/kotlin/pull/135)
69 |
70 | # 0.7.0
71 |
72 | - Add logger [@f-meloni] - [#126](https://github.com/danger/kotlin/pull/126)
73 | - Fix DangerKotlinScriptDefinition [@gianluz] - [#121](https://github.com/danger/kotlin/pull/121)
74 | - Update Kotlin to 1.4.0 [@uzzu][] - [#116](https://github.com/danger/kotlin/pull/116)
75 | - Fix crash at milestone.dueOn [@anton46][] - [#108](https://github.com/danger/kotlin/pull/119)
76 |
77 | # 0.6.1
78 |
79 | - Fix crash on milestone.closedAt [@anton46][] - [#108](https://github.com/danger/kotlin/pull/112)
80 | - Add abstraction for executing shell commands via `ShellExecutor` [@davidbilik][] - [#105](https://github.com/danger/kotlin/pull/105)
81 |
82 | # 0.6.0
83 |
84 | - Fix to allow for large GitHub id values [@brentwatson][] - [#108](https://github.com/danger/kotlin/pull/108)
85 | - Fix invalid parsing of changes in diff [@davidbilik][] - [#106](https://github.com/danger/kotlin/pull/106)
86 | - Add extensions for changed lines in Git [@davidbilik][] - [#102](https://github.com/danger/kotlin/pull/102)
87 | - Add exec function [@f-meloni][] - [#97](https://github.com/danger/kotlin/pull/97)
88 | - Add readFile function [@f-meloni][] - [#93](https://github.com/danger/kotlin/pull/93)
89 | - Github exposing user avatar [@gianluz] - [#96](https://github.com/danger/kotlin/pull/96)
90 |
91 | [@f-meloni]: https://github.com/f-meloni
92 | [@gianluz]: https://github.com/gianluz
93 | [@davidbilik]: https://github.com/davidbilik
94 | [@brentwatson]: https://github.com/brentwatson
95 | [@anton46]: https://github.com/anton46
96 | [@uzzu]: https://github.com/uzzu
97 | [@mariusgreve]: https://github.com/mariusgreve
98 | [@tegorov]: https://github.com/tegorov
99 | [@rojanthomas]: https://github.com/rojanthomas
100 | [@eygraber]: https://github.com/eygraber
101 | [@417-72KI]: https://github.com/417-72KI
102 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @f-meloni @gianluz @vacxe
2 |
--------------------------------------------------------------------------------
/Dangerfile.df.kts:
--------------------------------------------------------------------------------
1 | @file:Repository("https://repo.maven.apache.org/maven2/")
2 | @file:DependsOn("org.apache.commons:commons-text:1.6")
3 |
4 | import systems.danger.kotlin.*
5 |
6 | danger(args) {
7 | // Empty dangerFile
8 | }
9 |
--------------------------------------------------------------------------------
/Dangerfile_ci.df.kts:
--------------------------------------------------------------------------------
1 | // Dangerfile.df.kts
2 | /*
3 | * Use external dependencies using the following annotations:
4 | */
5 | @file:Repository("https://repo.maven.apache.org/maven2/")
6 | @file:DependsOn("org.apache.commons:commons-text:1.6")
7 |
8 | //Testing plugin
9 | @file:DependsOn("danger-kotlin-sample-plugin-sample.jar")
10 | @file:OptIn(kotlin.time.ExperimentalTime::class)
11 |
12 | import kotlinx.coroutines.async
13 | import kotlinx.coroutines.delay
14 | import kotlinx.coroutines.runBlocking
15 | import kotlinx.datetime.Clock
16 | import org.apache.commons.text.WordUtils
17 | import systems.danger.kotlin.*
18 | import systems.danger.kotlin.models.danger.DangerDSL
19 | import systems.danger.samples.plugin.SamplePlugin
20 |
21 | register plugin SamplePlugin
22 |
23 | danger(args) {
24 | val allSourceFiles = git.modifiedFiles + git.createdFiles
25 | val changelogChanged = allSourceFiles.contains("CHANGELOG.md")
26 | val sourceChanges = allSourceFiles.firstOrNull { it.contains("src") }
27 |
28 | SamplePlugin.myCustomCheck()
29 |
30 | onGitHub {
31 | val isTrivial = pullRequest.title.contains("#trivial")
32 |
33 | // Changelog
34 | if (!isTrivial && !changelogChanged && sourceChanges != null) {
35 | warn(WordUtils.capitalize("any changes to library code should be reflected in the Changelog.\n\nPlease consider adding a note there and adhere to the [Changelog Guidelines](https://github.com/Moya/contributors/blob/master/Changelog%20Guidelines.md)."))
36 | }
37 |
38 | // Big PR Check
39 | if ((pullRequest.additions ?: 0) - (pullRequest.deletions ?: 0) > 300) {
40 | warn("Big PR, try to keep changes smaller if you can")
41 | }
42 |
43 | // Work in progress check
44 | if (pullRequest.title.contains("WIP", false)) {
45 | warn("PR is classed as Work in Progress")
46 | }
47 | }
48 |
49 | onGit {
50 | //No Java files check
51 | createdFiles.filter {
52 | it.endsWith(".java")
53 | }.forEach {
54 | // Using apache commons-text dependency to be sure the dependency resolution always works
55 | warn(WordUtils.capitalize("please consider to create new files in Kotlin"), it, 1)
56 | }
57 | }
58 |
59 | // Coroutines checks in parallel test
60 | val before = Clock.System.now()
61 | runBlocking {
62 | async { expensiveCheck("1", 1000) }
63 | async { expensiveCheck("2", 3000) }
64 | async { expensiveCheck("3", 2000) }
65 | async { expensiveCheck("4", 5000) }
66 | }
67 | val after = Clock.System.now()
68 | val runningTime = after.minus(before)
69 | message("Coroutines checks terminated - runningFor $runningTime")
70 |
71 | if ((fails + warnings).isEmpty()) {
72 | message(":rocket: No errors or warnings!")
73 | }
74 | }
75 |
76 | suspend fun DangerDSL.expensiveCheck(name: String, runForMillis: Long) {
77 | // Example expensive check
78 | delay(runForMillis)
79 | message("Coroutine $name terminated in $runForMillis ms")
80 | }
81 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM eclipse-temurin:23-jdk
2 |
3 | MAINTAINER Konstantin Aksenov
4 |
5 | LABEL "com.github.actions.name"="Danger Kotlin"
6 | LABEL "com.github.actions.description"="Runs Kotlin Dangerfiles"
7 | LABEL "com.github.actions.icon"="zap"
8 | LABEL "com.github.actions.color"="blue"
9 |
10 | ARG KOTLINC_VERSION="2.0.21"
11 | ARG DANGER_KOTLIN_VERSION="1.3.3"
12 | ARG DANGER_JS_VERSION="12.3.3"
13 |
14 | # Install dependencies
15 | RUN apt-get update
16 | RUN apt-get install -y npm nodejs wget unzip git
17 |
18 | # Install Kotlin compiler
19 | RUN wget -q "https://github.com/JetBrains/kotlin/releases/download/v$KOTLINC_VERSION/kotlin-compiler-$KOTLINC_VERSION.zip" && \
20 | unzip "kotlin-compiler-$KOTLINC_VERSION.zip" -d /usr/lib && \
21 | rm "kotlin-compiler-$KOTLINC_VERSION.zip"
22 | ENV PATH $PATH:/usr/lib/kotlinc/bin
23 |
24 | # Install Danger-JS
25 | RUN npm install -g "danger@$DANGER_JS_VERSION"
26 |
27 | # Install Danger-Kotlin
28 | RUN wget -q "https://github.com/danger/kotlin/releases/download/$DANGER_KOTLIN_VERSION/danger-kotlin-linuxX64.tar" && \
29 | tar -xvf "danger-kotlin-linuxX64.tar" -C /usr/local && \
30 | rm "danger-kotlin-linuxX64.tar"
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2022 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.
22 |
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | TOOL_NAME = danger-kotlin
2 |
3 | PREFIX = /usr/local
4 | INSTALL_PATH = $(PREFIX)/bin/$(TOOL_NAME)
5 | BUILD_PATH = danger-kotlin/build/bin/runner/releaseExecutable/$(TOOL_NAME).kexe
6 | LIB_INSTALL_PATH = $(PREFIX)/lib/danger
7 | LIB_FLAT_DIR = $(LIB_INSTALL_PATH)/libs
8 |
9 | install: build
10 | mkdir -p $(PREFIX)/bin
11 | mkdir -p $(LIB_INSTALL_PATH)
12 | mkdir -p $(LIB_FLAT_DIR)
13 | cp -f $(BUILD_PATH) $(INSTALL_PATH)
14 | cp -f danger-kotlin-library/build/libs/danger-kotlin.jar $(LIB_INSTALL_PATH)/danger-kotlin.jar
15 |
16 | build:
17 | ./gradlew build -p danger-plugin-installer
18 | ./gradlew publishToMavenLocal -p danger-plugin-installer
19 | ./gradlew shadowJar -p danger-kotlin-library
20 | ./gradlew build -p danger-kotlin-kts
21 | ./gradlew build -p danger-kotlin
22 |
23 | uninstall:
24 | rm -rf $(INSTALL_PATH)
25 | rm -f $(LIB_INSTALL_PATH)/danger-kotlin.jar
26 | rm -rf $(LIB_FLAT_DIR)
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://danger.systems/kotlin/)
3 | [](https://search.maven.org/search?q=g:%22systems.danger%22%20AND%20a:%22danger-kotlin-sdk%22)
4 | [](https://github.com/KotlinBy/awesome-kotlin)
5 |
6 |
7 |
8 | ⚠️ Stop saying "you forgot to …" in code review in Kotlin
9 |
10 |
11 | # Project status
12 | The project is now on a stable version.
13 | Is possible to generate a working `danger-kotlin` instance from the code that is currently on this repo, or use it via GitHub actions or `brew`.
14 |
15 | ### What it looks like today
16 | You can make a `Dangerfile.df.kts` in your root project that looks through PR metadata, it's fully typed.
17 |
18 | ```kotlin
19 | import systems.danger.kotlin.*
20 |
21 | danger(args) {
22 |
23 | val allSourceFiles = git.modifiedFiles + git.createdFiles
24 | val changelogChanged = allSourceFiles.contains("CHANGELOG.md")
25 | val sourceChanges = allSourceFiles.firstOrNull { it.contains("src") }
26 |
27 | onGitHub {
28 | val isTrivial = pullRequest.title.contains("#trivial")
29 |
30 | // Changelog
31 | if (!isTrivial && !changelogChanged && sourceChanges != null) {
32 | warn(WordUtils.capitalize("any changes to library code should be reflected in the Changelog.\n\nPlease consider adding a note there and adhere to the [Changelog Guidelines](https://github.com/Moya/contributors/blob/master/Changelog%20Guidelines.md)."))
33 | }
34 |
35 | // Big PR Check
36 | if ((pullRequest.additions ?: 0) - (pullRequest.deletions ?: 0) > 300) {
37 | warn("Big PR, try to keep changes smaller if you can")
38 | }
39 |
40 | // Work in progress check
41 | if (pullRequest.title.contains("WIP", false)) {
42 | warn("PR is classed as Work in Progress")
43 | }
44 | }
45 | }
46 | ```
47 |
48 | ### Setup
49 |
50 | ### Docker
51 | ```sh
52 | docker run --rm -v "${PWD}:/code" -w /code ghcr.io/danger/danger-kotlin:1.3.3 danger-kotlin local
53 | ```
54 |
55 | #### macOS (ARM)
56 | ```sh
57 | brew install danger/tap/danger-kotlin
58 | ```
59 |
60 | #### macOS (Intel)
61 | ```sh
62 | brew install danger/tap/danger-kotlin-intel
63 | ```
64 |
65 | You need to have Xcode installed and not relying on command line tools.
66 | If you're seeing this error when running xcodebuild:
67 |
68 | ```sh
69 | $ xcodebuild -version
70 | xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
71 | ```
72 |
73 | You can fix it with:
74 |
75 | ```sh
76 | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
77 | ```
78 |
79 | ### Linux
80 | ```sh
81 | bash <(curl -s https://raw.githubusercontent.com/danger/kotlin/master/scripts/install.sh)
82 | source ~/.bash_profile
83 | ```
84 |
85 | ### GitHub Actions
86 | You can add danger/kotlin to your actions
87 |
88 | Parameters:
89 | * `dangerfile`: Path to danger file, required: `false`, default: `Dangerfile.df.kts`
90 | * `run-mode`: Run mode: `ci`, `local`, `pr`, required: `false` default: `ci`
91 | * `job-id:` Reported CI job ID, required: `false`, default: `danger/kotlin`
92 | * `args`: Extra custom arguments like "--failOnErrors --no-publish-check" and etc, required: `false`
93 |
94 | ```yml
95 | jobs:
96 | build:
97 | runs-on: ubuntu-latest
98 | name: "Run Danger"
99 | steps:
100 | - uses: actions/checkout@v4
101 | - name: Danger
102 | uses: danger/kotlin@1.3.3
103 | env:
104 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
105 | ```
106 |
107 | Danger a pre built images that you can use with your action:
108 |
109 | https://github.com/orgs/danger/packages/container/package/danger-kotlin
110 | In order to import one of those use the docker:// prefix
111 |
112 | ```yml
113 | jobs:
114 | build:
115 | runs-on: ubuntu-latest
116 | name: "Run Danger"
117 | container:
118 | image: docker://ghcr.io/danger/danger-kotlin:1.3.3
119 | steps:
120 | - uses: actions/checkout@v4
121 | - name: Run Danger
122 | run: danger-kotlin ci --failOnErrors --no-publish-check
123 | env:
124 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
125 | ```
126 |
127 | ### Autocomplete and Syntax highlighting in IntelliJ IDEA or Android Studio
128 | You can activate the autocomplete following this additional steps:
129 | - Install danger on your local machine
130 | - Go to `Preferences -> Build, Execution, Deployment -> Compiler -> Kotlin Compiler` (`Preferences -> Kotlin Compiler` in Android Studio, Recent Android Studio versions will show this option when you close all project and open the Settings from the initial screen)
131 | - At the bottom you will find a section `Kotlin Scripting`
132 | - Complete the field `Script template classes` with `systems.danger.kts.DangerFileScript`
133 | - Complete the field `Script templates classpath` with `/usr/local/lib/danger/danger-kotlin.jar`
134 | - Go to `Preferences -> Language & Frameworks -> Kotlin -> Kotlin Scripting`
135 | - Make sure the script template `DangerFileScript` is active and above the default `Kotlin Script`
136 | - Apply changes
137 | - If opening the `Dangerfile.df.kts` the autocomplete and syntax highlighting doesn't work, try to reboot your IDE or open the Dangerfile from your IDE as a single file.
138 | - If it still doesn't work, go to `Help -> Edit Custom VM Options...` and add `-Dkotlin.script.classpath=/danger-kotlin.jar` (replace the `` with the absolute path to the JAR). Then restart the IDE.
139 | - You may also need to disable the "K2 mode" (search the settings for it) if you enabled it previously.
140 |
141 |
142 | ### Using external maven dependencies into your Dangerfile
143 | You can use any external dependency by adding the following lines at the top of your `Dangerfile.df.kts`
144 | ```kotlin
145 | @file:Repository("https://repo.maven.apache.org")
146 | @file:DependsOn("groupId:artifactId:version")
147 | ```
148 |
149 | ### Commands
150 |
151 | - `danger-kotlin ci` - Use this on CI
152 | - `danger-kotlin pr https://github.com/Moya/Harvey/pull/23` - Use this to build your Dangerfile
153 | - `danger-kotlin local` - Use this to run danger against your local changes from master
154 |
155 | # Authors
156 | `danger-kotlin` was developed by [@gianluz][] and [@f-meloni][]
157 |
158 | [@f-meloni]: https://github.com/f-meloni
159 | [@gianluz]: https://github.com/gianluz
160 |
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: 'danger-kotlin'
2 | description: 'Stop saying "you forgot to …" in code review'
3 | author: 'Konstantin Aksenov'
4 | branding:
5 | icon: 'check-square'
6 | color: 'green'
7 | inputs:
8 | dangerfile:
9 | description: 'Path to danger file'
10 | required: false
11 | default: 'Dangerfile.df.kts'
12 | run-mode:
13 | description: 'Run mode: ci, local, pr'
14 | required: false
15 | default: 'ci'
16 | job-id:
17 | description: 'Reported CI job ID'
18 | required: false
19 | default: 'danger/kotlin'
20 | args:
21 | description: 'Extra custom arguments like "--failOnErrors --no-publish-check" and etc'
22 | required: false
23 |
24 | runs:
25 | using: 'docker'
26 | image: 'github-action/Dockerfile'
27 | args:
28 | - ${{ inputs.dangerfile }}
29 | - ${{ inputs.run-mode }}
30 | - ${{ inputs.job-id }}
31 | - ${{ inputs.args }}
32 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | gradlePluginPortal()
5 | }
6 |
7 | dependencies {
8 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
9 | classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion"
10 | classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
11 | classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.21.2"
12 | }
13 | }
14 |
15 | apply from: file('secrets.gradle')
16 | apply plugin: 'io.codearte.nexus-staging'
17 |
18 | nexusStaging {
19 | packageGroup = "systems.danger"
20 | username = loadSecret("SONATYPE_USER")
21 | password = loadSecret("SONATYPE_PASS")
22 | delayBetweenRetriesInMillis = 5000
23 | }
24 |
25 | allprojects {
26 | repositories {
27 | mavenCentral()
28 | maven {
29 | url = "https://kotlin.bintray.com/kotlinx/"
30 | }
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/configurations.gradle:
--------------------------------------------------------------------------------
1 | configurations {
2 | implementation.extendsFrom includeJar {
3 | transitive = false
4 | }
5 | api.extendsFrom includeRecursiveJar {
6 | transitive = true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/danger-kotlin-kts/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | gradlePluginPortal()
4 | }
5 | dependencies {
6 | classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
7 | }
8 | }
9 |
10 | plugins {
11 | id 'org.jetbrains.kotlin.jvm'
12 | id 'maven-publish'
13 | }
14 |
15 | apply plugin: 'com.github.johnrengelman.shadow'
16 |
17 | apply from: file('../dependencyVersions.gradle')
18 | apply from: file('version.gradle')
19 |
20 | dependencies {
21 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
22 | implementation "org.jetbrains.kotlin:kotlin-script-runtime:$versionKotlin"
23 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2"
24 |
25 | includeJar "org.jetbrains.kotlin:kotlin-main-kts:$versionKotlin"
26 | }
27 |
28 | shadowJar {
29 | getArchiveBaseName().set('danger-kotlin-kts')
30 | }
31 |
32 | compileKotlin {
33 | kotlinOptions.jvmTarget = "1.8"
34 | }
35 | compileTestKotlin {
36 | kotlinOptions.jvmTarget = "1.8"
37 | }
38 |
39 | tasks.withType(JavaCompile).configureEach {
40 | sourceCompatibility = JavaVersion.VERSION_1_8
41 | targetCompatibility = JavaVersion.VERSION_1_8
42 | }
43 |
44 | publishing {
45 | publications {
46 | maven(MavenPublication) {
47 | from components.java
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/danger-kotlin-kts/src/main/kotlin/systems/danger/kts/DangerFileScriptDefinition.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kts
2 |
3 | import org.jetbrains.kotlin.mainKts.*
4 | import java.io.File
5 | import kotlin.script.dependencies.ScriptContents
6 | import kotlin.script.dependencies.ScriptDependenciesResolver
7 | import kotlin.script.experimental.annotations.KotlinScript
8 | import kotlin.script.experimental.api.*
9 | import kotlin.script.experimental.dependencies.*
10 | import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
11 | import kotlin.script.experimental.host.FileBasedScriptSource
12 | import kotlin.script.experimental.host.FileScriptSource
13 | import kotlin.script.experimental.impl.internalScriptingRunSuspend
14 | import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity
15 | import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition
16 | import kotlin.script.experimental.jvm.dependenciesFromClassContext
17 | import kotlin.script.experimental.jvm.jvm
18 | import kotlin.script.experimental.jvm.updateClasspath
19 | import kotlin.script.experimental.jvmhost.jsr223.configureProvidedPropertiesFromJsr223Context
20 | import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
21 | import kotlin.script.experimental.jvmhost.jsr223.jsr223
22 | import kotlin.script.experimental.util.filterByAnnotationType
23 |
24 | @Suppress("unused")
25 | @KotlinScript(
26 | fileExtension = "df.kts",
27 | compilationConfiguration = DangerFileScriptDefinition::class,
28 | evaluationConfiguration = MainKtsEvaluationConfiguration::class,
29 | hostConfiguration = MainKtsHostConfiguration::class
30 | )
31 | abstract class DangerFileScript(val args: Array)
32 |
33 | object DangerFileScriptDefinition : ScriptCompilationConfiguration(
34 | {
35 | defaultImports(DependsOn::class, Repository::class, Import::class, CompilerOptions::class, ScriptFileLocation::class)
36 | jvm {
37 | dependenciesFromClassContext(
38 | DangerFileScriptDefinition::class,
39 | "danger-kotlin",
40 | "kotlin-stdlib",
41 | "kotlin-reflect"
42 | )
43 | }
44 | refineConfiguration {
45 | onAnnotations(
46 | DependsOn::class,
47 | Repository::class,
48 | Import::class,
49 | CompilerOptions::class,
50 | handler = DangerFileKtsConfigurator()
51 | )
52 | onAnnotations(ScriptFileLocation::class, handler = ScriptFileLocationCustomConfigurator())
53 | beforeCompiling(::configureScriptFileLocationPathVariablesForCompilation)
54 | beforeCompiling(::configureProvidedPropertiesFromJsr223Context)
55 | }
56 | ide {
57 | acceptedLocations(ScriptAcceptedLocation.Everywhere)
58 | }
59 | jsr223 {
60 | importAllBindings(true)
61 | }
62 | }
63 | )
64 |
65 | class DangerFileKtsConfigurator : RefineScriptCompilationConfigurationHandler {
66 | private val externalDependenciesResolvers = setOf(
67 | MavenDependenciesResolver()
68 | )
69 | private val resolvers = DANGER_DEFAULT_FLAT_DIRS
70 | .map { File(it) }
71 | .filter { it.exists() }
72 | .map { FileSystemDependenciesResolver(it) } +
73 | FileSystemDependenciesResolver() +
74 | externalDependenciesResolvers
75 |
76 | private val resolver = CompoundDependenciesResolver(resolvers)
77 |
78 | override operator fun invoke(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics =
79 | processAnnotations(context)
80 |
81 | fun processAnnotations(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics {
82 | val diagnostics = arrayListOf()
83 |
84 | fun report(severity: ScriptDependenciesResolver.ReportSeverity, message: String, position: ScriptContents.Position?) {
85 | diagnostics.add(
86 | ScriptDiagnostic(
87 | ScriptDiagnostic.unspecifiedError,
88 | message,
89 | mapLegacyDiagnosticSeverity(severity),
90 | context.script.locationId,
91 | mapLegacyScriptPosition(position)
92 | )
93 | )
94 | }
95 |
96 | val annotations = context.collectedData?.get(ScriptCollectedData.collectedAnnotations)?.takeIf { it.isNotEmpty() }
97 | ?: return context.compilationConfiguration.asSuccess()
98 |
99 | val scriptBaseDir = (context.script as? FileBasedScriptSource)?.file?.parentFile
100 | val importedSources = linkedMapOf>()
101 | var hasImportErrors = false
102 | annotations.filterByAnnotationType().forEach { scriptAnnotation ->
103 | scriptAnnotation.annotation.paths.forEach { sourceName ->
104 | val file = (scriptBaseDir?.resolve(sourceName) ?: File(sourceName)).normalize()
105 | val keyPath = file.absolutePath
106 | val prevImport = importedSources.put(keyPath, file to sourceName)
107 | if (prevImport != null) {
108 | diagnostics.add(
109 | ScriptDiagnostic(
110 | ScriptDiagnostic.unspecifiedError, "Duplicate imports: \"${prevImport.second}\" and \"$sourceName\"",
111 | sourcePath = context.script.locationId, location = scriptAnnotation.location?.locationInText
112 | )
113 | )
114 | hasImportErrors = true
115 | }
116 | }
117 | }
118 | if (hasImportErrors) return ResultWithDiagnostics.Failure(diagnostics)
119 |
120 | val compileOptions = annotations.filterByAnnotationType().flatMap {
121 | it.annotation.options.toList()
122 | }
123 |
124 | val resolveResult = try {
125 | @Suppress("DEPRECATION_ERROR")
126 | internalScriptingRunSuspend {
127 | resolver.resolveFromScriptSourceAnnotations(annotations.filter { it.annotation is DependsOn || it.annotation is Repository })
128 | }
129 | } catch (e: Throwable) {
130 | diagnostics.add(e.asDiagnostics(path = context.script.locationId))
131 | ResultWithDiagnostics.Failure(diagnostics)
132 | }
133 |
134 | return resolveResult.onSuccess { resolvedClassPath ->
135 | ScriptCompilationConfiguration(context.compilationConfiguration) {
136 | updateClasspath(resolvedClassPath)
137 | if (importedSources.isNotEmpty()) importScripts.append(importedSources.values.map { FileScriptSource(it.first) })
138 | if (compileOptions.isNotEmpty()) compilerOptions.append(compileOptions)
139 | }.asSuccess()
140 | }
141 | }
142 |
143 | private companion object {
144 | val DANGER_DEFAULT_FLAT_DIRS = setOf(
145 | "/usr/local", // x86 location
146 | "/opt/local", // Arm
147 | "/opt/homebrew", // Homebrew Arm
148 | "/usr", // Fallback
149 | ).map {
150 | "$it/lib/danger/libs"
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/danger-kotlin-kts/version.gradle:
--------------------------------------------------------------------------------
1 | group 'systems.danger'
2 | version '1.3.3'
3 |
--------------------------------------------------------------------------------
/danger-kotlin-library/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'org.jetbrains.kotlin.jvm'
3 | id 'org.jetbrains.kotlin.plugin.serialization'
4 | id 'maven-publish'
5 | }
6 |
7 | apply from: file('dependencies.gradle')
8 | apply from: file('version.gradle')
9 | apply plugin: 'kotlinx-serialization'
10 |
11 | shadowJar {
12 | getArchiveBaseName().set('danger-kotlin')
13 | getArchiveAppendix().set('')
14 | getArchiveClassifier().set('')
15 | getArchiveVersion().set('')
16 | }
17 |
18 | test {
19 | beforeTest { descriptor ->
20 | logger.lifecycle("Running test: " + descriptor)
21 | }
22 | }
23 |
24 | compileKotlin {
25 | kotlinOptions.jvmTarget = "1.8"
26 | }
27 | compileTestKotlin {
28 | kotlinOptions.jvmTarget = "1.8"
29 | }
30 |
31 | tasks.withType(JavaCompile).configureEach {
32 | sourceCompatibility = JavaVersion.VERSION_1_8
33 | targetCompatibility = JavaVersion.VERSION_1_8
34 | }
35 |
36 | publishing {
37 | publications {
38 | maven(MavenPublication) {
39 | from components.java
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/danger-kotlin-library/dependencies.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.johnrengelman.shadow'
2 | apply from: file('../dependencyVersions.gradle')
3 |
4 | dependencies {
5 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
6 | includeJar project(":danger-kotlin-sdk")
7 | includeJar project(":danger-kotlin-kts")
8 | utilsDependencies()
9 | kotlinDependencies()
10 | testingDependencies()
11 | }
12 |
--------------------------------------------------------------------------------
/danger-kotlin-library/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/danger-kotlin-library/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/KtxBitBucketServer.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | // extensions over [BitBucketServer] object
4 |
5 | // No extensions implemented
6 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/KtxDangerDSL.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import systems.danger.kotlin.models.bitbucket.BitBucketCloud
4 | import systems.danger.kotlin.models.bitbucket.BitBucketServer
5 | import systems.danger.kotlin.models.danger.DangerDSL
6 | import systems.danger.kotlin.models.git.Git
7 | import systems.danger.kotlin.models.github.GitHub
8 | import systems.danger.kotlin.models.gitlab.GitLab
9 |
10 | // extensions over [DangerDSL] object
11 |
12 | /**
13 | * Execute the block only if danger is running on GitHub
14 | * Example code:
15 | * ```
16 | * danger(args) {
17 | * onGitHub {
18 | * ...
19 | * }
20 | * }
21 | * ```
22 | *
23 | * @param onGitHub the block
24 | * @receiver the [GitHub] descriptor
25 | */
26 | inline fun DangerDSL.onGitHub(onGitHub: GitHub.() -> Unit) {
27 | if (this.onGitHub) {
28 | github.run(onGitHub)
29 | }
30 | }
31 |
32 | /**
33 | * Execute the block only if danger is running on GitLab
34 | * Example code:
35 | * ```
36 | * danger(args) {
37 | * onGitLab {
38 | * ...
39 | * }
40 | * }
41 | * ```
42 | *
43 | * @param onGitLab the block
44 | * @receiver the [GitLab] descriptor
45 | */
46 | inline fun DangerDSL.onGitLab(onGitLab: GitLab.() -> Unit) {
47 | if (this.onGitLab) {
48 | gitlab.run(onGitLab)
49 | }
50 | }
51 |
52 | /**
53 | * Execute the block only if danger is running on BitBucket
54 | * Example code:
55 | * ```
56 | * danger(args) {
57 | * onBitBucket {
58 | * ...
59 | * }
60 | * }
61 | * ```
62 | *
63 | * @param onBitBucket the block
64 | * @receiver the [BitBucketServer] descriptor
65 | */
66 | inline fun DangerDSL.onBitBucket(onBitBucket: BitBucketServer.() -> Unit) {
67 | if (this.onBitBucketServer) {
68 | bitBucketServer.run(onBitBucket)
69 | }
70 | }
71 |
72 | /**
73 | * Execute the block only if danger is running on BitBucketCloud
74 | * Example code:
75 | * ```
76 | * danger(args) {
77 | * onBitBucketCloud {
78 | * ...
79 | * }
80 | * }
81 | * ```
82 | *
83 | * @param onBitBucket the block
84 | * @receiver the [BitBucketCloud] descriptor
85 | */
86 | inline fun DangerDSL.onBitBucketCloud(onBitBucket: BitBucketCloud.() -> Unit) {
87 | if (this.onBitBucketCloud) {
88 | bitBucketCloud.run(onBitBucket)
89 | }
90 | }
91 |
92 | /**
93 | * Execute a [Git] block
94 | * Example code:
95 | * ```
96 | * danger(args) {
97 | * onGit {
98 | * ...
99 | * }
100 | * }
101 | * ```
102 | *
103 | * @param onGit the block
104 | * @receiver the [Git] descriptor
105 | */
106 | inline fun DangerDSL.onGit(onGit: Git.() -> Unit) {
107 | git.run(onGit)
108 | }
109 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/KtxGit.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import systems.danger.kotlin.models.git.Git
4 | import systems.danger.kotlin.models.git.GitCommit
5 | import systems.danger.kotlin.tools.shell.ShellExecutorFactory
6 |
7 | // extensions over [Git] object
8 |
9 | /**
10 | * Changed lines in this PR
11 | */
12 | val Git.changedLines: PullRequestChangedLines
13 | get() {
14 | if (headSha == null || baseSha == null) return PullRequestChangedLines(0, 0)
15 | val shellExecutor = ShellExecutorFactory.get()
16 | val commandRawOutput = shellExecutor.execute("git diff --numstat $baseSha $headSha")
17 | val additionDeletionPairs = commandRawOutput.lines()
18 | .filter { it.isNotEmpty() }
19 | .map { line ->
20 | val parts = line.split("\\s+".toRegex())
21 | (parts[0].toIntOrNull() ?: 0) to (parts[1].toIntOrNull() ?: 0)
22 | }
23 | val additions = additionDeletionPairs.fold(0) { acc, (addition, _) -> acc + addition }
24 | val deletions = additionDeletionPairs.fold(0) { acc, (_, deletion) -> acc + deletion }
25 | val commandRawDiffOutput = shellExecutor.execute("git diff $baseSha $headSha")
26 | return PullRequestChangedLines(additions, deletions, commandRawDiffOutput)
27 | }
28 |
29 | /**
30 | * Number of changed lines
31 | */
32 | val Git.linesOfCode: Int
33 | get() = additions + deletions
34 |
35 | /**
36 | * Number of added lines
37 | */
38 | val Git.additions: Int
39 | get() = changedLines.additions
40 |
41 | /**
42 | * Number of deleted lines
43 | */
44 | val Git.deletions: Int
45 | get() = changedLines.deletions
46 |
47 | /**
48 | * Reference to a SHA of head commit of this PR
49 | */
50 | val Git.headSha: String?
51 | get() = commits.sortChronologically().lastOrNull()?.sha
52 |
53 | /**
54 | * Reference to a SHA of base commit of this PR
55 | */
56 | val Git.baseSha: String?
57 | get() = commits.sortChronologically().firstOrNull()?.sha?.let { "$it^1" }
58 |
59 | /**
60 | * Unified diff of this PR
61 | */
62 | val Git.diff: String?
63 | get() = changedLines.diff
64 |
65 | /**
66 | * Wrapper for number of additions and deletions in currently processed Pull (or Merge) Request
67 | *
68 | * @param additions the number of additions
69 | * @param deletions the number of deletions
70 | * @param diff unified diff of the pr
71 | * @constructor Create empty PullRequestChangedLines
72 | */
73 | data class PullRequestChangedLines(
74 | val additions: Int,
75 | val deletions: Int,
76 | val diff: String? = null
77 | )
78 |
79 | private fun List.sortChronologically(): List {
80 | return sortedBy { it.author.date }
81 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/KtxGitHub.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | // extensions over [GitHub] object
4 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/KtxGitLab.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import systems.danger.kotlin.models.gitlab.GitLab
4 | import java.security.MessageDigest
5 |
6 | // extensions over [GitLab] object
7 |
8 | val GitLab.projectUrl: String
9 | get() = mergeRequest.webUrl.split("/merge_requests").first()
10 |
11 | fun GitLab.toWebUrl(filePath: String) = "$projectUrl/blob/${mergeRequest.sha}/${filePath}"
12 |
13 | fun GitLab.toWebDiffUrl(filePath: String) = "${mergeRequest.webUrl}/diffs#diff-content-${filePath.sha1}"
14 |
15 | val String.sha1: String
16 | get() = MessageDigest
17 | .getInstance("SHA-1")
18 | .digest(toByteArray())
19 | .joinToString(separator = "") { "%02x".format(it) }
20 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/MainDangerRunner.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import systems.danger.kotlin.json.JsonParser
4 | import systems.danger.kotlin.models.danger.ConcurrentDangerResults
5 | import systems.danger.kotlin.models.danger.DSL
6 | import systems.danger.kotlin.models.danger.DangerDSL
7 | import systems.danger.kotlin.models.git.FilePath
8 | import systems.danger.kotlin.sdk.DangerContext
9 | import systems.danger.kotlin.sdk.Violation
10 | import java.io.File
11 | import java.util.concurrent.atomic.AtomicReference
12 |
13 | /**
14 | * Main Danger runner
15 | *
16 | * @constructor Creates the main DangerContext
17 | *
18 | * @param jsonInputFilePath the input json file path (received from danger-js)
19 | * @param jsonOutputPath the output json file path used to publish the danger results on your Pull Request
20 | */
21 | internal class MainDangerRunner(jsonInputFilePath: FilePath, jsonOutputPath: FilePath) : DangerContext {
22 | private val jsonOutputFile: File = File(jsonOutputPath)
23 |
24 | val danger: DangerDSL = JsonParser.decodeJson(jsonInputFilePath).danger
25 |
26 | private val concurrentDangerResults: ConcurrentDangerResults = ConcurrentDangerResults()
27 |
28 | override val fails: List
29 | get() {
30 | return concurrentDangerResults.fails.get()
31 | }
32 | override val warnings: List
33 | get() {
34 | return concurrentDangerResults.warnings.get()
35 | }
36 | override val messages: List
37 | get() {
38 | return concurrentDangerResults.messages.get()
39 | }
40 | override val markdowns: List
41 | get() {
42 | return concurrentDangerResults.markdowns.get()
43 | }
44 |
45 |
46 | // Collect the registered plugins and initialize with the DangerContext
47 | // then creates an output json file
48 | init {
49 | register.dangerPlugins.forEach {
50 | it.withContext(this)
51 | }
52 | commit()
53 | }
54 |
55 | override fun fail(message: String) {
56 | fail(Violation(message))
57 | }
58 |
59 | override fun fail(message: String, file: FilePath, line: Int) {
60 | fail(Violation(message, file, line))
61 | }
62 |
63 | override fun warn(message: String) {
64 | warn(Violation(message))
65 | }
66 |
67 | override fun warn(message: String, file: FilePath, line: Int) {
68 | warn(Violation(message, file, line))
69 | }
70 |
71 | override fun message(message: String) {
72 | message(Violation(message))
73 | }
74 |
75 | override fun message(message: String, file: FilePath, line: Int) {
76 | message(Violation(message, file, line))
77 | }
78 |
79 | override fun markdown(message: String) {
80 | markdown(Violation(message))
81 | }
82 |
83 | override fun markdown(message: String, file: FilePath, line: Int) {
84 | markdown(Violation(message, file, line))
85 | }
86 |
87 | override fun suggest(code: String, file: FilePath, line: Int) {
88 | if (runnerInstance.danger.onGitHub) {
89 | val message = "```suggestion\n $code \n```"
90 | markdown(Violation(message, file, line))
91 | } else {
92 | val message = "```\n $code \n```"
93 | message(Violation(message))
94 | }
95 | }
96 |
97 | private fun warn(violation: Violation) {
98 | concurrentDangerResults.warnings.updateWith(violation)
99 | }
100 |
101 | private fun fail(violation: Violation) {
102 | concurrentDangerResults.fails.updateWith(violation)
103 | }
104 |
105 | private fun message(violation: Violation) {
106 | concurrentDangerResults.messages.updateWith(violation)
107 | }
108 |
109 | private fun markdown(violation: Violation) {
110 | concurrentDangerResults.markdowns.updateWith(violation)
111 | }
112 |
113 | private fun AtomicReference>.updateWith(violation: Violation) {
114 | this.getAndUpdate {
115 | it.apply {
116 | add(violation)
117 | }
118 | }
119 | commit()
120 | }
121 |
122 | // commit all the inline violations into the json output file
123 | private fun commit() {
124 | synchronized(this) {
125 | JsonParser.encodeJson(concurrentDangerResults.toDangerResults(), jsonOutputFile)
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/MainPlugins.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import systems.danger.kotlin.sdk.DangerContext
4 | import systems.danger.kotlin.sdk.DangerPlugin
5 |
6 | /**
7 | * Register
8 | * Helps to register a [DangerPlugin] before usage.
9 | * contains the plugins to be registered within [DangerContext]
10 | *
11 | * @constructor Create empty Register helper
12 | */
13 | object register {
14 | internal var dangerPlugins = mutableListOf()
15 |
16 | /**
17 | * Add a plugin to Danger
18 | * Example code:
19 | * ```
20 | * register plugin DangerPluginName
21 | *
22 | * // Then
23 | *
24 | * danger(args) {
25 | * ...
26 | * }
27 | * ```
28 | *
29 | * @param plugin the [DangerPlugin] to be registered
30 | */
31 | infix fun plugin(plugin: DangerPlugin) {
32 | dangerPlugins.add(plugin)
33 | }
34 |
35 | /**
36 | * Add more than one plugin to Danger
37 | * Example code:
38 | * ```
39 | * register.plugins(DangerPluginName1, DangerPluginName2, ...)
40 | *
41 | * // Then
42 | *
43 | * danger(args) {
44 | * ...
45 | * }
46 | * ```
47 | *
48 | * @param pluginArgs the [DangerPlugin]s
49 | */
50 | fun plugins(vararg pluginArgs: DangerPlugin) {
51 | dangerPlugins.addAll(pluginArgs)
52 | }
53 | }
54 |
55 | /**
56 | * Block that gave another option for registering plugins
57 | * Example code:
58 | * ```
59 | * register {
60 | * plugin(DangerPlugin1)
61 | * plugin(DangerPlugin2)
62 | * plugins(DangerPlugin3, DangerPlugin4)
63 | * }
64 | *
65 | * // Then
66 | *
67 | * danger(args) {
68 | * ...
69 | * }
70 | * ```
71 | *
72 | * @param block
73 | * @receiver [register] the registered plugins container
74 | */
75 | inline fun register(block: register.() -> Unit) = register.run(block)
76 |
77 | /**
78 | * internal util function that assign the [DangerContext] to a target [DangerPlugin]
79 | *
80 | * @param dangerContext the [DangerContext]
81 | */
82 | internal fun DangerPlugin.withContext(dangerContext: DangerContext) {
83 | registeredContext = dangerContext
84 | }
85 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/MainScript.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import systems.danger.kotlin.models.danger.DangerDSL
4 | import systems.danger.kotlin.models.git.FilePath
5 | import systems.danger.kotlin.sdk.Violation
6 |
7 | internal var dangerRunner: MainDangerRunner? = null
8 |
9 | internal val runnerInstance: MainDangerRunner
10 | get() {
11 | if(dangerRunner != null) {
12 | return dangerRunner!!
13 | } else {
14 | throw IllegalArgumentException("Danger must be initialised before accessing it")
15 | }
16 | }
17 |
18 | /**
19 | * Syntactic sugar that allows you to work with a [DangerDSL] descriptor in a single Danger block.
20 | * Example code:
21 | * ```
22 | * danger(args) {
23 | * ...
24 | * }
25 | * ```
26 | *
27 | * @param args the DangerFile arguments, is always just args
28 | * @param block the [DangerDSL] block
29 | * @receiver the [DangerDSL] descriptor
30 | */
31 | inline fun danger(args: Array, block: DangerDSL.() -> Unit) = Danger(args).run(block)
32 |
33 | /**
34 | * Create and return a [DangerDSL] descriptor
35 | * Example code:
36 | * ```
37 | * val danger = Danger(args)
38 | * ```
39 | *
40 | * @param args
41 | * @return a new [DangerDSL] descriptor
42 | */
43 | fun Danger(args: Array): DangerDSL {
44 | if (dangerRunner == null) {
45 | val argsCount = args.count()
46 |
47 | val jsonInputFilePath = args[argsCount - 2]
48 | val jsonOutputPath = args[argsCount - 1]
49 |
50 | dangerRunner = MainDangerRunner(jsonInputFilePath, jsonOutputPath)
51 | }
52 |
53 | return dangerRunner!!.danger
54 | }
55 |
56 | /**
57 | * Adds an inline message message to the Danger report
58 | *
59 | * @param message the standard message
60 | */
61 | fun message(message: String) =
62 | runnerInstance.message(message)
63 |
64 | /**
65 | * Adds an inline message message to the Danger report
66 | *
67 | * @param message the standard message
68 | * @param file the path to the target file
69 | * @param line the line number into the target file
70 | */
71 | fun message(message: String, file: FilePath, line: Int) =
72 | runnerInstance.message(message, file, line)
73 |
74 | /**
75 | * Adds an inline markdown message to the Danger report
76 | *
77 | * @param message the markdown formatted message
78 | */
79 | fun markdown(message: String) =
80 | runnerInstance.markdown(message)
81 |
82 | /**
83 | * Adds an inline markdown message to the Danger report
84 | *
85 | * @param message the markdown formatted message
86 | * @param file the path to the target file
87 | * @param line the line number into the target file
88 | */
89 | fun markdown(message: String, file: FilePath, line: Int) =
90 | runnerInstance.markdown(message, file, line)
91 |
92 | /**
93 | * Adds an inline warning message to the Danger report
94 | *
95 | * @param message the warning message
96 | */
97 | fun warn(message: String) =
98 | runnerInstance.warn(message)
99 |
100 | /**
101 | * Adds an inline warning message to the Danger report
102 | *
103 | * @param message the warning message
104 | * @param file the path to the target file
105 | * @param line the line number into the target file
106 | */
107 | fun warn(message: String, file: FilePath, line: Int) =
108 | runnerInstance.warn(message, file, line)
109 |
110 | /**
111 | * Adds an inline fail message to the Danger report
112 | *
113 | * @param message the fail message
114 | */
115 | fun fail(message: String) =
116 | runnerInstance.fail(message)
117 |
118 | /**
119 | * Adds an inline fail message to the Danger report
120 | *
121 | * @param message the fail message
122 | * @param file the path to the target file
123 | * @param line the line number into the target file
124 | */
125 | fun fail(message: String, file: FilePath, line: Int) =
126 | runnerInstance.fail(message, file, line)
127 |
128 | /**
129 | * Adds an inline suggested code message to the Danger report
130 | *
131 | * @param code the suggested code
132 | * @param file the path to the target file
133 | * @param line the line number into the target file
134 | */
135 | fun suggest(code: String, file: FilePath, line: Int) =
136 | runnerInstance.suggest(code, file, line)
137 |
138 | /** Fails on the Danger report */
139 | val fails: List
140 | get() = runnerInstance.fails.toList()
141 |
142 | /** Warnings on the Danger report */
143 | val warnings: List
144 | get() = runnerInstance.warnings.toList()
145 |
146 | /** Messages on the Danger report */
147 | val messages: List
148 | get() = runnerInstance.messages.toList()
149 |
150 | /** Markdowns on the Danger report */
151 | val markdowns: List
152 | get() = runnerInstance.markdowns.toList()
153 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/json/JsonParser.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.json
2 |
3 | import kotlinx.serialization.decodeFromString
4 | import kotlinx.serialization.encodeToString
5 | import kotlinx.serialization.json.Json
6 | import systems.danger.kotlin.models.git.FilePath
7 | import java.io.File
8 |
9 | // internal Json parser to decode and encode jsons from/to danger-js
10 | internal object JsonParser {
11 |
12 | private val decodeJsonParser = Json {
13 | ignoreUnknownKeys = true
14 | isLenient = true
15 | }
16 |
17 | private val encodeJsonParser = Json {
18 | encodeDefaults = true
19 | }
20 |
21 | inline fun decodeJson(path: FilePath): T {
22 | return decodeJsonParser.decodeFromString(path.readText())
23 | }
24 |
25 | inline fun encodeJson(value: T, outputFile: File) {
26 | val jsonString = encodeJsonParser.encodeToString(value)
27 | outputFile.writeText(jsonString)
28 | }
29 |
30 | private fun FilePath.readText() = File(this).readText()
31 | }
32 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/bitbucket/BitBucketCloud.kt:
--------------------------------------------------------------------------------
1 | @file:UseSerializers(DateSerializer::class)
2 |
3 | package systems.danger.kotlin.models.bitbucket
4 |
5 | import kotlinx.datetime.Instant
6 | import kotlinx.serialization.SerialName
7 | import kotlinx.serialization.Serializable
8 | import kotlinx.serialization.UseSerializers
9 | import systems.danger.kotlin.models.serializers.DateSerializer
10 |
11 | @Serializable
12 | data class BitBucketCloud(
13 | val metadata: BitBucketMetadata,
14 | @SerialName("pr")
15 | val pullRequest: PullRequest,
16 | val commits: List,
17 | val comments: List,
18 | val activities: List
19 | ) {
20 |
21 | @Serializable
22 | data class Activity(
23 | val comment: Comment? = null
24 | )
25 |
26 | @Serializable
27 | data class Comment(
28 | val id: Int,
29 | val content: Content,
30 | @SerialName("created_on")
31 | val createdOn: Instant,
32 | @SerialName("updated_on")
33 | val updatedOn: Instant,
34 | val deleted: Boolean,
35 | val user: User? = null,
36 | )
37 |
38 | @Serializable
39 | data class Content(
40 | val html: String,
41 | val markup: String,
42 | val raw: String
43 | )
44 |
45 | @Serializable
46 | data class User(
47 | val uuid: String,
48 | @SerialName("account_id")
49 | val accountId: String? = null,
50 | @SerialName("display_name")
51 | val displayName: String? = null,
52 | val nickname: String? = null
53 | )
54 |
55 | @Serializable
56 | data class Commit(
57 | val hash: String,
58 | val author: Author,
59 | val date: Instant,
60 | val message: String
61 | ) {
62 |
63 | @Serializable
64 | data class Author(
65 | val raw: String,
66 | val user: User? = null
67 | )
68 | }
69 |
70 | @Serializable
71 | data class PullRequest(
72 | val id: Int,
73 | val title: String,
74 | val author: User,
75 | val description: String,
76 | @SerialName("close_source_branch")
77 | val closeSourceBranch : Boolean,
78 | @SerialName("created_on")
79 | val createdOn: Instant,
80 | @SerialName("updated_on")
81 | val updatedOn: Instant,
82 | @SerialName("task_count")
83 | val taskCount: Int,
84 | @SerialName("comment_count")
85 | val commentCount: Int,
86 | val participants: List,
87 | val reviewers: List,
88 | val source: MergeRef,
89 | val destination: MergeRef,
90 | val state: State,
91 | val summary: Content,
92 | ) {
93 | @Serializable
94 | enum class State {
95 | OPEN, MERGED, SUPERSEDED, DECLINED
96 | }
97 |
98 | @Serializable
99 | data class Participant(
100 | val approved: Boolean,
101 | val role: Role,
102 | val user: User? = null
103 | ) {
104 |
105 | @Serializable
106 | enum class Role {
107 | REVIEWER, PARTICIPANT
108 | }
109 | }
110 | }
111 |
112 | @Serializable
113 | data class MergeRef(
114 | val branch: Branch,
115 | val commit: Commit,
116 | val repository: Repo
117 | ) {
118 |
119 | @Serializable
120 | data class Branch(
121 | val name: String
122 | )
123 |
124 | @Serializable
125 | data class Commit(
126 | val hash: String
127 | )
128 | }
129 |
130 | @Serializable
131 | data class Repo(
132 | val uuid: String,
133 | val name: String,
134 | @SerialName("full_name")
135 | val fullName: String
136 | )
137 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/bitbucket/BitBucketMetadata.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.bitbucket
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * The pull request and repository metadata
7 | * @property pullRequestId The PR's ID
8 | * @property repoSlug The complete repo slug including project slug.
9 | */
10 | @Serializable
11 | data class BitBucketMetadata internal constructor(
12 | val pullRequestID: String,
13 | val repoSlug: String
14 | )
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/danger/DangerDSL.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.danger
2 |
3 | import kotlinx.serialization.*
4 | import systems.danger.kotlin.models.bitbucket.BitBucketCloud
5 | import systems.danger.kotlin.models.bitbucket.BitBucketServer
6 | import systems.danger.kotlin.models.git.Git
7 | import systems.danger.kotlin.models.github.GitHub
8 | import systems.danger.kotlin.models.gitlab.GitLab
9 |
10 | @Serializable
11 | internal data class DSL(
12 | val danger: DangerDSL
13 | )
14 |
15 | @Serializable
16 | data class DangerDSL(
17 | @SerialName("github")
18 | private val _github: GitHub? = null,
19 | @SerialName("bitbucket_server")
20 | private val _bitBucketServer: BitBucketServer? = null,
21 | @SerialName("bitbucket_cloud")
22 | private val _bitBucketCloud: BitBucketCloud? = null,
23 | @SerialName("gitlab")
24 | private val _gitlab: GitLab? = null,
25 | val git: Git
26 | ) {
27 | val github: GitHub
28 | get() = _github!!
29 | val bitBucketServer: BitBucketServer
30 | get() = _bitBucketServer!!
31 | val bitBucketCloud: BitBucketCloud
32 | get() = _bitBucketCloud!!
33 | val gitlab: GitLab
34 | get() = _gitlab!!
35 |
36 | val onGitHub
37 | get() = _github != null
38 | val onBitBucketServer
39 | get() = _bitBucketServer != null
40 | val onBitBucketCloud
41 | get() = _bitBucketCloud != null
42 | val onGitLab
43 | get() = _gitlab != null
44 |
45 | val utils: Utils
46 | get() = Utils()
47 | }
48 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/danger/DangerResults.kt:
--------------------------------------------------------------------------------
1 | @file:UseSerializers(ViolationSerializer::class)
2 |
3 | package systems.danger.kotlin.models.danger
4 |
5 | import kotlinx.serialization.Serializable
6 | import kotlinx.serialization.UseSerializers
7 | import systems.danger.kotlin.sdk.Violation
8 | import systems.danger.kotlin.models.serializers.ViolationSerializer
9 | import java.util.concurrent.atomic.AtomicReference
10 |
11 | @Serializable
12 | internal data class Meta(
13 | val runtimeName: String = "Danger Kotlin",
14 | val runtimeHref: String = "https://danger.systems"
15 | )
16 |
17 | @Serializable
18 | internal data class DangerResults(
19 | val fails: List,
20 | val warnings: List,
21 | val messages: List,
22 | val markdowns: List,
23 | val meta: Meta = Meta()
24 | )
25 |
26 | internal data class ConcurrentDangerResults(
27 | val fails: AtomicReference> = AtomicReference(mutableListOf()),
28 | val warnings: AtomicReference> = AtomicReference(mutableListOf()),
29 | val messages: AtomicReference> = AtomicReference(mutableListOf()),
30 | val markdowns: AtomicReference> = AtomicReference(mutableListOf())
31 | ) {
32 | fun toDangerResults() = DangerResults(
33 | fails.get(), warnings.get(), messages.get(), markdowns.get()
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/danger/Utils.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.danger
2 |
3 | import systems.danger.kotlin.tools.shell.ShellExecutorFactory
4 | import java.io.File
5 |
6 | class Utils {
7 | /**
8 | * Let's you go from a file path to the contents of the file with less hassle.
9 | *
10 | * @param path the file reference from git.modified/creasted/deleted etc
11 | * @return the file contents
12 | */
13 | fun readFile(path: String): String {
14 | return File(path).readText()
15 | }
16 |
17 | /**
18 | * Gives you the ability to cheaply run a command and read the output without having to mess around
19 | *
20 | * @param command The first part of the command
21 | * @param arguments An optional list of arguments to pass in extra
22 | * @return the stdout from the command
23 | */
24 | fun exec(command: String, arguments: List = emptyList()): String {
25 | return ShellExecutorFactory.get().execute(command, arguments)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/git/Git.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.git
2 |
3 | import kotlinx.serialization.*
4 |
5 | typealias FilePath = String
6 |
7 | /**
8 | * The git specific metadata for a pull request
9 | *
10 | * @property modifiedFiles Modified file paths relative to the git root.
11 | * @property createdFiles Newly created file paths relative to the git root.
12 | * @property deletedFiles Removed file paths relative to the git root.
13 | */
14 | @Serializable
15 | data class Git(
16 | @SerialName("modified_files") val modifiedFiles: List,
17 | @SerialName("created_files") val createdFiles: List,
18 | @SerialName("deleted_files") val deletedFiles: List,
19 | @SerialName("commits") val commits: List
20 | )
21 |
22 | /**
23 | * A platform agnostic reference to a git commit.
24 | *
25 | * @property sha The SHA for the commit.
26 | * @property author Who wrote the commit.
27 | * @property committer Who shipped the code.
28 | * @property message The message for the commit.
29 | * @property parents SHAs for the commit's parents.
30 | * @property url The URL for the commit.
31 | */
32 | @Serializable
33 | data class GitCommit(
34 | val sha: String? = null,
35 | val author: GitCommitAuthor,
36 | val committer: GitCommitAuthor,
37 | val message: String,
38 | val parents: List = listOf(),
39 | val url: String
40 | )
41 |
42 | /**
43 | * A platform agnostic reference to a git commit.
44 | *
45 | * @property name The display name for the author.
46 | * @property email The email for the author.
47 | * @property date The ISO8601 date string for the commit.
48 | */
49 | @Serializable
50 | data class GitCommitAuthor(
51 | val name: String,
52 | val email: String,
53 | val date: String
54 | )
55 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/gitlab/GitLab.kt:
--------------------------------------------------------------------------------
1 | @file:UseSerializers(DateSerializer::class)
2 |
3 | package systems.danger.kotlin.models.gitlab
4 |
5 | import kotlinx.datetime.Instant
6 | import kotlinx.serialization.SerialName
7 | import kotlinx.serialization.Serializable
8 | import kotlinx.serialization.UseSerializers
9 | import systems.danger.kotlin.models.serializers.DateSerializer
10 |
11 | @Serializable
12 | data class GitLab(
13 | @SerialName("mr")
14 | val mergeRequest: GitLabMergeRequest,
15 | val metadata: GitLabMetadata
16 | )
17 |
18 | @Serializable
19 | data class GitLabDiffRefs(
20 | @SerialName("base_sha")
21 | val baseSha: String,
22 | @SerialName("head_sha")
23 | val headSha: String,
24 | @SerialName("start_sha")
25 | val startSha: String
26 | )
27 |
28 | @Serializable
29 | data class GitLabUserMergeData(
30 | @SerialName("can_merge")
31 | val canMerge: Boolean
32 | )
33 |
34 | @Serializable
35 | data class GitLabMergeRequest(
36 | @SerialName("allow_collaboration")
37 | val allowCollaboration: Boolean = false,
38 | @SerialName("allow_maintainer_to_push")
39 | val allowMaintainerToPush: Boolean = false,
40 | @SerialName("approvals_before_merge")
41 | val approvalsBeforeMerge: Int? = 0,
42 | val assignee: GitLabUser? = null,
43 | val author: GitLabUser,
44 | @SerialName("changes_count")
45 | val changesCount: String,
46 | @SerialName("closed_at")
47 | val closedAt: Instant? = null,
48 | @SerialName("closed_by")
49 | val closedBy: GitLabUser? = null,
50 | val description: String? = null,
51 | @SerialName("diff_refs")
52 | val diffRefs: GitLabDiffRefs,
53 | val downvotes: Int,
54 | @SerialName("first_deployed_to_production_at")
55 | val firstDeployedToProductionAt: Instant? = null,
56 | @SerialName("force_remove_source_branch")
57 | val forceRemoveSourceBranch: Boolean? = null,
58 | val id: Int,
59 | val iid: Int,
60 | @SerialName("latest_build_finished_at")
61 |
62 | val latestBuildFinishedAt: Instant? = null,
63 | @SerialName("latest_build_started_at")
64 |
65 | val latestBuildStartedAt: Instant? = null,
66 | val labels: List,
67 | @SerialName("merge_commit_sha")
68 | val mergeCommitSha: String? = null,
69 | @SerialName("merged_at")
70 | val mergedAt: Instant? = null,
71 | @SerialName("merged_by")
72 | val mergedBy: GitLabUser? = null,
73 | @SerialName("merge_when_pipeline_succeeds")
74 | val mergeOnPipelineSuccess: Boolean,
75 | val milestone: GitLabMilestone? = null,
76 | @SerialName("head_pipeline")
77 | val pipeline: GitLabPipeline,
78 | @SerialName("project_id")
79 | val projectId: String,
80 | val sha: String,
81 | @SerialName("should_remove_source_branch")
82 | val shouldRemoveSourceBranch: Boolean? = false,
83 | @SerialName("source_branch")
84 | val sourceBranch: String,
85 | @SerialName("source_project_id")
86 | val sourceProjectId: String,
87 | val state: GitLabMergeRequestState,
88 | val subscribed: Boolean,
89 | @SerialName("target_branch")
90 | val targetBranch: String,
91 | @SerialName("target_project_id")
92 | val targetProjectId: String,
93 | val timeStats: GitLabMergeRequestTimeStats? = null,
94 | val title: String,
95 | val upvotes: Int,
96 | @SerialName("user")
97 | private val userMergeData: GitLabUserMergeData,
98 | @SerialName("user_notes_count")
99 | val userNotesCount: Int,
100 | @SerialName("web_url")
101 | val webUrl: String,
102 | @SerialName("work_in_progress")
103 | val workInProgress: Boolean,
104 | val squash: Boolean,
105 | ) {
106 | val canMerge: Boolean
107 | get() = this.userMergeData.canMerge
108 | }
109 |
110 | @Serializable
111 | data class GitLabMergeRequestTimeStats(
112 | @SerialName("human_time_estimate")
113 | val humanTimeEstimate: Int = 0,
114 | @SerialName("human_time_spent")
115 | val humanTimeSpent: Int = 0,
116 | @SerialName("time_estimate")
117 | val timeEstimate: Int,
118 | @SerialName("total_time_spent")
119 | val totalTimeSpent: Int
120 | )
121 |
122 | @Serializable
123 | data class GitLabMetadata(
124 | val pullRequestID: String,
125 | val repoSlug: String
126 | )
127 |
128 | @Serializable
129 | enum class GitLabMergeRequestState {
130 | @SerialName("closed")
131 | CLOSED,
132 |
133 | @SerialName("locked")
134 | LOCKED,
135 |
136 | @SerialName("merged")
137 | MERGED,
138 |
139 | @SerialName("opened")
140 | OPENED
141 | }
142 |
143 | @Serializable
144 | data class GitLabMilestone(
145 | @SerialName("created_at")
146 | val createdAt: Instant,
147 | val description: String,
148 | @SerialName("due_date")
149 | val dueDate: Instant,
150 | val id: Int,
151 | val iid: Int,
152 | @SerialName("project_id")
153 | val projectID: Int,
154 | @SerialName("start_date")
155 | val startDate: Instant,
156 | val state: GitLabMilestoneState,
157 | val title: String,
158 | @SerialName("updated_at")
159 | val updatedAt: Instant,
160 | @SerialName("web_url")
161 | val webUrl: String
162 | )
163 |
164 | @Serializable
165 | enum class GitLabMilestoneState {
166 | @SerialName("active")
167 | ACTIVE,
168 |
169 | @SerialName("closed")
170 | CLOSED
171 | }
172 |
173 | @Serializable
174 | data class GitLabPipeline(
175 | val id: Int,
176 | val ref: String,
177 | val sha: String,
178 | val status: GitLabPipelineStatus,
179 | @SerialName("web_url")
180 | val webUrl: String
181 | )
182 |
183 | @Serializable
184 | enum class GitLabPipelineStatus {
185 | @SerialName("canceled")
186 | CANCELLED,
187 |
188 | @SerialName("failed")
189 | FAILED,
190 |
191 | @SerialName("pending")
192 | PENDING,
193 |
194 | @SerialName("running")
195 | RUNNING,
196 |
197 | @SerialName("skipped")
198 | SKIPPED,
199 |
200 | @SerialName("success")
201 | SUCCESS
202 | }
203 |
204 | @Serializable
205 | data class GitLabUser(
206 | @SerialName("avatar_url")
207 | val avatarUrl: String? = null,
208 | val id: Int,
209 | val name: String,
210 | val state: GitLabUserState,
211 | val username: String,
212 | @SerialName("web_url")
213 | val webUrl: String
214 | )
215 |
216 | @Serializable
217 | enum class GitLabUserState {
218 | @SerialName("active")
219 | ACTIVE,
220 |
221 | @SerialName("blocked")
222 | BLOCKED
223 | }
224 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/serializers/DateSerializer.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.serializers
2 |
3 | import kotlinx.datetime.Instant
4 | import kotlinx.serialization.ExperimentalSerializationApi
5 | import kotlinx.serialization.KSerializer
6 | import kotlinx.serialization.Serializer
7 | import kotlinx.serialization.descriptors.PrimitiveKind
8 | import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
9 | import kotlinx.serialization.descriptors.SerialDescriptor
10 | import kotlinx.serialization.encoding.Decoder
11 | import kotlinx.serialization.encoding.Encoder
12 | import java.text.SimpleDateFormat
13 | import java.util.*
14 |
15 | @ExperimentalSerializationApi
16 | @Serializer(forClass = DateSerializer::class)
17 | object DateSerializer : KSerializer {
18 |
19 | override val descriptor: SerialDescriptor
20 | get() = PrimitiveSerialDescriptor("kotlinx.datetime.Instant", PrimitiveKind.STRING)
21 |
22 | override fun serialize(encoder: Encoder, value: Instant) {
23 | // Implementation not needed for now
24 | }
25 |
26 | override fun deserialize(decoder: Decoder): Instant {
27 | val value = decoder.decodeString()
28 |
29 | return try {
30 | Instant.parse(value)
31 | } catch(e: Throwable) {
32 | Instant.fromEpochMilliseconds(ISO8601DateFormat().parse(value).toInstant().toEpochMilli())
33 | }
34 | }
35 | }
36 |
37 | class ISO8601DateFormat {
38 | fun parse(string: String?): Date {
39 | val formatter = SimpleDateFormat(
40 | "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
41 | ).apply {
42 | timeZone = TimeZone.getTimeZone("UTC")
43 | }
44 |
45 | return formatter.parse(string.toString())
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/models/serializers/ViolationSerializer.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.serializers
2 |
3 | import kotlinx.serialization.ExperimentalSerializationApi
4 | import kotlinx.serialization.KSerializer
5 | import kotlinx.serialization.Serializer
6 | import kotlinx.serialization.descriptors.SerialDescriptor
7 | import kotlinx.serialization.descriptors.buildClassSerialDescriptor
8 | import kotlinx.serialization.descriptors.element
9 | import kotlinx.serialization.encoding.*
10 | import systems.danger.kotlin.sdk.Violation
11 |
12 | @ExperimentalSerializationApi
13 | @Serializer(forClass = ViolationSerializer::class)
14 | object ViolationSerializer : KSerializer {
15 | override val descriptor: SerialDescriptor
16 | get() = buildClassSerialDescriptor(
17 | "systems.danger.kotlin.sdk.Violation"
18 | ) {
19 | element("message")
20 | element("file")
21 | element("line")
22 | }
23 |
24 | override fun deserialize(decoder: Decoder): Violation {
25 | return decoder.decodeStructure(descriptor) {
26 | lateinit var message: String
27 | var file: String? = null
28 | var line: Int? = null
29 | while (true) {
30 | when (val index = decodeElementIndex(descriptor)) {
31 | 0 -> message = decodeStringElement(descriptor, 0)
32 | 1 -> file = decodeStringElement(descriptor, 1)
33 | 2 -> line = decodeIntElement(descriptor, 2)
34 | CompositeDecoder.DECODE_DONE -> break
35 | else -> error("Unexpected index: $index")
36 | }
37 | }
38 | Violation(message, file, line)
39 | }
40 | }
41 |
42 | override fun serialize(encoder: Encoder, value: Violation) {
43 | encoder.encodeStructure(descriptor) {
44 | encodeStringElement(descriptor, 0, value.message)
45 | value.file?.let {
46 | encodeStringElement(descriptor, 1, it)
47 | }
48 | value.line?.let {
49 | encodeIntElement(descriptor, 2, it)
50 | }
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/main/kotlin/systems/danger/kotlin/tools/shell/ShellExecutor.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.tools.shell
2 |
3 | /**
4 | * ShellExecutor
5 | */
6 | interface ShellExecutor {
7 |
8 | /**
9 | * Execute [command] with optional list of arguments and return output from
10 | * stdout
11 | *
12 | * @param command the shell command
13 | * @param arguments the list of arguments to be passed to [command]
14 | * @return the stdout output
15 | */
16 | fun execute(command: String, arguments: List = emptyList()): String
17 | }
18 |
19 | // Internal implementation for ShellExecutor
20 | internal class ShellExecutorImpl : ShellExecutor {
21 |
22 | override fun execute(command: String, arguments: List): String {
23 | val commandWithArgs = command + if (arguments.isNotEmpty()) " " + arguments.joinToString(" ") else ""
24 |
25 | val process = Runtime.getRuntime().exec(arrayOf("/bin/bash", "-c", commandWithArgs))
26 | process.waitFor()
27 |
28 | return process.inputStream.bufferedReader().readText()
29 | }
30 | }
31 |
32 | /**
33 | * ShellExecutorFactory
34 | *
35 | * @constructor Creates a ShellExecutorFactory
36 | */
37 | object ShellExecutorFactory {
38 |
39 | private var shellExecutor: ShellExecutor = ShellExecutorImpl()
40 |
41 | // Useful for testing
42 | internal fun set(executor: ShellExecutor) {
43 | shellExecutor = executor
44 | }
45 |
46 | /**
47 | * Get the danger [ShellExecutor]
48 | */
49 | fun get() = shellExecutor
50 | }
51 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/KtxGitLabTest.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import kotlinx.serialization.decodeFromString
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 | import systems.danger.kotlin.models.danger.DSL
7 | import systems.danger.kotlin.models.gitlab.GitLab
8 | import systems.danger.kotlin.utils.TestUtils
9 |
10 | /**
11 | * Tests for [GitLab] extensions
12 | */
13 | internal class GitLabKtxTest {
14 |
15 | companion object {
16 | private const val filePath = "static/source/swift/guides/getting_started.html.slim"
17 | private const val projectUrl = "https://gitlab.com/danger-systems/danger.systems"
18 | private const val diffUrl = "$projectUrl/merge_requests/182/diffs#diff-content-6b0f4e17f37f5ea51f169e6e1eaa04a0151b17d1"
19 | private const val blobUrl = "$projectUrl/blob/621bc3348549e51c5bd6ea9f094913e9e4667c7b/$filePath"
20 | }
21 |
22 | private val dsl: DSL
23 | get() = TestUtils.Json.decodeFromString(TestUtils.JSONFiles.gitlabJSON)
24 |
25 | private val gitLab: GitLab
26 | get() = dsl.danger.gitlab
27 |
28 | @Test
29 | fun testProjectUrlAreCorrect() = assertEquals(projectUrl, gitLab.projectUrl)
30 |
31 | @Test
32 | fun testWebUrlAreCorrect() = assertEquals(blobUrl, gitLab.toWebUrl(filePath))
33 |
34 | @Test
35 | fun testWebDiffUrlWithAnchorAreCorrect() = assertEquals(diffUrl, gitLab.toWebDiffUrl(filePath))
36 | }
37 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/KtxGitTest.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import io.mockk.every
4 | import io.mockk.mockk
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Before
7 | import org.junit.Test
8 | import systems.danger.kotlin.models.git.Git
9 | import systems.danger.kotlin.models.git.GitCommit
10 | import systems.danger.kotlin.models.git.GitCommitAuthor
11 | import systems.danger.kotlin.tools.shell.ShellExecutorFactory
12 |
13 | /**
14 | * Tests for [Git] extensions
15 | */
16 | internal class GitKtxTest {
17 |
18 | companion object {
19 | private val diffCommandOutput = """
20 | 0 1 features/search/build.gradle
21 | 3 10 features/search/src/main/java/com/sampleapp/search/di/RepositoryModule.kt
22 | 2 4 features/search/src/main/java/com/sampleapp/search/model/ApiInteractor.kt
23 | 2 4 features/search/src/main/java/com/sampleapp/search/model/RecommendedPublishersRepository.kt
24 | 1 3 features/search/src/main/java/com/sampleapp/search/model/RecommendedTopicsRepository.kt
25 | """.trimIndent()
26 | }
27 |
28 | private val basicGit = Git(
29 | modifiedFiles = emptyList(),
30 | createdFiles = emptyList(),
31 | deletedFiles = emptyList(),
32 | commits = listOf(
33 | GitCommit(
34 | sha = "commit1",
35 | author = GitCommitAuthor("John Doe", "john@doe.com", "2024-11-28T13:41:53Z"),
36 | committer = GitCommitAuthor("John Doe", "john@doe.com", "2024-12-04T09:15:23Z"),
37 | message = "Random message",
38 | parents = listOf(),
39 | url = ""
40 | ),
41 | GitCommit(
42 | sha = "commit2",
43 | author = GitCommitAuthor("John Doe", "john@doe.com", "2024-11-28T13:54:45Z"),
44 | committer = GitCommitAuthor("John Doe", "john@doe.com", "2024-12-04T09:15:23Z"),
45 | message = "Random message",
46 | parents = listOf(),
47 | url = ""
48 | )
49 | )
50 | )
51 |
52 | private val expectedResult = PullRequestChangedLines(8, 22, diffCommandOutput)
53 |
54 | @Before
55 | fun setup() {
56 | ShellExecutorFactory.set(mockk {
57 | every { execute(any(), any()) } returns diffCommandOutput
58 | })
59 | }
60 |
61 | @Test
62 | fun testItCorrectlyParseDiff() {
63 | assertEquals(expectedResult, basicGit.changedLines)
64 | }
65 |
66 | @Test
67 | fun testAdditionsAreCorrect() {
68 | assertEquals(expectedResult.additions, basicGit.additions)
69 | }
70 |
71 | @Test
72 | fun testDeletionsAreCorrect() {
73 | assertEquals(expectedResult.deletions, basicGit.deletions)
74 | }
75 |
76 | @Test
77 | fun testLinesOfCodeAreCorrect() {
78 | assertEquals(expectedResult.deletions + expectedResult.additions, basicGit.linesOfCode)
79 | }
80 |
81 | @Test
82 | fun testNoChangedLinesForNoCommits() {
83 | val gitWOCommits = basicGit.copy(commits = emptyList())
84 | assertEquals(PullRequestChangedLines(0, 0), gitWOCommits.changedLines)
85 | }
86 |
87 | @Test
88 | fun testBaseShaIsCorrect() {
89 | assertEquals("commit1^1", basicGit.baseSha)
90 | }
91 |
92 | @Test
93 | fun testHeadShaIsCorrect() {
94 | assertEquals("commit2", basicGit.headSha)
95 | }
96 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/UtilsTests.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin
2 |
3 | import kotlinx.serialization.decodeFromString
4 | import org.junit.Assert
5 | import org.junit.Test
6 | import systems.danger.kotlin.models.danger.DSL
7 | import systems.danger.kotlin.utils.TestUtils.JSONFiles
8 | import systems.danger.kotlin.utils.TestUtils
9 | import java.io.File
10 |
11 | class UtilsTests {
12 | private val dsl: DSL = TestUtils.Json.decodeFromString(JSONFiles.githubDangerJSON)
13 |
14 | @Test
15 | fun testReadText() {
16 | val testFile = File("testFile")
17 | testFile.writeText("Test")
18 |
19 | Assert.assertEquals("Test", dsl.danger.utils.readFile("testFile"))
20 |
21 | testFile.delete()
22 | }
23 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/models/bitbucket/BitBucketCloudParsingTests.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.bitbucket
2 |
3 | import kotlinx.datetime.Instant
4 | import kotlinx.serialization.decodeFromString
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import systems.danger.kotlin.models.danger.DSL
8 | import systems.danger.kotlin.utils.TestUtils
9 | import systems.danger.kotlin.utils.TestUtils.JSONFiles
10 |
11 | class BitBucketCloudParsingTests {
12 |
13 | private val dsl: DSL = TestUtils.Json.decodeFromString(JSONFiles.dangerBitBucketCloudJSON)
14 |
15 | private val bitBucketCloud: BitBucketCloud = dsl.danger.bitBucketCloud
16 |
17 | @Test
18 | fun testItParsesTheBitBucketPullRequest() {
19 | with(bitBucketCloud.pullRequest) {
20 | val expectedUser = BitBucketCloud.User(
21 | uuid = "test",
22 | accountId = "test",
23 | displayName = "Foo Bar",
24 | nickname = "foo.bar"
25 | )
26 | assertEquals(expectedUser, author)
27 |
28 | val expectedDestination = BitBucketCloud.MergeRef(
29 | branch = BitBucketCloud.MergeRef.Branch(
30 | name = "destination",
31 | ),
32 | commit = BitBucketCloud.MergeRef.Commit(
33 | hash = "test"
34 | ),
35 | repository = BitBucketCloud.Repo(
36 | uuid = "test",
37 | name = "test",
38 | fullName = "test"
39 | )
40 | )
41 | assertEquals(expectedDestination, destination)
42 |
43 | val expectedSource = BitBucketCloud.MergeRef(
44 | branch = BitBucketCloud.MergeRef.Branch(
45 | name = "source",
46 | ),
47 | commit = BitBucketCloud.MergeRef.Commit(
48 | hash = "test"
49 | ),
50 | repository = BitBucketCloud.Repo(
51 | uuid = "test",
52 | name = "test",
53 | fullName = "test"
54 | )
55 | )
56 | assertEquals(expectedSource, source)
57 |
58 | val expectedParticipant = BitBucketCloud.PullRequest.Participant(
59 | approved = false,
60 | role = BitBucketCloud.PullRequest.Participant.Role.REVIEWER,
61 | user = BitBucketCloud.User(
62 | uuid = "danger",
63 | accountId = "danger",
64 | displayName = "Danger",
65 | nickname = "danger"
66 | )
67 | )
68 | assertEquals(1, participants.count())
69 | assertEquals(expectedParticipant, participants[0])
70 |
71 | assertEquals(Instant.parse("2022-04-07T15:19:56.209142+00:00"), createdOn)
72 | assertEquals(Instant.parse("2022-04-09T12:51:23.384574+00:00"), updatedOn)
73 | assertEquals(BitBucketCloud.PullRequest.State.OPEN, state)
74 | assertEquals("test", title)
75 |
76 | val expectedReviewer = BitBucketCloud.User(
77 | uuid = "danger",
78 | accountId = "danger",
79 | displayName = "Danger",
80 | nickname = "danger"
81 | )
82 | assertEquals(1, reviewers.count())
83 | assertEquals(expectedReviewer, reviewers.first())
84 | }
85 | }
86 |
87 | @Test
88 | fun testItParsesTheBitBucketCommits() {
89 | with(bitBucketCloud.commits) {
90 | val expectedCommit = BitBucketCloud.Commit(
91 | hash = "test",
92 | author = BitBucketCloud.Commit.Author(
93 | raw = "test",
94 | user = BitBucketCloud.User(
95 | uuid = "test",
96 | accountId = "test",
97 | displayName = "Foo Bar",
98 | nickname = "foo.bar"
99 | )
100 | ),
101 | date = Instant.parse("2022-04-07T15:18:09+00:00"),
102 | message = "test"
103 | )
104 | assertEquals(1, count())
105 | assertEquals(expectedCommit, first())
106 | }
107 | }
108 |
109 | @Test
110 | fun testItParsesTheBitBucketComments() {
111 | with(bitBucketCloud.comments) {
112 | val expectedComment = BitBucketCloud.Comment(
113 | id = 1,
114 | content = BitBucketCloud.Content(
115 | html = "test",
116 | markup = "markdown",
117 | raw = "test"
118 | ),
119 | createdOn = Instant.parse("2022-04-07T15:25:25.184212+00:00"),
120 | updatedOn = Instant.parse("2022-04-07T15:25:25.184261+00:00"),
121 | deleted = false,
122 | user = BitBucketCloud.User(
123 | uuid = "danger",
124 | accountId = "danger",
125 | displayName = "Danger",
126 | nickname = "danger"
127 | )
128 | )
129 |
130 | assertEquals(1, count())
131 | assertEquals(expectedComment, first())
132 | }
133 | }
134 |
135 | @Test
136 | fun testItParsesTheBitBucketMetadata() {
137 | with(bitBucketCloud.metadata) {
138 | assertEquals("artsy/emission", repoSlug)
139 | assertEquals("327", pullRequestID)
140 | }
141 | }
142 |
143 | @Test
144 | fun testItParsesTheBitBucketActivities() {
145 | with(bitBucketCloud.activities) {
146 | val expectedActivity = BitBucketCloud.Activity(
147 | comment = BitBucketCloud.Comment(
148 | id = 1,
149 | content = BitBucketCloud.Content(
150 | html = "test",
151 | markup = "markdown",
152 | raw = "test"
153 | ),
154 | createdOn = Instant.parse("2022-04-07T15:25:25.184212+00:00"),
155 | updatedOn = Instant.parse("2022-04-07T15:25:25.184261+00:00"),
156 | deleted = false,
157 | user = BitBucketCloud.User(
158 | uuid = "danger",
159 | accountId = "danger",
160 | displayName = "Danger",
161 | nickname = "danger"
162 | )
163 | )
164 | )
165 |
166 | assertEquals(1, count())
167 | assertEquals(expectedActivity, first())
168 | }
169 | }
170 |
171 | @Test
172 | fun testOnBitBucketCloudIsTrue() {
173 | assertEquals(true, dsl.danger.onBitBucketCloud)
174 | }
175 |
176 | @Test
177 | fun testOnBitBucketServerIsFalse() {
178 | assertEquals(false, dsl.danger.onBitBucketServer)
179 | }
180 |
181 | @Test
182 | fun testOnGitHubIsFalse() {
183 | assertEquals(false, dsl.danger.onGitHub)
184 | }
185 |
186 | @Test
187 | fun testOnGitLabIsFalse() {
188 | assertEquals(false, dsl.danger.onGitLab)
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/models/bitbucket/BitBucketServerParsingTests.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.bitbucket
2 |
3 | import kotlinx.serialization.decodeFromString
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 | import systems.danger.kotlin.models.danger.DSL
7 | import systems.danger.kotlin.utils.TestUtils.JSONFiles
8 | import systems.danger.kotlin.utils.TestUtils
9 |
10 | class BitBucketServerParsingTests {
11 |
12 | private val dsl: DSL = TestUtils.Json.decodeFromString(JSONFiles.dangerBitBucketServerJSON)
13 |
14 | private val bitBucketServer: BitBucketServer = dsl.danger.bitBucketServer
15 |
16 | @Test
17 | fun testItParsesTheBitBucketPullRequest() {
18 | with(bitBucketServer.pullRequest) {
19 | val expectedUser = BitBucketServerUser(
20 | null,
21 | "test",
22 | null,
23 | "user@email.com",
24 | true,
25 | null,
26 | BitBucketServerUser.Type.NORMAL
27 | )
28 | assertEquals(expectedUser, author?.user)
29 |
30 | val expectedProject =
31 | BitBucketServerProject(1, "PROJ", "Project", false, "NORMAL")
32 | val expectedRepo = BitBucketServerRepo(
33 | "Repo",
34 | "repo",
35 | "git",
36 | false,
37 | true,
38 | expectedProject
39 | )
40 | val expectedHead = BitBucketServerMergeRef(
41 | "refs/heads/foo",
42 | "foo",
43 | "d6725486c38d46a33e76f622cf24b9a388c8d13d",
44 | expectedRepo
45 | )
46 | assertEquals(expectedHead, toRef)
47 |
48 | val expectedBase = BitBucketServerMergeRef(
49 | "refs/heads/master",
50 | "master",
51 | "8942a1f75e4c95df836f19ef681d20a87da2ee20",
52 | expectedRepo
53 | )
54 | assertEquals(expectedBase, fromRef)
55 |
56 | val expectedPartecipant = BitBucketServerUser(
57 | 2,
58 | "danger",
59 | "DangerCI",
60 | "user@email.com",
61 | true,
62 | "danger",
63 | BitBucketServerUser.Type.NORMAL
64 | )
65 | assertEquals(1, participants?.count())
66 | assertEquals(expectedPartecipant, participants?.get(0)?.user)
67 |
68 | assertEquals(false, closed)
69 | assertEquals(1518863923273, createdAt)
70 | assertEquals(false, isLocked)
71 | assertEquals(true, open)
72 | assertEquals(BitBucketServerPR.State.OPEN, state)
73 | assertEquals("Pull request title", title)
74 |
75 | val expectedReviewerUser = BitBucketServerUser(
76 | 2,
77 | "danger",
78 | "DangerCI",
79 | "foo@bar.com",
80 | true,
81 | "danger",
82 | BitBucketServerUser.Type.NORMAL
83 | )
84 | val expectedReviewer = BitBucketServerReviewer(
85 | expectedReviewerUser,
86 | true,
87 | "8942a1f75e4c95df836f19ef681d20a87da2ee20"
88 | )
89 | assertEquals(1, reviewers?.count())
90 | assertEquals(expectedReviewer, reviewers?.get(0))
91 | }
92 | }
93 |
94 | @Test
95 | fun testItParsesTheBitBucketCommits() {
96 | with(bitBucketServer.commits) {
97 | val expectedUser = BitBucketServerUser(
98 | 2,
99 | "danger",
100 | "DangerCI",
101 | "foo@bar.com",
102 | true,
103 | "danger",
104 | BitBucketServerUser.Type.NORMAL
105 | )
106 | val expectedParent = BitBucketServerCommitParent(
107 | "c62ada76533a2de045d4c6062988ba84df140729",
108 | "c62ada76533"
109 | )
110 | val expectedCommit = BitBucketServerCommit(
111 | "d6725486c38d46a33e76f622cf24b9a388c8d13d",
112 | "d6725486c38",
113 | expectedUser,
114 | 1519442341000,
115 | expectedUser,
116 | 1519442341000,
117 | "Modify and remove files",
118 | listOf(expectedParent)
119 | )
120 | assertEquals(expectedCommit, first())
121 | assertEquals(2, count())
122 | }
123 | }
124 |
125 | @Test
126 | fun testItParsesTheBitBucketComments() {
127 | with(bitBucketServer.comments) {
128 | val expectedUser = BitBucketServerUser(
129 | 2,
130 | "danger",
131 | "DangerCI",
132 | "foo@bar.com",
133 | true,
134 | "danger",
135 | BitBucketServerUser.Type.NORMAL
136 | )
137 | val commentText = "test"
138 | val expectedProperty =
139 | BitBucketServerCommentInnerProperties(1, listOf())
140 | val expectedCommentDetail = BitBucketServerCommentDetail(
141 | 10,
142 | 23,
143 | commentText,
144 | expectedUser,
145 | 1518939353345,
146 | 1519449132488,
147 | listOf(),
148 | expectedProperty,
149 | listOf()
150 | )
151 | val expectedComment = BitBucketServerComment(
152 | 52,
153 | 1518939353345,
154 | expectedUser,
155 | "COMMENTED",
156 | null,
157 | null,
158 | null,
159 | null,
160 | "ADDED",
161 | expectedCommentDetail
162 | )
163 |
164 | assertEquals(expectedComment.toString(), this[1].toString())
165 | assertEquals(7, count())
166 | }
167 | }
168 |
169 | @Test
170 | fun testItParsesTheBitBucketMetadata() {
171 | with(bitBucketServer.metadata) {
172 | assertEquals("artsy/emission", repoSlug)
173 | assertEquals("327", pullRequestID)
174 | }
175 | }
176 |
177 | @Test
178 | fun testItParsesTheBitBucketActivities() {
179 | with(bitBucketServer.activities) {
180 | val expectedUser = BitBucketServerUser(
181 | 1,
182 | "test",
183 | "test",
184 | "foo@bar.com",
185 | true,
186 | "test",
187 | BitBucketServerUser.Type.NORMAL
188 | )
189 | val expectedActivity = BitBucketServerActivity(
190 | 61,
191 | 1519442356495,
192 | expectedUser,
193 | "RESCOPED",
194 | null
195 | )
196 |
197 | assertEquals(expectedActivity, first())
198 | assertEquals(7, count())
199 | }
200 | }
201 |
202 | @Test
203 | fun testOnBitBucketServerIsTrue() {
204 | assertEquals(true, dsl.danger.onBitBucketServer)
205 | }
206 |
207 | @Test
208 | fun testOnBitBucketCloudIsFalse() {
209 | assertEquals(false, dsl.danger.onBitBucketCloud)
210 | }
211 |
212 | @Test
213 | fun testOnGitHubIsFalse() {
214 | assertEquals(false, dsl.danger.onGitHub)
215 | }
216 |
217 | @Test
218 | fun testOnGitLabIsFalse() {
219 | assertEquals(false, dsl.danger.onGitLab)
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/models/git/GitParsingTests.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.git
2 |
3 | import kotlinx.serialization.decodeFromString
4 | import org.junit.Assert.*
5 | import org.junit.Test
6 | import systems.danger.kotlin.models.danger.DSL
7 | import systems.danger.kotlin.utils.TestUtils.JSONFiles
8 | import systems.danger.kotlin.utils.TestUtils
9 |
10 | class GitParsingTests {
11 |
12 | private val dsl: DSL = TestUtils.Json.decodeFromString(JSONFiles.githubDangerJSON)
13 |
14 | @Test
15 | fun testItParsesCorrectlyTheGitFiles() {
16 | val git = dsl.danger.git
17 |
18 | assertTrue(expectedModifiedFiles.containsAll(git.modifiedFiles.toList()))
19 | assertTrue(git.createdFiles[0] == ".ruby-version")
20 | }
21 |
22 | private val expectedModifiedFiles = listOf(
23 | ".travis.yml",
24 | "Kiosk.xcodeproj/project.pbxproj",
25 | "Kiosk/App/Logger.swift",
26 | "Kiosk/App/Networking/NetworkLogger.swift",
27 | "Kiosk/App/Networking/Networking.swift",
28 | "Kiosk/App/Networking/XAppToken.swift",
29 | "Kiosk/Auction Listings/ListingsViewModel.swift",
30 | "Kiosk/HelperFunctions.swift",
31 | "Kiosk/Images.xcassets/AppIcon.appiconset/Contents.json",
32 | "KioskTests/Bid Fulfillment/ConfirmYourBidArtsyLoginViewControllerTests.swift",
33 | "KioskTests/Bid Fulfillment/ConfirmYourBidEnterYourEmailViewControllerTests.swift",
34 | "KioskTests/Bid Fulfillment/LoadingViewControllerTests.swift",
35 | "KioskTests/Bid Fulfillment/RegistrationEmailViewControllerTests.swift",
36 | "KioskTests/Bid Fulfillment/RegistrationPasswordViewModelTests.swift",
37 | "KioskTests/Bid Fulfillment/SwipeCreditCardViewControllerTests.swift",
38 | "KioskTests/ListingsViewControllerTests.swift",
39 | "KioskTests/Models/SaleArtworkTests.swift",
40 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__alphabetical@2x.png",
41 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__grid@2x.png",
42 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__highest_bid@2x.png",
43 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__least_bids@2x.png",
44 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__lowest_bid@2x.png",
45 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__most_bids@2x.png",
46 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__alphabetical@2x.png",
47 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__grid@2x.png",
48 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__highest_bid@2x.png",
49 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__least_bids@2x.png",
50 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__lowest_bid@2x.png",
51 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__most_bids@2x.png",
52 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__alphabetical@2x.png",
53 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__grid@2x.png",
54 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__highest_bid@2x.png",
55 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__least_bids@2x.png",
56 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__lowest_bid@2x.png",
57 | "KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__most_bids@2x.png",
58 | "KioskTests/ReferenceImages/LoadingViewControllerTests/default__placing_a_bid@2x.png",
59 | "KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_error_due_to_outbid@2x.png",
60 | "KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_succeeded_but_not_resolved@2x.png",
61 | "KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_success_highest@2x.png",
62 | "KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_success_not_highest@2x.png",
63 | "KioskTests/ReferenceImages/LoadingViewControllerTests/ending__registering_user_not_resolved@2x.png",
64 | "KioskTests/ReferenceImages/LoadingViewControllerTests/ending__registering_user_success@2x.png",
65 | "KioskTests/ReferenceImages/LoadingViewControllerTests/errors__correctly_placing_a_bid@2x.png",
66 | "KioskTests/ReferenceImages/RegistrationEmailViewControllerTests/looks_right_by_default@2x.png",
67 | "KioskTests/ReferenceImages/RegistrationEmailViewControllerTests/looks_right_with_existing_email@2x.png",
68 | "KioskTests/ReferenceImages/RegistrationMobileViewControllerTests/looks_right_by_default@2x.png",
69 | "KioskTests/ReferenceImages/RegistrationMobileViewControllerTests/looks_right_with_existing_mobile@2x.png",
70 | "KioskTests/ReferenceImages/RegistrationPasswordViewControllerTests/looks_right_with_a_valid_password@2x.png",
71 | "KioskTests/ReferenceImages/RegistrationPasswordViewControllerTests/looks_right_with_an_invalid_password@2x.png",
72 | "KioskTests/ReferenceImages/RegistrationPostalZipViewControllerTests/looks_right_by_default@2x.png",
73 | "KioskTests/ReferenceImages/RegistrationPostalZipViewControllerTests/looks_right_with_existing_postal_code@2x.png",
74 | "KioskTests/ReferenceImages/YourBiddingDetailsViewControllerTests/displays_bidder_number_and_PIN@2x.png",
75 | "KioskTests/XAppTokenSpec.swift",
76 | "Podfile",
77 | "Podfile.lock"
78 | )
79 | }
80 |
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/models/gitlab/GitLabParsingTests.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.gitlab
2 |
3 | import kotlinx.datetime.Instant
4 | import kotlinx.serialization.decodeFromString
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import systems.danger.kotlin.models.danger.DSL
8 | import systems.danger.kotlin.utils.TestUtils.JSONFiles
9 | import systems.danger.kotlin.utils.TestUtils
10 |
11 | class GitLabParsingTests {
12 | private val dsl: DSL
13 | get() = TestUtils.Json.decodeFromString(JSONFiles.gitlabJSON)
14 | private val gitLab: GitLab
15 | get() = dsl.danger.gitlab
16 |
17 | @Test
18 | fun testItParsesTheGitLabMergeRequest() {
19 | with(gitLab.mergeRequest) {
20 | assertEquals(false, allowCollaboration)
21 | assertEquals(false, allowMaintainerToPush)
22 | assertEquals(1, approvalsBeforeMerge)
23 | val orta = GitLabUser(
24 | "https://secure.gravatar.com/avatar/f116cb3be23153ec08b94e8bd4dbcfeb?s=80&d=identicon", 377669, "Orta",
25 | GitLabUserState.ACTIVE, "orta", "https://gitlab.com/orta"
26 | )
27 | assertEquals(orta, assignee)
28 | val fmeloni = GitLabUser(
29 | "https://secure.gravatar.com/avatar/3d90e967de2beab6d44cfadbb4976b87?s=80&d=identicon",
30 | 3331525,
31 | "Franco Meloni",
32 | GitLabUserState.ACTIVE,
33 | "f-meloni",
34 | "https://gitlab.com/f-meloni"
35 | )
36 | assertEquals(fmeloni, author)
37 | assertEquals(false, canMerge)
38 | assertEquals("1", changesCount)
39 | assertEquals(null, closedAt)
40 | assertEquals(null, closedBy)
41 | assertEquals("Updating it to avoid problems like https://github.com/danger/swift/issues/221", description)
42 | val expectedDiffRefs = GitLabDiffRefs(
43 | "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f",
44 | "621bc3348549e51c5bd6ea9f094913e9e4667c7b",
45 | "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f"
46 | )
47 | assertEquals(expectedDiffRefs, diffRefs)
48 | assertEquals(0, downvotes)
49 | assertEquals(Instant.fromEpochMilliseconds(1554942622492), firstDeployedToProductionAt)
50 | assertEquals(true, forceRemoveSourceBranch)
51 | assertEquals(27469633, id)
52 | assertEquals(182, iid)
53 | assertEquals(Instant.fromEpochMilliseconds(1554942802492), latestBuildFinishedAt)
54 | assertEquals(Instant.fromEpochMilliseconds(1619786100103), latestBuildStartedAt)
55 | assertEquals(listOf(), labels)
56 | assertEquals("377a24fb7a0f30364f089f7bca67752a8b61f477", mergeCommitSha)
57 | assertEquals(Instant.fromEpochMilliseconds(1554943042492), mergedAt)
58 | assertEquals(orta, mergedBy)
59 | assertEquals(false, mergeOnPipelineSuccess)
60 | val expectedMilestone = GitLabMilestone(
61 | Instant.fromEpochMilliseconds(1554933465346),
62 | "Test Description",
63 | Instant.fromEpochMilliseconds(1560124800000),
64 | 1,
65 | 2,
66 | 1000,
67 | Instant.fromEpochMilliseconds(1554933465346),
68 | GitLabMilestoneState.CLOSED,
69 | "Test Milestone",
70 | Instant.fromEpochMilliseconds(1554933465346),
71 | "https://gitlab.com/milestone"
72 | )
73 | assertEquals(expectedMilestone, milestone)
74 | val expectedPipeline = GitLabPipeline(
75 | 50,
76 | "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f",
77 | "621bc3348549e51c5bd6ea9f094913e9e4667c7b",
78 | GitLabPipelineStatus.SUCCESS,
79 | "https://gitlab.com/danger-systems/danger.systems/pipeline/621bc3348549e51c5bd6ea9f094913e9e4667c7b"
80 | )
81 | assertEquals(expectedPipeline, pipeline)
82 | assertEquals("1620437", projectId)
83 | assertEquals("621bc3348549e51c5bd6ea9f094913e9e4667c7b", sha)
84 | assertEquals(null, shouldRemoveSourceBranch)
85 | assertEquals("patch-2", sourceBranch)
86 | assertEquals("10132593", sourceProjectId)
87 | assertEquals(GitLabMergeRequestState.MERGED, state)
88 | assertEquals(false, subscribed)
89 | assertEquals("master", targetBranch)
90 | assertEquals("1620437", targetProjectId)
91 | assertEquals(null, timeStats)
92 | assertEquals("Update getting_started.html.slim", title)
93 | assertEquals(0, upvotes)
94 | assertEquals(0, userNotesCount)
95 | assertEquals("https://gitlab.com/danger-systems/danger.systems/merge_requests/182", webUrl)
96 | assertEquals(false, workInProgress)
97 | assertEquals(false, squash)
98 | }
99 | }
100 |
101 | @Test
102 | fun testItParsesTheGitLabMetadata() {
103 | with(gitLab.metadata) {
104 | assertEquals("182", pullRequestID)
105 | assertEquals("danger-systems/danger.systems", repoSlug)
106 | }
107 | }
108 |
109 | @Test
110 | fun testOnGitHubIsFalse() {
111 | assertEquals(false, dsl.danger.onGitHub)
112 | }
113 |
114 | @Test
115 | fun testOnBitBucketCloudIsFalse() {
116 | assertEquals(false, dsl.danger.onBitBucketCloud)
117 | }
118 |
119 | @Test
120 | fun testOnBitBucketServerIsFalse() {
121 | assertEquals(false, dsl.danger.onBitBucketServer)
122 | }
123 |
124 | @Test
125 | fun testOnGitLabIsTrue() {
126 | assertEquals(true, dsl.danger.onGitLab)
127 | }
128 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/models/gitlab/GitLabPipelineStatusTest.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.models.gitlab
2 |
3 | import kotlinx.serialization.decodeFromString
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 | import systems.danger.kotlin.models.danger.DSL
7 | import systems.danger.kotlin.utils.TestUtils
8 | import systems.danger.kotlin.utils.TestUtils.JSONFiles
9 |
10 | class GitLabPipelineStatusTest {
11 |
12 | @Test
13 | fun testItParsesGitLabCancelledPipeline() {
14 | val dsl: DSL = TestUtils.Json.decodeFromString(JSONFiles.gitlabWithCancelledPipelineJSON)
15 | val gitLab = dsl.danger.gitlab
16 | assertEquals(GitLabPipelineStatus.CANCELLED, gitLab.mergeRequest.pipeline.status)
17 | }
18 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/kotlin/systems/danger/kotlin/utils/TestUtils.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.utils
2 |
3 | import kotlinx.serialization.json.Json
4 |
5 | object TestUtils {
6 |
7 | val Json: Json by lazy {
8 | Json {
9 | isLenient = true
10 | ignoreUnknownKeys = true
11 | }
12 | }
13 |
14 | object JSONFiles {
15 | val githubDangerJSON by lazy {
16 | loadJSON("githubDangerJSON.json")
17 | }
18 |
19 | val githubWithSomeNullsAttributeDangerJSON by lazy {
20 | loadJSON("githubWithSomeNullsAttributeDangerJSON.json")
21 | }
22 |
23 | val githubWithClosedMilestoneDangerJSON by lazy {
24 | loadJSON("githubWithClosedMilestoneDangerJSON.json")
25 | }
26 |
27 | val dangerBitBucketServerJSON by lazy {
28 | loadJSON("bitbucketServerDangerJSON.json")
29 | }
30 |
31 | val dangerBitBucketCloudJSON by lazy {
32 | loadJSON("bitbucketCloudDangerJSON.json")
33 | }
34 |
35 | val gitlabJSON by lazy {
36 | loadJSON("gitlabDangerJSON.json")
37 | }
38 |
39 | val gitlabWithCancelledPipelineJSON by lazy {
40 | loadJSON("gitlabWithCancelledPipelineDangerJSON.json")
41 | }
42 |
43 | private fun loadJSON(named: String): String {
44 | return this.javaClass.classLoader.getResource(named).readText()
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/resources/bitbucketCloudDangerJSON.json:
--------------------------------------------------------------------------------
1 | {
2 | "danger": {
3 | "git": {
4 | "modified_files": [
5 | ".gitignore"
6 | ],
7 | "created_files": [
8 | "banana",
9 | ".babelrc"
10 | ],
11 | "deleted_files": [
12 | ".babelrc.example",
13 | "jest.eslint.config.js"
14 | ],
15 | "commits": [
16 | {
17 | "sha": "d6725486c38d46a33e76f622cf24b9a388c8d13d",
18 | "parents": [
19 | "c62ada76533a2de045d4c6062988ba84df140729"
20 | ],
21 | "author": {
22 | "email": "foo@bar.com",
23 | "name": "danger",
24 | "date": "2018-02-24T03:19:01.000Z"
25 | },
26 | "committer": {
27 | "email": "foo@bar.com",
28 | "name": "danger",
29 | "date": "2018-02-24T03:19:01.000Z"
30 | },
31 | "message": "Modify and remove files",
32 | "tree": null,
33 | "url": "fake://host/artsy/emission/commits/d6725486c38d46a33e76f622cf24b9a388c8d13d"
34 | },
35 | {
36 | "sha": "c62ada76533a2de045d4c6062988ba84df140729",
37 | "parents": [
38 | "8942a1f75e4c95df836f19ef681d20a87da2ee20"
39 | ],
40 | "author": {
41 | "email": "foo@bar.com",
42 | "name": "danger",
43 | "date": "2018-02-17T10:38:02.000Z"
44 | },
45 | "committer": {
46 | "email": "foo@bar.com",
47 | "name": "danger",
48 | "date": "2018-02-17T10:38:02.000Z"
49 | },
50 | "message": "add banana",
51 | "tree": null,
52 | "url": "fake://host/artsy/emission/commits/c62ada76533a2de045d4c6062988ba84df140729"
53 | }
54 | ]
55 | },
56 | "bitbucket_cloud": {
57 | "metadata": {
58 | "repoSlug": "artsy/emission",
59 | "pullRequestID": "327"
60 | },
61 | "pr":{
62 | "description":"test",
63 | "title":"test",
64 | "close_source_branch":true,
65 | "reviewers":[
66 | {
67 | "display_name":"Danger",
68 | "uuid":"danger",
69 | "nickname":"danger",
70 | "account_id":"danger"
71 | }
72 | ],
73 | "id":1,
74 | "destination":{
75 | "commit":{
76 | "hash":"test"
77 | },
78 | "repository":{
79 | "name":"test",
80 | "full_name":"test",
81 | "uuid":"test"
82 | },
83 | "branch":{
84 | "name":"destination"
85 | }
86 | },
87 | "created_on":"2022-04-07T15:19:56.209142+00:00",
88 | "summary":{
89 | "raw":"test",
90 | "markup":"markdown",
91 | "html":"test"
92 | },
93 | "source":{
94 | "commit":{
95 | "hash":"test"
96 | },
97 | "repository":{
98 | "name":"test",
99 | "full_name":"test",
100 | "uuid":"test"
101 | },
102 | "branch":{
103 | "name":"source"
104 | }
105 | },
106 | "comment_count":1,
107 | "state":"OPEN",
108 | "task_count":0,
109 | "participants":[
110 | {
111 | "role":"REVIEWER",
112 | "user":{
113 | "display_name":"Danger",
114 | "uuid":"danger",
115 | "nickname":"danger",
116 | "account_id":"danger"
117 | },
118 | "approved":false
119 | }
120 | ],
121 | "reason":"",
122 | "updated_on":"2022-04-09T12:51:23.384574+00:00",
123 | "author":{
124 | "display_name":"Foo Bar",
125 | "uuid":"test",
126 | "nickname":"foo.bar",
127 | "account_id":"test"
128 | },
129 | "merge_commit":null,
130 | "closed_by":null
131 | },
132 | "commits": [
133 | {
134 | "hash":"test",
135 | "author":{
136 | "raw": "test",
137 | "user":{
138 | "display_name":"Foo Bar",
139 | "uuid":"test",
140 | "nickname":"foo.bar",
141 | "account_id":"test"
142 | }
143 | },
144 | "message": "test",
145 | "date": "2022-04-07T15:18:09+00:00"
146 | }
147 | ],
148 | "comments": [
149 | {
150 | "deleted":false,
151 | "content":{
152 | "markup":"markdown",
153 | "html":"test",
154 | "raw":"test"
155 | },
156 | "created_on":"2022-04-07T15:25:25.184212+00:00",
157 | "user":{
158 | "display_name":"Danger",
159 | "uuid":"danger",
160 | "nickname":"danger",
161 | "account_id":"danger"
162 | },
163 | "updated_on":"2022-04-07T15:25:25.184261+00:00",
164 | "id":1
165 | }
166 | ],
167 | "activities": [
168 | {
169 | "comment": {
170 | "deleted":false,
171 | "content":{
172 | "markup":"markdown",
173 | "html":"test",
174 | "raw":"test"
175 | },
176 | "created_on":"2022-04-07T15:25:25.184212+00:00",
177 | "user":{
178 | "display_name":"Danger",
179 | "uuid":"danger",
180 | "nickname":"danger",
181 | "account_id":"danger"
182 | },
183 | "updated_on":"2022-04-07T15:25:25.184261+00:00",
184 | "id":1
185 | }
186 | }
187 | ],
188 | "issues": [
189 | {
190 | "key": "JRA-11",
191 | "url": "https://jira.atlassian.com/browse/JRA-11"
192 | },
193 | {
194 | "key": "JRA-9",
195 | "url": "https://jira.atlassian.com/browse/JRA-9"
196 | }
197 | ]
198 | },
199 | "settings": {
200 | "github": {
201 | "accessToken": "12345",
202 | "additionalHeaders": {}
203 | },
204 | "cliArgs": {}
205 | }
206 | }
207 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/resources/gitlabDangerJSON.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": null,
117 | "head_pipeline": {
118 | "id": 50,
119 | "sha": "621bc3348549e51c5bd6ea9f094913e9e4667c7b",
120 | "ref": "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f",
121 | "status": "success",
122 | "web_url": "https://gitlab.com/danger-systems/danger.systems/pipeline/621bc3348549e51c5bd6ea9f094913e9e4667c7b"
123 | },
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 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/src/test/resources/gitlabWithCancelledPipelineDangerJSON.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": null,
117 | "head_pipeline": {
118 | "id": 50,
119 | "sha": "621bc3348549e51c5bd6ea9f094913e9e4667c7b",
120 | "ref": "ef28580bb2a00d985bffe4a4ce3fe09fdb12283f",
121 | "status": "canceled",
122 | "web_url": "https://gitlab.com/danger-systems/danger.systems/pipeline/621bc3348549e51c5bd6ea9f094913e9e4667c7b"
123 | },
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 | }
--------------------------------------------------------------------------------
/danger-kotlin-library/version.gradle:
--------------------------------------------------------------------------------
1 | group 'systems.danger'
2 | version '1.3.3'
3 |
--------------------------------------------------------------------------------
/danger-kotlin-sample-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenLocal()
4 | }
5 |
6 | dependencies {
7 | classpath "systems.danger:danger-plugin-installer:0.1-alpha"
8 | }
9 | }
10 |
11 | plugins {
12 | id 'org.jetbrains.kotlin.jvm' version '2.0.21'
13 | }
14 |
15 | apply plugin: 'danger-kotlin-plugin-installer'
16 |
17 | group 'systems.danger'
18 | version 'sample'
19 |
20 | repositories {
21 | mavenCentral()
22 | }
23 |
24 | dangerPlugin {
25 | outputJar = "${buildDir}/libs/danger-kotlin-sample-plugin-sample.jar"
26 | }
27 |
28 | dependencies {
29 | implementation "org.jetbrains.kotlin:kotlin-stdlib"
30 | implementation "systems.danger:danger-kotlin-sdk:1.2"
31 | }
32 |
--------------------------------------------------------------------------------
/danger-kotlin-sample-plugin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/danger-kotlin-sample-plugin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/danger-kotlin-sample-plugin/settings.gradle:
--------------------------------------------------------------------------------
1 | include ":danger-kotlin-sample-plugin"
--------------------------------------------------------------------------------
/danger-kotlin-sample-plugin/src/main/kotlin/systems/danger/samples/plugin/SamplePlugin.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.samples.plugin
2 |
3 | import systems.danger.kotlin.sdk.DangerPlugin
4 |
5 | object SamplePlugin : DangerPlugin() {
6 | override val id: String
7 | get() = "systems.danger.kotlin.samplePlugin"
8 |
9 | fun myCustomCheck() {
10 | context.message("✅ Custom plugin successfully linked")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'org.jetbrains.kotlin.jvm'
3 | id 'maven-publish'
4 | id 'signing'
5 | }
6 |
7 | apply from: file('version.gradle')
8 | apply from: file('maven-publish.gradle')
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
16 | }
17 |
18 | compileKotlin {
19 | kotlinOptions.jvmTarget = "1.8"
20 | }
21 | compileTestKotlin {
22 | kotlinOptions.jvmTarget = "1.8"
23 | }
24 |
25 | tasks.withType(JavaCompile).configureEach {
26 | sourceCompatibility = JavaVersion.VERSION_1_8
27 | targetCompatibility = JavaVersion.VERSION_1_8
28 | }
29 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Nov 03 23:08:58 GMT 2019
2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
3 | distributionBase=GRADLE_USER_HOME
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/maven-publish.gradle:
--------------------------------------------------------------------------------
1 | apply from: file('../secrets.gradle')
2 |
3 | task sourceJar(type: Jar) {
4 | archiveClassifier.set("sources")
5 | from sourceSets.main.allJava
6 | }
7 |
8 | task javadocJar(type: Jar, dependsOn: javadoc) {
9 | archiveClassifier.set("javadoc")
10 | from javadoc.destinationDir
11 | }
12 |
13 | signing {
14 | useGpgCmd()
15 | sign publishing.publications
16 | }
17 |
18 | publishing {
19 | repositories {
20 | maven {
21 | name = "Sonatype"
22 | def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
23 | def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots"
24 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
25 | credentials {
26 | username = loadSecret("SONATYPE_USER")
27 | password = loadSecret("SONATYPE_PASS")
28 | }
29 | }
30 | }
31 |
32 | publications {
33 | maven(MavenPublication) {
34 | from components.java
35 | artifact sourceJar
36 | artifact javadocJar
37 | pom {
38 | name = 'Danger Kotlin SDK'
39 | description = 'Develop your own plugin for Danger Kotlin'
40 | url = "https://github.com/danger/kotlin"
41 | licenses {
42 | license {
43 | name = 'MIT License'
44 | url = 'https://github.com/danger/kotlin/blob/master/LICENSE'
45 | }
46 | }
47 | developers {
48 | developer {
49 | id = 'gianluz'
50 | name = 'Gianluca Zuddas'
51 | }
52 | developer {
53 | id = 'f-meloni'
54 | name = 'Franco Meloni'
55 | }
56 | developer {
57 | id = 'danger'
58 | name = 'The Danger Community'
59 | }
60 | }
61 | scm {
62 | connection = 'scm:git:git://github.com/danger/kotlin.git'
63 | developerConnection = 'scm:git:ssh://github.com/danger/kotlin.git'
64 | url = 'https://github.com/danger/kotlin'
65 | }
66 | }
67 | }
68 | }
69 |
70 | gradle.taskGraph.whenReady { taskGraph ->
71 | if (taskGraph.allTasks.any { it instanceof Sign }) {
72 | allprojects {
73 | ext."signing.gnupg.keyName" = loadSecret("GPG_KEY_ID")
74 | ext."signing.gnupg.passphrase" = loadSecret("GPG_PASSPHRASE")
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/src/main/kotlin/systems/danger/kotlin/sdk/DangerKotlinAPI.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.sdk
2 |
3 | /**
4 | * Defines the API to post the Danger results on your Pull Request
5 | *
6 | * @constructor Create empty Danger context
7 | */
8 | interface DangerContext {
9 |
10 | /**
11 | * Adds an inline message message to the Danger report
12 | *
13 | * @param message the standard message
14 | */
15 | fun message(message: String)
16 |
17 | /**
18 | * Adds an inline message message to the Danger report
19 | *
20 | * @param message the standard message
21 | * @param file the path to the target file
22 | * @param line the line number into the target file
23 | */
24 | fun message(message: String, file: String, line: Int)
25 |
26 | /**
27 | * Adds an inline markdown message to the Danger report
28 | *
29 | * @param message the markdown formatted message
30 | */
31 | fun markdown(message: String)
32 |
33 | /**
34 | * Adds an inline markdown message to the Danger report
35 | *
36 | * @param message the markdown formatted message
37 | * @param file the path to the target file
38 | * @param line the line number into the target file
39 | */
40 | fun markdown(message: String, file: String, line: Int)
41 |
42 | /**
43 | * Adds an inline warning message to the Danger report
44 | *
45 | * @param message the warning message
46 | */
47 | fun warn(message: String)
48 |
49 | /**
50 | * Adds an inline warning message to the Danger report
51 | *
52 | * @param message the warning message
53 | * @param file the path to the target file
54 | * @param line the line number into the target file
55 | */
56 | fun warn(message: String, file: String, line: Int)
57 |
58 | /**
59 | * Adds an inline fail message to the Danger report
60 | *
61 | * @param message the fail message
62 | */
63 | fun fail(message: String)
64 |
65 | /**
66 | * Adds an inline fail message to the Danger report
67 | *
68 | * @param message the fail message
69 | * @param file the path to the target file
70 | * @param line the line number into the target file
71 | */
72 | fun fail(message: String, file: String, line: Int)
73 |
74 | /**
75 | * Adds an inline suggested code message to the Danger report
76 | *
77 | * @param code the suggested code
78 | * @param file the path to the target file
79 | * @param line the line number into the target file
80 | */
81 | fun suggest(code: String, file: String, line: Int)
82 |
83 | val fails: List
84 | val warnings: List
85 | val messages: List
86 | val markdowns: List
87 | }
88 |
89 | /**
90 | * Violation is any comment on your Pull Request
91 | *
92 | * @param message the violation message
93 | * @param file the path to the target file
94 | * @param line the line number into the target file
95 | * @constructor Create empty Violation
96 | */
97 | data class Violation(
98 | val message: String,
99 | val file: String? = null,
100 | val line: Int? = null
101 | )
102 |
103 | /**
104 | * Describe the Sdk, contains:
105 | * - [Sdk.API_VERSION]
106 | * - [Sdk.VERSION_NAME]
107 | *
108 | * @constructor Create empty Sdk
109 | */
110 | object Sdk {
111 | const val VERSION_NAME = "1.1"
112 | const val API_VERSION = 2
113 | }
114 |
115 | /**
116 | * A DangerPlugin is a special object that contains utils methods to be executed into the Danger File.
117 | * To create a new plugin you need to extend this class as per example:
118 | * ```
119 | * object MyDangerPlugin: DangerPlugin() {
120 | * override val id = "MyUniquePluginId"
121 | *
122 | * fun myUtilMethod() {
123 | * context.warn("This is a util method")
124 | * }
125 | * }
126 | * ```
127 | * your plugin can be registered and executed into your DangerFile with:
128 | * ```
129 | * register plugin MyDangerPlugin
130 | * ```
131 | * and then used:
132 | * ```
133 | * danger(args) {
134 | * MyDangerPlugin.myUtilMethod()
135 | * }
136 | * ```
137 | * with this example a warning message is published on your Pull Request.
138 | *
139 | * @constructor Create empty Danger plugin
140 | */
141 | abstract class DangerPlugin {
142 | companion object {
143 | const val DEVELOPED_WITH_API = Sdk.API_VERSION
144 | }
145 |
146 | // The plugin unique id
147 | abstract val id: String
148 |
149 | /**
150 | * The context that will be set by the danger runner. This wil be null if the plugin has not been registered in the
151 | * Dangerfile.
152 | */
153 | var registeredContext : DangerContext? = null
154 |
155 | /**
156 | * Provides a backing getter around registeredContext to avoid null checks if we know the plugin must be registered
157 | * in the Dangerfile.
158 | *
159 | * @throws NullPointerException if the plugin was not registered in the Dangerfile.
160 | */
161 | val context : DangerContext
162 | get() = registeredContext ?: throw NullPointerException(
163 | "DangerContext is null! Have you registered this plugin in your Dangerfile e.g. " +
164 | "'register plugin ${this::class.simpleName}'?"
165 | )
166 | }
167 |
--------------------------------------------------------------------------------
/danger-kotlin-sdk/version.gradle:
--------------------------------------------------------------------------------
1 | group 'systems.danger'
2 | version '1.2'
3 |
--------------------------------------------------------------------------------
/danger-kotlin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | kotlin("multiplatform")
3 | }
4 |
5 | kotlin {
6 | /* Targets configuration omitted.
7 | * To find out how to configure the targets, please follow the link:
8 | * https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets */
9 |
10 | val targetOS: String by project
11 | val buildTarget = if (project.hasProperty("targetOS")) {
12 | when (val osName = targetOS) {
13 | "macosX64" -> macosX64("runner")
14 | "linuxX64" -> linuxX64("runner")
15 | "macosArm64" -> macosArm64("runner")
16 | "mingwX64" -> mingwX64("runner")
17 | else -> throw GradleException("OS '$osName' is not supported.")
18 | }
19 | } else {
20 | when (val osName = System.getProperty("os.name")) {
21 | "Mac OS X" -> macosX64("runner")
22 | "Linux" -> linuxX64("runner")
23 | "Mac OS X Apple silicon" -> macosArm64("runner")
24 | "Windows 11" -> mingwX64("runner")
25 | else -> throw GradleException("OS '$osName' is not supported.")
26 | }
27 | }
28 |
29 | buildTarget.apply {
30 | binaries {
31 | executable()
32 | }
33 | }
34 |
35 | sourceSets {
36 | val runnerMain by getting {
37 | dependencies {
38 | implementation(kotlin("stdlib-common"))
39 | }
40 | }
41 | val runnerTest by getting {
42 | dependencies {
43 | implementation(kotlin("test-common"))
44 | implementation(kotlin("test-annotations-common"))
45 | }
46 | }
47 | all {
48 | languageSettings.optIn("kotlinx.cinterop.ExperimentalForeignApi")
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/danger-kotlin/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | kotlin.import.noCommonSourceSets=true
--------------------------------------------------------------------------------
/danger-kotlin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import platform.posix.getenv
2 | import systems.danger.DangerKotlin
3 | import systems.danger.Log
4 | import systems.danger.cmd.Command
5 | import systems.danger.cmd.dangerjs.DangerJS
6 |
7 | const val PROCESS_DANGER_KOTLIN = "danger-kotlin"
8 | const val VERSION = "1.3.3"
9 |
10 | fun main(args: Array) {
11 | Log.isVerbose = args.contains("--verbose") || (getenv("DEBUG")?.toString()?.isNotEmpty() ?: false)
12 | Log.info("Starting Danger-Kotlin $VERSION with args '${args.joinToString(", ")}'", verbose = true)
13 |
14 | if (args.isNotEmpty()) {
15 | when {
16 | args.contains("--help") -> {
17 | Log.info("danger-kotlin [command]")
18 | Log.info("")
19 | Log.info("Commands:")
20 | Log.info(Command.values().joinToString("\n") { it.argument + "\t" + it.description })
21 | }
22 | args.contains("--version") -> {
23 | Log.info(VERSION)
24 | }
25 | else -> {
26 | when (val command = Command.forArgument(args.first())) {
27 | Command.CI, Command.LOCAL, Command.PR -> {
28 | DangerJS.process(command, PROCESS_DANGER_KOTLIN, args.drop(1).map { if(it.contains(" ")) "'$it'" else it })
29 | }
30 | Command.RUNNER -> DangerKotlin.run()
31 | else -> Log.error("Invalid command received: $command")
32 | }
33 | }
34 | }
35 | } else {
36 | DangerKotlin.run()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/DangerKotlin.kt:
--------------------------------------------------------------------------------
1 | package systems.danger
2 |
3 | import systems.danger.cmd.dangerfile.DangerFile
4 |
5 | object DangerKotlin {
6 | private const val FILE_TMP_OUTPUT_JSON = "danger_out.json"
7 |
8 | fun run() {
9 | val dangerDSLPath = readLine()
10 |
11 | if (dangerDSLPath != null) {
12 | Log.info("Got Danger DSL path $dangerDSLPath", true)
13 | } else {
14 | Log.error("Didn't receive a DSL path")
15 | }
16 |
17 | dangerDSLPath?.removePrefix("danger://dsl/")?.stripEndLine()?.let {
18 | Log.info("Stripped DSL Path $it", true)
19 | with(DangerFile) {
20 | execute(it, FILE_TMP_OUTPUT_JSON)
21 | }
22 |
23 | printResult()
24 | }
25 | }
26 |
27 | private fun printResult() {
28 | println("danger-results:/$FILE_TMP_OUTPUT_JSON")
29 | }
30 |
31 | private fun String.stripEndLine(): String {
32 | return replaceAfter(".json", "")
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/Log.kt:
--------------------------------------------------------------------------------
1 | package systems.danger
2 |
3 | import kotlin.native.concurrent.ThreadLocal
4 |
5 | private object Color {
6 | private const val escape = '\u001B'
7 | const val default = "$escape[0;0m"
8 | const val red = "$escape[31m"
9 | const val yellow = "$escape[33m"
10 | }
11 |
12 | @ThreadLocal
13 | object Log {
14 |
15 | var isVerbose: Boolean = false
16 |
17 | fun info(message: String, verbose: Boolean = false) {
18 | printMessage(message, Color.default, verbose)
19 | }
20 |
21 | fun warning(message: String, verbose: Boolean = false) {
22 | printMessage("WARNING: $message", Color.yellow, verbose)
23 | }
24 |
25 | fun error(message: String, verbose: Boolean = false) {
26 | printMessage("ERROR: $message", Color.red, verbose)
27 | }
28 |
29 | private fun printMessage(message: String, color: String, verbose: Boolean) {
30 | if (!verbose || (verbose && this.isVerbose)) {
31 | println(color + message + Color.default)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/cmd/Cmd.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.cmd
2 |
3 | import platform.posix.*
4 | import systems.danger.Log
5 |
6 | class Cmd {
7 | private lateinit var name: String
8 | private lateinit var args: Array
9 |
10 | fun name(name: String) = apply {
11 | this.name = name
12 | }
13 |
14 | fun args(vararg args: String) = apply {
15 | this.args = args
16 | }
17 |
18 | fun exec() {
19 | exec(true)
20 | }
21 |
22 | private fun exec(printCallLog: Boolean) {
23 | "$name ${args.joinToString(" ")}".apply {
24 | if (printCallLog) {
25 | Log.info("Executing $this - pid ${getpid()}")
26 | }
27 | }.also {
28 | val exitCode = system(it)
29 |
30 | if (exitCode != 0) {
31 | throw Exception("Command $it exited with code $exitCode")
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/cmd/Command.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.cmd
2 |
3 | enum class Command(val argument: String) {
4 | CI("ci"),
5 | LOCAL("local"),
6 | PR("pr"),
7 | RUNNER("runner");
8 |
9 | companion object {
10 | fun forArgument(argument: String) = values().find{ it.argument == argument }
11 | }
12 |
13 | val description: String
14 | get() {
15 | when (this) {
16 | Command.CI -> {
17 | return "Use this on CI"
18 | }
19 | Command.LOCAL -> {
20 | return "Use this to run danger against your local changes from master/main"
21 | }
22 | Command.PR -> {
23 | return "Run danger-kotlin locally against a PR"
24 | }
25 | Command.RUNNER -> {
26 | return "Triggers the Dangerfile evaluation (used mainly by DangerJS)"
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/cmd/dangerfile/DangerFile.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.cmd.dangerfile
2 |
3 | import systems.danger.cmd.*
4 | import kotlinx.cinterop.CPointer
5 | import platform.posix.*
6 | import systems.danger.Log
7 |
8 | object DangerFile : DangerFileBridge {
9 | private const val DANGERFILE_EXTENSION = ".df.kts"
10 | private const val DANGERFILE = "Dangerfile$DANGERFILE_EXTENSION"
11 | private val platformExpectedLibLocations = setOf(
12 | "/usr/local", // x86 location
13 | "/opt/local", // Arm
14 | "/opt/homebrew", // Homebrew Arm
15 | "/usr", // Fallback
16 | )
17 |
18 | override fun execute(inputJson: String, outputJson: String) {
19 | val dangerKotlinJarPath = platformExpectedLibLocations
20 | .map { "$it/lib/danger/danger-kotlin.jar" }
21 | .filter { access(it, F_OK) == 0 }
22 | .also {
23 | if (it.isEmpty()) {
24 | Log.error("lib/danger/danger-kotlin.jar not found in following location ${platformExpectedLibLocations.joinToString()}")
25 | exit(1)
26 | }
27 | }.first()
28 |
29 | val dangerfile = dangerfileParameter(inputJson) ?: DANGERFILE
30 |
31 | if (!dangerfile.endsWith(DANGERFILE_EXTENSION)) {
32 | Log.error("The Dangerfile is not valid, it must have '$DANGERFILE_EXTENSION' as extension")
33 | exit(1)
34 | }
35 |
36 | Log.info("Compiling Dangerfile $dangerfile", true)
37 |
38 | Cmd().name("kotlinc").args(
39 | "-script-templates",
40 | "systems.danger.kts.DangerFileScript",
41 | "-cp",
42 | dangerKotlinJarPath,
43 | "-script",
44 | dangerfile,
45 | inputJson,
46 | outputJson
47 | ).exec()
48 | }
49 | }
50 |
51 | private fun dangerfileParameter(inputJson: String): String? {
52 | var result: String? = null
53 |
54 | fopen(inputJson, "r")?.apply {
55 | do {
56 | val line = readLine(this)?.let {
57 | val trimmedLine = it.trim()
58 | if (trimmedLine.startsWith("\"dangerfile\":")) {
59 | val dangerFile =
60 | trimmedLine.removePrefix("\"dangerfile\": \"").removeSuffix("\"").removeSuffix("\",")
61 | result = dangerFile
62 | }
63 | }
64 | } while (line != null && result == null)
65 | }.also {
66 | fclose(it)
67 | }
68 |
69 | return result
70 | }
71 |
72 | private fun readLine(file: CPointer): String? {
73 | var ch = getc(file)
74 | var lineBuffer: Array = arrayOf()
75 |
76 | while ((ch != '\n'.code) && (ch != EOF)) {
77 | lineBuffer += ch.toChar()
78 |
79 | ch = getc(file)
80 | }
81 |
82 | return if (lineBuffer.isEmpty()) {
83 | null
84 | } else {
85 | lineBuffer.joinToString("")
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/cmd/dangerfile/DangerFileBridge.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.cmd.dangerfile
2 |
3 | interface DangerFileBridge {
4 | fun execute(inputJson: String, outputJson: String)
5 | }
6 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/cmd/dangerjs/DangerJS.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.cmd.dangerjs
2 |
3 | import systems.danger.Log
4 | import systems.danger.cmd.Cmd
5 | import systems.danger.cmd.Command
6 |
7 | object DangerJS: DangerJSBridge {
8 | override fun process(command: Command, processName: String, args: List) {
9 | Log.info("Launching Danger-JS", verbose = true)
10 | with(Cmd()) {
11 | val dangerJSArgumentIndex = args.indexOf("--danger-js-path")
12 | val dangerJSPath: String
13 | if (dangerJSArgumentIndex != -1 && args.count() > dangerJSArgumentIndex + 1) {
14 | dangerJSPath = args[dangerJSArgumentIndex + 1]
15 | } else {
16 | dangerJSPath = "$(which danger)"
17 | }
18 | name("$dangerJSPath ${command.argument} --process $processName --passURLForDSL")
19 | args(args.joinToString(" "))
20 | exec()
21 | }
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/danger-kotlin/src/runnerMain/kotlin/systems.danger/cmd/dangerjs/DangerJSBridge.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.cmd.dangerjs
2 |
3 | import systems.danger.cmd.Command
4 |
5 | interface DangerJSBridge {
6 | fun process(command: Command, processName: String, args: List)
7 | }
8 |
--------------------------------------------------------------------------------
/danger-plugin-installer/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'org.jetbrains.kotlin.jvm'
3 | id 'java-gradle-plugin'
4 | id 'maven-publish'
5 | }
6 |
7 | group 'systems.danger'
8 | version '0.1-alpha'
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | gradlePlugin {
15 | plugins {
16 | simplePlugin {
17 | id = "danger-kotlin-plugin-installer"
18 | implementationClass = "systems.danger.kotlin.plugininstaller.PluginInstaller"
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
25 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
26 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
27 | implementation gradleApi()
28 | }
29 |
30 | test {
31 | useJUnitPlatform()
32 | }
33 |
--------------------------------------------------------------------------------
/danger-plugin-installer/src/main/kotlin/systems/danger/kotlin/plugininstaller/PluginInstaller.kt:
--------------------------------------------------------------------------------
1 | package systems.danger.kotlin.plugininstaller
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import java.io.File
6 |
7 | open class PluginInstallerExtension {
8 | var outputJar: String? = null
9 | }
10 |
11 | @SuppressWarnings("unused")
12 | class PluginInstaller : Plugin {
13 | override fun apply(target: Project) {
14 | val extension = target.extensions.create("dangerPlugin", PluginInstallerExtension::class.java)
15 | val dangerLibDir = File("/usr/local/lib/danger/libs")
16 |
17 | target.tasks.create("installDangerPlugin") {
18 | it.doLast {
19 | extension.outputJar?.let { outputJar ->
20 | val compiledJar = File(outputJar).takeIf { jar -> jar.isFile && jar.exists() }
21 | compiledJar?.let { jar ->
22 | jar.run {
23 | copyTo(File(dangerLibDir, jar.name), true)
24 | }
25 | }
26 | }
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/dependencyVersions.gradle:
--------------------------------------------------------------------------------
1 | apply from: file('../shadow.gradle')
2 |
3 | def group(Closure closure) {
4 | closure.delegate = dependencies
5 | return closure
6 | }
7 |
8 | // Utils
9 | ext.utils = [
10 | // Empty
11 | ]
12 |
13 | ext.utilsDependencies = group {
14 | // Empty
15 | }
16 |
17 | project.ext.artifactIdMoshi = 'moshi'
18 | project.ext.versionOkio = '1.16.0'
19 | project.ext.groupIdOkio = 'com.squareup.okio'
20 | project.ext.artifactIdOkio = 'okio'
21 |
22 | // Kotlin
23 | project.ext.versionKotlin = '2.0.21'
24 | project.ext.groupIdKotlin = 'org.jetbrains.kotlin'
25 | project.ext.groupIdKotlinx = 'org.jetbrains.kotlinx'
26 | project.ext.artifactIdKotlinMain = 'kotlin-main-kts'
27 | project.ext.artifactIdKotlinSerializationJson = 'kotlinx-serialization-json'
28 | project.ext.artifactIdKotlinDatetime = "kotlinx-datetime"
29 | project.ext.artifactIdKotlinCoroutines = "kotlinx-coroutines-core"
30 | project.ext.versionKotlinSerializationJson = '1.7.3'
31 | project.ext.versionKotlinDatetime = '0.6.1'
32 | project.ext.versionKotlinCoroutines = '1.9.0'
33 |
34 | ext.kotlin = [
35 | mainKts: "$groupIdKotlin:$artifactIdKotlinMain:$versionKotlin",
36 | serialization: "$groupIdKotlinx:$artifactIdKotlinSerializationJson:$versionKotlinSerializationJson",
37 | datetime: "$groupIdKotlinx:$artifactIdKotlinDatetime:$versionKotlinDatetime",
38 | coroutines: "$groupIdKotlinx:$artifactIdKotlinCoroutines:$versionKotlinCoroutines"
39 | ]
40 | ext.kotlinDependencies = group {
41 | includeJar kotlin.mainKts
42 | includeRecursiveJar kotlin.serialization
43 | includeRecursiveJar kotlin.datetime
44 | includeRecursiveJar kotlin.coroutines
45 | }
46 |
47 | // Testing
48 | project.ext.versionJunit = '4.12'
49 | project.ext.groupIdJunit = 'junit'
50 | project.ext.artifactIdJunit = 'junit'
51 | project.ext.versionMockK = "1.10.0"
52 | project.ext.groupIdMockK = "io.mockk"
53 | project.ext.artifactIdMockK = "mockk"
54 | ext.testing = [
55 | junit: "junit:junit:$versionJunit",
56 | mockK: "$groupIdMockK:$artifactIdMockK:$versionMockK"
57 | ]
58 | ext.testingDependencies = group {
59 | testImplementation testing.junit
60 | testImplementation testing.mockK
61 | }
62 |
--------------------------------------------------------------------------------
/docs/guides/about_the_dangerfile.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About the Dangerfile
3 | subtitle: The Dangerfile
4 | layout: guide_kt
5 | order: 1
6 | blurb: Step two on using Danger in your app, how to work locally and nuances around working with files.
7 | ---
8 |
9 | ## Writing your Dangerfile
10 |
11 | All of Danger is built in Kotlin, aims to have 100% in-line docs. This means a lot of your exploration can be done inside Intellij Idea.
12 | This document aims to give you some high level knowledge on how to work on your `Dangerfile.df.kts`.
13 |
14 | ## Working on your Dangerfile
15 |
16 | There are two ways to locally work on your Dangerfile. These both rely on using an external API locally, so you may hit
17 | their API rate-limits or need to have authenticated request for private repos. In which case you can use an access token
18 | to do authenticated requests by exposing a token to Danger.
19 |
20 | ```sh
21 | export DANGER_GITHUB_API_TOKEN='xxxx'
22 |
23 | # or for BitBucket by username and password
24 | export DANGER_BITBUCKETSERVER_HOST='xxxx' DANGER_BITBUCKETSERVER_USERNAME='yyyy' DANGER_BITBUCKETSERVER_PASSWORD='zzzz'
25 |
26 | # or for BitBucket by username and personal access token
27 | export DANGER_BITBUCKETSERVER_HOST='xxxx' DANGER_BITBUCKETSERVER_USERNAME='yyyy' DANGER_BITBUCKETSERVER_TOKEN='zzzz'
28 | ```
29 |
30 | Then the danger CLI will use authenticated API calls, which don't get hit by API limits.
31 |
32 | ### Using danger pr
33 |
34 | The command `danger-kotlin pr` expects an argument of a PR url, e.g:
35 |
36 | ```sh
37 | danger-kotlin pr https://github.com/danger/kotlin/pull/64
38 | ```
39 |
40 | This will use your local `Dangerfile.df.kts` against the metadata of the linked PR. Danger will then output the results
41 | into your terminal, instead of inside the PR itself.
42 |
43 | This _will not_ post comments in that PR.
44 |
45 | ### Using `danger` and Faking being on a CI
46 |
47 | If you create an
48 | [appropriately scoped temporary api token](http://danger.systems/js/guides/getting_started.html#setting-up-an-access-token)
49 | for your GitHub account, this can be a good way to see if danger is suitable for you before integrating it into your CI
50 | system.
51 |
52 | You can manually trigger danger against a pull request on the command line by setting the following environmental
53 | variables:
54 |
55 | ```bash
56 | export DANGER_FAKE_CI="YEP"
57 | export DANGER_TEST_REPO='username/reponame'
58 | ```
59 |
60 | Then you can run against a local branch that is attached to a pull-request, by running the following:
61 |
62 | ```bash
63 | git checkout branch-for-pr-1234
64 | DANGER_TEST_PR='1234' danger-kotlin ci
65 | ```
66 |
67 | Assuming that your local file-system matches up to that branch for your code review, this will be a good approximation
68 | of how danger will work when you integrate it into your CI system. Note: this **will** leave a comment on the PR.
69 |
70 | ### Plugins
71 |
72 | You can use any external dependency by adding the following lines at the top of your Dangerfile.df.kts
73 |
74 | ```kotlin
75 | @file:Repository("https://repo.maven.apache.org")
76 | @file:DependsOn("groupId:artifactId:version")
77 | ```
78 |
79 | In case you are importing a Danger Kotlin plugin, you will have to register it with:
80 |
81 | ```kotlin
82 | register plugin AndroidLint
83 | ```
84 |
85 | ## Finding more info
86 |
87 | The [CHANGELOG][changelog] for Danger is kept entirely end-user focused, so if there is an aspect of the Dangerfile that
88 | you do not know, or looks confusing and there is nothing in the documentation - [check the CHANGELOG][changelog]. This
89 | is where we write-up why a change happened, and how it can affect Danger users.
90 |
91 | [changelog]: http://danger.systems/kotlin/changelog.html
92 |
--------------------------------------------------------------------------------
/docs/tutorials/architecture.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Architecture
3 | subtitle: How is Danger Kotlin architected
4 | layout: guide_kt
5 | order: 1
6 | blurb: How do Danger Kotlin and JS interact?
7 | ---
8 |
9 | ## How does Danger Kotlin work?
10 |
11 | Danger provides an evaluation system for creating per-application rules. Basically, it is running arbitrary Kotlin with
12 | some extra PR metadata added in at runtime.
13 |
14 | Pulling this off though, is a bit of a thing.
15 |
16 | ## Setup
17 |
18 | Danger Kotlin is powered by Danger JS. Think of it as a Kotlin sandwich: `[Danger JS] -> [Danger Kotlin] -> [Danger JS]`.
19 | Danger JS first gets all the CI and Platform metadata, then passes that to Danger Kotlin, which returns the results of
20 | your Kotlin rules back to Danger JS.
21 |
22 | ```
23 | +--------------------------------+ +----------------------+ +--------------------+
24 | | | | | | |
25 | | ## Danger JS | | ## Danger Kotlin | | ## Danger JS |
26 | | | | | | |
27 | | Get GitHub/BitBucket/etc info | +----> | Setup plugins | +----> | Update PR info |
28 | | | | | | |
29 | | Transform into JSON | | Evaluate Dangerfile | | Pass / fail build |
30 | | | | | | |
31 | +--------------------------------+ +----------------------+ +--------------------+
32 | ```
33 |
34 | **Step 1: CI**. Danger JS needs to figure out what CI we're running on. You can see them all [in
35 | `source/ci_source/providers`][provs]. These use ENV VARs to figure out which CI `danger ci` is running on and validate
36 | whether it is a pull request.
37 |
38 | **Step 2: Platform**. Next, Danger JS needs to know which platform the code review is happening in. Today it's GitHub, BitBucket Server and GitLab.
39 |
40 | **Step 3: JSON DSL**. All the metadata from the above two steps are transformed into a JSON file, which is passed into
41 | Danger Kotlin.
42 |
43 | **Step 4: Kotlin Plugin Setup**. Danger has to prepare your code to be compiled, so any plugins need to be set up before
44 | compilation and runtime evaluation.
45 |
46 | **Step 5: Evaluation**. Most of the Danger Kotlin setup occurs when you run, `val danger = Danger(args)` in your
47 | `Dangerfile.df.kts` - it's nearly all smart JSON parsing into real Kotlin objects. The dangerfile uses `markdown`,
48 | `warning`, `fail` or `message` to pass results to a singleton.
49 |
50 | **Step 6: Passing Results**. The results from the evaluation are turned into JSON, and then passed back to Danger JS.
51 |
52 | **Step 6: Feedback**. Danger JS reads the results, then chooses whether to create/delete/edit any messages in the code
53 | review site. From the results of the run, Danger JS will then pass or fail the build.
54 |
55 | [provs]: https://github.com/danger/danger-js/tree/master/source/ci_source/providers
56 |
--------------------------------------------------------------------------------
/docs/tutorials/fast_feedback.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Fast Feedback via Danger Local
3 | subtitle: Platformless
4 | layout: guide_kt
5 | order: 4
6 | blurb: How to use Danger to get per-commit feedback
7 | ---
8 |
9 | ## Before we get started
10 |
11 | This tutorial continues after "Getting Started" - it's not required that you have Danger Kotlin running on your CI
12 | though, but assumes some familiarity.
13 |
14 | ## Locality
15 |
16 | With Danger, the typical flow is to help you can check rules on CI and get feedback inside your PR. With Peril you can
17 | move those rules to run on an external server making feedback instant. `danger-kotlin local` provides a somewhat hybrid
18 | approach.
19 |
20 | `danger-kotlin local` provides a way to run a Dangerfile based on git-hooks. This let's you run rules while you are still in
21 | the same context as your work as opposed to later during the code review. Personally, I find this most useful on
22 | projects when I ship 90% of the code to it.
23 |
24 | ## How it works
25 |
26 | Where `danger-kotlin ci` uses information from the Pull Request to figure out what has changed, `danger-kotlin local` naively uses the
27 | local differences in git from master to the current commit to derive the runtime environment. This is naive because if
28 | you don't keep your master branch in-sync, then it will be checking across potentially many branches.
29 |
30 | Inside a Dangerfile `danger.github` and `danger.bitbucketServer` will be `nil`, so you can share a Dangerfile between
31 | `danger-kotlin local` and `danger-kotlin ci` as long as you verify that these objects exist before using them.
32 |
33 | When I thought about how I wanted to use `danger-kotlin local` on repos in the Danger org, I opted to make a separate
34 | Dangerfile for `danger-kotlin local` and import this at the end of the main Dangerfile. This new Dangerfile only contains rules
35 | which can run with just `danger.git`, e.g. CHANGELOG/README checks. I called it `Dangerfile.lite.kt`.
36 |
--------------------------------------------------------------------------------
/docs/tutorials/plugin_development.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Plugin Developement
3 | subtitle: How to build a plugin for Danger Kotlin
4 | layout: guide_kt
5 | order: 2
6 | blurb: How do i make a plugin for Danger Kotlin?
7 | ---
8 |
9 | ## Introduction
10 |
11 | Danger provides an sdk for the plugin development. This sdk works with the principle of dependency inversion,
12 | that means you will be able to use the danger kotlin interfaces without import danger directly in your project.
13 |
14 | Everything you need is just IntelliJ IDEA and the kotlin environment setup on your machine.
15 |
16 | ## Setup
17 |
18 | **Step 1: Create a new project**. From IntelliJ IDEA create a new Project `File -> New -> Project` and choose a `Gradle` project with `Java` and `Koltin/JVM`
19 |
20 | **Step 2: Add the sdk as dependency**. In your `build.gradle` add the following dependency:
21 | ```groovy
22 | dependencies {
23 | implementation "systems.danger:danger-kotlin-sdk:1.2"
24 | }
25 | ```
26 |
27 | **Step 3: Create your main plugin class**. Create your plugin class as follow:
28 | ```kotlin
29 | package com.test.myawesomeplugin
30 |
31 | import systems.danger.kotlin.sdk.DangerPlugin
32 |
33 | object MyAwesomeDangerPlugin : DangerPlugin() {
34 | override val id: String
35 | get() = this.javaClass.name
36 |
37 | fun helloPlugin() {
38 | context.message("Hello Danger Plugin!")
39 | }
40 | }
41 | ```
42 |
43 | **Step 4: Build your plugin**. You can copy manually your compiled jar into `/usr/local/lib/danger/libs` or alternatively use the gradle plugin as follow:
44 | ```groovy
45 | buildscript {
46 | repositories {
47 | mavenLocal()
48 | }
49 |
50 | dependencies {
51 | classpath "systems.danger:danger-plugin-installer:0.1-alpha"
52 | }
53 | }
54 |
55 | apply plugin: 'danger-kotlin-plugin-installer'
56 |
57 | group 'com.test'
58 | version '0.0.1'
59 |
60 | dangerPlugin {
61 | outputJar = "${buildDir}/libs/my-awesome-plugin-0.0.1.jar"
62 | }
63 | ```
64 | then invoke `./gradlew build` and `./gradlew installDangerPlugin`.
65 |
66 | **Step 5: Try your plugin with Danger**. Create your `Dangerfile.df.kts` and import your plugin.
67 | ```kotlin
68 | @file:DependsOn("my-awesome-plugin-0.0.1.jar")
69 |
70 | import com.test.myawesomeplugin.MyAwesomePlugin
71 | import systems.danger.kotlin.*
72 |
73 | register plugin MyAwesomePlugin
74 |
75 | val danger = Danger(args)
76 |
77 | MyAwesomePlugin.helloPlugin()
78 | ```
79 | If danger is setup correctly you should see a message on your PR: `Hello Danger Plugin!`
80 |
81 | **Step 5: Maven publication**. Publish your plugin to maven central and add your plugin in [awesome-danger]. Then your `Dangerfile.df.kts` will be like:
82 | ```kotlin
83 | @file:DependsOn("com.test:my-awesome-plugin:version")
84 | //You can add more than one maven repository
85 | @file:Repository("http://url.to.maven.repo/repository")
86 |
87 | import com.test.myawesomeplugin.MyAwesomePlugin
88 | import systems.danger.kotlin.*
89 |
90 | register plugin MyAwesomePlugin
91 |
92 | val danger = Danger(args)
93 |
94 | MyAwesomePlugin.helloPlugin()
95 | ```
96 |
97 | ## Resources
98 |
99 | Some plugins can be found in [awesome-danger] and an example plugin is also available [here]
100 |
101 | [awesome-danger]: https://github.com/danger/awesome-danger#kotlin-danger-kotlin
102 | [here]: https://github.com/danger/kotlin/danger-kotlin-sample-plugin
103 |
--------------------------------------------------------------------------------
/docs/usage/bitbucket.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Danger + BitBucket Server
3 | subtitle: Dangerous bits
4 | layout: guide_kt
5 | order: 3
6 | blurb: An overview of using Danger with BitBucket Server, and some examples
7 | ---
8 |
9 | To use Danger Kotlin with BitBucket Server: you'll need to create a new account for Danger to use, then set the following
10 | environment variables on your CI:
11 |
12 | - `DANGER_BITBUCKETSERVER_HOST` = The root URL for your server, e.g. `https://bitbucket.mycompany.com`.
13 | - `DANGER_BITBUCKETSERVER_USERNAME` = The username for the account used to comment.
14 |
15 | Also you need to set password or
16 | [personal access token](https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html) by
17 | environment variables:
18 |
19 | - `DANGER_BITBUCKETSERVER_PASSWORD` = The password for the account used to comment.
20 | - `DANGER_BITBUCKETSERVER_TOKEN` = The personal access token for the account used to comment.
21 |
22 | Then in your Dangerfiles you will have a fully fleshed out `danger.bitbucketServer` object to work with. For example:
23 |
24 | ```kotlin
25 | val danger = Danger(args)
26 |
27 | val isAssignedToMe = danger.bitBucketServer.pullRequest.reviewers.map { it.user.name }.contains("orta")
28 | if (isAssignedToMe) {
29 | fail("You should probably assign someone else")
30 | }
31 | ```
32 |
33 | The DSL is expansive, but the TLDR is:
34 |
35 | ```kotlin
36 | danger.bitbucketServer.
37 |
38 | /** The pull request and repository metadata */
39 | metadata: RepoMetaData
40 | /** The PR metadata */
41 | pullRequest: BitBucketServerPR
42 | /** The commits associated with the pull request */
43 | commits: [BitBucketServerCommit]
44 | /** The comments on the pull request */
45 | comments: [BitBucketServerPRActivity]
46 | /** The activities such as OPENING, CLOSING, MERGING or UPDATING a pull request */
47 | activities: [BitBucketServerPRActivity]
48 | ```
49 |
50 | Any example you can find that uses GitHub, will probably work in BitBucket Server, with a bit of DSL
51 | translation.
52 |
53 | In addition, it is possible to specify a proxy to be used for the requests using environmental variables. This is useful
54 | for debugging:
55 |
56 | ```bash
57 | export NODE_TLS_REJECT_UNAUTHORIZED=0 # Avoid certificate error
58 |
59 | export http_proxy=http://127.0.0.1:8080
60 | or
61 | export https_proxy=https://127.0.0.1:8080
62 | ```
63 |
--------------------------------------------------------------------------------
/docs/usage/culture.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Cultural Changes
3 | subtitle: Cultural Changes
4 | layout: guide_kt
5 | order: 0
6 | blurb:
7 | Discussing introducing Danger into a team, how you can use it to provide positive feedback and encourage adoption of
8 | new rules.
9 | ---
10 |
11 | ## Introducing Danger
12 |
13 | It can be easy to try and jump straight from no Dangerfile to a 200 line complex set of cultural rules. We'd advise
14 | against introducing a long list of rules for Danger all at once. In our experience, gradual integration works better.
15 | The entire team may have agreed on the changes, but slower adoption has worked better for teams new to working with
16 | Danger.
17 |
18 | At Artsy we've found that first just integrating Danger with a single simple rule (like checking for a CHANGELOG entry)
19 | then starting to introduce complexity piece-meal. Encouraging different contributors to make the changes has made it
20 | easier to go from "Ah, we shouldn't do that again" to "Oh, we could make a Danger rule for that" to "Here's the PR".
21 |
22 | That is your end goal, making it so that everyone feels like it's easy to add and amend the rules as a project evolves.
23 | Making dramatic changes erodes that feeling, making regular small ones improves it.
24 |
25 | ## Phrasing
26 |
27 | One of Danger's greatest features is that it can free individuals up on the team to stop being "the person who always
28 | requests more tests" on a PR. By moving a lot of the rote tasks in code review to a machine, you free up some mental
29 | space to concentrate on more important things. One of the downsides is that it is impossible to provide the same level
30 | of nuance in how you provide feedback.
31 |
32 | You should use Danger to provide impartial feedback. Consider how these messages come across:
33 |
34 | - You have not added a CHANGELOG entry.
35 | - There isn't a CHANGELOG entry.
36 | - No CHANGELOG entry.
37 | - This PR does not include a CHANGELOG entry.
38 |
39 | The first feels like a statement that someone has intentionally done something wrong, and Danger has caught them in the
40 | act.
41 |
42 | The second aims to feel a lot like a testing framework telling you "Test Suites: 104 passed, 2 failures".
43 |
44 | The third if done consistently can work out well. Terse entries can work well when you have a large series of rules, as
45 | it feels like a check list to do.
46 |
47 | The fourth is what we generally try to aim for, an impartial but polite mention about the state of submitted PR.
48 |
49 | You can find what fits for you and your team, but being blameless in your messaging is one way to ensure that someone's
50 | first and 500th interaction is still great.
51 |
52 | ## Positive Rules
53 |
54 | Danger doesn't have to be used to provide a checklist of TODOs which have to be done. You can make rules that celebrate
55 | achievements, for example:
56 |
57 | - Submit congratulations when your app has had a version bump.
58 | - Thank the author for reducing the dependency tree.
59 | - Highlighting when someone has removed more code than adding it.
60 | - If there are notably tricky areas of the codebase, pass along a thumbs up for daring to improve it.
61 |
62 | There's aren't contrived either - I've seen variations on all of these rules inside Dangerfiles.
63 |
64 |
--------------------------------------------------------------------------------
/docs/usage/gitlab.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Danger + GitLab
3 | subtitle: Self-Hosted
4 | layout: guide_kt
5 | order: 5
6 | blurb: An overview of using Danger with GitLab, and some examples
7 | ---
8 |
9 | To use Danger Kotlin with GitLab: you'll need to create a new account for Danger to use, then set the following environment
10 | variables on your CI system:
11 |
12 | - `DANGER_GITLAB_HOST` = Defaults to `https://gitlab.com` but you can use it for your own url
13 | - `DANGER_GITLAB_API_TOKEN` = An access token for the account which will post comments
14 |
15 | Then in your Dangerfiles you will have a fully fleshed out `danger.gitlab` object to work with. For example:
16 |
17 | ```kotlin
18 | if (danger.gitlab.mr.title.contains("WIP")) {
19 | warn("PR is considered WIP")
20 | }
21 | ```
22 |
23 | The DSL is expansive, you can see all the details inside the [Danger Kotlin Reference][ref]
24 |
--------------------------------------------------------------------------------
/github-action/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ghcr.io/danger/danger-kotlin:1.3.3
2 |
3 | COPY entrypoint.sh /entrypoint.sh
4 |
5 | RUN chmod +x /entrypoint.sh
6 |
7 | ENTRYPOINT ["/entrypoint.sh"]
8 |
--------------------------------------------------------------------------------
/github-action/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | set -e
4 |
5 | dangerFile=$1
6 | runMode=$2
7 | jobId=$3
8 | args=$4
9 |
10 | echo "Danger JS version:"
11 | danger --version
12 | echo "Danger Kotlin version:"
13 | danger-kotlin --version
14 |
15 | if [ -f "$dangerFile" ]; then
16 | danger-kotlin $runMode --dangerfile="$dangerFile" --id="$jobId" $args
17 | exit 0
18 | else
19 | echo "Danger file $dangerFile does not exist."
20 | exit 1
21 | fi
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlinVersion=2.0.21
2 | kotlin.code.style=official
3 | systemProp.org.gradle.internal.publish.checksums.insecure=true
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danger/kotlin/2fc3cf363279b061be07fd82b28e405c2d53b922/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/scripts/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | VERSION=1.3.3
4 |
5 | while getopts v:h: flag
6 | do
7 | case "${flag}" in
8 | v) VERSION=${OPTARG};;
9 | esac
10 | done
11 |
12 | sudo -v && sudo="true" || sudo=""
13 |
14 | if ! [[ -x "$(command -v danger)" ]]; then
15 | if ! [[ -x "$(command -v npm)" ]]; then
16 | echo "Please install node js"
17 | exit 1
18 | fi
19 |
20 | echo "Installing danger"
21 |
22 | if [[ -n "$sudo" ]]; then
23 | sudo npm install -g danger
24 | else
25 | npm install -g danger
26 | fi
27 | fi
28 |
29 | if [[ -n "$sudo" && "$OSTYPE" != "darwin"* ]]; then
30 | sudo chmod -R a+rwx /usr/local/
31 | fi
32 |
33 | if ! [[ -x "$(command -v kotlinc)" ]]; then
34 | echo "Installing kotlin compiler 2.0.21"
35 | curl -o kotlin-compiler.zip -L https://github.com/JetBrains/kotlin/releases/download/v2.0.21/kotlin-compiler-2.0.21.zip
36 | unzip -d /usr/local/ kotlin-compiler.zip
37 | echo 'export PATH=/usr/local/kotlinc/bin:$PATH' >> ~/.bash_profile
38 | rm -rf kotlin-compiler.zip
39 | fi
40 |
41 | if ! [[ -x "$(command -v gradle)" ]]; then
42 | echo "Installing gradle 8.10.2"
43 | curl -o gradle.zip -L https://downloads.gradle-dn.com/distributions/gradle-8.10.2-bin.zip
44 | mkdir /opt/gradle
45 | unzip -d /opt/gradle gradle.zip
46 | echo 'export PATH=/opt/gradle/gradle-8.10.2/bin:$PATH' >> ~/.bash_profile
47 | rm -rf gradle.zip
48 | fi
49 |
50 | git clone https://github.com/danger/kotlin.git --branch $VERSION --depth 1 _danger-kotlin
51 | cd _danger-kotlin && make install
52 | cd ..
53 | rm -rf _danger-kotlin
54 |
--------------------------------------------------------------------------------
/scripts/release_changelog.sh:
--------------------------------------------------------------------------------
1 | TEXT=`cat CHANGELOG.md| sed -n "/##\ $VERSION/,/##/p"`
2 |
3 | TEXT=`echo "$TEXT" | sed '1d;$d' | sed 's/\[\]//g'`
4 |
5 | echo "gh release create $VERSION -n \"## What's Changed\r\n$TEXT\""
6 |
7 | gh release create $VERSION -n "$TEXT"
8 |
--------------------------------------------------------------------------------
/secrets.gradle:
--------------------------------------------------------------------------------
1 | ext.loadSecret = { key ->
2 | try {
3 | def secret = System.getenv(key) ?: loadLocalSecret(key)
4 | } catch (FileNotFoundException ignored) {
5 | System.out.println("Secret key $key not found. Falling back to default")
6 | def secret = ""
7 | }
8 | }
9 |
10 | def String loadLocalSecret(key) {
11 | def localSecrets = new Properties()
12 | file("secrets.properties").withInputStream { localSecrets.load(it) }
13 | return localSecrets.getProperty(key)
14 | }
15 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | mavenCentral()
5 | mavenLocal()
6 | }
7 | }
8 |
9 | include ':danger-kotlin'
10 | include ':danger-kotlin-library'
11 | include ':danger-kotlin-sdk'
12 | include ':danger-kotlin-kts'
13 | include ':danger-plugin-installer'
--------------------------------------------------------------------------------
/shadow.gradle:
--------------------------------------------------------------------------------
1 | apply from: file('../configurations.gradle')
2 | shadowJar {
3 | configurations = [
4 | project.configurations.includeJar,
5 | project.configurations.includeRecursiveJar
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------