messages について
safe-output メッセージシステムに型を追加するための開発ガイドです。コントリビューター向けに、スキーマ、Go パーサー、JavaScript モジュール、テスト、バンドル、ドキュメントの更新手順を示します。
主な機能
- 01JSON Schema と Go 構造体の更新
- 02メッセージ設定の解析
- 03JavaScript メッセージモジュールの作成
- 04テストとエクスポートの追加
- 05埋め込みスクリプトの登録と文書更新
活用シーン
- 01カスタマイズ可能な safe-output メッセージの追加
- 02Go と JavaScript 間でのメッセージ型の連携
- 03新しいメッセージ実装の検証とバンドル
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ gh-aw --skill messagesインストール後、Claude Code で/messagesを入力して読み込まれたか確認します。
詳細
新しいメッセージタイプの追加ガイド
このガイドでは、安全な出力メッセージシステムに新しいメッセージタイプを追加し、フロントマター、コンパイラーでの解析、JavaScript、バンドルで利用できるようにする方法を説明します。
概要
メッセージシステムを使うと、ワークフローの作成者は安全な出力メッセージをカスタマイズできます。メッセージの流れ:
- フロントマター(YAML)→ 2. JSON Schema → 3. Go コンパイラー → 4. JavaScript モジュール → 5. バンドラー
Step 1: JSON Schema を更新する
pkg/parser/schemas/main_workflow_schema.json の messages オブジェクトに新しいメッセージフィールドを追加します:
{
"messages": {
"properties": {
"my-new-message": {
"type": "string",
"description": "Description of when this message is used. Available placeholders: {placeholder1}, {placeholder2}.",
"examples": [
"Example message with {placeholder1}"
]
}
}
}
}
重要なポイント:
- YAML フィールド名には
kebab-caseを使用します(例:my-new-message) - 説明には使用可能なすべてのプレースホルダーを記載します
- 参考になる例を用意します
- 変更後に
make buildを実行します(スキーマはバイナリに埋め込まれます)
Step 2: Go 構造体を更新する
pkg/workflow/compiler.go の SafeOutputMessagesConfig に新しいフィールドを追加します:
type SafeOutputMessagesConfig struct {
// ... existing fields ...
MyNewMessage string `yaml:"my-new-message,omitempty" json:"myNewMessage,omitempty"` // Description of the message
}
重要なポイント:
- Go のフィールド名には
CamelCaseを使用します - YAML タグには
kebab-caseを使用します(フロントマターと一致させます) - JSON タグには
camelCaseを使用します(JavaScript で使用します) - 両方のタグに
omitemptyを追加します
Step 3: Go パーサーを更新する
必要に応じて、pkg/workflow/safe_outputs.go のパーサーを更新します:
func parseMessagesConfig(messagesMap map[string]any) *SafeOutputMessagesConfig {
config := &SafeOutputMessagesConfig{}
// ... existing parsing ...
if myNewMessage, ok := messagesMap["my-new-message"].(string); ok {
config.MyNewMessage = myNewMessage
}
return config
}
注: パーサーはほとんどのフィールドでリフレクションを使用するため、単純な文字列フィールドの場合、この手順は不要なことがあります。
Step 4: JavaScript メッセージモジュールを作成する
新しいファイル pkg/workflow/js/messages_my_new.cjs を作成します:
// @ts-check
/// <reference types="@actions/github-script" />
/**
* My New Message Module
*
* This module provides the my-new-message generation
* for [describe when it's used].
*/
const { getMessages, renderTemplate, toSnakeCase } = require("./messages_core.cjs");
/**
* @typedef {Object} MyNewMessageContext
* @property {string} placeholder1 - Description of placeholder1
* @property {string} placeholder2 - Description of placeholder2
*/
/**
* Get the my-new-message, using custom template if configured.
* @param {MyNewMessageContext} ctx - Context for message generation
* @returns {string} The generated message
*/
function getMyNewMessage(ctx) {
const messages = getMessages();
// Create context with both camelCase and snake_case keys
const templateContext = toSnakeCase(ctx);
// Default message template
const defaultMessage = "Default message with {placeholder1} and {placeholder2}";
// Use custom message if configured
return messages?.myNewMessage
? renderTemplate(messages.myNewMessage, templateContext)
: renderTemplate(defaultMessage, templateContext);
}
module.exports = {
getMyNewMessage,
};
重要なポイント:
- ファイル名:
messages_<category>.cjs(サブフォルダーではなくフラットな構成) - 共通ユーティリティは
./messages_core.cjsからインポートします - 型定義には JSDoc を使用します
- 適切なデフォルトメッセージを用意します
- カスタムテンプレートとデフォルトテンプレートの両方に対応します
Step 5: テストを追加する
pkg/workflow/js/messages_my_new.test.cjs を作成します:
import { describe, it, expect, beforeEach, vi } from "vitest";
// Mock core global
const mockCore = {
warning: vi.fn(),
};
global.core = mockCore;
describe("getMyNewMessage", () => {
beforeEach(() => {
vi.clearAllMocks();
delete process.env.GH_AW_SAFE_OUTPUT_MESSAGES;
});
it("should return default message when no custom message configured", async () => {
const { getMyNewMessage } = await import("./messages_my_new.cjs");
const result = getMyNewMessage({
placeholder1: "value1",
placeholder2: "value2",
});
expect(result).toBe("Default message with value1 and value2");
});
it("should use custom message when configured", async () => {
process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({
myNewMessage: "Custom: {placeholder1}",
});
const { getMyNewMessage } = await import("./messages_my_new.cjs");
const result = getMyNewMessage({
placeholder1: "test",
placeholder2: "ignored",
});
expect(result).toContain("Custom: test");
});
});
make test-js を実行してテストします。
Step 6: コアモジュールの TypeDef を更新する
pkg/workflow/js/messages_core.cjs の SafeOutputMessages typedef に新しいプロパティを追加します:
/**
* @typedef {Object} SafeOutputMessages
* @property {string} [footer] - Custom footer message template
* // ... existing properties ...
* @property {string} [myNewMessage] - Custom my-new-message template
*/
さらに、getMessages() 関数の戻り値オブジェクトも更新します:
return {
footer: rawMessages.footer,
// ... existing fields ...
myNewMessage: rawMessages.myNewMessage,
};
Step 7: バレルファイルを更新する
pkg/workflow/js/messages.cjs に再エクスポートを追加します:
// Re-export my new messages
const { getMyNewMessage } = require("./messages_my_new.cjs");
module.exports = {
// ... existing exports ...
getMyNewMessage,
};
Step 8: Go の埋め込みに登録する
pkg/workflow/js.go に追加します:
//go:embed js/messages_my_new.cjs
var messagesMyNewScript string
GetJavaScriptSources() に追加します:
func GetJavaScriptSources() map[string]string {
return map[string]string{
// ... existing entries ...
"messages_my_new.cjs": messagesMyNewScript,
}
}
Step 9: 呼び出し元のスクリプトで使用する
必要なスクリプトでは、対象のモジュールから直接インポートします:
const { getMyNewMessage } = require("./messages_my_new.cjs");
// Use the message
const message = getMyNewMessage({
placeholder1: actualValue1,
placeholder2: actualValue2,
});
Step 10: ドキュメントを更新する
scratchpad/safe-output-messages.md を更新します:
- 「Message Categories」セクションに新しいメッセージを追加する
- プレースホルダーと使い方を記載する
- 例を追加する
Message Module Architecture の表を更新します:
| Module | Purpose | Exported Functions |
|--------|---------|-------------------|
| `messages_my_new.cjs` | My new message description | `getMyNewMessage` |
検証チェックリスト
コミットする前に、次の項目を確認してください:
-
pkg/parser/schemas/main_workflow_schema.jsonの JSON Schema を更新した -
pkg/workflow/compiler.goの Go 構造体を更新した - 必要に応じて、
pkg/workflow/safe_outputs.goの Go パーサーが新しいフィールドを処理するようにした - JavaScript モジュールを作成した:
pkg/workflow/js/messages_my_new.cjs - テストを作成した:
pkg/workflow/js/messages_my_new.test.cjs -
messages_core.cjsの TypeDef を更新した - バレルファイルを更新した:
messages.cjs -
js.goに Go の埋め込みディレクティブを追加した -
GetJavaScriptSources()のマップに追加した - 呼び出し元のスクリプトを更新し、必要最小限のインポートを使用するようにした
-
scratchpad/safe-output-messages.mdのドキュメントを更新した - テストが成功する:
make test-js - ビルドが成功する:
make build - Lint が成功する:
make lint
ファイルの概要
| ファイル | 目的 | 必要な変更 |
|---|---|---|
pkg/parser/schemas/main_workflow_schema.json | JSON Schema | フィールド定義を追加 |
pkg/workflow/compiler.go | Go 構造体 | 構造体フィールドを追加 |
pkg/workflow/safe_outputs.go | パーサー | 必要に応じて解析ロジックを追加 |
pkg/workflow/js/messages_my_new.cjs | JavaScript モジュール | 新しいファイルを作成 |
pkg/workflow/js/messages_my_new.test.cjs | テスト | 新しいファイルを作成 |
pkg/workflow/js/messages_core.cjs | コアユーティリティ | typedef を更新 |
pkg/workflow/js/messages.cjs | バレルファイル | 再エクスポートを追加 |
pkg/workflow/js.go | Go の埋め込み | embed ディレクティブを追加 |
scratchpad/safe-output-messages.md | ドキュメント | 新しいメッセージを記載 |
例:close-older-discussion メッセージの追加
このメッセージタイプは、次の手順で追加されました。
- スキーマ:プレースホルダー
{new_discussion_number}、{new_discussion_url}、{workflow_name}、{run_url}を含むclose-older-discussionフィールドを追加 - Go 構造体:
CloseOlderDiscussion stringフィールドを追加 - JavaScript:
getCloseOlderDiscussionMessage()を含むmessages_close_discussion.cjsを作成 - テスト:対応するテストファイルを追加
- バンドラー:
GetJavaScriptSources()に登録 - コンシューマー:直接インポートして
close_older_discussions.cjsで使用
実装例については、これらのファイルを参照してください。