feat(release): release.sh + test-release.sh с валидацией semver
This commit is contained in:
parent
7e3d7cdf43
commit
9627486288
110
scripts/release.sh
Executable file
110
scripts/release.sh
Executable file
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Release script для 222a-seo-audit plugin.
|
||||||
|
# Использование: ./scripts/release.sh <semver> [--message "changelog text"] [--dry-run]
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VERSION="${1:-}"
|
||||||
|
DRY_RUN=0
|
||||||
|
MESSAGE=""
|
||||||
|
|
||||||
|
shift || true
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dry-run) DRY_RUN=1 ;;
|
||||||
|
--message) MESSAGE="$2"; shift ;;
|
||||||
|
*) echo "Unknown arg: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# 1. Валидация semver
|
||||||
|
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "ERROR: версия должна быть в формате MAJOR.MINOR.PATCH (например, 1.0.0)"
|
||||||
|
echo "Получено: '$VERSION'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAG="v${VERSION}"
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
# 2. Проверка чистоты и ветки
|
||||||
|
if [[ "$DRY_RUN" -eq 0 ]]; then
|
||||||
|
if [[ -n "$(git status --porcelain)" ]]; then
|
||||||
|
echo "ERROR: рабочая копия не чистая. Закоммитьте или стэшните изменения."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
|
if [[ "$CURRENT_BRANCH" != "main" ]]; then
|
||||||
|
echo "ERROR: релиз только из ветки main. Текущая: $CURRENT_BRANCH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Проверка, что тег ещё не существует
|
||||||
|
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||||
|
echo "ERROR: тег $TAG уже существует"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||||
|
echo "Would release $VERSION (dry-run)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Подменить версию в 3 json-файлах (sed inline)
|
||||||
|
PLUGIN_JSON="plugins/222a-seo-audit/.claude-plugin/plugin.json"
|
||||||
|
MCP_JSON="plugins/222a-seo-audit/.mcp.json"
|
||||||
|
MARKETPLACE_JSON=".claude-plugin/marketplace.json"
|
||||||
|
|
||||||
|
# Используем python для безопасной правки JSON
|
||||||
|
python3 - "$VERSION" "$PLUGIN_JSON" "$MCP_JSON" "$MARKETPLACE_JSON" <<'PY'
|
||||||
|
import json, sys
|
||||||
|
version = sys.argv[1]
|
||||||
|
plugin_json, mcp_json, marketplace_json = sys.argv[2], sys.argv[3], sys.argv[4]
|
||||||
|
|
||||||
|
with open(plugin_json) as f: p = json.load(f)
|
||||||
|
p["version"] = version
|
||||||
|
with open(plugin_json, "w") as f: json.dump(p, f, indent=2, ensure_ascii=False); f.write("\n")
|
||||||
|
|
||||||
|
with open(mcp_json) as f: m = json.load(f)
|
||||||
|
m["mcpServers"]["222a-seo-audit"]["headers"]["X-Plugin-Version"] = version
|
||||||
|
with open(mcp_json, "w") as f: json.dump(m, f, indent=2, ensure_ascii=False); f.write("\n")
|
||||||
|
|
||||||
|
with open(marketplace_json) as f: mk = json.load(f)
|
||||||
|
mk["plugins"][0]["version"] = version
|
||||||
|
with open(marketplace_json, "w") as f: json.dump(mk, f, indent=2, ensure_ascii=False); f.write("\n")
|
||||||
|
|
||||||
|
print(f"Updated version to {version} in 3 files")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# 5. Обновить CHANGELOG.md
|
||||||
|
CHANGELOG="plugins/222a-seo-audit/CHANGELOG.md"
|
||||||
|
TODAY="$(date +%Y-%m-%d)"
|
||||||
|
|
||||||
|
if [[ -n "$MESSAGE" ]]; then
|
||||||
|
# Вставить новую секцию после "## [Unreleased]"
|
||||||
|
TMP="$(mktemp)"
|
||||||
|
awk -v v="$VERSION" -v d="$TODAY" -v m="$MESSAGE" '
|
||||||
|
/^## \[Unreleased\]/ { print; print ""; print "## [" v "] - " d; print ""; print m; print ""; next }
|
||||||
|
{ print }
|
||||||
|
' "$CHANGELOG" > "$TMP"
|
||||||
|
mv "$TMP" "$CHANGELOG"
|
||||||
|
else
|
||||||
|
# Открыть редактор для ручного ввода
|
||||||
|
echo "Откройте $CHANGELOG, добавьте секцию для $VERSION в начало, сохраните и закройте."
|
||||||
|
${EDITOR:-nano} "$CHANGELOG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. Коммит, тег, push
|
||||||
|
git add "$PLUGIN_JSON" "$MCP_JSON" "$MARKETPLACE_JSON" "$CHANGELOG"
|
||||||
|
git commit -m "release: v$VERSION"
|
||||||
|
git tag -a "$TAG" -m "Release $VERSION"
|
||||||
|
git push origin main
|
||||||
|
git push origin "$TAG"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Released $VERSION (tag $TAG)."
|
||||||
|
echo "Клиенты обновятся через:"
|
||||||
|
echo " /plugin marketplace update"
|
||||||
|
echo " /plugin update 222a-seo-audit"
|
||||||
21
scripts/test-release.sh
Executable file
21
scripts/test-release.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Smoke-тесты для release.sh. Запускать вручную перед коммитом изменений в release.sh.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Тест 1: невалидный semver должен фейлиться
|
||||||
|
if ./scripts/release.sh "1.0" 2>/dev/null; then
|
||||||
|
echo "FAIL: невалидный semver принят"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: невалидный semver отклонён"
|
||||||
|
|
||||||
|
# Тест 2: dry-run на корректном semver должен пройти валидацию
|
||||||
|
if ! ./scripts/release.sh "9.9.9" --dry-run 2>&1 | grep -q "Would release"; then
|
||||||
|
echo "FAIL: dry-run на 9.9.9 не сработал"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "OK: dry-run работает"
|
||||||
|
|
||||||
|
echo "All smoke tests passed"
|
||||||
Loading…
Reference in New Issue
Block a user