공개: alpha.4 기준선 갱신

This commit is contained in:
Ian 2026-04-16 11:14:22 +09:00
commit b63832706b
37 changed files with 1839 additions and 822 deletions

View file

@ -7,17 +7,23 @@ Usage:
./scripts/release/release-publish-forge.sh --version v0.2.0-alpha.1 [options]
Options:
--remote <name> Git remote name. Default: public-stage
--base-url <url> Forge base URL. Example: https://forge.example.com
--repo <owner/name> Repository in owner/name form
--token <token> Gitea API token
--target-commitish <ref> Branch or commit to associate when creating the tag
--notes <path> Release notes markdown file
--dry-run Print planned uploads without calling the API
EOF
}
version=""
remote_name="public-stage"
base_url=""
repo_full_name=""
token="${FORGE_RELEASE_TOKEN:-${GITEA_RELEASE_TOKEN:-}}"
target_commitish=""
notes_path=""
dry_run="false"
while [[ $# -gt 0 ]]; do
@ -30,6 +36,10 @@ while [[ $# -gt 0 ]]; do
base_url="${2:-}"
shift 2
;;
--remote)
remote_name="${2:-}"
shift 2
;;
--repo)
repo_full_name="${2:-}"
shift 2
@ -38,6 +48,14 @@ while [[ $# -gt 0 ]]; do
token="${2:-}"
shift 2
;;
--target-commitish)
target_commitish="${2:-}"
shift 2
;;
--notes)
notes_path="${2:-}"
shift 2
;;
--dry-run)
dry_run="true"
shift
@ -67,20 +85,24 @@ if [[ ! -d "$release_root" ]]; then
exit 1
fi
origin_url="$(git -C "$repo_root" remote get-url origin 2>/dev/null || true)"
remote_url="$(git -C "$repo_root" remote get-url "$remote_name" 2>/dev/null || true)"
if [[ -z "$base_url" ]]; then
if [[ "$origin_url" =~ ^(https?://[^/]+)/(.+)\.git$ ]]; then
if [[ "$remote_url" =~ ^(https?://[^/]+)(/open-source/projects)/([^/]+)/([^/]+?)(\.git)?$ ]]; then
base_url="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
elif [[ "$remote_url" =~ ^(https?://[^/]+)/(.+?)(\.git)?$ ]]; then
base_url="${BASH_REMATCH[1]}"
elif [[ "$origin_url" =~ ^git@([^:]+):(.+)\.git$ ]]; then
elif [[ "$remote_url" =~ ^git@([^:]+):(.+)\.git$ ]]; then
base_url="https://${BASH_REMATCH[1]}"
fi
fi
if [[ -z "$repo_full_name" ]]; then
if [[ "$origin_url" =~ ^https?://[^/]+/(.+)\.git$ ]]; then
if [[ "$remote_url" =~ ^https?://[^/]+/open-source/projects/([^/]+)/([^/]+?)(\.git)?$ ]]; then
repo_full_name="${BASH_REMATCH[1]}/${BASH_REMATCH[2]}"
elif [[ "$remote_url" =~ ^https?://[^/]+/(.+?)(\.git)?$ ]]; then
repo_full_name="${BASH_REMATCH[1]}"
elif [[ "$origin_url" =~ ^git@[^:]+:(.+)\.git$ ]]; then
elif [[ "$remote_url" =~ ^git@[^:]+:(.+)\.git$ ]]; then
repo_full_name="${BASH_REMATCH[1]}"
fi
fi
@ -90,8 +112,47 @@ if [[ -z "$base_url" || -z "$repo_full_name" ]]; then
exit 1
fi
if [[ "$dry_run" != "true" && -z "$token" ]]; then
echo "A Gitea API token is required. Use --token or FORGE_RELEASE_TOKEN." >&2
if [[ -z "$notes_path" ]]; then
notes_path="$release_root/RELEASE_NOTES.ko.md"
fi
if [[ -n "$notes_path" && ! -f "$notes_path" ]]; then
echo "Release notes file not found: $notes_path" >&2
exit 1
fi
if [[ -z "$target_commitish" ]]; then
target_commitish="main"
fi
basic_auth_user=""
basic_auth_password=""
if [[ -z "$token" ]]; then
for fallback_path in \
"$repo_root/.workspace-secrets/${remote_name}.token" \
"$repo_root/.workspace-secrets/forge-release.token"; do
if [[ -f "$fallback_path" ]]; then
token="$(tr -d '\r\n' < "$fallback_path")"
break
fi
done
fi
if [[ -z "$token" && -n "$remote_url" ]]; then
credential_output="$(printf 'url=%s\n\n' "$remote_url" | git credential fill 2>/dev/null || true)"
if [[ -n "$credential_output" ]]; then
while IFS='=' read -r key value; do
case "$key" in
username) basic_auth_user="$value" ;;
password) basic_auth_password="$value" ;;
esac
done <<< "$credential_output"
fi
fi
if [[ "$dry_run" != "true" && -z "$token" && ( -z "$basic_auth_user" || -z "$basic_auth_password" ) ]]; then
echo "A Gitea API token or basic credential is required. Use --token, FORGE_RELEASE_TOKEN, a local secret file, or configured git credentials." >&2
exit 1
fi
@ -108,7 +169,7 @@ esac
mapfile -t asset_files < <(
find "$release_root" -type f \
\( -name '*.zip' -o -name '*.apk' -o -name 'RELEASE_NOTES.ko.md' -o -name 'SHA256SUMS.txt' -o -name 'version.json' \) \
\( -name '*.zip' -o -name '*.apk' -o -name '*.png' -o -name '*.jpg' -o -name '*.jpeg' -o -name 'RELEASE_NOTES.ko.md' -o -name 'SHA256SUMS.txt' -o -name 'version.json' \) \
| sort
)
@ -118,7 +179,9 @@ if [[ ${#asset_files[@]} -eq 0 ]]; then
fi
echo "Forge release target: $base_url/$repo_full_name"
echo "Remote: $remote_name"
echo "Version: $version"
echo "Target commitish: $target_commitish"
printf 'Assets:\n'
printf ' - %s\n' "${asset_files[@]#$release_root/}"
@ -126,11 +189,16 @@ if [[ "$dry_run" == "true" ]]; then
exit 0
fi
auth_header="Authorization: token $token"
auth_args=()
if [[ -n "$token" ]]; then
auth_args=(-H "Authorization: token $token")
else
auth_args=(-u "$basic_auth_user:$basic_auth_password")
fi
tmp_response="$(mktemp)"
trap 'rm -f "$tmp_response"' EXIT
existing_status="$(curl -sS -o "$tmp_response" -w '%{http_code}' -H "$auth_header" "$tag_api")"
existing_status="$(curl -sS -o "$tmp_response" -w '%{http_code}' "${auth_args[@]}" "$tag_api")"
if [[ "$existing_status" == "200" ]]; then
existing_release_id="$(python3 - <<'PY' "$tmp_response"
import json, sys
@ -138,17 +206,17 @@ with open(sys.argv[1], "r", encoding="utf-8") as fh:
print(json.load(fh)["id"])
PY
)"
curl -sS -X DELETE -H "$auth_header" "${release_api}/${existing_release_id}" >/dev/null
curl -sS -X DELETE "${auth_args[@]}" "${release_api}/${existing_release_id}" >/dev/null
fi
release_body=$'Windows와 Android 클라이언트 산출물을 병렬로 정리한 릴리즈입니다.\n\n'
release_body+=$'동일 버전 번호 아래 OS별 자산을 함께 게시하며, 최신 다운로드 채널은 download-vs-messanger.phy.kr에서 운영합니다.'
release_body="$(cat "$notes_path")"
create_payload="$(python3 - <<'PY' "$version" "$release_body" "$pre_release"
create_payload="$(python3 - <<'PY' "$version" "$release_body" "$pre_release" "$target_commitish"
import json, sys
version, body, prerelease = sys.argv[1], sys.argv[2], sys.argv[3] == "true"
version, body, prerelease, target_commitish = sys.argv[1], sys.argv[2], sys.argv[3] == "true", sys.argv[4]
print(json.dumps({
"tag_name": version,
"target_commitish": target_commitish,
"name": version,
"body": body,
"draft": False,
@ -159,7 +227,7 @@ PY
create_status="$(curl -sS -o "$tmp_response" -w '%{http_code}' \
-X POST \
-H "$auth_header" \
"${auth_args[@]}" \
-H 'Content-Type: application/json' \
-d "$create_payload" \
"$release_api")"
@ -181,7 +249,7 @@ for asset in "${asset_files[@]}"; do
name="$(basename "$asset")"
curl -sS \
-X POST \
-H "$auth_header" \
"${auth_args[@]}" \
-H 'Content-Type: application/octet-stream' \
--data-binary @"$asset" \
"${release_api}/${release_id}/assets?name=${name}" >/dev/null