ZapretKVN-android/scripts/test-publish-github-stable.sh
2026-07-24 23:20:48 +03:00

162 lines
5.1 KiB
Shell
Executable file

#!/usr/bin/env bash
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PUBLISHER="$PROJECT_ROOT/scripts/publish-github-stable.sh"
TAG="v9.8.7"
REPOSITORY="example/release-test"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "$TEST_ROOT"' EXIT
BUNDLE_DIR="$TEST_ROOT/bundle"
MOCK_BIN="$TEST_ROOT/bin"
MOCK_STATE="$TEST_ROOT/state"
mkdir -p "$BUNDLE_DIR" "$MOCK_BIN" "$MOCK_STATE"
ASSET_NAMES=(
"Zapret-KVN-$TAG-arm64-v8a.apk"
"Zapret-KVN-$TAG-arm64-v8a.apk.sha256"
"Zapret-KVN-$TAG-armeabi-v7a.apk"
"Zapret-KVN-$TAG-armeabi-v7a.apk.sha256"
"Zapret-KVN-$TAG-x86_64.apk"
"Zapret-KVN-$TAG-x86_64.apk.sha256"
"release-metadata-v2.json"
"release-metadata.json"
)
for name in "${ASSET_NAMES[@]}"; do
printf 'fixture:%s\n' "$name" > "$BUNDLE_DIR/$name"
done
printf 'Release test notes\n' > "$BUNDLE_DIR/RELEASE_NOTES.md"
cat > "$MOCK_BIN/gh" <<'MOCK_GH'
#!/usr/bin/env bash
set -euo pipefail
STATE_DIR="${MOCK_GH_STATE:?}"
TAG="${MOCK_GH_TAG:?}"
STATE_FILE="$STATE_DIR/release-state"
ASSETS_FILE="$STATE_DIR/assets.tsv"
LOG_FILE="$STATE_DIR/calls.log"
release_json() {
local state draft assets name size digest
[[ -f "$STATE_FILE" ]] || exit 1
state="$(<"$STATE_FILE")"
draft=false
[[ "$state" == draft ]] && draft=true
assets='[]'
if [[ -f "$ASSETS_FILE" ]]; then
while IFS=$'\t' read -r name size digest; do
[[ -n "$name" ]] || continue
assets="$(
jq -c \
--arg name "$name" \
--argjson size "$size" \
--arg digest "$digest" \
'. + [{name: $name, size: $size, state: "uploaded", digest: $digest}]' \
<<<"$assets"
)"
done < "$ASSETS_FILE"
fi
jq -n \
--arg tag "$TAG" \
--argjson draft "$draft" \
--argjson assets "$assets" \
'{
tag_name: $tag,
draft: $draft,
prerelease: false,
assets: $assets,
html_url: ("https://example.invalid/releases/tag/" + $tag)
}'
}
case "${1:-} ${2:-}" in
"api repos/"*)
release_json
;;
"release create")
[[ ! -e "$STATE_FILE" ]]
printf 'draft\n' > "$STATE_FILE"
printf 'CREATE\n' >> "$LOG_FILE"
printf 'https://example.invalid/draft\n'
;;
"release upload")
[[ "$#" -eq 6 && "${5:-}" == --repo ]]
[[ "$(<"$STATE_FILE")" == draft ]]
asset="${4:?}"
name="$(basename "$asset")"
printf 'UPLOAD\t%s\n' "$name" >> "$LOG_FILE"
if [[ "${MOCK_GH_FAIL_ASSET:-}" == "$name" ]]; then
exit 23
fi
if [[ -f "$ASSETS_FILE" ]] && cut -f1 "$ASSETS_FILE" | grep -Fx "$name" >/dev/null; then
echo "duplicate asset: $name" >&2
exit 1
fi
printf '%s\t%s\tsha256:%s\n' \
"$name" \
"$(stat -c '%s' "$asset")" \
"$(sha256sum "$asset" | awk '{print $1}')" \
>> "$ASSETS_FILE"
;;
"release edit")
[[ "$(<"$STATE_FILE")" == draft ]]
printf 'published\n' > "$STATE_FILE"
printf 'EDIT\n' >> "$LOG_FILE"
printf 'https://example.invalid/releases/tag/%s\n' "$TAG"
;;
*)
echo "Unexpected mock gh call: $*" >&2
exit 1
;;
esac
MOCK_GH
chmod 700 "$MOCK_BIN/gh"
export PATH="$MOCK_BIN:$PATH"
export MOCK_GH_STATE="$MOCK_STATE"
export MOCK_GH_TAG="$TAG"
export ZAPRET_RELEASE_UPLOAD_TIMEOUT_SECONDS=5
export ZAPRET_RELEASE_UPLOAD_ATTEMPTS=1
export MOCK_GH_FAIL_ASSET="Zapret-KVN-$TAG-armeabi-v7a.apk"
if "$PUBLISHER" "$TAG" "$BUNDLE_DIR" "$REPOSITORY" >/dev/null 2>&1; then
echo "Interrupted publication test unexpectedly succeeded" >&2
exit 1
fi
[[ "$(<"$MOCK_STATE/release-state")" == draft ]]
[[ "$(grep -c '^CREATE$' "$MOCK_STATE/calls.log")" -eq 1 ]]
[[ "$(grep -c '^EDIT$' "$MOCK_STATE/calls.log" || true)" -eq 0 ]]
unset MOCK_GH_FAIL_ASSET
"$PUBLISHER" "$TAG" "$BUNDLE_DIR" "$REPOSITORY" >/dev/null
[[ "$(<"$MOCK_STATE/release-state")" == published ]]
[[ "$(grep -c '^CREATE$' "$MOCK_STATE/calls.log")" -eq 1 ]]
[[ "$(grep -c $'^UPLOAD\t' "$MOCK_STATE/calls.log")" -eq 9 ]]
[[ "$(grep -c '^EDIT$' "$MOCK_STATE/calls.log")" -eq 1 ]]
[[ "$(wc -l < "$MOCK_STATE/assets.tsv")" -eq 8 ]]
if "$PUBLISHER" "$TAG" "$BUNDLE_DIR" "$REPOSITORY" >/dev/null 2>&1; then
echo "Published immutable release was accepted as resumable" >&2
exit 1
fi
[[ "$(grep -c '^EDIT$' "$MOCK_STATE/calls.log")" -eq 1 ]]
MISMATCH_STATE="$TEST_ROOT/mismatch-state"
mkdir -p "$MISMATCH_STATE"
printf 'draft\n' > "$MISMATCH_STATE/release-state"
printf '%s\t%s\tsha256:%064d\n' \
"Zapret-KVN-$TAG-arm64-v8a.apk" \
"$(stat -c '%s' "$BUNDLE_DIR/Zapret-KVN-$TAG-arm64-v8a.apk")" \
0 \
> "$MISMATCH_STATE/assets.tsv"
export MOCK_GH_STATE="$MISMATCH_STATE"
if "$PUBLISHER" "$TAG" "$BUNDLE_DIR" "$REPOSITORY" >/dev/null 2>&1; then
echo "Mismatched remote digest was accepted" >&2
exit 1
fi
[[ "$(<"$MISMATCH_STATE/release-state")" == draft ]]
[[ ! -e "$MISMATCH_STATE/calls.log" ]]
echo "Resumable sequential GitHub release publication verified."