取り組んだきっかけ
先月末から今月の上旬にかけて、Github Actionsに浸かっています。
色々触っている中で、Custom Actionが気になり始めました。
あるworkflowを作成時、AWS Lambda更新のため、以下を利用しました。
どんなことをしているか、大雑把にはわかりましたが、
まずは、一通りリリースまでやってみよう!
ということで、より初歩的なCustom Actionを探しました。
Custom Actionとは?
Custom Action
は、workflow内のuses:
で記述したアクションのことです。
actions/checkout
がその一例です。
steps:
- uses: actions/checkout@v4
アクションとしての作り方として、以下の3種類あるようです。
- Docker コンテナー(linuxのみ対応)
- JavaScript
- 複合アクション
初歩的なCustom Actionをマネる
gitの基本的な操作(Push、PR)はご存知の前提で進めます。
以下の動画が、Custom Action駆け出しの私にはピッタリでした。
この動画に沿って進めて作業をします。
先ほどお話した3種類の作り方の中では、JavaScriptに分類されます。
主なスタックですが、TypescriptとJestをです。
前提知識はなくても作業は進められる、と思います。
土台作成
Custom Action作成で基本的には必要なファイルから用意します。
action.yml、package.json
action.yml
の記載項目です。
-
name
:作成するアクションの名前を設定します。マーケットプレイスに公開するために、この値は他の公開されたアクションと重複してはいけません。 -
description
:何ができるアクションか、説明を記載します。 -
inputs
:実行時にどのようなパラメータを必要とするか記載します。 -
outputs
:以降のworkflowで使用できるパラメータと設定値を記載します。 -
runs
:実行環境と実行ファイルを指定します。
他の項目について、詳細はこちらに記載されています。
name: "Label new pull requests Try"
description: "Add a label when a new PR is opened Try."
author: "eno-conan"
runs:
using: "node16"
main: "dist/index.js"
以下を実行すると、package.json
が生成されます。
npm init -y
gitignore
この段階では、コマンド実行のみでOKです。
npx gitignore node
tsconfig.json
typescriptのインストール・初期化を実施します。
npm i -D typescript
npx tsc --init
コンパイル設定は以下の通りです。
{
"compilerOptions": {
"target": "ES2019",
"module": "commonjs",
"outDir": "dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
}
src/index.ts
最初はこれだけでいきます。
console.log("Hello My World!!");
package.json
を以下のようにして、buildを実行し、jsファイルを生成します。
"scripts": {
"build":"tsc",
"test": "echo \"Error: no test specified\" && exit 1"
}
npm run build
.github/workflows/XXX.yml
最初は手動でworkflowを実行できるようにします。
ymlの内容
name: "Hello"
on:
workflow_dispatch:
jobs:
hello:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./
コードをpushします。
Run workflow
をクリックします。成功が確認できましたら、次に進みましょう。
Github Actionsの動作確認ですが、nektos/actを使うと、ローカルでも行えます。
気になる方は、自分の記事で恐縮ですが、ご覧ください!
githubとの連携実装
必要なライブラリをインストールします。
npm install @actions/core @actions/github
npm install -D ts-node
src/index.ts更新
適切なパラメータが与えられれば、
パラメータlabel
の値で、PRのLabelsにその値を設定するworkflowです。
index.tsの内容
import { getInput, setFailed } from "@actions/core";
import { context, getOctokit } from "@actions/github";
export async function run() {
const token = getInput("gh-token");
const label = getInput("label");
const octokit = getOctokit(token);
const pullRequest = context.payload.pull_request;
try {
if (!pullRequest) {
throw new Error("This action can only be run on Pull Requests");
}
await octokit.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
labels: [label],
});
} catch (error) {
setFailed((error as Error)?.message ?? "Unknown error");
}
}
if (!process.env.JEST_WORKER_ID) {
run();
}
.github/workflows/XXX.yml更新
PRがopened
またはreopened
をトリガーに、実行します。
name: "Hello"
on:
pull_request:
types: [opened, reopened]
jobs:
hello:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
label: "needs-review"
build、pushと行います。main以外のブランチでテキトーにファイル作成して、
PRを作成します。workflowが実行されますが、失敗します。
Error: Cannot find module '@actions/core'
@vercel/ncc導入
動画内の説明より
TypeScriptでコードを書いている場合、tscコンパイル後のコードは自動的にはNode.js互換形式にはなりません。
これを解決するために、@vercel/ncc
を使います。
nccはTypeScriptのコードをCommonJSに変換して1つのファイルにbundleしてくれます。import/export文を解決し、Node.jsのモジュールシステムと互換性を持たせることで、先ほどのエラーを解消します。
npm i @vercel/ncc
package.json
、tsconfig.json
、.gitignore
更新
- "build": "tsc",
+ "build": "tsc && ncc build lib/index.js",
- "outDir": "dist",
+ "outDir": "lib",
.pnp.*
+ lib
lib
を追加した理由(動画内の説明より)
ビルド結果のアーティファクトであり、ソースコードではありません。
Gitではソースコードのみ追跡するのが、望ましいはずです。
dist
が公開されるべき最終成果物で、lib
は中間生成物的な位置づけです。
Gitに含める必要性が低いため除外します。
これでbuild、pushで完成!といきたいですが、
もう1つ修正が必要です。
リポジトリの権限変更
push後、PRをclosed
→reopened
として、workflowを確認すると、
以下エラーが表示されます。
Resource not accessible by integration
特定のLabelsを付与する、つまり書き込み(更新)権限が必要です。
Settings(※)から以下画像の通り修正し、保存して完了です。
※以下URLの一番下の項目
https://github.com/{username}/{repo_name}/settings/actions
テストコード
必要なライブラリをインストールします。
npm i -D jest ts-jest @types/jest
動画では、Github Copilotでテストコードを生成していました。
以下のテストを実施しています。
- should throw an error if not run on a pull request
- PRで実行されてない場合にエラーを出力すること
- should add label to the pull request
- PRでlabelが設定されていること
- should handle error and set failed
- Error時にステータスが失敗になること
詳細は以下の通りです。
Market Placeに公開
青い部分のボタンをクリックします。規約の承認後、必要事項の設定をします。
See list of avaliable XXX
というリンクから、IconとColorを選んで、action.yml
に設定します。
runs:
using: "node16"
main: "dist/index.js"
+ branding:
+ icon: "anchor"
+ color: "blue"
Push後、README.md
を追加して、Commitします。
以下状態になったら、Publish Release
をクリックします。
二段階認証の対応があるので、それが終われば、リリース完了です!!!
赤線部分、MarketPlace
をクリックすると、以下のように表示されます。
また、Use latest Version
をクリックすると、workflowでの記述を内容をコピーできます。
他リポジトリから利用
リリースできました。
他リポジトリから利用してみます。新しい/既存リポジトリはお任せします。
name: Label new pull requests Try
の部分に、作成したCustomアクションの名前とパラメータを設定します。
name: act-sample
on:
# push:
pull_request:
types: [opened, reopened]
jobs:
echo_text:
runs-on: ubuntu-latest
steps:
- name: echo Hello world
run: echo "Hello world!!"
- name: Label new pull requests Try
uses: eno-conan/ga-label-issue-try@v1.0.0
with:
label: "needs-infra-member-review"
gh-token: ${{secrets.GITHUB_TOKEN}}
PRを作成して実行すると、label
の文言がLabelsに設定できました!
残り作業と補足
この後、huskyやLinterの設定などを行う部分が残っていますが、この記事ではその内容はスキップします。
また、作業が一通り終わってから気付いたのですが、テンプレートが用意されていました。(JS/TS)
LICENSE周りの理解
動画では登場しませんでしたが、より本格的になったときに、避けて通れない内容です。しかし、全く触れてきておらず、マズイかも・・といった気持ちも持ちつつこの文章を書いています。
公式ドキュメントや皆さまが書かれた記事の情報をお借りして、超基本的な部分だけかもしれませんが、学んでいる最中です。。。
自分のソースコードを広く提供し、自由に利用してもらいたいという場合は「MIT License」が最適だとのこと。
確かに、MIT License
は見覚えがあります。
OSSライセンスとは、OSSの使用許諾条件のことであり、著作権に基づいてOSSの利用条件を定義するものとなります。逆に言えばOSSとは、OSSライセンスを遵守することを条件に使用が許諾されていると言うことができます。
まとめと今後
初歩的な内容ですしたが、Custom Actionの公開、利用まで実施できました。
以前npmのライブラリ公開の初歩を学んだときがありましたが、
何かを便利に柔軟に、といった考え方に基づいて自作するのは、面白いと感じます。
今後は、OSSライセンスの話も勉強しながら、
githubのPRに関係する別のActionや、AWSサービスが関係するActionの作成をしていきたいと思います!