#!/bin/bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "$ROOT_DIR/entrypoint.sh" declare -a CLEANUP_PATHS=() cleanup() { if [ "${#CLEANUP_PATHS[@]}" -gt 0 ]; then rm -rf "${CLEANUP_PATHS[@]}" fi } trap cleanup EXIT fail() { printf '[error] %s\n' "$1" >&2 exit 1 } assert_eq() { local expected="$1" local actual="$2" local label="$3" if [ "$expected" != "$actual" ]; then fail "$label: expected '$expected', got '$actual'" fi } make_mock_curl() { local bin_dir="$1" local response_file="$2" cat >"$bin_dir/curl" <<'EOF' #!/bin/sh if [ -n "${FAKE_CURL_LOG_FILE:-}" ]; then printf '%s\n' "$*" >> "$FAKE_CURL_LOG_FILE" fi if [ "${FAKE_CURL_STATUS:-0}" != "0" ]; then exit "$FAKE_CURL_STATUS" fi cat "${FAKE_CURL_RESPONSE_FILE:?}" EOF chmod +x "$bin_dir/curl" } make_mock_jq() { local bin_dir="$1" cat >"$bin_dir/jq" <<'EOF' #!/bin/sh is_beta="" query="" while [ "$#" -gt 0 ]; do case "$1" in -r) shift ;; --arg) if [ "$2" = "is_beta" ]; then is_beta="$3" fi shift 3 ;; *) query="$1" shift break ;; esac done python3 -c 'import json, sys query = sys.argv[1] is_beta = sys.argv[2] payload = sys.stdin.read() try: data = json.loads(payload) except Exception: sys.exit(4) def next_version(latest): parts = [int(p or 0) for p in latest.split(".")] while len(parts) < 3: parts.append(0) major, minor, patch = parts[:3] patch += 1 if patch >= 10: patch = 0 minor += 1 if minor >= 10: minor = 0 major += 1 return f"{major}.{minor}.{patch}" def beta_max(data, prefix): values = [] for item in data: if not isinstance(item, dict): continue tag = item.get("tag_name") if isinstance(tag, str) and tag.startswith(prefix): suffix = tag[len(prefix):] try: values.append(int(suffix)) except Exception: pass return max(values) if values else 0 if not isinstance(data, list): base = "0.0.0" else: base = "0.0.0" for item in data: if not isinstance(item, dict): continue tag = item.get("tag_name") if isinstance(tag, str) and "-beta." not in tag: base = tag[1:] if tag.startswith("v") else tag break next_ver = next_version(base) if is_beta == "true": beta = beta_max(data, f"v{next_ver}-beta.") + 1 sys.stdout.write(f"{base}\t{next_ver}-beta.{beta}") else: sys.stdout.write(f"{base}\t{next_ver}") ' "$query" "$is_beta" EOF chmod +x "$bin_dir/jq" } run_entrypoint() { local response_file="$1" local is_beta="$2" local token="${3:-}" local fake_status="${4:-0}" local workdir local output_file local bin_dir local stdout_file local stderr_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") bin_dir="$workdir/bin" mkdir -p "$bin_dir" make_mock_curl "$bin_dir" "$response_file" make_mock_jq "$bin_dir" output_file="$workdir/github_output" stdout_file="$workdir/stdout" stderr_file="$workdir/stderr" if [ -n "$token" ]; then FAKE_CURL_STATUS="$fake_status" \ FAKE_CURL_RESPONSE_FILE="$response_file" \ FAKE_CURL_LOG_FILE="$workdir/curl_args" \ PATH="$bin_dir:$PATH" \ GITEA_SERVER_URL="https://gitea.example.com" \ GITEA_REPOSITORY="org/repo" \ RUNNER_TOKEN="$token" \ IS_BETA="$is_beta" \ GITHUB_OUTPUT="$output_file" \ bash "$ROOT_DIR/entrypoint.sh" >"$stdout_file" 2>"$stderr_file" else FAKE_CURL_STATUS="$fake_status" \ FAKE_CURL_RESPONSE_FILE="$response_file" \ FAKE_CURL_LOG_FILE="$workdir/curl_args" \ PATH="$bin_dir:$PATH" \ GITEA_SERVER_URL="https://gitea.example.com" \ GITEA_REPOSITORY="org/repo" \ IS_BETA="$is_beta" \ GITHUB_OUTPUT="$output_file" \ bash "$ROOT_DIR/entrypoint.sh" >"$stdout_file" 2>"$stderr_file" fi printf '%s\n' "$output_file" } test_unit_helpers() { assert_eq "false" "$(normalize_beta_flag "")" "normalize_beta_flag empty" assert_eq "false" "$(normalize_beta_flag "null")" "normalize_beta_flag null" assert_eq "true" "$(normalize_beta_flag "true")" "normalize_beta_flag true" assert_eq "0.1.0" "$(next_release_version "0.0.9")" "next_release_version carry patch" assert_eq "2.0.0" "$(next_release_version "1.9.9")" "next_release_version carry minor" assert_eq "100.0.0" "$(next_release_version "99.9.9")" "next_release_version carry major" } test_stable_release_flow() { local workdir local response_file local output_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" cat >"$response_file" <<'EOF' [ {"tag_name":"v1.2.3-beta.1"}, {"tag_name":"v1.2.3"}, {"tag_name":"v1.2.4-beta.1"} ] EOF output_file="$(run_entrypoint "$response_file" "false")" assert_eq "version=1.2.4" "$(cat "$output_file")" "stable release output" } test_beta_release_flow() { local workdir local response_file local output_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" cat >"$response_file" <<'EOF' [ {"tag_name":"v1.2.3"}, {"tag_name":"v1.2.4-beta.1"}, {"tag_name":"v1.2.4-beta.3"} ] EOF output_file="$(run_entrypoint "$response_file" "true")" assert_eq "version=1.2.4-beta.4" "$(cat "$output_file")" "beta release output" } test_empty_release_list() { local workdir local response_file local output_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" printf '%s\n' '[]' >"$response_file" output_file="$(run_entrypoint "$response_file" "false")" assert_eq "version=0.0.1" "$(cat "$output_file")" "empty release list" } test_only_beta_releases() { local workdir local response_file local output_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" cat >"$response_file" <<'EOF' [ {"tag_name":"v2.4.6-beta.1"}, {"tag_name":"v2.4.6-beta.2"} ] EOF output_file="$(run_entrypoint "$response_file" "false")" assert_eq "version=0.0.1" "$(cat "$output_file")" "only beta releases" } test_null_release_payload() { local workdir local response_file local output_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" printf '%s\n' 'null' >"$response_file" output_file="$(run_entrypoint "$response_file" "false")" assert_eq "version=0.0.1" "$(cat "$output_file")" "null release payload" } test_token_auth_header() { local workdir local response_file local bin_dir local output_file local curl_args local stdout_file local stderr_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" printf '%s\n' '[]' >"$response_file" bin_dir="$workdir/bin" mkdir -p "$bin_dir" make_mock_curl "$bin_dir" "$response_file" make_mock_jq "$bin_dir" output_file="$workdir/github_output" stdout_file="$workdir/stdout" stderr_file="$workdir/stderr" FAKE_CURL_STATUS=0 \ FAKE_CURL_RESPONSE_FILE="$response_file" \ FAKE_CURL_LOG_FILE="$workdir/curl_args" \ PATH="$bin_dir:$PATH" \ GITEA_SERVER_URL="https://gitea.example.com" \ GITEA_REPOSITORY="org/repo" \ RUNNER_TOKEN="secret-token" \ IS_BETA="false" \ GITHUB_OUTPUT="$output_file" \ bash "$ROOT_DIR/entrypoint.sh" >"$stdout_file" 2>"$stderr_file" curl_args="$workdir/curl_args" if ! grep -q 'Authorization: token secret-token' "$curl_args"; then fail "token auth header: missing Authorization header" fi assert_eq "version=0.0.1" "$(cat "$output_file")" "token auth output" } test_malformed_release_payload() { local workdir local response_file local bin_dir local output_file local stdout_file local stderr_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" printf '%s\n' '{' >"$response_file" bin_dir="$workdir/bin" mkdir -p "$bin_dir" make_mock_curl "$bin_dir" "$response_file" make_mock_jq "$bin_dir" output_file="$workdir/github_output" stdout_file="$workdir/stdout" stderr_file="$workdir/stderr" if FAKE_CURL_STATUS=0 \ FAKE_CURL_RESPONSE_FILE="$response_file" \ PATH="$bin_dir:$PATH" \ GITEA_SERVER_URL="https://gitea.example.com" \ GITEA_REPOSITORY="org/repo" \ IS_BETA="false" \ GITHUB_OUTPUT="$output_file" \ bash "$ROOT_DIR/entrypoint.sh" >"$stdout_file" 2>"$stderr_file"; then fail "malformed release payload: expected failure" fi } test_curl_failure() { local workdir local response_file local bin_dir local output_file local stdout_file local stderr_file workdir="$(mktemp -d)" CLEANUP_PATHS+=("$workdir") response_file="$workdir/releases.json" printf '%s\n' '[]' >"$response_file" bin_dir="$workdir/bin" mkdir -p "$bin_dir" make_mock_curl "$bin_dir" "$response_file" output_file="$workdir/github_output" stdout_file="$workdir/stdout" stderr_file="$workdir/stderr" if FAKE_CURL_STATUS=22 \ FAKE_CURL_RESPONSE_FILE="$response_file" \ PATH="$bin_dir:$PATH" \ GITEA_SERVER_URL="https://gitea.example.com" \ GITEA_REPOSITORY="org/repo" \ IS_BETA="false" \ GITHUB_OUTPUT="$output_file" \ bash "$ROOT_DIR/entrypoint.sh" >"$stdout_file" 2>"$stderr_file"; then fail "curl failure: expected failure" fi } test_unit_helpers test_stable_release_flow test_beta_release_flow test_empty_release_list test_only_beta_releases test_null_release_payload test_token_auth_header test_malformed_release_payload test_curl_failure printf '[info] all tests passed\n'