Swift Foundationにコントリビュートする

本エントリは [Swift Tweets 2018 Winter](https://swift-tweets.github.io/2018-winter) でのツイートをまとめ、加筆修正したものです。実際のツイートについては、 [2018/1/20 #swtws Swift Tweets 2018 Winter - Togetter](https://togetter.com/li/1191688) をご覧下さい。

# はじめに

これは昨年末、発見したFoundationのバグを見つけてPRを出した経験をまとめた発表です。
ちなみにまだマージされていないので、発表タイトルは過去形ではなく現在形です…。

# あなたがSwiftのFoundation frameworkの挙動にバグを発見したとします。

さあ、どうしますか？
ひとつの方法としては、バグレポがあります。 https://bugs.swift.org/ に報告しましょう。
また、自分で直すというのも手です。Swiftはオープンソースです。[Foundationリポジトリ](https://github.com/apple/swift-corelibs-foundation)にも "We welcome contributions to Foundation!" とあります。やっちゃいましょう。

と言っても、まずはこれまでの議論のログを辿って、既知のバグではないことを確認する必要があります。
議論は、メーリングリストで行われています。それをたぐるのは正直かなり、相当めんどくさいです。
…が、朗報です！
つい昨日、メーリングリストの全議論は https://forums.swift.org/ へとインポートされ、検索しやすくなりました！
なおバグレポの https://bugs.swift.org/ は別管理のようですので、そちらはそちらで要チェック。

検索の結果、それが未知あるいは既知であっても未着手のバグで、それが自分で直せるものだった場合、コントリビュートチャンス到来です。バグを修正しましょう。

---

ここでSwiftコミッタの @rintaro さんより一言。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">バグの重複はそのバグに遭遇している人が多いというインジケータになり重要度が上がるので、気にせずどんどん投げちゃえば良いと思います。 <a href="https://twitter.com/hashtag/swtws?src=hash&amp;ref_src=twsrc%5Etfw">#swtws</a></p>&mdash; Rintaro Ishizaki (@rintaro) <a href="https://twitter.com/rintaro/status/954697513251958784?ref_src=twsrc%5Etfw">2018年1月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

とのことですので、やっぱりバグレポは重複気にせずバンバン上げましょう！

# コントリビューションの手順

手順はだいたい [Getting Started](https://github.com/apple/swift-corelibs-foundation/blob/master/Docs/GettingStarted.md) に書かれているとおりなのですが、一応日本語で説明します。

## 環境構築

環境構築に必要なのは、

- 最新バージョンのXcode
- 最新バージョンのmacOS SDK
- 現在のSwift toolchainのsnapshot (これは Trunk Development (master) のものという意味)

です。

### Swift toolchainのsnapshot のダウンロード

https://swift.org/download/#snapshots にあるsnapshotのリストの、「Xcode」をクリックしてダウンロード。
👇これです。

<img width="752" alt="dl_toolchain.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/c036aea9-33d8-92c2-bbf4-1da8e5537809.png">

だいぶサイズが大きいので気長に待ちつつ、並行してリポジトリのクローンの準備をしましょうか。

---

ここで Foundationコミッタ且つswiftenvコミッタの @ikesyo さんからの一言。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">スナップショット版のツールチェーンのインストールにはswiftenvも便利ですね <a href="https://twitter.com/hashtag/swtws?src=hash&amp;ref_src=twsrc%5Etfw">#swtws</a></p>&mdash; いけしょー@本書きました (@ikesyo) <a href="https://twitter.com/ikesyo/status/954698590986776576?ref_src=twsrc%5Etfw">2018年1月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[swiftenv](https://github.com/kylef/swiftenv) はSwiftのVersion Managerです。

`swiftenv install --list-snapshots` でインストール可能なsnapshotのバージョンを一覧することができ、
`swiftenv install <バージョン名>` でそれをインストールできます。


### リポジトリのクローン

話は戻ってリポジトリのクローンについてです。
https://github.com/apple/swift-corelibs-foundation をクローンして終わり……ではありません。
一点気をつける必要があるのは、 `Foundation.xcworkspace` には Foundation だけでなく XCTest も含まれているということ。
https://github.com/apple/swift-corelibs-xctest もクローンしてください。
クローンしたふたつのディレクトリは隣接させて配置し、 `Foundation.xcworkspace` を開いてください。

SwiftFoundation targetを選択してビルドすると、赤いビルドエラーが大量に出ます。

<img width="492" alt="build_failed.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/f0a0d812-62a4-c193-2369-b5099dae9d81.png">

toolchainのせいですね。snapshotのダウンロードが終わるまで何もできなさそうです。休憩！

---

☕️

---

さて、そろそろtoolchainのダウンロード終わりましたかね。休憩終わり！
toolchainの導入は簡単です。pkgを入れたら、Xcodeのメニューから画像のように選択するだけ。

<img width="580" alt="toolchains.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/14150aa6-8143-a3ac-348e-f261b68d0485.png">

再度SwiftFoundation targetのビルドを試みれば、無事に成功です🎉

## いよいよバグ修正本番！

バグ修正の手順は、実際に私が修正した https://github.com/apple/swift-corelibs-foundation/pull/1386 を元に解説します。
PRの内容は、Decimal型の極小値の定数が間違っていた（もっと小さな数を作ることができてしまう）のを直すというものです。
定数が記述された `Decimal.swift` を修正します。

なお、修正コミットのメッセージはリンク先のガイドラインに準じましょう。
https://swift.org/contributing/#contributing-code

実装ファイルを修正すれば終わり？
もちろんそれだけではなく、テストも必要ですね。 `TestDecimal.swift` も辻褄合わせて、あとはいつものように `Product -> Test (⌘U)` すれば…

<img width="209" alt="no_test.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/483db599-b16f-e7ac-0f1b-dcc972b4b073.png">

**…⁉️**

## Foundation のテスト

**注意。**
Foundationのテストは、普段Xcodeで書いているSwiftのプロジェクトとは違い、TestFoundation targetの `Run` で行います。
テスト結果はコンソールに出力されます。

<img width="733" alt="test_console.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/2f995a2c-b0f8-a8eb-8630-41e7cdd837f2.png">

どうやら18個のfailがあるようですね。
……えっマジで？
"failed" でコンソールをフィルタして確認してみると、

<img width="596" alt="fails.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/4ebfd3d5-c3d1-c041-eaaa-880d602a71e0.png">

どうやら16個のfailは元々のようです。…よくないけれど、ここはとりあえず無視しましょう。
ただ、もうふたつ（赤枠）は今回の修正の影響っぽいですね。これは通るように直しました。

これで対応は完璧！　
…と思って[PRを投げたところ、コアチームからコメントがつきました](https://github.com/apple/swift-corelibs-foundation/pull/1386)。

<img width="625" alt="pr_comments1.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/dcd8ac72-7b2b-7cbb-f217-713fb164e7ed.png">

> 「この挙動が正しいことを保証するテストをいくつか、我々は追加できる？」

…どういうことだろう🤔と思いつつ「OK、やっといて！」とぶん投げたところ…


<img width="624" alt="pr_comments2.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/5ea89cc1-facb-5967-7cd7-1a114cf4fb75.png">

> 「お前がテストを書くんだよ！」

😱
…今回のケース、既存テストの修正だけでなく、テストケース追加が必要みたいです。

## Foundation のテスト（advanced）

テストの追加方法ですが、先述したとおり、普段の Xcode のテストとは少し勝手が違います。
普段であれば `test` で始まる func を実装すればテストスイートが自動認識してくれますが、 Foundation の場合、それを手作業で行う必要があります。
Foundation のテストケースは、 `static var allTests : [(String, (TestDecimal) -> () throws -> Void)]` に纏められています。ここにケースを追加し、該当するメソッドに適切なテスト内容を記述。

<img width="558" alt="add_test.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/c0d72a8c-0706-2276-a57e-dd06ec1302c0.png">

これで、今度こそ作業完了！…のはずです。

# おわりに

正直なところ、本当にこれですべての正しい手順を踏めているのかはわかりません。なぜなら最後の対応をしてから半月経っても、コアチームからは対応へのレスポンスがないからです…たぶん大丈夫だとは思うんですが。
さらなるリテイクが来た場合には、このQiita記事を修正して続報を追記する予定です。尻切れトンボで申し訳ないです。🙇

とはいえ、Foundationのビルドは思ったよりも簡単です。[Swiftコンパイラ開発環境構築](https://qiita.com/rintaro/items/2047a9b88d9249459d9a)のようにCUIコマンドを駆使する必要もなく、普段のOSS利用の延長線上で気軽に触ることができます。
ですので、ものは試しにFoundationのプロジェクトのビルドをしてみたり、テストを実行してみるだけでも面白いのではないでしょうか。

…以上で発表を終わります。ごTwee聴ありがとうございました！