Files
calculate-version/app/config.js
T
JefferyandClaude Opus 4.8 bc4cea6daf refactor(calculate-version): 抽出 truncateString 並明確化 repository 驗證命名
- releases 將片段截斷邏輯抽為可重用、可獨立測試的 truncateString(text, limit) 並 export
- config 將 assertRepository 更名為 assertGiteaRepositoryFormat,凸顯其驗證 Gitea owner/repo 格式的領域語義

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 15:21:45 +08:00

102 lines
3.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
* 判斷環境變數值是否視為「未設定」。
*
* 下列任一情況皆視為未設定:undefined、null、空字串、字面字串 "null"。
*
* @param {*} value - 欲檢查的值(通常為環境變數字串)。
* @returns {boolean} 視為未設定時回傳 true,否則回傳 false。
*/
function isUnset(value) {
return value === undefined || value === null || value === '' || value === 'null';
}
/**
* 驗證必填環境變數;未設定時拋出錯誤。
*
* @param {string} name - 環境變數名稱,用於組出錯誤訊息。
* @param {*} value - 環境變數的值。
* @returns {*} 驗證通過後原樣回傳的 value。
* @throws {Error} 當 value 被視為未設定(undefined/null/空字串/"null")時拋出,訊息為 `${name} 未設定`。
*/
function requireEnv(name, value) {
if (isUnset(value)) {
throw new Error(`${name} 未設定`);
}
return value;
}
/**
* 將 beta 旗標正規化為布林值。
*
* 未設定時預設為 false;僅當值嚴格等於字面字串 "true" 時回傳 true。
*
* @param {*} value - beta 旗標環境變數的值。
* @returns {boolean} 啟用 beta 時回傳 true,否則回傳 false。
*/
function normalizeBetaFlag(value) {
if (isUnset(value)) {
return false;
}
return value === 'true';
}
// 驗證字串為合法的 http/https URL,否則拋出錯誤(避免指向非預期協定或格式錯誤的位址)
function assertHttpUrl(name, value) {
let parsed;
try {
parsed = new URL(value);
} catch {
throw new Error(`${name} 格式錯誤,必須為合法的 URL`);
}
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
throw new Error(`${name} 必須使用 http 或 https 協定`);
}
}
// repository 每段名稱的最大長度與允許字元(字母數字與 . _ -)
const MAX_REPO_NAME_LENGTH = 100;
const REPO_SEGMENT_PATTERN = /^[A-Za-z0-9._-]+$/;
// 單一 repository 區段是否合法:長度在範圍內、僅含允許字元,且非 . 或 .. 路徑穿越段
function isValidRepoSegment(part) {
return part.length > 0
&& part.length <= MAX_REPO_NAME_LENGTH
&& REPO_SEGMENT_PATTERN.test(part)
&& part !== '.' && part !== '..';
}
// 驗證 repository 為 owner/repo 格式(恰兩段,且每段皆為合法區段)
function assertGiteaRepositoryFormat(name, value) {
const parts = value.split('/');
const isRepoFormatValid = parts.length === 2 && parts.every(isValidRepoSegment);
if (!isRepoFormatValid) {
throw new Error(`${name} 格式錯誤,必須為 owner/repo`);
}
}
/**
* 從環境變數載入並驗證執行所需的設定。
*
* GITEA_SERVER_URL 與 GITEA_REPOSITORY 為必填,未設定時會拋出錯誤;GITEA_SERVER_URL
* 另需為合法的 http/https URLGITEA_REPOSITORY 另需為 owner/repo 格式;
* GITEA_TOKEN 為非必填,未設定時為 null;IS_BETA 會被正規化為布林值。
*
* @param {Object} [env=process.env] - 環境變數來源物件,預設為 process.env。
* @returns {{ serverUrl: string, repository: string, token: (string|null), isBeta: boolean }} 已驗證的設定物件。
* @throws {Error} 當必填項未設定、GITEA_SERVER_URL 非合法 http/https URL,或 GITEA_REPOSITORY 非 owner/repo 格式時拋出。
*/
function loadConfig(env = process.env) {
const serverUrl = requireEnv('GITEA_SERVER_URL', env.GITEA_SERVER_URL);
assertHttpUrl('GITEA_SERVER_URL', serverUrl);
const repository = requireEnv('GITEA_REPOSITORY', env.GITEA_REPOSITORY);
assertGiteaRepositoryFormat('GITEA_REPOSITORY', repository);
const token = isUnset(env.GITEA_TOKEN) ? null : env.GITEA_TOKEN;
const isBeta = normalizeBetaFlag(env.IS_BETA);
return { serverUrl, repository, token, isBeta };
}
module.exports = { isUnset, requireEnv, normalizeBetaFlag, loadConfig };