feat(清理成品): 刪除舊版本成品後清理未指定 release 的 tag #1
@@ -1,6 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
repo_root="$(cd "$script_dir/.." && pwd)"
|
||||||
|
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
trap 'rm -rf "$tmpdir"' EXIT
|
trap 'rm -rf "$tmpdir"' EXIT
|
||||||
|
|
||||||
@@ -22,14 +25,20 @@ if [[ " $* " == *" -X DELETE "* ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# tags 端點沒有需要清理的 tag
|
||||||
|
if [[ "$last_arg" == */tags?* ]]; then
|
||||||
|
printf '%s' '[]'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
case "$last_arg" in
|
case "$last_arg" in
|
||||||
*page=1)
|
*/releases?*page=1)
|
||||||
printf '%s' '[{"id":4,"tag_name":"v4","name":"release-4","created_at":"2024-04-01T00:00:00Z"},{"id":3,"tag_name":"v3","name":"release-3","created_at":"2024-03-01T00:00:00Z"}]'
|
printf '%s' '[{"id":4,"tag_name":"v4","name":"release-4","created_at":"2024-04-01T00:00:00Z"},{"id":3,"tag_name":"v3","name":"release-3","created_at":"2024-03-01T00:00:00Z"}]'
|
||||||
;;
|
;;
|
||||||
*page=2)
|
*/releases?*page=2)
|
||||||
printf '%s' '[{"id":2,"tag_name":"v2","name":"release-2","created_at":"2024-02-01T00:00:00Z"},{"id":1,"tag_name":"v1","name":"release-1","created_at":"2024-01-01T00:00:00Z"}]'
|
printf '%s' '[{"id":2,"tag_name":"v2","name":"release-2","created_at":"2024-02-01T00:00:00Z"},{"id":1,"tag_name":"v1","name":"release-1","created_at":"2024-01-01T00:00:00Z"}]'
|
||||||
;;
|
;;
|
||||||
*page=3)
|
*/releases?*page=3)
|
||||||
printf '%s' '[]'
|
printf '%s' '[]'
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -40,80 +49,7 @@ esac
|
|||||||
EOF
|
EOF
|
||||||
chmod +x "$bin_dir/curl"
|
chmod +x "$bin_dir/curl"
|
||||||
|
|
||||||
cat >"$bin_dir/jq.py" <<'PY'
|
cp "$script_dir/lib/jq_mock.py" "$bin_dir/jq.py"
|
||||||
#!/usr/bin/env python3
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
expr = ""
|
|
||||||
flags = set()
|
|
||||||
args = sys.argv[1:]
|
|
||||||
|
|
||||||
while args:
|
|
||||||
current = args.pop(0)
|
|
||||||
if current in {"-e", "-c", "-r", "-s"}:
|
|
||||||
flags.add(current)
|
|
||||||
continue
|
|
||||||
if current == "--":
|
|
||||||
if not args:
|
|
||||||
raise SystemExit("missing jq expression")
|
|
||||||
expr = args.pop(0)
|
|
||||||
break
|
|
||||||
if current.startswith("-"):
|
|
||||||
flags.add(current)
|
|
||||||
continue
|
|
||||||
expr = current
|
|
||||||
break
|
|
||||||
|
|
||||||
raw = sys.stdin.read()
|
|
||||||
|
|
||||||
def dump(value):
|
|
||||||
if "-r" in flags and isinstance(value, (str, int, float)) and not isinstance(value, bool):
|
|
||||||
sys.stdout.write(str(value))
|
|
||||||
else:
|
|
||||||
sys.stdout.write(json.dumps(value, separators=(",", ":")))
|
|
||||||
|
|
||||||
if expr == "length":
|
|
||||||
data = json.loads(raw or "null")
|
|
||||||
print(len(data))
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
if expr == "add":
|
|
||||||
arrays = [json.loads(line) for line in raw.splitlines() if line.strip()]
|
|
||||||
merged = []
|
|
||||||
for item in arrays:
|
|
||||||
merged.extend(item)
|
|
||||||
dump(merged)
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
if expr == "sort_by(.created_at) | reverse":
|
|
||||||
data = json.loads(raw or "[]")
|
|
||||||
dump(sorted(data, key=lambda item: item["created_at"], reverse=True))
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
match = re.fullmatch(r"\.\[(\d+):\]", expr)
|
|
||||||
if match:
|
|
||||||
data = json.loads(raw or "[]")
|
|
||||||
dump(data[int(match.group(1)):])
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
if expr == ".[]":
|
|
||||||
data = json.loads(raw or "[]")
|
|
||||||
for item in data:
|
|
||||||
dump(item)
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
match = re.fullmatch(r"\.(id|tag_name|name)", expr)
|
|
||||||
if match:
|
|
||||||
data = json.loads(raw or "null")
|
|
||||||
value = data.get(match.group(1))
|
|
||||||
dump(value)
|
|
||||||
raise SystemExit(0)
|
|
||||||
|
|
||||||
raise SystemExit(f"unsupported jq expression: {expr}")
|
|
||||||
PY
|
|
||||||
chmod +x "$bin_dir/jq.py"
|
chmod +x "$bin_dir/jq.py"
|
||||||
|
|
||||||
cat >"$bin_dir/jq" <<'EOF'
|
cat >"$bin_dir/jq" <<'EOF'
|
||||||
@@ -129,7 +65,7 @@ GITEA_SERVER_URL="https://gitea.example.test" \
|
|||||||
GITEA_REPOSITORY="owner/repo" \
|
GITEA_REPOSITORY="owner/repo" \
|
||||||
KEEP_COUNT="2" \
|
KEEP_COUNT="2" \
|
||||||
RUNNER_TOKEN="" \
|
RUNNER_TOKEN="" \
|
||||||
bash ./entrypoint.sh >/dev/null
|
bash "$repo_root/entrypoint.sh" >/dev/null
|
||||||
|
|
||||||
grep -q 'page=1' "$curl_log"
|
grep -q 'page=1' "$curl_log"
|
||||||
grep -q 'page=2' "$curl_log"
|
grep -q 'page=2' "$curl_log"
|
||||||
@@ -138,6 +74,11 @@ grep -q '/releases/2' "$curl_log"
|
|||||||
grep -q '/releases/1' "$curl_log"
|
grep -q '/releases/1' "$curl_log"
|
||||||
|
|
||||||
if grep -q '/releases/3' "$curl_log" || grep -q '/releases/4' "$curl_log"; then
|
if grep -q '/releases/3' "$curl_log" || grep -q '/releases/4' "$curl_log"; then
|
||||||
printf 'unexpected deletion request in %s\n' "$curl_log" >&2
|
printf 'unexpected release deletion request in %s\n' "$curl_log" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q '/tags/' "$curl_log"; then
|
||||||
|
printf 'unexpected tag deletion request in %s\n' "$curl_log" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
repo_root="$(cd "$script_dir/.." && pwd)"
|
||||||
|
|
||||||
|
tmpdir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$tmpdir"' EXIT
|
||||||
|
|
||||||
|
curl_log="$tmpdir/curl.log"
|
||||||
|
bin_dir="$tmpdir/bin"
|
||||||
|
mkdir -p "$bin_dir"
|
||||||
|
|
||||||
|
cat >"$bin_dir/curl" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
log_file="${CURL_LOG:?}"
|
||||||
|
printf '%s\n' "$*" >>"$log_file"
|
||||||
|
|
||||||
|
last_arg="${!#}"
|
||||||
|
|
||||||
|
if [[ " $* " == *" -X DELETE "* ]]; then
|
||||||
|
printf '204'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 倉庫所有 tag:v1~v4 加上兩個未指定 release 的孤兒 tag
|
||||||
|
if [[ "$last_arg" == */tags?* ]]; then
|
||||||
|
case "$last_arg" in
|
||||||
|
*page=1)
|
||||||
|
printf '%s' '[{"name":"v4"},{"name":"v3"},{"name":"v2"},{"name":"v1"},{"name":"tmp-build"},{"name":"v0"}]'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s' '[]'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# /releases GET:刪除舊版本後重新取得時,只回傳仍保留的 release
|
||||||
|
if grep -Eq -- '-X DELETE .*/releases/[0-9]' "$log_file"; then
|
||||||
|
case "$last_arg" in
|
||||||
|
*page=1)
|
||||||
|
printf '%s' '[{"id":4,"tag_name":"v4","name":"release-4","created_at":"2024-04-01T00:00:00Z"},{"id":3,"tag_name":"v3","name":"release-3","created_at":"2024-03-01T00:00:00Z"}]'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s' '[]'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$last_arg" in
|
||||||
|
*page=1)
|
||||||
|
printf '%s' '[{"id":4,"tag_name":"v4","name":"release-4","created_at":"2024-04-01T00:00:00Z"},{"id":3,"tag_name":"v3","name":"release-3","created_at":"2024-03-01T00:00:00Z"}]'
|
||||||
|
;;
|
||||||
|
*page=2)
|
||||||
|
printf '%s' '[{"id":2,"tag_name":"v2","name":"release-2","created_at":"2024-02-01T00:00:00Z"},{"id":1,"tag_name":"v1","name":"release-1","created_at":"2024-01-01T00:00:00Z"}]'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s' '[]'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
EOF
|
||||||
|
chmod +x "$bin_dir/curl"
|
||||||
|
|
||||||
|
cp "$script_dir/lib/jq_mock.py" "$bin_dir/jq.py"
|
||||||
|
chmod +x "$bin_dir/jq.py"
|
||||||
|
|
||||||
|
cat >"$bin_dir/jq" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
exec python3 "$0.py" "$@"
|
||||||
|
EOF
|
||||||
|
chmod +x "$bin_dir/jq"
|
||||||
|
|
||||||
|
PATH="$bin_dir:$PATH" \
|
||||||
|
CURL_LOG="$curl_log" \
|
||||||
|
GITEA_SERVER_URL="https://gitea.example.test" \
|
||||||
|
GITEA_REPOSITORY="owner/repo" \
|
||||||
|
KEEP_COUNT="2" \
|
||||||
|
RUNNER_TOKEN="" \
|
||||||
|
bash "$repo_root/entrypoint.sh" >/dev/null
|
||||||
|
|
||||||
|
# 舊版本 release 仍被刪除
|
||||||
|
grep -q '/releases/2' "$curl_log"
|
||||||
|
grep -q '/releases/1' "$curl_log"
|
||||||
|
|
||||||
|
# 未指定 release 的 tag(含被刪除 release 留下的 tag 與其他孤兒 tag)被刪除
|
||||||
|
for tag in v2 v1 tmp-build v0; do
|
||||||
|
if ! grep -q "/tags/$tag" "$curl_log"; then
|
||||||
|
printf 'expected tag deletion /tags/%s not found in %s\n' "$tag" "$curl_log" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 仍指定 release 的 tag 不可被刪除
|
||||||
|
for tag in v4 v3; do
|
||||||
|
if grep -q "/tags/$tag" "$curl_log"; then
|
||||||
|
printf 'unexpected deletion of release-assigned tag /tags/%s in %s\n' "$tag" "$curl_log" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Minimal jq stand-in for entrypoint.sh tests.
|
||||||
|
|
||||||
|
Only the jq expressions used by entrypoint.sh are implemented. Unknown
|
||||||
|
expressions fail loudly so new jq usage is noticed instead of silently
|
||||||
|
producing wrong results.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
expr = ""
|
||||||
|
flags = set()
|
||||||
|
named_args = {}
|
||||||
|
args = sys.argv[1:]
|
||||||
|
|
||||||
|
while args:
|
||||||
|
current = args.pop(0)
|
||||||
|
if current in {"-e", "-c", "-r", "-s"}:
|
||||||
|
flags.add(current)
|
||||||
|
continue
|
||||||
|
if current == "--arg":
|
||||||
|
key = args.pop(0)
|
||||||
|
value = args.pop(0)
|
||||||
|
named_args[key] = value
|
||||||
|
continue
|
||||||
|
if current == "--":
|
||||||
|
if not args:
|
||||||
|
raise SystemExit("missing jq expression")
|
||||||
|
expr = args.pop(0)
|
||||||
|
break
|
||||||
|
if current.startswith("-"):
|
||||||
|
flags.add(current)
|
||||||
|
continue
|
||||||
|
expr = current
|
||||||
|
break
|
||||||
|
|
||||||
|
raw = sys.stdin.read()
|
||||||
|
|
||||||
|
|
||||||
|
def dump(value):
|
||||||
|
if "-r" in flags and isinstance(value, (str, int, float)) and not isinstance(value, bool):
|
||||||
|
sys.stdout.write(str(value))
|
||||||
|
else:
|
||||||
|
sys.stdout.write(json.dumps(value, separators=(",", ":")))
|
||||||
|
|
||||||
|
|
||||||
|
if expr == "length":
|
||||||
|
data = json.loads(raw or "null")
|
||||||
|
print(len(data))
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
if expr == "add":
|
||||||
|
arrays = [json.loads(line) for line in raw.splitlines() if line.strip()]
|
||||||
|
merged = []
|
||||||
|
for item in arrays:
|
||||||
|
merged.extend(item)
|
||||||
|
dump(merged)
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
if expr == "sort_by(.created_at) | reverse":
|
||||||
|
data = json.loads(raw or "[]")
|
||||||
|
dump(sorted(data, key=lambda item: item["created_at"], reverse=True))
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
if expr == "[.[].tag_name]":
|
||||||
|
data = json.loads(raw or "[]")
|
||||||
|
dump([item["tag_name"] for item in data])
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
match = re.fullmatch(r"any\(\.\[\]; \. == \$(\w+)\)", expr)
|
||||||
|
if match:
|
||||||
|
data = json.loads(raw or "[]")
|
||||||
|
needle = named_args[match.group(1)]
|
||||||
|
sys.stdout.write("true" if any(item == needle for item in data) else "false")
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
match = re.fullmatch(r"\.\[(\d+):\]", expr)
|
||||||
|
if match:
|
||||||
|
data = json.loads(raw or "[]")
|
||||||
|
dump(data[int(match.group(1)):])
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
if expr == ".[]":
|
||||||
|
data = json.loads(raw or "[]")
|
||||||
|
for item in data:
|
||||||
|
dump(item)
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
match = re.fullmatch(r"\.(id|tag_name|name)", expr)
|
||||||
|
if match:
|
||||||
|
data = json.loads(raw or "null")
|
||||||
|
value = data.get(match.group(1))
|
||||||
|
dump(value)
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
raise SystemExit(f"unsupported jq expression: {expr}")
|
||||||
Reference in New Issue
Block a user