GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。 NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは 別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
124 lines
4.8 KiB
JavaScript
124 lines
4.8 KiB
JavaScript
"use strict";
|
||
/*
|
||
* production側SiteId=504407/504412のClassX(状態)ChoicesTextに、staging側で追加済みの
|
||
* 中間状態4件(退職判定/新規登録判定/ユーザー更新判定/グループ更新判定)が欠落している
|
||
* (scripts/compare-master-sites-staging-prod.js で検出)。staging側の値をそのままproductionへ反映する。
|
||
* 既定はドライラン。実際に送信するには --execute を付ける。
|
||
*
|
||
* 実行: node scripts/push-classx-choices-production.js [--execute]
|
||
*/
|
||
const fs = require("fs");
|
||
const path = require("path");
|
||
const { getSite: fetchSite } = require("../src/lib/pleasanterClient");
|
||
const { saveSiteSnapshot } = require("../src/lib/siteConfigStore");
|
||
|
||
function parseEnv(text) {
|
||
const result = {};
|
||
for (const line of text.split(/\r?\n/)) {
|
||
const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/);
|
||
if (!m || line.trim().startsWith("#")) continue;
|
||
result[m[1]] = m[2];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function loadEnv(file) {
|
||
const result = parseEnv(fs.readFileSync(path.join(__dirname, "..", file), "utf8"));
|
||
return { baseUrl: result.PLEASANTER_BASE_URL, apiKey: result.PLEASANTER_API_KEY };
|
||
}
|
||
|
||
const TARGET_SITE_IDS = [504407, 504412];
|
||
|
||
// staging側の完全な選択肢(scripts/compare-master-sites-staging-prod.js実行結果より)
|
||
const WANT_CHOICES_TEXT =
|
||
"0,在籍中,在籍中,status-blue\n" +
|
||
"1,退職済み,退職,status-red\n" +
|
||
"2,退職判定,退職判定,status-black\n" +
|
||
"3,新規登録判定,新規登録判定,status-yellow\n" +
|
||
"4,ユーザー更新判定,ユーザー更新判定,status-green\n" +
|
||
"5,グループ更新判定,グループ更新判定,status-purple\n" +
|
||
"8,要確認,要確認,status-yellow\n" +
|
||
"9,その他,その他,status-green\n";
|
||
|
||
async function getSite(baseUrl, apiKey, siteId) {
|
||
const data = await fetchSite({ baseUrl, apiKey, siteId });
|
||
saveSiteSnapshot(siteId, data);
|
||
return data;
|
||
}
|
||
|
||
async function updateSite(baseUrl, apiKey, siteId, body) {
|
||
const res = await fetch(`${baseUrl.replace(/\/$/, "")}/api/items/${siteId}/updatesite`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json; charset=utf-8" },
|
||
body: JSON.stringify(body),
|
||
});
|
||
const data = await res.json();
|
||
if (!res.ok || data.StatusCode !== 200) {
|
||
throw new Error(`updatesite failed(SiteId=${siteId}): ${res.status} ${JSON.stringify(data)}`);
|
||
}
|
||
return data;
|
||
}
|
||
|
||
async function main() {
|
||
const execute = process.argv.includes("--execute");
|
||
const production = loadEnv(".env.production");
|
||
if (!production.baseUrl || !production.apiKey) {
|
||
console.error("production の PLEASANTER_BASE_URL / PLEASANTER_API_KEY が読み取れなかった");
|
||
process.exit(1);
|
||
}
|
||
|
||
for (const siteId of TARGET_SITE_IDS) {
|
||
console.log(`\n=== SiteId=${siteId} ===`);
|
||
const current = await getSite(production.baseUrl, production.apiKey, siteId);
|
||
const currentColumns = (current.SiteSettings && current.SiteSettings.Columns) || [];
|
||
const classXCol = currentColumns.find((c) => c.ColumnName === "ClassX");
|
||
if (!classXCol) {
|
||
console.error(` ClassX列が見つからない、スキップ`);
|
||
continue;
|
||
}
|
||
if (classXCol.ChoicesText === WANT_CHOICES_TEXT) {
|
||
console.log(` すでに一致、変更不要`);
|
||
continue;
|
||
}
|
||
|
||
console.log(` 現状 ChoicesText:\n ${JSON.stringify(classXCol.ChoicesText)}`);
|
||
console.log(` 変更後 ChoicesText:\n ${JSON.stringify(WANT_CHOICES_TEXT)}`);
|
||
|
||
const mergedColumns = currentColumns.map((col) =>
|
||
col.ColumnName === "ClassX" ? { ...col, ChoicesText: WANT_CHOICES_TEXT } : col
|
||
);
|
||
|
||
const body = {
|
||
ApiVersion: "1.1",
|
||
ApiKey: production.apiKey,
|
||
Title: current.Title,
|
||
ReferenceType: current.ReferenceType,
|
||
ParentId: current.ParentId,
|
||
InheritPermission: current.InheritPermission,
|
||
Permissions: current.Permissions,
|
||
SiteSettings: { ...current.SiteSettings, Columns: mergedColumns },
|
||
};
|
||
|
||
if (!execute) {
|
||
console.log(` [ドライラン] --execute を付けずに実行したため送信していません`);
|
||
continue;
|
||
}
|
||
|
||
const result = await updateSite(production.baseUrl, production.apiKey, siteId, body);
|
||
console.log(` [OK] 送信結果: ${JSON.stringify(result)}`);
|
||
|
||
const after = await getSite(production.baseUrl, production.apiKey, siteId);
|
||
const afterClassX = ((after.SiteSettings && after.SiteSettings.Columns) || []).find((c) => c.ColumnName === "ClassX");
|
||
if (afterClassX && afterClassX.ChoicesText === WANT_CHOICES_TEXT) {
|
||
console.log(` [OK] 再取得で反映確認済み`);
|
||
} else {
|
||
console.error(` [NG] 再取得結果が期待値と不一致: ${JSON.stringify(afterClassX && afterClassX.ChoicesText)}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
main().catch((e) => {
|
||
console.error(e);
|
||
process.exit(1);
|
||
});
|