- 投稿日:2020-01-20T23:05:11+09:00
Github ActionsでiOSアプリのテストの結果をSlackに通知したい!
Github ActionsとSlackを連携したい!
以前投稿したGithub ActionsでiOSのプロジェクトをビルドしたい!でとりあえずGithubにPushして、ビルドとテストが実行されるところまではできるようになりました。
そうすると、今度はその結果の通知がほしくなります。そこで今回はActionの実行結果をSlackに通知できるようにしてみたいと思います。すでにSlackに通知できるActionがあるじゃあないか、、と思ったら、、
早速GithunのMarketPlaceで「Slack」と検索すると、よさげにSlackへ通知できそうなActionがいっぱい出てきました。
そこの先頭にある「Slack Notify」を使ってみることに。
瞬殺じゃん、と思い、実行してみると、エラーが表示された。
エラーをみると、このActionはLinuxのOSでしか動かせないようです(理由ははっきりわかっておりません、、、)。
検索結果の上位にある他のActionもいくつか試しましたが、同じエラーが出ました。iOSアプリをビルドする以上、MacOSの指定は必須なので、仕方なくWebhookのURLを直叩きすることにしました。WebhookのURLをcurlで実行して、Slackに通知を送る。
WebhookのURLの取得はこちらを参考にしました。
あとはそれを使ったActionを実行するだけです。# Notify to slack when build and test succeeded - name: Slack success notification - run: | curl -X POST --data-urlencode 'payload={ "text": ":tada::tada::tada:${{github.repository}}: Build and Test succeeded!:tada::tada::tada:" }' ${{secrets.SLACK_WEBHOOK_URL}}
github.repository
は「{ユーザー名}/{リポジトリ名}」の形式で文字列を取得できる環境変数です。
先ほど取得したSlackのWebhookのURLはGithubのリポジトリのSecretsに保存しています。
ここに登録することで、PublicリポジトリがForkされても、そのSecretsの値はコピーされません。WebhookURLはそれを知っていれば、誰でもそれを設定したチャネルに投稿できてしまうので、ハードコーディングしないようにしましょう。登録した値は、secrets.{登録したkey名}
で取得できます。
実行して、ビルドやテストが成功すると、以下のようにちゃんとSlackに通知が届きました。
ちなみにエラーの時は以下のように設定しています。##### Run build action ##### # Notify to slack when build failed - name: Slack build failure notification - if: failure() run: | curl -X POST --data-urlencode 'payload={ "text": ":fire::fire::fire:${{github.repository}}: Build failed..:fire::fire::fire:" }' ${{secrets.SLACK_WEBHOOK_URL}} ##### Run unit test action ##### # Notify to slack when test failed - name: Slack test failure notification if: failure() run: | curl -X POST --data-urlencode 'payload={ "text": ":fire::fire::fire:${{github.repository}}: Test failed..:fire::fire::fire:" }' ${{secrets.SLACK_WEBHOOK_URL}}
if: failure()
を入れることで、直前のActionが失敗した時に実行されるようになるになります。参考
ビルド失敗時とテスト失敗時の結果は以下の通りです。
本当はビルドに失敗した場合は、「Build failed..」のメッセージだけが表示されるようにしたいのですが、今のところやり方がわからず、、(知っている方はぜひおしえていただけると!)最後に
Slackに通知できるようになったので、これである程度業務でも使えるようになったかなと思います。
あとはSlackに通知されるメッセージをもう少し見やすくしたり、Github Actionsへのリンクを貼ったりと、カスタムできればと思います。
このサイトが参考になりそう!
これから自動デプロイなどより充実させていきたいです。テストで使用しているリポジトリ
https://github.com/u5-03/Swift-github-actions
Publicリポジトリであれば、Github Actionsは無料で使用できるので、検証で使用する場合はPublicリポジトリで!参考資料
- 投稿日:2020-01-20T21:40:13+09:00
UITableViewでセルを選択不可にする方法
- 投稿日:2020-01-20T19:15:54+09:00
signin with apple 実装するときの注意点まとめ
対応バージョン
iOS13以上、iOS13以下は対応しないため、別々のデザイン準備する必要があります。
取得できるユーザーデータ
- ユーザーの選択でランダム生成されたメール渡せる可能性があります
- full name
- ユーザーの編集可能で、apple id登録された名前とは限らない
sign in 初回と2回目の違い
sign in 初回はメールと名前のユーザーデータ取れますが、その以後sign inする場合は取得できなくなります。
初回取得成功後key chainなどに保存し、登録成功後削除したほうが一番無難。let request = ASAuthorizationAppleIDProvider().createRequest() request.requestedScopes = [.fullName, .email] let controller = ASAuthorizationController(authorizationRequests: [request]) controller.delegate = self controller.presentationContextProvider = self controller.performRequests()extension AppleSigninService: ASAuthorizationControllerDelegate { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { guard let credentials = authorization.credential as? ASAuthorizationAppleIDCredential else { let error = NSError(domain: "jp.huiping192.signInWithApple", code: -1000, userInfo: nil) signInSubject?.onError(error) return } // アプリ起動時ログイン状態チェックのためcredentials.user keychainに保持する saveUserId(credentials.user) // mailとnameある場合一時保持、登録成功後に削除 saveUserInfo(nickname: credentials.fullName?.nickname, email: credentials.email) } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { // error handing } }AppleID使用停止検知
「設定」 -> 「{Apple ID}」->「パスワードとセキュリティ」-> 「Apple IDを使用中のApp」 -> 「{app name}」-> 「Apple IDの使用を停止する」
ユーザーは上の手順でSign in with Apple使用停止することが可能なので、アプリ側にチェックする必要があります。
- アプリ起動時
ASAuthorizationAppleIDProvider().getCredentialState(forUserID: appleUserID) { credentialState, _ in if credentialState != .authorized { // logout User.current.logout() } }
- アプリ起動中
NotificationCenter.default.rx.notification(ASAuthorizationAppleIDProvider.credentialRevokedNotification).subscribe(onNext: { _ in // logoutしとく User.current.logout() }).disposed(by: disposeBag)AppleID使用停止後再度登録
新しいユーザーを扱い、token、ユーザー情報新しく取得できる。
- 投稿日:2020-01-20T17:19:15+09:00
【Swift】Must translate autoresizing mask into constraints to have _setHostsLayoutEngine:YES.でクラッシュする
概要
iPhone6s (iOS9.3) で実行すると
掲題のエラー
Must translate autoresizing mask into constraints to have _setHostsLayoutEngine:YES.と出てクラッシュする問題。
解決方法
どうやらいろんな原因でこのクラッシュが起きるみたいですが僕の場合は
クラッシュ対象となるクラスのxib上で赤枠で囲っているプルダウンをAutomaticからTranslates Mask Into Constraintsに変更
するだけ、で直りました。
なんで、これでなおるかは要調査ですが。他の事例。
https://qiita.com/matsuyoro/items/9219c23a70c012d6e3e5
https://qiita.com/kaktaam/items/1c07f6bf003cee77cc31誰かのお役に立てば。
- 投稿日:2020-01-20T17:14:25+09:00
【Swift】dyld: Library not loaded: /usr/lib/libauto.dylib で古いSimulatorで実行出来ない
概要
dyld: Library not loaded: /usr/lib/libauto.dylib Referenced from: /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation Reason: no suitable image found. Did find: /usr/lib/libauto.dylib: mach-o, but not built for iOS simulatorと言うエラーが出てきて古いSimulatorで実行出来ないと言うものだ。
環境
Xcode: 11.3
対象Simulator: iOS Simulator6S
対象OS: 9.3解決方法
https://stackoverflow.com/questions/55389080/xcode-10-2-failed-to-run-app-on-simulator-with-ios-10
sudo mkdir '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 9.3.simruntime/Contents/Resources/RuntimeRoot/usr/lib/swift'このコマンドを叩くだけ。
Simulatorはruntimeと言うルートを元に動作しているが、
そもそものruntimeがないため起こっているみたい。
だから、強制的に作ってやろうよみたいな感じですかね。誰かのお役に立てば。
- 投稿日:2020-01-20T12:54:57+09:00
Swift で 画像 (UIImage ) の リサイズ と トリミング (切り抜き) を一度の処理で行う。
0.はじめに
Swift で画像の切り抜きとリサイズを一度の処理で行いたかったので、やってみました。
以下の記事を参考にさせて頂きました。
- UIImageのリサイズ方法と注意点 - Qiita
- 【Swift4】UIImageで画像のサイズ変更、指定した倍率で拡大/縮小 - Qiita
- Swift3.0で画像の切り抜き - Qiita
- [Swift] 画像のサムネイル生成(縮小&切り抜き) - Qiita
感謝 ♪♪♪
?♂️?♂️?♂️
1.コード
今回は、画像を 0.5 倍にリサイズしつつ、中心部分を正方形に切り抜いてみました。
var _image: UIImage = image var compress: CGFloat = 0.5 var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height let origin: CGPoint = _image.size.width < _image.size.height ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress) : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0) UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0) _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress))) _image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext()■ リサイズ
まず、以下の処理で、出力先のサイズを指定します。
var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0)■ トリミング (切り抜き)
そして、以下の処理で、画像をトリミング (切り抜き) します。
let origin: CGPoint = _image.size.width < _image.size.height ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress) : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0) _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress)))重要なポイントは、
draw 関数の引数に指定する CGRect の値 (origin も、size も) を出力後の値で設定する
こと。
99.ハマりポイント
- 上述しましたが、draw 関数の引数に指定に結構手間取りました…。
???
XX.まとめ
以上、ご参考になれば ♪♪♪
???
- 投稿日:2020-01-20T12:17:35+09:00
CustomCellに置いたButtonの選択状態によってTableViewの処理を変える
タップしたButtonが乗ってるCellの情報をFirestoreに保存したい。
その想いから、こんなややこしい(?)記述方法になってしまいました。ご了承下さい。
Firestoreの部分は他記事にDelegate!開発環境
・Xcode 11.3
・Swift 5.0UIButtonのextensionを作る
CustomCell.swiftextension FaveButton { func switchAction(onAction: @escaping ()->Void, offAction: @escaping ()->Void) { switch self.isSelected { case true: //ONにする時に走らせたい処理 onAction() case false: //OFFにする時に走らせたい処理 offAction() } } }ButtonActionにDelegateを設定する
CustomCell.swiftimport UIKit protocol CellDelegate: AnyObject { func didTapButton(cell: CustomCell) //ON func didUnTapButton(cell: CustomCell) //OFF } class CustomCell: UITableViewCell { weak var delegate: CellDelegate? @IBAction func didButtonTapped(_ sender: UIButton) { sender.switchAction(onAction: { //TableViewController.swiftのdidTapButton()に委任 self.delegate?.didTapButton(cell: self) },offAction: { //TableViewController.swiftのdidUnTapButton()に委任 self.delegate?.didUnTapButton(cell: self) }) } }TableViewController.swiftimport UIKit class TableViewController: UITableViewController, CellDelegate /*追記*/ { func didTapButton(cell: CustomCell) { print("ON") } func didUnTapButton(cell: CustomCell) { print("OFF") } }参考
- 投稿日:2020-01-20T11:18:23+09:00
swift サーバへPOST送信のimage無しとimage有りの処理
image無しのpost送信
func myMessageUploadRequest(){ var url = URL(string: "http://受取処理.php"); print(url) let config = URLSessionConfiguration.default let session = URLSession(configuration: config) var req = NSMutableURLRequest(url: url!) var token = "lastName=\(commentText.text!)&TypeName=Message&groupid="+textgid+"&userId="+userid! req.httpMethod = "POST" req.httpBody = token.data(using: String.Encoding.utf8) var task = session.dataTask(with: req as URLRequest, completionHandler: { (data, resp, err) in print(resp!.url!) print(NSString(data: data!, encoding: String.Encoding.utf8.rawValue)) }) task.resume() }image有りの場合
func myImageUploadRequest(){ print(globalmainurl) let myUrl = URL(string: globalmainurl! + "/swift_receive_app.php"); let request = NSMutableURLRequest(url:myUrl!); request.httpMethod = "POST"; print("ok2xxxx"+globalauthid!+globalmainurl! + "/swift_receive_app.php") let param = [ "groupid" : textgid, "firstName" : "Message", "lastName" : commentText.text!, "userId" : globalauthid! ] let boundary = generateBoundaryString() request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") let imageData = UIImageJPEGRepresentation(ImageView.image!, 0.5) if(imageData==nil) { print("error") return; } print("ok3") request.httpBody = createBodyWithParameters(param, filePathKey: "file", imageDataKey: imageData!, boundary: boundary) let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in if error != nil { print("error=\(error)") return } // レスポンスを出力 print("******* response = \(response)") let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) print("****** response data = \(responseString!)") DispatchQueue.main.async(execute: { //アップロード完了 self.ImageView.image = nil; }); } task.resume() } func createBodyWithParameters(_ parameters: [String: String]?, filePathKey: String?, imageDataKey: Data, boundary: String) -> Data { let body = NSMutableData(); print("ok4") if parameters != nil { for (key, value) in parameters! { body.appendString("--\(boundary)\r\n") body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") body.appendString("\(value)\r\n") } } let filename = "user-profile.jpg" let mimetype = "image/jpg" body.appendString("--\(boundary)\r\n") body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n") body.appendString("Content-Type: \(mimetype)\r\n\r\n") body.append(imageDataKey) body.appendString("\r\n") body.appendString("--\(boundary)--\r\n") return body as Data } func generateBoundaryString() -> String { return "Boundary-\(UUID().uuidString)" }
- 投稿日:2020-01-20T10:59:37+09:00
玩玩 @propertyWrapper
看了這兩篇文章動手做之後簡單來做個筆記
規格提案小聲說:寫這篇的時候我還沒詳細讀完所有的內容
玩過之後看到的優點
- 過去以來需要寫在 didSet 裡面的邏輯有辦法再封裝,讓宣告的地方能夠更加乾淨
- 似乎可以解決在設定初始值無法觸發 didSet 的問題
語法
對我來說,直覺是有 Java 中 annotation 的 fu
詳細說明可以參照
- https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
- 的
Property Wrapper
段落定義
@propertyWrapper struct Trimmed { private(set) var value: String = "" // 根據文件指出,「必須」定義這個 property var wrappedValue: String { get { value } set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) } } init(wrappedValue: String) { self.wrappedValue = wrappedValue } }
wrappedValue
通常會是一個 computed value ,用這樣的寫法的話,在set
裡面可以拿到在 init 中被設定的值,而get
中回傳的值則是放處理完成的值。使用方式
先定義一個簡單的 struct 並把剛剛定義的 property wrapper 放在一個屬性前面
struct Post { @Trimmed var title: String }使用之後如下:
let post = Post(title: " B A A ") print(post.title) // "B A A"因為有透過 property wrapper 的處理,這時候在 console 輸出的內容會是
B A A
,而不是前後有空白的B A A
。結
目前還沒摸清楚可以在實際專案中怎麼用,不過看來是個可以拿來做適度封裝的好工具。
接下來還要繼續去看 Projected Value 到底是什麼東西和可以怎麼用,看懂之後再來多寫一篇。環境
- Xcode 11.3.1
- Swift 5.1
- Playground
參考
- 投稿日:2020-01-20T10:18:43+09:00
Swift for TensorFlowでSinGAN
SinGAN
SinGAN on Swift for TensorFlow #S4TFhttps://t.co/KhGm5jmScZ pic.twitter.com/YVHgDRRzde
— t.ae (@ar_t_ae) January 19, 2020QiitaでもSinGANの論文が話題になって久しいですが、Swift for TensorFlowでSinGANを実装してみました。
https://github.com/t-ae/singan-s4tf公式の資料は以下
公式実装との違い
だいたいReadmeに書いたんですが、工夫した点は大事なのでここにも書いておきます。
BatchNormをやめてInstanceNorm導入
SinGANは画像一枚を入力とするので、訓練時にはその画像自体の統計量で正規化する=InstanceNormと同等の振る舞いになります。
しかし推論時には、BatchNormは入力ではなく訓練時に得た統計量を用いて正規化します。バッチサイズがある程度ある場合は訓練時にもバッチ内統計量になるので問題ないのですが、上述の通りバッチサイズが1なので、訓練時と推論時で正規化方法が大きく異なるということになってしまいます。これを避けるため、私の実装ではInstanceNormを用いることにしました。これだと訓練時・推論時で同様の正規化を行うことになります。
WGAN-GPを使わない
オリジナル実装ではWGAN-GPを用いています。
issueに書いたのですが、公式の実装はWGAN-GPの論文に従ったgradient penaltyになっていないのではないかと考えています(レスがなくて結論まで至れてませんが)。
またSwift for TensorFlowはまだ高階微分を実装していないため、そもそもgradient penaltyを用いるような方法は使用不可能です。
そういうわけで、ここはオリジナル実装から離れてWGAN-GPをやめることにしました。
Spectral Normalizationの導入
GANの訓練でよく使われているのがWGAN-GPとSpectral Normalizationです。最近は両者の併用で更に安定化できるという論文も発表されていました。
https://tech.preferred.jp/ja/blog/smoothness-and-stability-in-gans/
Spectral Normalizaitonには高階微分が必要なく、Swift for TensorFlowでも使用することができるので、これを用いることにしました。
この記事とは関係ないですが、Spectral Normalizationを使った一般的(?)なGANも書いてます。
SNGAN on Swift for TensorFlow / LSUN bedroom #S4TFhttps://t.co/Bd0I0PBrWs pic.twitter.com/ySEeavhMWW
— t.ae (@ar_t_ae) January 15, 2020結果
学習・生成した結果のうちいくつかを掲載します。ここに載せていない結果は以下に置いてあります。
https://github.com/t-ae/singan-s4tf/tree/master/Results上に書いた別のGANのほうでUbuntu機が埋まっていたのでMacBookProで学習させたのですが、GPUなしでも数時間〜半日くらいで学習できます。
乱数のシードは固定しているので、ここに掲載した結果は手元で実行すれば再現できるはずです。複数サイズは4つのアスペクト比を、高解像度化は4/3倍の拡大を5回分(約4倍まで)の内容を掲載しています。
balloons
オリジナルの入力画像と最構成結果
オリジナル 最構成 小さいバルーンが見逃されています。SinGANは小さなスケールから徐々にアップスケールしてくるため、直前の解像度では何もなかったところに小さなオブジェクトが出てくるということがあります。
複数サイズ
ランダム生成においてはバルーンの形がかなり崩れてしまっています。大域的な歪みは低解像度からの生成の歪みが積み重なっていると考えられるので、各段階のトレーニングステップ数を増やす等で改善できそうな気がします。
33039_LR
オリジナルの入力画像と最構成結果
オリジナル 最構成 元が小さいので割ときれいにできています。
高解像度化
これは実験した中では最も綺麗にできた結果だと思います。
SinGANの高解像度化は最大の解像度で学習したモデルを用い、拡大→モデルに通す→拡大→モデルに通す……と繰り返して行きます。この方法ではフラクタル的に細部が生成されるのではないかと考えられます。そのため岩の表面のような自然物はSinGANでの生成に向いているのでしょう。birds.png
オリジナルの入力画像と最構成結果
オリジナル 最構成 バルーンと同じく小さな鳥が消えてしまっています。色合いもちょっと違っています。
複数サイズ
オリジナルは縦方向の変動が大きく、横方向の変動が小さいため、横に長い画像のほうがよくできている印象です。
lightning1
オリジナル 最構成 複数サイズ
地面まで届かずに途中で切れてる稲妻が複数あります。
高解像度化
これは33039_LRで触れたフラクタル的に細部が生成されるというのがよく分かる結果になっています。解像度が上がるに従って細い稲妻が枝分かれして増えています。
まとめ
公式実装がかなり読みにくくて苦労しましたが、なんとかそれらしい結果を出すところまで行けました。
ハイパラ調整はあんまりやっていないのですが、もっと詰めればバルーンの崩れていたのあたりは綺麗に出せるようになるんじゃないかと思っています。
- 投稿日:2020-01-20T09:54:06+09:00
[Swift] IntやDoubleなどの数字オブジェクトを2倍にする関数でジェネリクスを使ってみた
概要
業務でInt型やDouble型を単純に2倍する関数を作りたい時に戸惑いましたのでググってみました。
/// これを型ごとに作ると、関数が増えてしまって冗長なので書きたくない func multipleValue(_ value: Int) -> Int { return value * 2 } func multipleValue(_ value: Double) -> Double { return value * 2 } func multipleValue(_ value: CGFloat) -> CGFloat { return value * 2 } multipleValue(2) // 4 multipleValue(3.14) // 6.28 }これをクールに一つの関数にまとめたいと思いました。
さてどうすればいいのかを考えるのが今回のテーマです。ジェネリクスを使う
すぐに思いつくやり方は、ジェネリスクでパラメータを一つにまとめる方法です。
ジェネリスクはSwift のドキュメントでこう記されています。
ジェネリクスの用法としては
[Swift]ジェネリクスについてが参考になります。
それはいいとして、ジェネリクスを使ってこんな風に書きたいです。
/// Tがジェネリックパラメータ func multipleValue<T>(_ value: T) -> T { return value * 2 } multipleValue(2) // 4 multipleValue(3.14) // 6.28 }これでいけるかと思ったのですがビルドエラーになってしまいました。
エラーの内容は
Binary operator '*' cannot be applied to operands of type 'T' and 'Int'どうやらジェネリクスに二項演算子「*」などのoperatorが使えないみたいなエラーでした。
そのため、てっきりジェネリクスで数値を2倍にできないのかと諦めかけましたが、
エラーの文章からググってみましたら解決策が見つかりました。Binary operator '+' cannot be applied to two 'T' operands
ということで Numeric protocol に準拠させたら使えるそうです。
/// Tがジェネリックパラメータ func multipleValue<T: Numeric>(_ value: T) -> T { return value * 2 } multipleValue(2) // 4 multipleValue(3.14) // 6.28 }これで目標のあらゆる数値を単純に2倍にする関数が作れました。
Numeric とは何なのか
乗算をサポートする値を持つ型だそうです。
Numericプロトコルを汎用制約として使用すれば、標準ライブラリ内の任意の数値型を操作する関数が作れるようになるとの事でした。
これで数値を操作する汎用メソッドが作れます。
と調べた後にこれについて詳しい資料がありましたので最後に貼って終わります。
- 投稿日:2020-01-20T00:58:30+09:00
Github ActionsでiOSのプロジェクトをビルドしたい!
CI環境として、Github Actionsを使ってみたい!
アプリを開発する時に、以下のようなことを自動化してみたいと思いました。そこで調べたことを備忘録として、まとめてみました。
- プッシュした時に、ビルドやテストを実行する。
- プルリクを出した時に、ビルドやテストに失敗している時はマージできないようにする。
- developブランチにマージされたタイミングで、開発用のipaをビルドする。
- releaseブランチにマージされたタイミングで、デプロイする。
そこでCI環境を使ってみようと思い、Betaが外れたばかりのGithub Actionsを使ってみようと思い、調べてみました。
使い方
1.Githubのプロジェクトを開き、「Actions」タブを開く。そうすると、以下のような画面が表示される。
右側の「Set up a workflow yourself」を選択する。
2.そうすると、Github actionsで使用するworkflowのymlファイルのテンプレートが表示されます。
ちなみにこのままテストをすると、失敗します。(swift
コマンドが実行されるので、当然ですが、、、)
3.なのでテンプレートのymlファイルを修正する。とりあえず最低限動くように、以下のように修正しました。
scheme名を自分のプロジェクトのものに変更してもらえれば、そのまま使えると思います。swift.ymlname: Swift on: [push] jobs: build: runs-on: macOS-latest steps: - uses: actions/checkout@v1 # Select Xcode version - name: Select Xcode version run: sudo xcode-select -s '/Applications/Xcode_11.3.app/Contents/Developer' - name: Show Xcode version run: xcodebuild -version # Run build - name: Build run: xcodebuild -scheme Swift-github-actions -sdk iphonesimulator -configuration Debug build # Run unit test - name: Run tests run: xcodebuild -scheme Swift-github-actions -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11 Pro Max' clean test4.修正が終わったら、コミットする。「Start commit」からコミットします。
5.「Actions」タブを開き、workflowの実行結果を確認する。きっと成功しているはずです!
ちなみにデフォルトではリポジトリへのPushがworkflow実行のトリガーになっています。
Swift Package Manager(SPM)を使ってみる。
上記のworkflowであれば、SPMをインストールしても、そのままビルドとテストが成功するはずです。
以下、SPMでRxSwiftをインストールしてから、Pushしたものです。無事成功しています。
やってみた感想
Bitriseの使用も検証しましたが、普段使っているGithubのサービス内で完結できるのは魅力的かなと思いました。
最低限のworkflowしか記述していないので、今後追加して、最初に書いたようなこともできるようにしたいです。
修正点があれば、ご指摘いただけると。テストで使用しているリポジトリ
https://github.com/u5-03/Swift-github-actions
Publicリポジトリであれば、Github Actionsは無料で使用できるので、検証で使用する場合はPublicリポジトリで!参考資料