GitHub PagesのSourceにGitHub Actions(beta)を指定し、AsciiDocとSwaggerUIを公開する構成
はじめに
GitHub PagesへデプロイするSourceの指定先は2つあります。それぞれ以下のような違いがあります。
指定先 | 概要 |
---|---|
Deploy From a branch | ホスティングするビルド成果物をコミット、GitHub Pagesで公開 |
GitHub Actions(beta) | GitHub Actionsでビルド成果物を作成、GitHubのartifactとしてアップロードし、GitHub Pagesで公開 |
※ リポジトリのページから「Settings」->「Source」設定確認可能
Source指定にDeploy From a branch
と比較し、GitHub Actions(beta)
を利用するメリットには以下があります。
- ホスティングのために用意しているブランチやビルド成果物が不要になり、認知負荷を下げられる
- ビルド資材をコミットする作業がなくなる
- ビルド資材の容量が大きい場合、pullやcheckoutにかかる時間を削減できる(モノレポの場合コードに対するCIにも影響する)
設定方法
前提
今回は以下をホスティングする想定にします。
- Swagger UI
- AsciiDoc with PlantUML
何らかのHTTP REST APIの仕様書を作る想定です。
リポジトリテンプレート
リポジトリテンプレートは公開しています。用途に応じてカスタマイズして頂けたらと思います。
ファイル/フォルダ構成
$ exa -L 4 -T --git-ignore . ├── bin │ └── build.sh ... ./documents配下をビルドし、./distディレクトリに出力する ├── documents │ ├── assets │ │ ├── swagger-ui.html ... SwaggerUIのHTML。同一ドメインの./api.ymlにアクセスし、内容APIの内容をレンダリング │ │ └── VL-Gothic-Regular.ttf ... PlantUMLの文字化け防止 │ └── docs │ ├── blog-api │ │ ├── api.yml ... APIのOpenAPI定義 │ │ └── spec.adoc ... APIの仕様を書いたドキュメント │ └── index.adoc ... 仕様書のルートページ └── README.md
リポジトリの設定
Settings
-> Source
から、GitHub Actions(beta)
を選択
ビルド設定
documents/docs配下
をビルドして、./dist
に結果を出力するシェルです。個人的にはシェルスクリプトではなくzxやdaxを使う方が推奨だったりします。
#!/bin/bash BIN_PATH="$(dirname -- ${0})" WS_ROOT_PATH="$BIN_PATH/../" DIST_PATH="$BIN_PATH/../dist" DOCUMENT_DIR="docs" rm -rf $DIST_PATH # AsciiDocの再起的ビルド for filename in $(find ./docs -type f |cut -d/ -f3- | grep .adoc); do asciidoctor \ -a imagesdir@=images \ -a imagesoutdir=$DIST_PATH/images \ -a outdir=$DIST_PATH \ -o $DIST_PATH/${filename%.*}.html \ -r asciidoctor-diagram \ -b html5 \ $DOCUMENT_DIR/${filename} done # swaggerの設定 cp $WS_ROOT_PATH/docs/blog-api/api.yml $DIST_PATH/blog-api/ perl -pe 's/<ymlPath>/api.yml/g' $WS_ROOT_PATH/assets/swagger-ui.html > $DIST_PATH/blog-api/api.html
ドキュメント(サンプル)
テスト用に以下のようなドキュメントを用意します。
仕様書のルートページ
:docname: サンプルブログ :lang: ja :doctype: book :icons: font :toc: left :toc-title: 目次 :toclevels: 2 :example-caption: 例 :table-caption: 表 :figure-caption: 図 :chapter-label: :imagesdir: images :imagesoutdir: images = サンプルブログ仕様書 == サンプルブログAPI ==== link:blog-api/spec.html[設計書^] ==== link:blog-api/api.html[API仕様書^]
API仕様書ページ
:docname: API仕様書 :lang: ja :doctype: book :icons: font :toc: left :toc-title: 目次 :toclevels: 3 :example-caption: 例 :table-caption: 表 :figure-caption: 図 :chapter-label: :imagesdir: ../images :imagesoutdir: images = サンプルブログドキュメント == 仕様書 === 記事取得 [cols="3*", options="header"] |=== |メソッド|パス|補足 |GET|/users/{userId}/articles| |=== [plantuml] ---- @startuml box "Web" #fff2df participant "blog.sample.dev" as blog end box box "AWS" #fff2df participant "APIGateway" as apig participant "lambda" as lambda database "User" as db_user database "Article" as db_article end box blog -> apig: 記事取得 activate blog activate apig apig -> lambda: 記事取得 activate lambda lambda -> db_user: UIDを取得(userId) activate db_user alt 存在しない場合 db_user-->lambda: 取得NG lambda-->apig: 400 BadRequest apig-->blog: 400 BadRequest end lambda --> apig: 200 OK + 記事情報 apig --> blog: 200 OK deactivate lambda deactivate apig deactivate blog @enduml ----
SwaggerUIページ
openapi: "3.0.0" info: title: "サンプルブログAPI" version: "1" servers: - url: "https://api.sample.dev/v1" tags: - name: "User" description: "ユーザーに関する操作" paths: /users/{userId}/articles: get: tags: - "User" summary: "ユーザーの記事一覧取得" security: [] parameters: - in: "path" name: "userId" required: true schema: type: string description: "userId" - in: "query" name: "type" required: true schema: type: string description: "記事タイプ" responses: 200: description: "成功" content: application/json: schema: type: "object" properties: articles: type: "array" items: $ref: "#/components/schemas/article" components: schemas: article: required: - "articleId" - "content" - "title" - "type" - "category" - "description" - "publishAt" - "ogpUrl" - "updateAt" - "createAt" type: "object" properties: articleId: type: "string" example: "xxxxxxxxxxx" content: type: "string" example: "# h1" title: type: "string" example: "XXをやってみた" type: type: "string" enum: ["tech", "gaget", "life"] example: "tech" category: type: "string" example: ["typescript"] description: type: "string" example: "記事の説明!" ogpUrl: type: "string" example: "https://res.cloudinary.com/sample" thumbnail: type: "string" example: "https://res.cloudinary.com/sample" createAt: type: "number" example: 160915346897 updateAt: type: "number" example: 160915346897 publishAt: type: "number" example: 160915346897 securitySchemes: bearerAuth: type: http scheme: bearer description: access token for API security: - bearerAuth: []
GitHub Actions設定
name: Deploy document on: push: branches: - main permissions: id-token: write contents: read actions: read jobs: build: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: actions/checkout@v4 - name: build documents run: | sudo gem install asciidoctor sudo gem install asciidoctor-diagram mkdir -p /usr/share/fonts/VLGothic cp ./documents/assets/VL-Gothic-Regular.ttf /usr/share/fonts/VLGothic ./bin/build.sh - name: Upload Pages artifact uses: actions/upload-pages-artifact@v3 with: path: dist deploy: runs-on: ubuntu-latest needs: build permissions: pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4
GitHub Pagesで公開された内容
うまくホスティングされていることが確認できました。
さいごに
ホスティングする場所は、S3の静的サイトホスティングなど他にも色んな候補があります。GitHub Pagesのメリットは、EnterpriseだとGitHubのユーザーで認証ができる点があると思います。S3の静的サイトホスティングと比較すると、過去のビルド結果も保持できるといいなと思います。SourceにGitHub Action(beta)を指定することで、より手軽で柔軟にサイトをホスティング出来るので、試して頂けたらと思います!