リリースは、git タグでマークされたコードの重要なスナップショットを GitHub の優れた UI で表示できる GitHub の機能です。現在リリースを使用していない方に、リリースを使用するべき理由と、リリースを自動的に実装する方法を紹介します。

リリースを使用すると、タグが提供する情報(バージョン番号と説明)を取得できますが、リリースノートの詳細なセクションと、リリースアーティファクトを保存および表示する場所も利用できます。つまり、ソフトウェアバイナリ、.deb、.rpm、および AppImage ファイルはリリースごとに GitHub でホストされ、ユーザーが簡単にソフトウェアをインストールできるようになります。

このブログでは、CircleCI 内でリリースを作成する方法を紹介します。 リリース作成に関する概要については、GitHub のドキュメントをご覧ください。

大事な部分を最初に言うと、GitHub リリースは、git タグの上に単に重ねられる GitHub の機能の 1 つであることです。では、詳しく見ていきましょう。

Git タグ

Git タグは、特定の git コミットをマークするためのバージョン番号と簡単な説明を提供します。 GitHub に git タグをプッシュするだけで、GitHub のプロジェクトの [Releases] タブに新しいリリースが作成されます。 これは、タグ情報だけが含まれるベアボーンリリースです。

リリース

リリースではより長い「詳細」な説明、通常リリースかプレリリースかのタグをマークする機能からgit タグが追加されます。また最も重要なことには、そのリリースのバイナリなどのアーティファクトをアップロードする機能も提供されています。 CircleCI からこれらのアーティファクトをアップロードする方法について、このブログで説明します。

ツール

CircleCI ビルドから GitHub リリースにアーティファクトをパブリッシュする方法はいくつかあります。

  • curl と GitHub API を手動で使用する
  • GitHub リリースを使用する
  • GotHub(GitHub リリースフォーク)を使用する
  • ghrを使用する(この例で使用します)

ghr の使用

ghr コマンドの詳細は [GitHub で確認できますが、][ghr]実際に習得する必要があるサブコマンドは次の 1 つだけです。

ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/

このコマンドは、特定のアーティファクト(通常はバイナリ)を GitHub リリースにアップロードします。 これを詳しく見ていきましょう。

  • ghr -t ${GITHUB_TOKEN} - ここでこのコマンドを開始し、認証のために GitHub トークンを渡します。 これは GitHub のパーソナルアクセストークン であり、OAuth トークン/キーではありません。

これは、個人の GitHub アカウントで個別に作成されたトークンですので、このトークンは保護し、プライベート環境変数を使用する場合にのみ CircleCI 環境にロードする必要があります。

  • -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} - これは、GitHub ユーザー/組織名とリポジトリ名を渡す場所です。両方の値は、組み込まれている CircleCI 環境変数を介して渡されます。追加の操作は不要です。

  • -c ${CIRCLE_SHA1} - ここで ghr に Git コミットハッシュ(CircleCI で $CIRCLE_SHA1として利用可能)を提供します。これにより、リリースの対象となるコミット、つまりタグがわかります。

  • -delete - git タグを削除します。すでに存在する場合はリリースします。

  • ${VERSION} - $VERSION 環境変数を介して git タグ/リリースバージョンを設定します。 これには、任意の変数または文字列を指定できます。 通常は、これはソフトウェアリリースのバージョンと同じになります。

  • ./artifacts/ - 次に、アーティファクトを見つけるための PATH を設定します。 この場合、現在のディレクトリ内にある artifacts という名前のディレクトリ内のすべてが対象となります。

CircleCI 2.0 の簡単な例

ghr を使用して GitHub リリースを作成する方法を説明しました。では、CircleCI 2.0 のコンフィグファイルでこれがどのように見えるか確認しましょう。

  publish-github-release:
    docker:
      - image: circleci/golang:1.8
    steps:
      - attach_workspace:
          at: ./artifacts
      - run:
          name: "Publish Release on GitHub"
          command: |
            go get github.com/tcnksm/ghr
            VERSION=$(my-binary --version)
            ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/

CI ビルドの CircleCI 2.0 の例

これは、CircleCI Go の便利なイメージを使用する publish-github-release と呼ばれる CircleCI ジョブです。詳細を見ていきましょう。

  • ワークスペースを使用して、前のジョブからプロジェクトのバイナリを取得します(このブログでは説明しません)。
  • ghr は Go で記述されているため、このジョブは、go get を介して ghr をプルおよびコンパイルします。
  • このブログのサンプルアプリケーションである my-binary --version の出力を $VERSION に設定します。
  • 次に、ghr コマンドを使用して、artifacts ディレクトリのバイナリを GitHub にアップロードします。

CI ビルドghr Docker イメージを使用することで、上記のジョブを数秒短縮できます。 これは、ghr がインストールされている軽量の Docker イメージです。 新しいコンフィグ例は次のようになります。

  publish-github-release:
    docker:
      - image: cibuilds/github:0.10
    steps:
      - attach_workspace:
          at: ./artifacts
      - run:
          name: "Publish Release on GitHub"
          command: |
            VERSION=$(my-binary --version)
            ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/

ワークフローの例

上記のジョブのバリエーションの 1 つを ワークフロー に実装して、タグ付きコミットを GitHub リリースにパブリッシュする方法の例を次に示します。

workflows:
  version: 2
  main:
    jobs:
      - build:
          filters:
            tags:
              only: /^\d+\.\d+\.\d+$/
      - publish-github-release:
          requires:
            - build
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /^\d+\.\d+\.\d+$/

この例では、git タグがプッシュされると、CircleCI が publish-github-release ジョブを開始します。 GitHub リリースをパブリッシュするタイミングを正確に選択する方法は、ユーザー次第ですが、ここでは SemVer のような git タグを使用します。 使用する /^\d+\.\d+\.\d+$/ のタグ正規表現は、1.2.3 などのタグと一致しますが、SemVerセマンティックバージョン管理)のルールはまったく考慮しないため、「SemVer のような」という表現を使用しています。完全を期すために、rgxdb.comに記載されている SemVer の完全な正規表現を次に示します。

/(?<=^[Vv]|^)(?:(?<major>(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?<minor>(?:0|[1-9](?:(?:0|[1-9])+)*))[.](?<patch>(?:0|[1-9](?:(?:0|[1-9])+)*))(?:-(?<prerelease>(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:0|[1-9](?:(?:0|[1-9])+)*)))*))?(?:[+](?<build>(?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+))(?:[.](?:(?:(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?|(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)(?:[A-Za-z]|-)(?:(?:(?:0|[1-9])|(?:[A-Za-z]|-))+)?)|(?:(?:0|[1-9])+)))*))?)$/

参考情報: