- 投稿日:
この記事ではGitHub ActionsのCustom actionをJavaScriptで実装するJavaScript actionをTypeScriptとSWCを使って実装した方法を書いてます。
モチベーション
- GitHub ActionsのWorkflowsを共通化したい
- TypeScriptでロジックを書きたい
- SWCを使いたい(nccはtscを使うので避けたい
- github-scriptは一定以上のボリュームがあるものには向かない
- これを使いつつUTを書いたりするとなると結構面倒になると思う
今回作るもの
Custom actionのうちJavaScript actionを作成します。
実装コードはTypeScript、トランスパイラはSWC、バンドラはwebpackを利用します。
バンドラを利用するのは、node_modules/
をGitで管理したくないためです。
ビルド成果物であるdist/
は実行時に必要なため、Gitで管理します。
(CI上でビルドしてキャッシュさせておくことも出来ると思いますが、今回は扱いません)
確認環境
Env | Ver |
---|---|
@actions/core | 1.10.0 |
@actions/github | 5.1.1 |
@swc/cli | 0.1.57 |
@swc/core | 1.3.26 |
swc-loader | 0.2.3 |
typescript | 4.9.5 |
webpack | 5.75.0 |
webpack-cli | 5.0.1 |
サンプルコード
Custom Actions本体
Custom action本体のサンプルコードです。以下に一式があります。
https://github.com/Lycolia/typescript-code-examples/tree/main/swc-ts-custom-actions
ディレクトリ構成
dist/
配下を叩くため、ここはGit管理に含めます。バンドルするのでnode_modules/
はGit管理から外して問題ありません。
├─dist/
│ └─index.js # Custom Actionsとして実行するファイル本体
├─node_modules/
├─src/
│ └─index.ts # TypeScript実装
├─action.yaml # Custom Actionsの定義
├─package-lock.json
├─package.json
├─swcrc-base.js # SWCの設定
├─tsconfig.json # tscの設定
└─webpack.config.js # webpackの設定
swcrc-base.js
SWCの設定例。特にJavaScript actionのための設定はなく、CLI向けのトランスパイルが出来る設定ならおk。
ファイル名は何でも大丈夫ですが、この場では.swcrc
にしないことで、直接SWCで利用しないことを判りやすくするために違う名前にしています。
module.exports = {
module: {
type: 'commonjs',
},
jsc: {
target: 'es2020',
parser: {
syntax: 'typescript',
tsx: false,
decorators: false,
dynamicImport: false,
},
baseUrl: '.',
paths: {
'src/*': ['src/*'],
},
},
};
webpack.config.js
SWCを使って.ts
ファイルをバンドルするための設定。これがないとimport
の解決ができずにコケます。
node_modules/
配下をGit管理に含める場合は不要かもしれませんが、それをするのは微妙だと思います。
const path = require('path');
const swcrcBase = require(path.resolve(__dirname, 'swcrc-base'));
module.exports = {
// エントリポイント
entry: path.resolve(__dirname, 'src/index.ts'),
// 出力設定
output: {
// クリーンアップ後に出力
clean: true,
// 出力ファイル名
filename: 'index.js',
// 出力パス
path: path.resolve(__dirname, 'dist'),
},
// 設定必須なので何か指定しておく
mode: 'production',
// 指定してないとNode.jsのネイティブAPIが呼べない
target: ['node'],
module: {
// swc-loaderの設定
rules: [
{
test: /\.ts$/,
exclude: /(node_modules)/,
use: {
loader: 'swc-loader',
// swcrcの設定
options: {
...swcrcBase,
},
},
},
],
},
resolve: {
// import時のファイル拡張子を省略してる場合にパスを解決するための設定
extensions: ['', '.ts', '.js'],
},
};
src/index.ts
最低限これだけ確認できれば応用して実装できるだろうという程度のサンプルコード。
@actions/*
系の使い方は以下のリンクから確認できます。
actions/toolkit: The GitHub ToolKit for developing GitHub Actions.
import * as core from '@actions/core';
import * as github from '@actions/github';
const githubToken = core.getInput('GITHUB_TOKEN', { required: true });
const octokit = github.getOctokit(githubToken);
console.log('octokit', octokit);
console.log('context', github.context);
core.setOutput('RESULT_MESSAGE', 'test result message');
action.yaml
実装の参考例として引数と出力を定義してます。特に不要な場合は書かなくてもいいです。
Node.jsのバージョンを詳細に指定したい場合は、composite action にすれば可能だとは思いますが、試してない。
composite actionにしてnvmか何かでインストールしてやれば恐らく可能。
構文は以下のページで確認できます。
GitHub Actions のメタデータ構文 - GitHub Docs
name: example
description: custom actions example
inputs:
GITHUB_TOKEN:
description: 'Repogitory GITHUB_TOKEN'
required: true
outputs:
RESULT_MESSAGE:
description: 'Result message'
on:
workflow_call:
runs:
using: node16
main: dist/index.js
Custom actionを使う側
Custom actionを使うWorkflowのサンプルコードです。以下にソースがあります。
https://github.com/Lycolia/custom-actions-usage-example
.github/workflows/example.yaml
uses
のところにはリポジトリの組織名と、リポジトリ名、action.yaml
が配置されているディレクトリまでのパスを書きます。ルートディレクトリにある場合はパスを書かなくてOK
最後に@sha-hash
でコミットハッシュかタグを付けてやれば呼べるようになります。
動作確認中はハッシュが頻繁に変わるので、最新のハッシュを取得してきて設定されるようにしておくと便利かもしれません。
name: run example
on:
workflow_dispatch:
jobs:
example:
runs-on: ubuntu-latest
steps:
- name: run custom actions
id: test
uses: org-name/repo-name/path/to/file@sha-hash
with:
# Custom action側で定義されている引数(input)の設定
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: show custom actions output
# Custom action側で定義されている出力(output)の取得
run: echo ${{ steps.test.outputs.RESULT_MESSAGE }}
参考資料
- Getting Started – SWC
- swcrcの書き方やswc-loaderの使い方
- Concepts | webpack
- webpackの設定
- カスタム アクションについて - GitHub Docs
- GitHub Actions のメタデータ構文 - GitHub Docs
- プライベート リポジトリからのアクションとワークフローの共有 - GitHub Docs
- actions/toolkit: The GitHub ToolKit for developing GitHub Actions.
@actions/*
系のドキュメントなど
- 投稿日:
FocalboardというNotionクローンがあるらしく試してみた結果のメモ。
外部に公開することは一切考慮していません。ローカルマシンでの個人利用を想定しています。
確認環境
Env | Ver |
---|---|
Ubuntu | 20.04.4 LTS |
WSL2 | 1.0.3.0 |
Focalboard | 0.15.0 |
MySQL | Ver 15.1 Distrib 10.3.37-MariaDB |
前提条件
- MySQLはセットアップ済み
手順
基本的なセットアップ
wget https://github.com/mattermost/focalboard/releases/download/v0.15.0/focalboard-server-linux-amd64.tar.gz
tar -xvzf focalboard-server-linux-amd64.tar.gz
sudo mv focalboard /var/lib/
cat <<'EOF' | sudo tee /etc/nginx/conf.d/focalboard.conf
upstream focalboard {
server localhost:15001;
keepalive 32;
}
server {
server_name focalboard.test;
access_log /var/log/nginx/focalboard.access.log;
error_log /var/log/nginx/focalboard.error.log;
location ~ /ws/* {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 50M;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
client_body_timeout 60;
send_timeout 300;
lingering_timeout 5;
proxy_connect_timeout 1d;
proxy_send_timeout 1d;
proxy_read_timeout 1d;
proxy_pass http://focalboard;
}
location / {
client_max_body_size 50M;
proxy_set_header Connection "";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
proxy_read_timeout 600s;
proxy_cache_revalidate on;
proxy_cache_min_uses 2;
proxy_cache_use_stale timeout;
proxy_cache_lock on;
proxy_http_version 1.1;
proxy_pass http://focalboard;
}
}
EOF
sudo cat << 'EOF' | sudo tee /etc/init.d/focalboard
#!/bin/sh
## BEGIN INIT INFO
# Provides: focalboard
# Required-Start: $syslog $network
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: A self-hosted Git service written in Go.
# Description: A self-hosted Git service written in Go.
## END INIT INFO
. /lib/lsb/init-functions
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
DESC="Focalboard server"
NAME=focalboard
SERVICEVERBOSE=yes
PIDFILE=/run/$NAME.pid
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/1/KILL/5}"
do_start()
{
start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \
--background --chdir /var/lib/focalboard \
--exec /var/lib/focalboard/bin/focalboard-server
}
do_stop()
{
kill -9 $(cat /run/focalboard.pid)
# does not work
#start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PIDFILE --name $NAME --oknodo
rm -f $PIDFILE
}
do_status()
{
if [ -f $PIDFILE ]; then
if kill -0 $(cat "$PIDFILE"); then
echo "$NAME is running, PID is $(cat $PIDFILE)"
else
echo "$NAME process is dead, but pidfile exists"
fi
else
echo "$NAME is not running"
fi
}
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
do_start
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
;;
status)
do_status
;;
restart)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
do_start
;;
*)
log_daemon_msg "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 2
;;
esac
exit 0
EOF
sudo chmod 755 /etc/init.d/focalboard
sudo update-rc.d focalboard defaults
mysql -u XXX -pYYY
DBの作成
CREATE DATABASE boards;
GRANT ALL on boards.* to 'boardsuser'@'localhost' identified by 'boardsuser-password';
exit
DBとportの変更
nano /var/lib/focalboard/config.json
port
とdbtype
を以下の内容に書き換え
"port": 15001,
"dbtype": "mysql",
起動
以下を叩き http://focalboard.test/ にアクセスできればOK
sudo service focalboard start
感想
Notionっぽいけどかなりしょぼい
ボードが作れてmdが書ける程度
2カラムレイアウト作るとか、画像をドラッグで移動するとかはできない
表組みへの画像挿入は「画像添付 -> 表のmdを書く -> HTMLからblob URLを貼る」で可能だが、見切れるので微妙
今のところ実用性はあまりないかも
参考
- 投稿日:
変数の文字列を文字列で置換
@ECHO OFF
SET text="hoge piyo fuga"
REM 置換文字を標準出力
ECHO %text:hoge=XXX%
REM 置換文字を変数に設定
SET replaced_text=%text:hoge=XXX%
ECHO %replaced_text%
@ECHO ON
変数の文字列を変数の文字列で置換
SET "var=value"
とSET var="value"
の差は後述のAppendixを参照
CALL
を付けているのは、これがないと変数名そのものが文字列として扱われるため
@ECHO OFF
SET "text2=foo bar baz"
SET "search_word=baz"
SET "replacer=ZZZ"
REM 置換文字を標準出力
CALL ECHO %%text2:%search_word%=%replacer%%%
REM 置換文字を変数に設定
CALL SET replaced_text2=%%text2:%search_word%=%replacer%%%
ECHO %replaced_text2%
REM 検索文字列を削除
CALL SET replaced_text3=%%text2:%search_word%=%%
ECHO %replaced_text3%
@ECHO ON
Appendix
SETコマンドの記述方法を変えた場合の出力結果の差について
SET "var=foo bar ZZZ" |
SET var="foo bar ZZZ" |
---|---|
foo bar ZZZ |
"foo bar ZZZ" |
参考
- 投稿日:
ローカルで個人メモを管理したいがRedmineでは物足りない。そうだGiteaを使おう。
この記事ではDockerを使用せず、バイナリからセットアップします。
Gitのリポジトリをホスティングできる部分までは確認してます。
外部に公開することは一切考慮していません。ローカルマシンでの個人利用を想定しています。
確認環境
Env | Ver |
---|---|
Ubuntu | 20.04.4 LTS |
WSL2 | 1.0.3.0 |
Gitea | 1.18.5 |
MySQL | Ver 15.1 Distrib 10.3.37-MariaDB |
Git | 2.25.1 |
前提条件
- WSL2上にUbuntu 20.04.4 LTSをインストール済
- GitとMySQLは構築済
手順
公式の手順ではユーザーがgit
ですが、ここではgitea
に変えてます
他にも多少変えてます
Giteaディレクトリの作成とバイナリ配置
# 動作用ユーザーの追加
sudo adduser \
--system \
--shell /bin/bash \
--gecos 'Git Version Control' \
--group \
--disabled-password \
--home /home/gitea \
gitea
# 必要なフォルダを切る
sudo mkdir -p /var/lib/gitea/{custom,data,log}
sudo chown -R gitea:gitea /var/lib/gitea/
sudo chmod -R 750 /var/lib/gitea/
sudo mkdir /etc/gitea
sudo chown root:gitea /etc/gitea
sudo chmod 770 /etc/gitea
# バイナリのインストール
wget -O gitea https://dl.gitea.com/gitea/1.18.5/gitea-1.18.5-linux-amd64
chmod +x gitea
sudo cp gitea /usr/local/bin/gitea
# mysqlにログイン
mysql -u XXX -pYYY
DBのセットアップ
SET old_passwords=0;
CREATE USER 'gitea' IDENTIFIED BY 'gitea';
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
GRANT ALL PRIVILEGES ON giteadb.* TO 'gitea';
FLUSH PRIVILEGES;
quit
Giteaの起動とWebインストール
以下のコマンドを叩き表示されたURLを開き、Webインストーラーで適当に設定
gitea web -c /etc/gitea/app.ini
Webインストール後の後処理とデーモンへの登録
# 自分以外書き換え不能に変更
sudo chmod 750 /etc/gitea
sudo chmod 640 /etc/gitea/app.ini
# デーモンの定義を作成
cat <<'EOF' | sudo tee /etc/init.d/gitea
#!/bin/sh
## BEGIN INIT INFO
# Provides: gitea
# Required-Start: $syslog $network
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: A self-hosted Git service written in Go.
# Description: A self-hosted Git service written in Go.
## END INIT INFO
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
DESC="Gitea - Git with a cup of tea"
NAME=gitea
SERVICEVERBOSE=yes
PIDFILE=/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
WORKINGDIR=/var/lib/$NAME
DAEMON=/usr/local/bin/$NAME
DAEMON_ARGS="web -c /etc/$NAME/app.ini"
USER=gitea
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/1/KILL/5}"
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
do_start()
{
GITEA_ENVS="USER=$USER GITEA_WORK_DIR=$WORKINGDIR HOME=/home/$USER"
GITEA_EXEC="$DAEMON -- $DAEMON_ARGS"
sh -c "start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
--background --chdir $WORKINGDIR --chuid $USER \\
--exec /bin/bash -- -c '/usr/bin/env $GITEA_ENVS $GITEA_EXEC'"
}
do_stop()
{
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PIDFILE --name $NAME --oknodo
rm -f $PIDFILE
}
do_status()
{
if [ -f $PIDFILE ]; then
if kill -0 $(cat "$PIDFILE"); then
echo "$NAME is running, PID is $(cat $PIDFILE)"
else
echo "$NAME process is dead, but pidfile exists"
fi
else
echo "$NAME is not running"
fi
}
case "$1" in
start)
echo "Starting $DESC" "$NAME"
do_start
;;
stop)
echo "Stopping $DESC" "$NAME"
do_stop
;;
status)
do_status
;;
restart)
echo "Restarting $DESC" "$NAME"
do_stop
do_start
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 2
;;
esac
exit 0
EOF
# デーモン登録
sudo chmod 755 /etc/init.d/gitea
sudo update-rc.d gitea defaults
# デーモン起動
sudo service gitea start
自動起動する場合はWindowsのスタートアップ時に以下が走るようにしておけばOK
wsl -d Ubuntu -u root -- service gitea start
トラブルシュート
この記事を書くにあたってハマったことのまとめ
gitea 起動時にpermission denied
とエラーが出る
/var/lib/gitea/custom/options/locale: permission denied
以下のコマンドを流せばいける。公式のコマンドではコケる
gitea web -c /etc/gitea/app.ini
サービス起動時にFailed to get home directory
とエラーが出る
2023/03/03 13:17:38 ...s/setting/setting.go:656:loadFromConf() [F] Failed to get home directory: cannot get home directory
/etc/init.d/gitea
のdo_start()
の部分を以下の内容にすればいける
do_start()
{
GITEA_ENVS="USER=$USER GITEA_WORK_DIR=$WORKINGDIR HOME=/home/$USER"
GITEA_EXEC="$DAEMON -- $DAEMON_ARGS"
sh -c "start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
--background --chdir $WORKINGDIR --chuid $USER \\
--exec /bin/bash -- -c '/usr/bin/env $GITEA_ENVS $GITEA_EXEC'"
}
git push
でエラーが出る
RPC failed; HTTP 413 curl 22 The requested URL returned error: 413
nginxからgiteaにリバースプロキシしてる場合はconfのserverセクションに以下を追加
client_max_body_size 0;
参考
- Installation from binary - Docs
- 公式ドキュメント
- 投稿日:
公式のリファレンスが情報少なすぎるのでメモ
特にこれというフォーマットはなく、ある程度幅広い書式があるようで、公式のドキュメントを見る限り、多少のブレはよしなに解釈してくれるっぽい?
この記事ではoperatorなどの用語が登場しますが、これは私が勝手に名付けたものなので、特に公式の用語ではありません
手組するの面倒なので雑にコマンド生成ツールを作りました。
https://tool.lycolia.info/slack-remider-creator
登録
基本
- フォーマット
/remind [宛先] [メッセージ] [実行日時]
- 例
/remind #random "hoge piyo fuga" at 10:00 every monday, sunday
書式
宛先
宛先 | 意味 |
---|---|
me | 自分 |
@someone | メンション |
#channel | チャンネル |
メッセージ
"hoge piyo fuga"
のように書けるが、hoge piyo fuga
でも一応通じる
ダブルクォートで囲む場合、改行も利用可能
実行日時
<oparator> <repeat-operator>
<oparator>
で実行日時を設定<repeat-operator>
で繰り返しを設定
- 例
at 10:00 every monday, sunday
oparator
オペレーター | 例 | 意味 |
---|---|---|
in <value> (seconds \ | minutes \ | hours) |
at <HH:mm> | at 1700 | 指定時刻に実行 |
on <yyyy-MM-dd HH:mm> | on 2023-10-10 09:15 | 指定日時に実行 |
repeat-operator
every <operator>
- 例
every monday, sunday
operator |
---|
day |
weekday |
sunday, monday, tuesday, wednesday, thursday, friday, saturday |
削除
/remind list
でリスト表示して消す
一覧
/remind list