LoginSignup
9
5

More than 1 year has passed since last update.

Danger-Swift のプラグインを SwiftPM で導入する手引き

Last updated at Posted at 2021-12-20

前書き

以前 Danger-Swift 移行の手引き記事を書きましたが、その記事には残念ながら一つ大きな問題点があります:プラグインの利用Marathon というすでに Deprecated 済みのツールに依存しています。もちろん Danger-Swift 公式はちゃんとした SwiftPM を利用した方法も紹介していますが、微妙に面倒だったので自分はこれまで避けてきました。

でもやはり Deprecated なものにいつまでも依存してはリスクが高いです;また場合によってプライベートなプラグインを利用したり、最新リリースではなく特定のバージョンやブランチを利用したいこともありますが、そんな時は SwiftPM の利用が必須です。というわけで、この記事でちゃんと SwiftPM を利用したプラグインの導入の仕方を紹介したいと思います。

ただし、残念ながら現在 M1 Mac の場合、ローカルで実行できないことがマシンによってあるようです。CI 環境が Intel Mac であれば問題ないですが、M1 なら注意が必要です。

ローカル環境の整備

Danger 用のフォルダーを作成

まず手始めに、Danger 用のフォルダーを作っておきます。もちろんこれを作らなくても、動作させる分には問題ないですが、その場合ルートディレクトリーに Package.swift ファイルを置くことになります。このやり方は少なくとも 2 つのデメリットがあります:

  1. xed . コマンドの動作が変わってしまいます。
    ターミナルから Xcode を起動させるのに xed というコマンドがあります。このコマンドに今のディレクトリー . を渡してあげれば、xed は自動的に適切なファイルを開いてくれますが、残念ながら優先順位としては *.xcworkspace よりも、Package.swift ファイルの方が優先されます、つまりルートに Package.swift を置いておくと、xed はこのディレクトリーを Swift Package のプロジェクトとして認識してしまいます。

  2. 人間の目にも優しくないです。
    xed を使わなくても、結果としてルートディレクトリーに Package.swift を置いていると、人間がぱっと見これが正規なプロジェクトに関係する設定と認識してしまいますので、フォルダー構成としても非常に紛らわしいです。おまけに Danger-Swift に関係するファイルはこれだけでなく、他にも Dangerfile.swiftSources などがありますので、ルートディレクトリーが非常に煩雑になってしまいやすいです。

というわけで、Danger 用のファイルは全部 Danger フォルダーにぶち込んでおきましょう。

Packages.swift を作成

Marathon を利用しないので、代わりに依存を Packages.swift で指定する必要があります。ここで必要なのは Danger-Swift 自身と、利用するプラグインのパッケージです。パッケージ構成としては、プロダクトとして DangerDepsProduct というライブラリーを作る必要があります、そしてこのプロダクトが含まれるターゲットは DangerDependencies で、このターゲットには Danger-Swift と各プラグインが含まれています。公式でも大まかなサンプルが用意されていますが、ここでより詳細なサンプルも上げておきます:

Package.swift
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription

let package = Package(
    name: "Dangerfile",
    platforms: [.macOS("10.12")],
    products: [
        .library(name: "DangerDepsProduct",
                 type: .dynamic,
                 targets: ["DangerDependencies"]),
    ],
    dependencies: [
        // Danger
        .package(name: "danger-swift", url: "https://github.com/danger/swift.git", from: "3.0.0"),
        // Danger Plugins
        .package(name: "DangerXCodeSummary", url: "https://github.com/f-meloni/danger-swift-xcodesummary.git", from: "1.2.0"),
        .package(name: "DangerSwiftCoverage", url: "https://github.com/f-meloni/danger-swift-coverage.git", from: "1.2.0"),
        .package(name: "DangerSwiftEda", url: "https://github.com/yumemi-inc/danger-swift-eda.git", from: "0.1.0"),
    ],
    targets: [
        .target(
            name: "DangerDependencies",
            dependencies: [
                .product(name: "Danger", package: "danger-swift"),
                "DangerXCodeSummary",
                "DangerSwiftCoverage",
                "DangerSwiftEda",
            ]
        ),
    ]
)

ここで注意が必要なのは Danger-Swift 本体の取り入れ方でしょうか、これはパッケージアドレスとパッケージ名とプロダクト名がそれぞれ全部違うため、dependencies の宣言では文字列そのままが使えず、必ず .product(name:package:) で導入する必要があります1。他のプラグインも、もしパッケージ名とプロダクト名が違ったら、このように導入する必要があります。

そのほかに、プロダクトの宣言で type は必ず .dynamic にしておく必要があります。また、platforms 指定も、空欄にしておくとデフォルトでは .macOS("10.10") が使われますが、利用するライブラリーによってそれより高いバージョンが必要になることがあるので、その場合はそれに合わせて platforms の指定も必要です。

Dangerfile.swift を修正

Marathon を使わなくなったので、Dangerfile.swift に書かれてある各種アドレスも必要なくなるから、それらを削除しておきましょう。

ローカルでの動作確認

Danger-Swift を動かすのに、Danger-JS も必要です。以前の手引き記事ですでに brew などでインストール済みであれば問題ないですが、もしまだであれば npm で Danger-JS をインストールしましょう。また npm 自体のインストールは brew install node でできます。npm がインストールされたら、npm install danger で Danger-JS をインストールできます。

Danger-JS がインストールされたら、今度はターミナルで Danger のディレクトリーに移動して、swift run danger-swift edit をすれば、Danger-Swift の実行に必要なものを Swift が全部落としてきてビルドして、Dangerfile.swift の編集画面を開いてくれます。ただし今ターミナルのディレクトリーはプロジェクトではなく Danger というフォルダにあるので、prci コマンドには --cwd ../2 3 パラメーターを付与する必要があります。なので例えばローカルで PR チェックを実行したい場合は、swift run danger-swift pr <url/to/pull-request> --cwd ../ を実行すれば OK です。

CI での導入

こちらもローカルの動作確認と同じように npm で Danger-JS をインストールしておく必要があります、そして Danger-Swift を実行するときもローカルの時と同じように、先に Danger に移動してから、swift run danger ci --cwd ../ で実行する必要があります。

また、せっかく SwiftPM で導入したので、Marathon の時と違ってキャッシュが取りやすいから、それも CI にキャッシュさせておきましょう。キャッシュしておきたいパスは Danger/.build です、ここには Danger-Swift の実行に必要なものが大体揃ってあります。これの生成は一度 swift run danger-swift <command> を実行させるとできますが、もしキャッシュするタイミングが Danger の実行前であれば、先に swift build しておくと大抵のものが先に生成されますので、実行時の処理がだいぶ軽くなります。ただし注意しないといけないのは Danger/.build ディレクトリーはパッケージが実行やビルドされるたびに内容に差分ができてしまいますので、キャッシュのフラグとして Danger/Package.resolved ファイルを指定しましょう、そうすればこのファイルが変更された時だけ Danger/.build フォルダーがキャッシュされます。

SwiftLint についての TIPS

ここまでしたら、Danger-Swift の導入がプラグイン含めて全て SwiftPM でできるようになりましたが、実際のシナリオとして SwiftLint の利用も Danger-Swift 内でよくあります。ところでせっかくなので SwiftLint も SwiftPM で導入したい気持ちありますよね。というわけでここで Danger-Swift 向けの SwiftLint の導入についても少し TIPS を書かせてください。

まず、Danger-Swift 用の SwiftLint なので、依存も Danger-Swift と同じ Package.swift 内で宣言しておきましょう。そして Package.swift を開いた時にワーニングが出ないように、ダミーのターゲットも作っておきましょう:

Package.swift
let package = Package(
    // ...
    dependencies: [
        // ...
        // SwiftLint
        .package(name: "SwiftLint", url: "https://github.com/realm/SwiftLint", from: "0.45.0"), // Only for Danger-Swift runtime
    ],
    targets: [
        // ...
        .target(
            name: "SwiftLintDependencies", // Only for Danger-Swift runtime
            dependencies: [
                .product(name: "swiftlint", package: "SwiftLint"),
            ]
        ),
    ]
)

そうすれば SwiftLint の導入も SwiftPM でできます;また利用する際は、Dangerfile.swiftSwiftLint コマンドで swiftlintPath を指定しましょう:

Dangerfile.swift
// ...
SwiftLint.lint(/* ... */, swiftlintPath: .swiftPackage("$(pwd)/Danger"))

ちなみにここの $(pwd) は本来なら現在いるディレクトリー、つまり Danger になるはずですが、おそらく --cwd ../ の影響で、Danger-Swift の実行が親ディレクトリーに移動されたため、$(pwd) が実際取れてるのはプロジェクトのパスになります。そのため、Danger のディレクトリーにある SwiftLint を指定させるには、$(pwd)/Danger にする必要があります。

後書き

ところで気づいた人がいるのでしょうか。そう、この記事に登場した Package.swift のサンプルに、実は弊社が公開したプラグインもあります:DangerSwiftEda です。このプラグインは一体どんなものか、そしてそもそも Danger-Swift のプラグインはどう作ればいいのかーーDanger-Swift のプラグイン作成編を乞うご期待!


  1. 正確にはこのファイルの一番先頭に書かれてある // swift-tools-version: のバージョンによって違いますが、少なくとも 5.3〜5.5 のツールバージョンはこのような書き方が必要です。Danger-Swift の実行は作業プロジェクト自体のバージョンには全く依存しないのである程度の自由は効きますが、とは言え古すぎるバージョンはやはり避けるべきでしょう。 

  2. cwdcurrent working directory、そして ../ は親パスを指します。この仕様は公式ドキュメントからも確認できます。 

  3. Swift パッケージの実行には他にも Danger フォルダーに移動せず、プロジェクトにいたまま例えば swift run --package-path Danger danger-swift <command> を実行する方法も本来ならありますが、残念ながら danger-swift の実行にはそれでは libDanger のライブラリーのパス解決ができず、失敗してしまいますので、大人しく cd Danger して --cwd ../ パラメーターを使いましょう。 

9
5
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
9
5