42のCLIツールを作った
こんにちは、42tokyo Advent Calendar 2021 の8日目を担当する、在校生のtkomatsuです。
今回の記事では、42 Network APIを使ってCLIツールを作成した話を書きたいと思います。
はじめに
42 Tokyoは世界中にある42 Network校の一つであり、intranetが中の活動では使われています。intranetでは課題の管理から、イベントやeラーニングの動画コンテンツの配信など42の活動の大部分が提供されています。42では課題の提出に内部で管理されたGitのリポジトリが使われています。普段はGitHubのリポジトリで作業を進めている学生であっても提出してレビューを行う際にはintranet内で提供されたリポジトリを使う必要があります。
intranetのリポジトリにアクセスするためにはブラウザからURLをコピーしてくる必要があり、正直とても面倒でした。GitHubではCLIツールが提供されており、リポジトリのcloneなどがとても簡単にできるようになっています。これに
似た、42のリポジトリから簡単にcloneできるCLIツールを作りました。
ゼロから作るか
はじめは、全部自分でゼロからCLIツールを作ろうと思い技術選定などを進めていました。最近Goをよく触るようになり、GitHub CLIもGoで書かれていたため、Goを使って作成することにしました。CLIを作る上で、cobraとviperの組み合わせで作られているものが多かったのでこれらも採用することにしました。
色々調べながら作っていく途中で、42 Networkの姉妹校である1337のスタッフがgoftという42 intranetのCLIツールを作っているのをGitHub上で発見しました。Goで書かれていて、自分で作成しようとしていたものにとても近いものでした。
しかし、goftは42スタッフのためのツールとして作成されており、学生として使いたい上記の機能は実装されていませんでした。
今回はゼロからCLIツールを作るのではなく、このリポジトリからフォークして機能を追加することにし、本家のgoftにも共有できる機能はPRを出すことに方針転換をしました。
実装
APIクライアントのエンドポイント追加
ftapiというパッケージがgoftの中にありましたが、対応できているエンドポイントが少なく今回の実装で必要なものがありませんでした。必要なエンドポイントのクライアントを作成しました。
エンドポイントごとに定義されているJSONレスポンスに対応する構造体を定義しました。今回は必要なものがそれほど多くはなかったので自分で書きましたが、APIクライアントライブラリとして整備する際はこのあたりの構造体の生成を自動化する必要がありそうだと感じました。
CLIのサブコマンドの追加
APIクライアントができたらそれらを組み合わせてgoft
にサブコマンドを追加しました。今回は機能を絞り、今すぐ欲しい機能だけを実装しました。
また、コマンドはGitHub CLIと似た操作ができるようサブコマンドの名前を統一しました。
repo
42の内部システムで管理されたリポジトリをとってくるコマンドです。これにより、ブラウザを開いて42のintranetにログインして自分のプロジェクトページを開いてリポジトリのURLをコピーしてターミナルでクローンするという一連の作業をコマンド一つで行うことができるようになりました。
goft repo list
で、自分や他の学生が登録しているプロジェクト一覧を表示することができます。
goft repo clone <project slug>
で、リポジトリをクローンすることができます。今回はos.exec
からgit
コマンドを呼び出しています。Gitクライアントを作るのも面白そうなので、今後これはオリジナルのクライアントを作れると面白そうです。
browse
前述のrepo
コマンドを追加したことにより、リポジトリの管理は簡単になりました。もう一つの問題は課題の提出です。提出もAPI経由でできれば良いのですが、学生には提出するためのAPIが開放されていません。そのためブラウザからGUIで提出やレビューの予約を行う必要があります。ブラウザからスタートするとリポジトリの時と同様に手間がかかります。browse
コマンドを使うことでプロジェクトページを開くことができ、そのページから課題の提出やレビューの予約がすぐできるようになります。
レビューの予約はカレンダー形式で選択するので、結果的にこの方が良かったのかもしれません。
Pull Requestを投げる
上記一式の変更のプルリクを投げました。最終的にだいぶコード行数が多いプルリクになってしまいました。
メンテナの方から複数のプルリクに分けて改めて送って欲しいと返信があったため、その後チェリーピックを行って分割をして再度プルリクを送りました。機能ごとにプルリクを分けることでそれぞれの議論に集中できるようになりました。自分では気をつけてコミットの粒度を小さくしていたつもりでしたが、チェリーピックを実際にしてみると粗さがあり、機能の分割をするのに苦労しました。後からコミットをまとめることは分割するより負担が軽いので、もっと細かくコミットしていった方がいいと実感しました。
また、元のプロジェクトとのスコープの違いも勉強になりました。メンテナが考えるスコープはあくまでスタッフに向けたツールであり、今回のプルリクの大半のスコープとは異なっているというレビューを受けました。その結果一部の設定ファイルのプルリクのみがマージされました。なんでも便利になれば機能が追加できる訳ではなく、プロジェクトの向いている方向がブレないように機能を追加していく必要があり、そのあたりも考えるべきだったと反省しました。
今後学生用の機能を追加していくつもりですが、それらの機能はプルリクを出さずに学生用のgoftとして開発を続けることになりそうです。
おわりに
今回の開発では、すでに作られたコードをベースに機能を追加し、一部プルリクを送りマージされるところまで行いました。既存のプロジェクトはあるスコープが存在しそれに合わせた開発が求められること、プルリクは機能ごとに分割すること、APIを使った開発などを学ぶことができました。
明日は、tkanzaki42さんが【42Tokyo】Unityで横スクロールアクションゲームを作る入門について書いてくれる予定ですので、そちらの記事もお楽しみに!f
Discussion