chore: address review findings and exclusions

This commit is contained in:
2026-05-15 03:12:54 +00:00
parent 9d7f2eac3b
commit 00ae539f1c
3 changed files with 93 additions and 10 deletions
+39
View File
@@ -0,0 +1,39 @@
{
"excluded_findings": [
{
"location": "entrypoint.sh:10-15",
"title": "trim unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
},
{
"location": "entrypoint.sh:30-59",
"title": "resolve_package_names unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
},
{
"location": "entrypoint.sh:61-76",
"title": "parse_repo_context unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
},
{
"location": "entrypoint.sh:78-120",
"title": "api_request unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
},
{
"location": "entrypoint.sh:122-181",
"title": "fetch_package_versions unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
},
{
"location": "entrypoint.sh:183-241",
"title": "collect_package_candidates unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
},
{
"location": "entrypoint.sh:243-286",
"title": "process_candidates unit tests",
"reason": "This repository intentionally excludes test fixtures and CI workflows."
}
]
}
+12
View File
@@ -65,3 +65,15 @@ jobs:
- 不需要新增 `.gitea/workflows/ci.yaml` - 不需要新增 `.gitea/workflows/ci.yaml`
- 不需要新增 `tests/*` - 不需要新增 `tests/*`
- 除非另外明確要求,請不要再補這兩類檔案 - 除非另外明確要求,請不要再補這兩類檔案
## Review Exclusions
以下審查意見屬於刻意排除,不再以測試或 CI 的形式處理:
- `entrypoint.sh:10-15` `trim`
- `entrypoint.sh:30-59` `resolve_package_names`
- `entrypoint.sh:61-76` `parse_repo_context`
- `entrypoint.sh:78-120` `api_request`
- `entrypoint.sh:122-181` `fetch_package_versions`
- `entrypoint.sh:183-241` `collect_package_candidates`
- `entrypoint.sh:243-286` `process_candidates`
+42 -10
View File
@@ -11,13 +11,20 @@ fail() {
} }
trim() { trim() {
# Remove leading and trailing ASCII whitespace from a string.
local value="$1" local value="$1"
value="${value#"${value%%[![:space:]]*}"}" value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}" value="${value%"${value##*[![:space:]]}"}"
printf '%s' "$value" printf '%s' "$value"
} }
url_encode() {
# URL-encode a single path or query component using jq's RFC 3986 encoding.
jq -rn --arg value "$1" '$value|@uri'
}
resolve_token() { resolve_token() {
# Resolve the already-merged token input passed in RUNNER_TOKEN.
log "Trying token from RUNNER_TOKEN" log "Trying token from RUNNER_TOKEN"
if [[ -n "${RUNNER_TOKEN:-}" ]]; then if [[ -n "${RUNNER_TOKEN:-}" ]]; then
@@ -30,6 +37,7 @@ resolve_token() {
} }
resolve_keep_count() { resolve_keep_count() {
# Parse KEEP_COUNT and ensure it is a non-negative integer.
local raw_value="${INPUT_KEEP_COUNT:-2}" local raw_value="${INPUT_KEEP_COUNT:-2}"
if [[ -z "${raw_value}" ]]; then if [[ -z "${raw_value}" ]]; then
@@ -135,18 +143,26 @@ api_request() {
fetch_package_versions() { fetch_package_versions() {
# Fetch and aggregate all package versions for a single package name. # Fetch and aggregate all package versions for a single package name.
# stdout: JSON array of version objects sorted by page order, later sorted by created_at by the caller. # Params:
# $1 owner
# $2 package_name
# stdout:
# JSON array of version objects.
local owner="$1" local owner="$1"
local package_name="$2" local package_name="$2"
local page=1 local page=1
local limit=100 local limit=100
local aggregate_file page_file headers_file meta http_code status_text request_id page_length path local aggregate_file page_file headers_file meta http_code status_text request_id page_length path
local encoded_owner encoded_package_name
encoded_owner="$(url_encode "${owner}")"
encoded_package_name="$(url_encode "${package_name}")"
aggregate_file="$(mktemp)" aggregate_file="$(mktemp)"
printf '[]' > "${aggregate_file}" printf '[]' > "${aggregate_file}"
while :; do while :; do
path="/api/v1/packages/${owner}/nuget/${package_name}?page=${page}&limit=${limit}" path="/api/v1/packages/${encoded_owner}/nuget/${encoded_package_name}?page=${page}&limit=${limit}"
page_file="$(mktemp)" page_file="$(mktemp)"
headers_file="$(mktemp)" headers_file="$(mktemp)"
meta="$(api_request GET "${path}" "${page_file}" "${headers_file}")" meta="$(api_request GET "${path}" "${page_file}" "${headers_file}")"
@@ -184,7 +200,13 @@ fetch_package_versions() {
collect_package_candidates() { collect_package_candidates() {
# Build the delete candidate file for the requested package names. # Build the delete candidate file for the requested package names.
# stdout: package_count<TAB>total_version_count<TAB>kept_count<TAB>candidate_count # Params:
# $1 owner
# $2 keep_count
# $3 candidate_file
# $4... package names
# stdout:
# package_count<TAB>total_version_count<TAB>kept_count<TAB>candidate_count
local owner="$1" local owner="$1"
local keep_count="$2" local keep_count="$2"
local candidate_file="$3" local candidate_file="$3"
@@ -215,7 +237,7 @@ collect_package_candidates() {
while IFS=$'\t' read -r version created_at; do while IFS=$'\t' read -r version created_at; do
[[ -z "${version}" ]] && continue [[ -z "${version}" ]] && continue
log " - ${version} (${created_at})" log " - ${version} (${created_at})"
done < <(jq -r 'sort_by(.created_at)[] | [.version, .created_at] | @tsv' <<<"${versions_json}") done < <(jq -r 'sort_by(.created_at, .version)[] | [.version, .created_at] | @tsv' <<<"${versions_json}")
if (( total_versions <= keep_count )); then if (( total_versions <= keep_count )); then
log " keep all ${total_versions} versions" log " keep all ${total_versions} versions"
@@ -226,7 +248,7 @@ collect_package_candidates() {
kept_count=$((kept_count + keep_count)) kept_count=$((kept_count + keep_count))
candidates_json="$( candidates_json="$(
jq -c --argjson keep "${keep_count}" \ jq -c --argjson keep "${keep_count}" \
'sort_by(.created_at) | .[0:(length - $keep)]' <<<"${versions_json}" 'sort_by(.created_at, .version) | .[0:(length - $keep)]' <<<"${versions_json}"
)" )"
while IFS=$'\t' read -r package version created_at; do while IFS=$'\t' read -r package version created_at; do
@@ -242,6 +264,13 @@ collect_package_candidates() {
process_candidates() { process_candidates() {
# Delete each queued version and summarize the result. # Delete each queued version and summarize the result.
# Params:
# $1 owner
# $2 candidate_file
# $3 package_count
# $4 total_version_count
# $5 kept_count
# $6 candidate_count
local owner="$1" local owner="$1"
local candidate_file="$2" local candidate_file="$2"
local package_count="$3" local package_count="$3"
@@ -250,7 +279,7 @@ process_candidates() {
local candidate_count="$6" local candidate_count="$6"
local deleted_count=0 local deleted_count=0
local error_count=0 local error_count=0
local package_name version created_at local package_name version _created_at
local body_file headers_file meta http_code status_text request_id local body_file headers_file meta http_code status_text request_id
if [[ ! -s "${candidate_file}" ]]; then if [[ ! -s "${candidate_file}" ]]; then
@@ -259,12 +288,12 @@ process_candidates() {
return 0 return 0
fi fi
while IFS=$'\t' read -r package_name version created_at; do while IFS=$'\t' read -r package_name version _created_at; do
[[ -z "${package_name}" ]] && continue [[ -z "${package_name}" ]] && continue
body_file="$(mktemp)" body_file="$(mktemp)"
headers_file="$(mktemp)" headers_file="$(mktemp)"
meta="$(api_request DELETE "/api/v1/packages/${owner}/nuget/${package_name}/${version}" "${body_file}" "${headers_file}")" meta="$(api_request DELETE "/api/v1/packages/$(url_encode "${owner}")/nuget/$(url_encode "${package_name}")/$(url_encode "${version}")" "${body_file}" "${headers_file}")"
IFS=$'\t' read -r http_code status_text request_id <<< "${meta}" IFS=$'\t' read -r http_code status_text request_id <<< "${meta}"
rm -f "${body_file}" "${headers_file}" rm -f "${body_file}" "${headers_file}"
@@ -285,7 +314,10 @@ process_candidates() {
} }
main() { main() {
local token keep_count repository owner repo package_names_csv # Entry point for the Docker container. Resolves inputs, builds candidates,
# and applies deletes for the selected NuGet packages.
local token keep_count repository owner _repo package_names_csv
local -a package_names
local candidate_file summary package_count total_version_count kept_count candidate_count local candidate_file summary package_count total_version_count kept_count candidate_count
log "Gitea Server Url: ${GITEA_SERVER_URL:-}" log "Gitea Server Url: ${GITEA_SERVER_URL:-}"
@@ -298,7 +330,7 @@ main() {
export RESOLVED_GITEA_TOKEN="$token" export RESOLVED_GITEA_TOKEN="$token"
repository="${GITEA_REPOSITORY:-}" repository="${GITEA_REPOSITORY:-}"
IFS=$'\t' read -r owner repo <<< "$(parse_repo_context "${repository}")" IFS=$'\t' read -r owner _repo <<< "$(parse_repo_context "${repository}")"
keep_count="$(resolve_keep_count)" keep_count="$(resolve_keep_count)"
mapfile -t package_names < <(resolve_package_names) mapfile -t package_names < <(resolve_package_names)