😵‍💫

GitHub ActionsでAWS S3にSwift DocCをデプロイしようとしてできない

2023/12/25に公開
1

Swift/Kotlin愛好会 Advent Calendar 2023の18日目の記事です。18日目の記事です。

はじめに

みなさん Swift DocC 使ってますか?
私は DocC 大好きです。特にTutorialが好きで、よく使ってます。

DocCはGitHub Actions経由でGitHub Pagesで公開するのが定石となっており、こちらの方法はたくさん記事が出ています。
使いたい GitHub Organization がエンタープライズプランであれば、リポジトリにアクセス権のある人だけが見られるようにアクセス制御を行うこともできてとても便利です。

でも GitHub Organization がエンタープライズじゃなければ...?
Enterprise プランは Team の5倍のお値段するので、これだけのためにアップグレードするのは躊躇ってしまいます..。 しかし、一部の人だけにドキュメントを公開したい場面は多々あると思います。

...という苦しみの末に、どうしても Swift DocC を使いたい人が AWS S3 で静的サイトホスティングを行い、 GitHub Actions で CI/CD を実現しようとして上手くいかなかった話です。(本当は解決してから記事を出したかったんですが、時間なさすぎて諦めました。わかる方教えてください🤲)

https://github.com/apple/swift-docc

結論

サイトをホストする用のS3バケットを作成してウェブサイトのホスティングの有効化を行い、この GitHub Actions を仕込むと、S3にアップロードするところまではできます。
※ Xcode15を使用している想定です

.github/workflows/deploy.yml
name: DeployDocc
on:
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: macos-13
    env:
      DEVELOPER_DIR: /Applications/Xcode_15.0.1.app/Contents/Developer
    steps:
      - uses: actions/checkout@v3
      - name: Build docc
        run: |
          cd Tutorial
          swift package \
            --allow-writing-to-directory ../docs \
            generate-documentation \
            --target Tutorial \
            --disable-indexing \
            --transform-for-static-hosting \
            --hosting-base-path . \
            --output-path ../docs
          cd ..
      - name: Create tar file
        run: |
          chmod -v -R +rX "./docs/" | while read line; do
            echo "::warning title=Invalid file permissions automatically fixed::$line"
          done
          gtar \
            --dereference --hard-dereference \
            --directory "./docs/" \
            -cvf "$RUNNER_TEMP/docs.tar" \
            --exclude=.git \
            --exclude=.github \
            .
      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: docs
          path: /Users/runner/work/_temp/docs.tar
          retention-days: 1
          if-no-files-found: error

  deploy:
    needs: build
    environment: Develop
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v3
        with:
          name: docs
          path: .
      - name: Extract And Delete tar file
        run: |
          tar -xvf docs.tar
          rm docs.tar
      - name: Configure AWS crredentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
          aws-region: ap-northeast-1
      - name: Upload to S3
        env:
          S3_UPLOAD_BUCKET: ${{ vars.S3_BUCKET_NAME }}
        run: |
          aws s3 sync . s3://$S3_UPLOAD_BUCKET/ --delete

GitHub Actionsの解説

まず前半のジョブの解説です。
ここでは、静的サイトホスティングができるように変換し、artifactsに一時保存しています。
GitHub ActionsでmacOSを使うとストレージをめちゃくちゃに食い潰すので必要最小限に抑えています。

  1. Xcode15で作っていたため、 macos-13 及び Xcode_15.0.1.app でセットアップしています。

    jobs:
      build:
        runs-on: macos-13
        env:
          DEVELOPER_DIR: /Applications/Xcode_15.0.1.app/Contents/Developer
    
  2. Swift-DocC Pluginを使用して静的サイトホスティングができる形式に変換します。
    targetやホスティングベースパスは以下を参考に適宜環境に合わせて書き換えてください。
    https://apple.github.io/swift-docc-plugin/documentation/swiftdoccplugin/publishing-to-github-pages/

    steps:
      - uses: actions/checkout@v3
      - name: Build docc
        run: |
          cd Tutorial
          swift package \
            --allow-writing-to-directory ../docs \
    	generate-documentation \
    	--target Tutorial \
    	--disable-indexing \
    	--transform-for-static-hosting \
    	--hosting-base-path . \
    	--output-path ../docs
          cd ..
    
  3. 一度tarファイルに圧縮します。
    これは、2の手順で変換したものをリポジトリ内に保存するとリポジトリが汚染されて好ましくないため artifacts に一時的に保存したいのですが、変換すると謎のコロンを含むファイルを含んでいてエラーになってしまう事情があり、一度tarファイルに圧縮しています。

    - name: Create tar file
      run: |
        chmod -v -R +rX "./docs/" | while read line; do
        echo "::warning title=Invalid file permissions automatically fixed::$line"
        done
        gtar \
          --dereference --hard-dereference \
          --directory "./docs/" \
          -cvf "$RUNNER_TEMP/docs.tar" \
          --exclude=.git \
          --exclude=.github \
          .
    
  4. artifactsに3で圧縮したtarファイルをアップロードします。

    - name: Upload artifact
      uses: actions/upload-artifact@v3
          with:
            name: docs
            path: /Users/runner/work/_temp/docs.tar
            retention-days: 1
            if-no-files-found: error
    

    このジョブは不安になるほど時間がかかりますが、macOS13ランナーのXcode15のビルド時間自体がなぜかめちゃくちゃ遅くなるので、耐えます。解決策プリーズ🤲 コストが不安になりますが、そう頻繁に更新するものじゃないから・・・と私は言い聞かせてます。

そして後半のS3アップロード部分の解説です。
前述のmacOSランナーでの実行にコストの不安を感じるため、ここはubuntuを使っています。

  1. 3、4で圧縮・アップロードしたtarファイルをダウンロード・解凍しています。
    ダウンロードしたらtarファイルをartifactから削除しておきます。

      deploy:
        needs: build
        environment: Develop
        runs-on: ubuntu-latest
        steps:
          - name: Download artifact
    	uses: actions/download-artifact@v3
    	with:
    	  name: docs
    	  path: .
          - name: Extract And Delete tar file
    	run: |
    	  tar -xvf docs.tar
    	  rm docs.tar
    
  2. AWSの認証を通し、S3にアップロードします。
    この時、リポジトリに Develop Envirionmentを作成し、以下の値をEnvironment secretsおよびEnvironment variablesに設定しています。

    • AWS_ACCESS_KEY (secrets): S3にアップロードできる権限をつけたIAMのアクセスキー
    • AWS_SECRET_KEY (secrets):S3にアップロードできる権限をつけたIAMのシークレットキー
    • S3_BUCKET_NAME (variables):アップロードしたいS3バケット名
          - name: Configure AWS crredentials
    	uses: aws-actions/configure-aws-credentials@v4
    	with:
    	  aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
    	  aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
    	  aws-region: ap-northeast-1
          - name: Upload to S3
    	env:
    	  S3_UPLOAD_BUCKET: ${{ vars.S3_BUCKET_NAME }}
    	run: |
    	  aws s3 sync . s3://$S3_UPLOAD_BUCKET/ --delete
    

S3側の設定

  1. 静的ウェブサイトホスティングを有効化します。

  2. とりあえずブロックパブリックアクセスを全てオフにします。

  3. バケットポリシーを設定して外部から読み取れるようにします。

    {
        "Version": "2012-10-17",
        "Statement": [
    	{
    	    "Sid": "PublicReadGetObject",
    	    "Effect": "Allow",
    	    "Principal": "*",
    	    "Action": "s3:GetObject",
    	    "Resource": "arn:aws:s3:::hoge/*"
    	}
        ]
    }
    

でも上手く動かない🫠

このように 「An unknown error occurred.」 と表示されてしまい、内容が表示されないのです。

コンソールを確認したところ、 theme-settings.json が見当たらないそうです。

theme-settings.jsonはXcode15で登場した、webで公開するときにdoccのドキュメントを他コンテンツに合うような見た目にしたいときに使えるテーマを設定するJSONです。

https://developer.apple.com/videos/play/wwdc2023/10244

でもこれ無くても良かったのでは...?と思いつつ、大人しく追加してみました。

するとどうでしょう!

何も変わりません!

コンソールを見てみると、もはやウンともスンとも言わなくなってしました!お手上げです!

どうして〜?

アドベントカレンダーの担当日どころかクリスマスも過ぎそうだったので諦めて途中経過で出しました。

有識者の方、アンサー記事をお待ちしております。

Discussion

tanakatanaka

私もそれにハマったのですが、以下のIssueの最後のコメントに書いてあって、
swift package --disable-sandbox preview-documentationをローカルで実行した際に出てくるURLのパスがあるので

========================================
Starting Local Preview Server
	 Address: http://localhost:8080/documentation/passkey
========================================

本番環境でもhttps://hostname/documentation/passkeyにアクセスしたら私の場合は見れました。

https://github.com/apple/swift-docc-plugin/issues/70