1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftPMでのSwift製Danger導入

Last updated at Posted at 2025-02-23

はじめに

前回書いたRuby版のDanger導入方法に続き、今回はSwift製のDangerであるDanger Swiftでの導入を試しためましたので、その方法やハマりポイントについて記事にしようと思います。

環境

  • Xcode16
  • Swift6.0
  • macOS 15.0
  • CI: GitHub Actions

導入方法

基本的に公式の導入方法を参考に進めていきます。
https://danger.systems/swift/guides/getting_started

1. SPMでDanger Swiftの依存を持ったダイナミックライブラリを作成する

dependencies: [
    .package(url: "https://github.com/danger/swift.git", exact: "3.21.1")
],
targets: [
        .target(
            name: "DangerDependencies",
            dependencies: ["Danger"]
        )
    ]
  • dependencies に Danger を追加する
  • Danger に依存したターゲットを追加

ただ、公式の方法でtargetにDangerへの依存を追加しようとしてもビルドエラーが出てしまい、以下のようにnamepackageを指定してやる必要がありました。

targets: [
    .target(
        name: "DangerDependencies",
-       dependencies: ["Danger"]
+       dependencies: [
+           .product(name: "Danger", package: "swift")
+       ]
    )
]

最終的な Package.swift の内容が以下になります。

// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "Dangerfile",
    platforms: [.macOS(.v14)],
    products: [
        .library(
            name: "Dangerfile",
            type: .dynamic,
            targets: ["Dangerfile"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/danger/swift.git", exact: "3.21.1")
    ],
    targets: [
        .target(
            name: "Dangerfile",
            dependencies: [
                .product(name: "Danger", package: "swift")
            ]
        )
    ]
)

記事を参考に、ルートディレクトリにDangerfileフォルダーを作り、
先ほど作成したSPMライブラリを全て突っ込みます。

ここまでで、Danger Swiftをコマンドラインで実行するためのダイナミックライブラリの作成準備までできました。

2. Dangerfileを作る

次にDangerfileというものを作ります。
前回の記事でDangerfileがどういうものかは説明していますので、よければこちらもご覧ください。
ここでは何をどのように自動レビューするのかを定義するファイルという説明に留めます。

編集方法は公式ドキュメントを参照したところ、以下コマンドを打てば良さそうです。

swift build
swift run danger-swift edit

ここで、以下エラーにつまづきました。

Building for debugging...
[1/1] Write swift-version-7ECE0B649383FE20.txt
Build of product 'danger-swift' complete! (0.28s)
ERROR: Could not find a libDanger to link against at any of: [".build/debug", ".build/x86_64-unknown-linux/debug", ".build/release", "/usr/local/lib/danger", "/opt/homebrew/lib/danger", "/Users/satoutaichi/.local/share/mise/installs/danger-swift/3.21.1/lib/danger"]
Or via Homebrew, or Marathon, or Mise

libDangerがないと言っており、.build/debugにはlibDangerfileというファイルがあったので、Package.swiftのlibrary名に関係していると思い、library名をDangerに修正したところ、libDangerが作成されるようになりました。

products: [
        .library(
-           name: "Dangerfile",
+           name: "Danger",
            type: .dynamic,
            targets: ["MachoDanger"]
        ),
    ],

上記に修正したら、再度以下コマンドを実行します。

swift build
swift run danger-swift edit

上記コマンドを打つと、xcode が開いて Dangerfile を編集できるようになりました。
以下のような画面が開きます。
image.png

ここで、Sources/Dangerfile/main.swiftを編集して以下のようにしてみます。

import Danger

let danger = Danger()
if let github = danger.github {
    // PRのタイトルが "WIP" を含んでいる場合、警告を出す
    if github.pullRequest.title.contains("WIP") {
        warn("PRが 'WIP' のままです。完了したらタイトルを変更してください。")
    }
    
    // PRの説明が短すぎる場合に警告を出す
    if let body = github.pullRequest.body, body.count < 100 {
        warn("PRの説明が短すぎます。詳細を追加してください。")
    }
    
    // 変更行が500行を超える場合に警告を出す
    let changeFilesCount = github.pullRequest.additions ?? 0
    if changeFilesCount > 500 {
        warn("変更行数が500行を超えています(修正行: \(changeFilesCount))。PRを小さく分けられるか検討してください。")
    }
}

image.png

上記XcodeでDangerfile修正後、swift run danger-swift editを実行したコンソールで、Enterを押下するとDangerfileの編集が完了します。(逆にいうとEnterを押して正しくeditモードを終了しないと保存されないので注意が必要です!)

ℹ️  Danger will keep running, in order to commit any changes you make in Xcode back to the original script file
   Press the return key once you're done

3. DangerJSをインストールする

一旦ローカル確認ようにDangerJSをインストールします。

インストールは以下コマンドを実行すれば良いです。

npm install -g danger

上記インストールするにはnpmが必要になるので、もし入っていなければ以下あたりを参考にすれば良いかなと思います。

4. ローカルでDangerの動作確認をする

公式のREADMEに倣って、以下コマンドを実行してみます。

swift run danger-swift local --base main
% swift run danger-swift local --base BR_develop-1.0 --verbose
Building for debugging...
[1/1] Write swift-version-7ECE0B649383FE20.txt
Build of product 'danger-swift' complete! (0.21s)
Launching Danger Swift local (v3.20.2)
Finding out where the danger executable is
Running: /Users/satoutaichi/.nvm/versions/node/v18.16.0/bin/danger local --process .build/debug/danger-swift --passURLForDSL --base BR_develop-1.0 --verbose
/var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/_tmp_dangerfile.swift:3:14: error: cannot call value of non-function type 'module<Danger>'
1 | import Danger
2 | import Foundation
3 | let danger = Danger()
  |              `- error: cannot call value of non-function type 'module<Danger>'
4 |

Launching Danger Swift runner (v3.20.2)
Got URL for JSON: /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger-dsl-c1899073.json
Created a temporary file for the Dangerfile DSL at: /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger-dsl-c1899073.json
Running Dangerfile at: Dangerfile.swift
Preparing to compile
Running: /Applications/Xcode16.2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift --driver-mode=swift -L /Users/satoutaichi/work/product/AkiraDiary/Danger/Dangerfile/.build/debug -I /Users/satoutaichi/work/product/AkiraDiary/Danger/Dangerfile/.build/debug -lDanger /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/_tmp_dangerfile.swift runner /Users/satoutaichi/.nvm/versions/node/v18.16.0/lib/node_modules/danger/distribution/commands/danger-local.js --process .build/debug/danger-swift --passURLForDSL --base BR_develop-1.0 --verbose /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger-dsl-c1899073.json /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/danger-response.json
Completed evaluation
ERROR: Dangerfile eval failed at Dangerfile.swift
ERROR: Could not get the results JSON file at /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/danger-response.json

Danger: ⅹ Failing the build, there is 1 fail.
## Failures
`danger-swift` failed.
## Markdowns
### Log

<details>



/var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/\_tmp_dangerfile.swift:3:14: error: cannot call value of non-function type 'module<Danger>'
1 | import Danger
2 | import Foundation
3 | let danger = Danger()
| `- error: cannot call value of non-function type 'module<Danger>'
4 |
Launching Danger Swift runner (v3.20.2)
Got URL for JSON: /var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger-dsl-c1899073.json
Created a temporary file for the Dangerfile DSL at: /var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger-dsl-c1899073.json
Running Dangerfile at: Dangerfile.swift
Preparing to compile
Running: /Applications/Xcode16.2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift --driver-mode=swift -L /Users/satoutaichi/work/product/AkiraDiary/Danger/Dangerfile/.build/debug -I /Users/satoutaichi/work/product/AkiraDiary/Danger/Dangerfile/.build/debug -lDanger /var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/\_tmp_dangerfile.swift runner /Users/satoutaichi/.nvm/versions/node/v18.16.0/lib/node_modules/danger/distribution/commands/danger-local.js --process .build/debug/danger-swift --passURLForDSL --base BR_develop-1.0 --verbose /var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger-dsl-c1899073.json /var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/danger-response.json
Completed evaluation
ERROR: Dangerfile eval failed at Dangerfile.swift
ERROR: Could not get the results JSON file at /var/folders/dz/\_vzvz7yn6hg_by51jhrw1tz80000gn/T/danger/12C0154A-9691-458D-94AB-EE1F0A8D8FF0/danger-response.json


</details>

この問題は、Package.swiftのlibrary名に原因があったようで、
名前をDangerDepsにすると 動作するようになりました。

products: [
        .library(
-           name: "Danger",
+           name: "DangerDeps",
            type: .dynamic,
            targets: ["Dangerfile"]
        ),
    ],

Danger Swift のコードを確認してみたところ、libraly 名の頭にDangerDepsが付いていないとSPMDangerを初期化せず実行内容が少し変わっているため、そこに原因がありそうでした。
(この問題はXcode16系の環境でしか起きず、Xcode15系の場合では発生しなかったです!罠すぎる、、)

image.png

image.png

image.png

ただ、公式の README でも library 名はDangerDepsが付いていたため公式の方法に準拠するのが良さそうですね。

改めて、ローカル確認をしてみると、うまくいきました。

% swift run danger-swift local --base main
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist
Building for debugging...
[1/1] Write swift-version-7ECE0B649383FE20.txt
Build of product 'danger-swift' complete! (0.61s)
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist



Danger: ✓ passed review, received no feedback.

以下を実行すると、実際のPRに対してローカルでDangerの自動レビュー結果を見ることができますのでこれも試してみます。

swift run danger-swift pr <PRのURL>

ただこのコマンドでは実際のPRを参照する都合上、GitHub APIを使用することになるので、GitHub API実行用のGitHubトークンが必要になります。
GitHubトークンをDANGER_GITHUB_API_TOKENという名前の環境変数に設定することで動こかせるようになるはずです。

export DANGER_GITHUB_API_TOKEN=<GitHubトークン>
% swift run danger-swift pr https://github.com/stotic-dev/DangerSwiftModule/pull/2
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist
Building for debugging...
[1/1] Write swift-version-7ECE0B649383FE20.txt
Build of product 'danger-swift' complete! (0.66s)
Starting Danger PR on stotic-dev/DangerSwiftModule#2
You don't have a DANGER_GITHUB_API_TOKEN set up, this is optional, but TBH, you want to do this
Check out: http://danger.systems/js/guides/the_dangerfile.html#working-on-your-dangerfile
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist



Danger: ✓ found only warnings, not failing the build
## Warnings
PRの説明が短すぎます。詳細を追加してください。
-
変更行数が500行を超えています(修正行: 16239)。PRを小さく分けられるか検討してください。

一部 Warning が出ているが、ちゃんと動いてくれていそうです!

5. CIでDanger Swiftを動かせるようにする

今回は GitHub Actions で動かす方法で試します。
以下は GitHub Actions のワークフローファイルです。

name: danger-ci_xcode_16

on:
  pull_request:
    branches: "*"

jobs:
  build:
    # 実行環境はmacosに設定
    runs-on: macos-latest

    steps:
      # fetch-depth の計算
      - run: echo "fetch_depth=$(( commits + 1 ))" >> $GITHUB_ENV
        env:
          commits: ${{ github.event.pull_request.commits }}

      # チェックアウト(リポジトリからソースコードを取得)
      - uses: actions/checkout@v4.2.2
        with:
          fetch-depth: ${{ env.fetch_depth }}

      # Xcodeのバージョン一覧を出力
      - name: Show Xcode list
        run: ls /Applications | grep 'Xcode'

      # Xcodeのバージョンを指定
      - name: Set Xcode Path
        run: sudo xcode-select --switch /Applications/Xcode_16.2.app/Contents/Developer

      # 現在のXcodeバージョンを確認
      - name: Show Xcode version
        run: xcodebuild -version

      # danger jsのインストール
      - name: Install Danger JS
        run: npm install -g danger

      # dangerを実行
      - name: Analytics with danger
        run: |
          swift run --disable-sandbox danger-swift ci
        env:
          # Dangerはプルリクエストを読み取ってコメントをするので、必要な権限を持ったGithubトークンを渡してあげる必要がある
          DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_BOT_GITHUB_TOKEN }}

補足

リポジトリのチェックアウト

PRのベースブランチと比較して何かしらのレビューをしたいケースがあると思うので、こちらの記事で、ベースブランチ - 現在のPRの情報までをチェックアウトするようにします。

.buildをリポジトリにPushする

SPMでDangerを導入すると、どうしてもSPMのビルド時間がかかってしまうので、swift buildの成果物である.build自体もリポジトリにPushすることで、GitHub ActionsのステップではSPMのビルドは省略し、いきなりswift runによるDangerの実行を行うようにしています。
これは、公式でも推奨する方法です。

Danger で SwiftLint の警告やエラーが起きていないかも自動レビューしてもらう

Danger Swift は Ruby 版と違い、SwiftLint の Plugin はデフォルトで入っています。
image.png

ただ、Danger で SwiftLint を使用するときに内部的に swiftlint コマンドを使用する都合上、swiftlint のバイナリを容易する必要があります。
今回はこちらの記事を参考に、SPM に SwiftLint の依存を追加して SwiftLint のバイナリを使えるようにします。

具体的には Package.swift を以下のようにします。

import PackageDescription

let package = Package(
    name: "Dangerfile",
    platforms: [.macOS(.v14)],
    products: [
        .library(name: "DangerDeps",
                 type: .dynamic,
                 targets: ["Dangerfile"]),
    ],
    dependencies: [
        .package(url: "https://github.com/danger/swift.git", exact: "3.21.1"),
+       .package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "0.58.2"),
    ],
    targets: [
        .target(
            name: "Dangerfile",
            dependencies: [
                .product(name: "Danger", package: "swift")
            ]
        )
    ]
)

SwiftLint には以下のリポジトリのものもあるが、あくまで swiftlint のバイナリを使いたいだけで以下は不要な依存が含まれておりサイズが大きすぎるので、SwiftLintPluginsの方を使用しています。

https://github.com/realm/SwiftLint

Dangerfile には以下を追記します。

+let lintPath = SwiftLint.SwiftlintPath.bin(".build/artifacts/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/swiftlint-0.58.2-macos/bin/swiftlint")
+
+SwiftLint.lint(.modifiedAndCreatedFiles(directory: "<Lint対象のディレクトリ>"),
+               inline: true,
+               configFile: "<リポジトリのルートディレクトリから見た.swiftlint.ymlのファイルパス>",
+               swiftlintPath: lintPath)

lint関数の一つ目の引数には、SwiftLint.LintStyleを設定する。
定義は以下のような感じになっています。

public enum LintStyle {
    /// Lints all the files instead of only the modified and created files.
    /// - Parameters:
    ///   - directory: Optional property to set the --path to execute at.
    case all(directory: String?)
    /// Only lints the modified and created files with `.swift` extension.
    /// - Parameters:
    ///   - directory: Optional property to set the --path to execute at.
    case modifiedAndCreatedFiles(directory: String?)
    /// Lints only the given files. This can be useful to do some manual filtering.
    /// The files will be filtered on `.swift` only.
    case files([File])
}

今回設定した以下は、PR の変更ファイルの内、directoryに指定したディレクトリに含まれるファイルを対象に Lint することを表します。
.modifiedAndCreatedFiles(directory: "<Lint対象のディレクトリ>")

inlineの引数では、Lint で検知した警告やエラーをインラインにコメント(つまり問題のあるコードの行に対してレビューコメントをする)するかどうかを表します。
SwiftLint の静的解析によるレビューに関しては、具体的にどの部分が問題なのかを知りたいので、大抵の場合はインラインでのコメントにした方が、幸せになるケースが多いと思います。

configFileの引数には、どのようなルールで静的解析するのかを定義する.swiftlint.ymlのパスを指定します。
もしこの引数を設定しない場合は、SwiftLint のデフォルトのルールで静的解析することになるので必須の引数ではありません。
(swiftlint コマンドの--configオプションを指定しないのと同じ)

swiftlintPathの引数では、swiftlint を実行するためのバイナリを指定するための情報を設定します。
この引数の型はSwiftLint.SwiftlintPathで内容は以下のようになっています。

public enum SwiftlintPath {
    case swiftPackage(String)
    case bin(String)
    var command: String {
        switch self {
        case let .bin(path):
            return path
        case let .swiftPackage(path):
            return "swift run --package-path \(path) swiftlint"
        }
    }
}

swiftPackage(String)swift runコマンドで swiftlint を実行できる Package.swift のディレクトリを指定することで、SwiftlintPath を正しく設定することができます。

bin(String)は swiftlint のバイナリの相対パス(Dangerfile から見た)を指定することで SwiftlintPath を正しく設定することができます。

今回だと用意した SwiftLint の依存がSwiftLintPluginsでこのライブラリの Package.swift にはexecutableな product がなくswift runから実行することができないので、
bin(String)で swiftlint のバイナリを直接指定します。

let lintPath = SwiftLint.SwiftlintPath.bin(".build/artifacts/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/swiftlint-0.58.2-macos/bin/swiftlint")

Package.swift と Dangerfile の修正は一旦完了したので、ローカルで動作するか確認してみます。

swift run danger-swift local --cwd .. --base main

ただこれだと以下エラーが発生します。

warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/Dangerfile/.build/checkouts/octokit.swift/OctoKit/Info.plist
Building for debugging...
[49/49] Applying danger-swift
Build of product 'danger-swift' complete! (3.37s)
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/Dangerfile/.build/checkouts/octokit.swift/OctoKit/Info.plist

The operation couldn’t be completed. (SwiftLintCore.Issue error 15.)
Could not read configuration: file Configuration.swift, line 289

/bin/sh: line 1: 68032 Abort trap: 6           .build/artifacts/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/swiftlint-0.58.2-macos/bin/swiftlint lint --reporter json --quiet --config "DangerSample/.swiftlint.yml" --use-script-input-files --force-exclude > /var/folders/dz/_vzvz7yn6hg_by51jhrw1tz80000gn/T/swiftlintReport.json



Danger: ✓ passed review, received no feedback.

これは Dangerfile で指定した.swiftlint.ymlのパスを指定が誤っており、見つからなかったためでした。

.swiftlint.ymlのパス指定を以下のように修正したら、この問題は解消されました。

let lintPath = SwiftLint.SwiftlintPath.bin(".build/artifacts/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/swiftlint-0.58.2-macos/bin/swiftlint")

SwiftLint.lint(.modifiedAndCreatedFiles(directory: "<Lint対象のディレクトリ>"),
                inline: true,
-               configFile: "<リポジトリのルートディレクトリから見た.swiftlint.ymlのファイルパス>",
+               configFile: "<Dangerfileの場所から相対的.swiftlint.ymlのファイルパス>",
                swiftlintPath: lintPath)

これで再度danger-swift localを実行します。

先ほどの事象は解消されたが、Lint 対象のファイルが読み込めず静的解析ができない問題にぶち当たりました。

% swift run danger-swift local --cwd ../ --base main
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/Dangerfile/.build/checkouts/octokit.swift/OctoKit/Info.plist
Building for debugging...
[1/1] Write swift-version-7ECE0B649383FE20.txt
Build of product 'danger-swift' complete! (0.52s)
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/Dangerfile/.build/checkouts/octokit.swift/OctoKit/Info.plist

Could not read contents of `/Users/satoutaichi/work/swift/DangerSwiftModule/Dangerfile/DangerSample/DangerSample/ContentView.swift`



Danger: ✓ passed review, received no feedback.

以下ログから読み取れるのは、存在しないパスを参照しに行っているということ。

Could not read contents of `/Users/satoutaichi/work/swift/DangerSwiftModule/Dangerfile/DangerSample/DangerSample/ContentView.swift`

danger-swift の--cwdでワーキングディレクトリを指定できるらしいのですが、これがなぜか効かないため、swiftlint もリポジトリのルートディレクトリ/Dangerfileから実行されており Lint 対象のファイルをうまく指定できていないっぽいです。(この問題わかる人いたら教えて欲しいです、、)

これの根本的な解決法は現状思いついてないですが、Dangerfile にある SPM のファイルたちをリポジトリのルートディレクトリに配置するとうまく動くようになりました。

修正前のディレクトリ構成
image.png

修正後のディレクトリ構成
image.png

Dangerfile をリポジトリのルートディレクトリに移動したので、.swiftlint.ymlの指定パスも以下のように変更します。

let lintPath = SwiftLint.SwiftlintPath.bin(".build/artifacts/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/swiftlint-0.58.2-macos/bin/swiftlint")

SwiftLint.lint(.modifiedAndCreatedFiles(directory: "<Lint対象のディレクトリ>"),
                inline: true,
-               configFile: "<Dangerfileの場所から相対的.swiftlint.ymlのファイルパス>",
+               configFile: "<リポジトリのルートディレクトリから見た.swiftlint.ymlのファイルパス>",
                swiftlintPath: lintPath)

これで再度 local での danger-swift の動作確認を行いました。

 % swift run danger-swift local --base main
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist
Building for debugging...
[49/49] Applying danger-swift
Build of product 'danger-swift' complete! (4.18s)
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist



Danger: ✓ found only warnings, not failing the build
## Warnings
Line should be 110 characters or less; currently it has 130 characters (`line_length`)
-
Lines should not have trailing whitespace (`trailing_whitespace`)
-
Lines should not have trailing whitespace (`trailing_whitespace`)
-
Lines should not have trailing whitespace (`trailing_whitespace`)
-
Lines should not have trailing whitespace (`trailing_whitespace`)
-
Limit vertical whitespace to a single empty line; currently 4 (`vertical_whitespace`)

SwiftLint がきちんと動作してくれた!

これでリポジトリを Push すると CI でも SwiftLint の静的解析を実行して、警告やエラーがあればレビューしてくれるようになります。

はまりポイント

SwiftLint を Danger Swift の Dangerfile で実行するようにして、danger-swift を実行すると以下のようなエラーが発生するようになる場合があります。

% swift run danger-swift local --base main
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist
Building for debugging...
[1/1] Write swift-version-7ECE0B649383FE20.txt
Build of product 'danger-swift' complete! (0.62s)
warning: 'octokit.swift': found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Users/satoutaichi/work/swift/DangerSwiftModule/.build/checkouts/octokit.swift/OctoKit/Info.plist



## Failures
Error deserializing SwiftLint JSON response ([
  {
    "character" : null,
    "file" : "/Users/satoutaichi/work/swift/DangerSwiftModule/DangerSample/DangerSample/ContentView.swift",
    "line" : 13,
    "reason" : "Line should be 110 characters or less; currently it has 130 characters",
    "rule_id" : "line_length",
    "severity" : "Warning",
    "type" : "Line Length"
  },
  {
    "character" : null,
    "file" : "/Users/satoutaichi/work/swift/DangerSwiftModule/DangerSample/DangerSample/ContentView.swift",
    "line" : 14,
    "reason" : "Lines should not have trailing whitespace",
    "rule_id" : "trailing_whitespace",
    "severity" : "Warning",
    "type" : "Trailing Whitespace"
  },
  {
    "character" : null,
    "file" : "/Users/satoutaichi/work/swift/DangerSwiftModule/DangerSample/DangerSample/ContentView.swift",
    "line" : 15,
    "reason" : "Lines should not have trailing whitespace",
    "rule_id" : "trailing_whitespace",
    "severity" : "Warning",
    "type" : "Trailing Whitespace"
  },
  {
    "character" : null,
    "file" : "/Users/satoutaichi/work/swift/DangerSwiftModule/DangerSample/DangerSample/ContentView.swift",
    "line" : 16,
    "reason" : "Lines should not have trailing whitespace",
    "rule_id" : "trailing_whitespace",
    "severity" : "Warning",
    "type" : "Trailing Whitespace"
  },
  {
    "character" : null,
    "file" : "/Users/satoutaichi/work/swift/DangerSwiftModule/DangerSample/DangerSample/ContentView.swift",
    "line" : 17,
    "reason" : "Lines should not have trailing whitespace",
    "rule_id" : "trailing_whitespace",
    "severity" : "Warning",
    "type" : "Trailing Whitespace"
  },
  {
    "character" : null,
    "file" : "/Users/satoutaichi/work/swift/DangerSwiftModule/DangerSample/DangerSample/ContentView.swift",
    "line" : 17,
    "reason" : "Limit vertical whitespace to a single empty line; currently 4",
    "rule_id" : "vertical_whitespace",
    "severity" : "Warning",
    "type" : "Vertical Whitespace"
  }
]
Your version of SwiftLint is up to date.
): dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Unexpected character 'Y' after top-level value around line 57, column 1." UserInfo={NSJSONSerializationErrorIndex=1956, NSDebugDescription=Unexpected character 'Y' after top-level value around line 57, column 1.})))

Danger: ⅹ Failing the build, there is 1 fail.

このエラーは SwiftLint の実行結果の json を Danger Swift がパースするときに予期せぬ文字が入り込んでしまっているためにパースに失敗することで発生するエラーです。

具体的には、以下 json のYour version...の文字が入っており純粋な json 形式以外の文字が SwiftLint によって出力されているのが問題。

[
  ・・・省略
]
Your version of SwiftLint is up to date. # ⇦この文字が悪い

これは指定している.swiftlint.ymlの以下設定をfalseもしくは削除することで解消できます。

# If true, SwiftLint will check for updates after linting or analyzing.
check_for_updates: true

おわり

以上が、SPMでのDangerの導入方法でした。
ちょくちょくハマりポイントがあり、初見の導入には苦労した印象ですが、
わかってしまえば簡単かもしれないですね。
ただ、結局未解決の問題(--cwdオプションが効かない問題)があったり、DangerJSに依存していたりと面倒な部分があるのも事実でした。
とはいえ、DangerfileをSwiftでかけるのは、個人的にはメンテしやすくてかなり良いと感じたので事情がない限りはSPMでの導入が良いかなと思いました。

SPMでのDangerの導入を試すためのサンプルプロジェクトを作っているので、よければこちらも参考にしていただければと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?