device_preview / Github Pages / Github Actionsでプルリクレビューを楽にしたい

# 記事の目的

Flutterでモバイル・Web開発をする中で、スピード感あるレビューを受けたい場合どのような手段があるでしょうか？
いくつかケースはあると思いますが、昨今の流行りを踏まえて「スピーディーに」というところを考慮するとCI/CDの実装は不可欠になると思います。

### サービス例

https://bitrise.io/

https://firebase.google.com/docs/app-distribution?hl=ja

https://deploygate.com/?locale=ja

https://codemagic.io/start/


ただ、これらは多少なり費用面と実装のコストがかかります。
そのため、今回は`device_preview`パッケージと`Github Actions`, `Github Pages`を用いたプレビュー環境を整えてみることを目的としています。

# 準備

それでは、下準備とともに実装しましょう。

## Flutter側
### device_preview導入
それではパッケージを入れましょう
```bash
$ flutter pub add device_preview
```

### Dartコード修正
main関数とMaterialAppに以下のような設定をしましょう
```diff_dart:main.dart
void main() {
  runApp(
+   DevicePreview(
+     enabled: true, // ここは正しくは!kReleaseModeなど設定してください
+     tools: const [
+       ...DevicePreview.defaultTools,
+       CustomPlugin(),
+     ],
+     builder: (context) => const MyApp(),
+   ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.black),
        useMaterial3: true,
      ),
+     builder: DevicePreview.appBuilder,
+     locale: DevicePreview.locale(context),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
```

### HTMLコードの修正
今回、device_previewを使ったりGithubPagesにアップすることから、webでビルドします。そのための設定をしましょう。
Github PagesにFlutter Webをアップロードする際、以下の`<base>`タグの編集が必要です。
左右のスラッシュも込みリポジトリ名を設定してください。

```diff_html:index.html
- <base href="$FLUTTER_BASE_HREF">
+ <base href="/リポジトリ名/">
```

## Github側の設定

### Github Pages設定
まだBeta状態ですが、Github Actions経由でGithub Pagesをアップロードできるようになりました

1. 対象リポジトリを開く
1. Settings > Pagesを選択
1. 以下のSourceを設定し、「Github Actions」を指定

![スクリーンショット 2023-12-11 23.26.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/9a2dfcb5-68c9-3313-2e1b-a0a61086596b.png)

色々試せそうなので詳しくはドキュメントを確認してみてください

https://docs.github.com/ja/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0-github-actions-%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8B%E5%85%AC%E9%96%8B

### Environmentsの設定

最終的にGithub Actions経由でGithubPagesをアップするためには設定が必要です。
Settings > Environments > New environmentsを選択

![スクリーンショット 2023-12-11 23.35.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/681ab4ff-4781-a8c6-8dd9-0aae97579d9b.png)

名前はラベルみたいなものなのでなんでも良いです。悩んだら`device_preview`と付けておいてください

次に、**Deployment branches and tags** の右側のドロップダウンを**Selected branches and tags**としてください。その後、**Add deployment branch or tag rule**をクリックしてください


![スクリーンショット 2023-12-11 23.45.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/b97d4080-a2fb-d99a-58e1-f231375a8f27.png)


そうすると、以下のような画面が出ます。
未設定の場合mainブランチしかGithub Pagesへアップできないのですが、今回したいことは「プルリクエストを作成時にプレビューを出す」なのでアップするブランチはmainより子のブランチになります。

例えば`feature/*`のようなブランチを切っている場合は以下のようになります。

![スクリーンショット 2023-12-11 23.44.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/d8c4ac0e-eb43-4d3e-44b7-6449de2bdfbc.png)

最終的に一番親のブランチとプレビューを出したいブランチが設定されていれば問題ないかと思います

![スクリーンショット 2023-12-11 23.55.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/6497e110-6b2a-3ad9-f38e-c1ac5a5e8b9d.png)


## Github Actions設定
それではいよいよActionsの実装です。
```yaml
name: Flutter Web Build and Deploy

on:
  pull_request:
    branches:
      - main
      - feature/*

permissions:
  contents: read
  issues: write
  pull-requests: write
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: 'stable' # ここはバージョン固定したほうがいいです
          cache: true

      - run: flutter pub get
      - run: flutter build web --web-renderer html

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v2
        with:
          path: ./build/web

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

      - name: Notify Pull Request
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v4
        with:
          script: |
            const pullRequestNumber = context.issue.number;
            const repositoryOwner = context.repo.owner;
            const repositoryName = context.repo.repo;
            const pageUrl = `https://${repositoryOwner}.github.io/${repositoryName}/`;
            const comment = `Preview URL for this pull request: ${pageUrl}`;
            github.issues.createComment({
              owner: repositoryOwner,
              repo: repositoryName,
              issue_number: pullRequestNumber,
              body: comment
            });
```
### 完了！

実際に、`feature/*`ブランチから適当に差分を作ってmainブランチへプルリクエストを作成していただければ、Actionsが走りプルリクエスト上に以下のように通知されます。

![スクリーンショット 2023-12-12 0.03.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/b4b668c5-5b15-6a43-c8dd-53365a2de970.png)


### 今後の課題

こちら、現状の課題としては「他の誰かがPRを立てたら上書きされてしまう」ということです。
こちらは良い運用方法がわかり次第記事をアップデートしたいと思います。

### 終わりに

ここまでみていただきありがとうございました！
改善点等あれば励みになるためコメントをお願いします。