- 投稿日:
Node.jsのスクリプトを適当に書き次のようなWorkflowsを記述することで実行できる。勿論Dockerイメージを作ってそこから立ち上げることもできるので好みの問題。直に呼べる分、取り回しは楽だと思う
name: hoge
description: hoge
inputs:
GITHUB_TOKEN:
description: 'Workflowsを実行するリポジトリのGITHUB_TOKEN'
required: true
on:
workflow_call:
runs:
using: node20
main: dist/index.js
inputs:
やoutputs:
を記述すれば入出力の引数も定義できる。
inputs.GITHUB_TOKEN
について
これを書いておくとoctokitを使ってGitHubのAPIを叩けるようになる。普通は何かAPIを叩くはずなので書いておいた方が良い。
以下は一例。
const github = require('@actions/github');
const core = require('@actions/core');
async function run() {
const token = core.getInput('GITHUB_TOKEN');
const octokit = github.getOctokit(token);
const { data: pullRequest } = await octokit.rest.pulls.get({
owner: 'octokit',
repo: 'rest.js',
pull_number: 123,
mediaType: {
format: 'diff'
}
});
console.log(pullRequest);
}
参考
- Metadata syntax for GitHub Actions (docs.github.com)
- @actions/github
- 投稿日:
prettier-vscodeをPrettier v3に対応させる試みは既にあるのだが、PRがRejectされている。レビューを見た感じtypoが原因っぽいのでtypoを直してみたのだがテストが落ちる。
まずテストが通らない原因だが、これはアサーション結果とテストコード、落ちた時の結果を三点比較したときに落ちた時の結果がプラグインを反映せずprettier -w
されたものであることに気が付いた。次にこの解決法だが、原因が複数あるため、その切り分けが必要だと考えている。これはテスト走行時に指定されたプラグインが正しく読み込まれていればテストを通すことができるはずだが、package.json
の指定通りインストールされているのかや、prettier側が正常に読み込めているのかなどが解らないと、真の原因が突き止められないためだ。
見た感じ割と面倒な仕組みなテストを実行してそうだったので一旦私は諦めることにした。これはprettier v3を個別にインストールすることで基本的に解決できるためだ。とはいえ、インストールできない条件だとその回避に苦労するのでネイティブに対応してほしい思いはあるが、検証するにも本家リポジトリにPRを向けないとテスト走行すらままならず、ローカルでの検証が極めて厳しいので、正直やる気が起きない。ぶっちゃけDockerで個別テストケースごとにビルドしてやるのが一番仕組みが単純で安全に思うが、敷くほど遅くなりそうだし、イメージのメンテも大変そうだし、アホほどイメージができるはずなので、容量も食いそうでなかなか微妙そうである。
そもそも論としてmainブランチを引っ張ってきてビルドすると、この時点で型エラーを吐くので、ここからどうにかしていく必要があり、割としんどい作業になりそうだ。
- 投稿日:
動機としてはcurlだと見えない部分があるので、自分でHTTPメッセージを手組みして送ってみたかった。
Node.jsとPHPのサーバーでリクエストが期待通り取得できたので、メッセージの実装としては問題ないと思われる。
検証用サーバー
以下のコードをNode.js v20.11.1を用いて検証
import http from 'node:http';
http
.createServer((req, res) => {
console.log(req.headers);
req.on('data', (chunk) => {
// body
console.log(Buffer.from(chunk).toString());
});
res.statusCode = 200;
res.end();
})
.listen(9999);
netcatコマンドによるリクエスト検証
GETリクエスト
echo -e 'GET / HTTP/1.1\r\nHost: localhost:9999\r\n\r\n' | nc localhost 9999
POSTリクエスト
echo -e 'POST / HTTP/1.1\r\nHost: localhost:9999\r\nContent-Length: 4\r\n\r\nhoge' | nc localhost 9999
備考
PHPで検証サーバーを作る場合
実際にAPサーバーでリクエストの中身をパース出来るかどうかの観点で見た場合にNode.jsよりPHPのが楽なので、PHPで作ってみた結果、軽くハマったので残しておく。
以下のコードを用いてPHP 8.0.29で検証サーバーを作る場合に、php -S 0.0.0.0:9999
としてサーバーを起動すると、Content-Type
ヘッダがない場合に正常な動作をしなかった。
<?php
var_dump($_SERVER);
var_dump($_REQUEST);
ncで検証サーバーを作る場合
デバッグ用。生のメッセージが見れるのでダンプしてdiffを取るなどでcurlとecho + ncの差分を見るのに使える。
nc -l 9999
HTTPメソッド名を非標準的なものにした場合の挙動
前述のNode.jsサーバーでは400 Bad Request
、PHPサーバーでは501 Not Implemented
が応答された。
- 投稿日:
HTTPヘッダを持たないHTTPリクエストはあり得るのか?というのを検証しているときに気づいた話。
RFC 7230ではHostヘッダを持たないHTTPリクエストは禁止されており、これを受けたサーバーは400応答を返すことを必須としている。
RFC 7230:Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and RoutingのHostより
A client MUST send a Host header field in an HTTP/1.1 request even if
the request-target is in the absolute-form, since this allows the
Host information to be forwarded through ancient HTTP/1.0 proxies
that might not have implemented Host.
A server MUST respond with a 400 (Bad Request) status code to any
HTTP/1.1 request message that lacks a Host header field and to any
request message that contains more than one Host header field or a
Host header field with an invalid field-value.
なお、Node.jsのHTTPサーバー機能ではHostヘッダーのない要求を受け入れることができる。
http.createServer([options][, requestListener])を見ると、以下のようにrequireHostHeader: false
を渡すことで実現可能だ。規定値はtrue
であるため、基本的にはHostヘッダーなしの要求は400応答が返される。
import http from 'node:http';
http
.createServer({requireHostHeader: false}, (req, res) => {
console.log(req.headers);
res.statusCode = 200;
res.end();
})
.listen(3000);
nginxにおいてもHostヘッダーなしの要求は以下の応答が返されたため同様と思われる。
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.26.0</center>
</body>
</html>
但し、nginxにおいてHostなしの要求を許容する方法は見つからなかった。Server namesによるとserver_name "";
とすることで出来そうに見えたが、これは機能させることができず、400応答が返された。
- 投稿日:
依存ライブラリの関係でESLint v9への移行はできていないが、取り合えずFlat configに移行した。ESLintは7.9.0から8.57.0に更新している。
確認環境
Flat configになってからeslint:recommended
は@eslint/jsに移った模様。
Env | Ver |
---|---|
@eslint/js | 9.2.0 |
@lycolia/eslint-config | 0.9.1 |
@swc/jest | 0.2.31 |
@types/jest | 29.5.11 |
@types/node | 20.11.5 |
eslint | 8.57.0 |
eslint-plugin-jest | 28.5.0 |
jest | 29.7.0 |
prettier | 3.2.5 |
typescript | 5.4.5 |
typescript-eslint | 7.8.0 |
元の設定
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/style",
"plugin:jest/recommended",
"@lycolia/eslint-config",
"prettier"
],
"plugins": [
"@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
}
}
やったこと
ESLintなど必要ライブラリのアップデート
npm i -D eslint @eslint/js eslint-plugin-jest jest prettier typescript typescript-eslint @lycolia/eslint-config
新設定の作成
eslint.config.js
を作成
extendsの設定
今までextends
に書いていたものはrequire
でモジュールを参照してmodule.exports = []
の配列の中に書いた。typescript-eslintとeslint-plugin-jestの対応が何とも言えない。なお、この状態だとtypescript-eslintが正常に動かない。
const eslint = require("@eslint/js");
const eslintTypeScript = require("typescript-eslint");
const eslintJest = require("eslint-plugin-jest");
const eslintLycolia = require("@lycolia/eslint-config");
module.exports = [
eslint.configs.recommended,
eslintTypeScript.configs.recommended[0],
eslintJest.configs["flat/style"],
eslintJest.configs["flat/recommended"],
eslintLycolia,
];
設定が競合して都合が悪かったので、この時にPrettierの設定を削除しているが、Flat config化とは特に関係ないので無視してよい。
@lycolia/eslint-configは私が作っているカスタム設定だが、これは特に何もせずとも使えた。
.eslintignore対応
extendsしたオブジェクトの次にオブジェクトを記述し、そこにignores: []
を追加し、その中に同じことを書いた。恐らく根っこの配列はESLintの設定オブジェクトの羅列で、最終的に後勝ちでマージされる様に出来ているのだろう。
const eslint = require("@eslint/js");
const eslintTypeScript = require("typescript-eslint");
const eslintJest = require("eslint-plugin-jest");
const eslintLycolia = require("@lycolia/eslint-config");
module.exports = [
eslint.configs.recommended,
eslintTypeScript.configs.recommended[0],
eslintJest.configs["flat/style"],
eslintJest.configs["flat/recommended"],
eslintLycolia,
{
ignores: [
'dist/*',
'coverage/*',
'**/*.d.ts',
'/src/public/',
'/src/type',
'*.config.js'
],
}
];
TypeScript対応
eslintTypeScript.config()
でESLintの設定配列全体を引数としてラップし、languageOptions
の中身を移植した。旧設定にあったplugins
は公式のドキュメントを見る限り不要になっている模様。
const eslint = require('@eslint/js');
const eslintTypeScript = require('typescript-eslint');
const eslintJest = require('eslint-plugin-jest');
const eslintLycolia = require('@lycolia/eslint-config');
module.exports = eslintTypeScript.config(
eslint.configs.recommended,
...eslintTypeScript.configs.recommended,
eslintJest.configs['flat/style'],
eslintJest.configs['flat/recommended'],
eslintLycolia,
{
ignores: [
'dist/*',
'coverage/*',
'**/*.d.ts',
'/src/public/',
'/src/type',
'*.config.js'
],
languageOptions: {
parser: eslintTypeScript.parser,
parserOptions: {
project: './tsconfig.json'
}
}
}
);
旧設定の削除
.eslintrc
と.eslintignore
を消した。
ESLint v9対応
typescript-eslintが対応していないため、現時点ではできなかった。
変更差分まとめ
-{
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:jest/style",
- "plugin:jest/recommended",
- "@lycolia/eslint-config",
- "prettier"
- ],
- "plugins": [
- "@typescript-eslint"
- ],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "project": "./tsconfig.json"
+const eslint = require('@eslint/js');
+const eslintTypeScript = require('typescript-eslint');
+const eslintJest = require('eslint-plugin-jest');
+const eslintLycolia = require('@lycolia/eslint-config');
+
+module.exports = eslintTypeScript.config(
+ eslint.configs.recommended,
+ ...eslintTypeScript.configs.recommended,
+ eslintJest.configs['flat/style'],
+ eslintJest.configs['flat/recommended'],
+ eslintLycolia,
+ {
+ ignores: [
+ 'dist/*',
+ 'coverage/*',
+ '**/*.d.ts',
+ '/src/public/',
+ '/src/type',
+ '*.config.js'
+ ],
+ rules: {
+ semi: ['error', 'always']
+ },
+ languageOptions: {
+ parser: eslintTypeScript.parser,
+ parserOptions: {
+ project: './tsconfig.json'
+ }
+ }
}
-}
+);