name: Release on: push: tags: - "v*" jobs: release: runs-on: ubuntu-latest container: golang:1.24 steps: # Код забираем сами: actions/checkout — JS-действие, которому нужен Node # внутри контейнера, а в образе golang его нет. История нужна целиком, # чтобы собрать список изменений с прошлого тега. - name: Забрать код env: TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eu git config --global --add safe.directory "$PWD" git init -q . git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" git -c http.extraheader="Authorization: token ${TOKEN}" \ fetch --tags origin git checkout -q "${GITHUB_SHA}" - name: Собрать бинарники run: | set -eu VERSION="${GITHUB_REF_NAME}" mkdir -p dist for arch in amd64 arm64; do echo "==> pzmanager-linux-${arch}" CGO_ENABLED=0 GOOS=linux GOARCH="${arch}" \ go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" \ -o "dist/pzmanager-linux-${arch}" ./cmd/pzmanager done # Скрипты установки кладём в релиз: тогда get.sh ставит версию # целиком из одного источника и не зависит от состояния ветки. cp deploy/install.sh deploy/pzmanager.service deploy/get.sh dist/ cd dist sha256sum pzmanager-linux-* install.sh pzmanager.service get.sh > checksums.txt cat checksums.txt - name: Опубликовать релиз env: # Токен репозитория Actions выдаёт сам; RELEASE_TOKEN нужен, только # если в настройках инстанса права такого токена урезаны. RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} DEFAULT_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eu apt-get update -qq && apt-get install -y -qq jq TOKEN="${RELEASE_TOKEN:-$DEFAULT_TOKEN}" if [ -z "$TOKEN" ]; then echo "Нет токена для публикации: заведите секрет RELEASE_TOKEN" >&2 exit 1 fi API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}" TAG="${GITHUB_REF_NAME}" AUTH="Authorization: token ${TOKEN}" # Список изменений с предыдущего тега; для первого релиза — вся # история. PREV="$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || true)" if [ -n "$PREV" ]; then CHANGES="$(git log --no-merges --pretty=format:'- %s' "${PREV}..${TAG}")" else CHANGES="$(git log --no-merges --pretty=format:'- %s')" fi NOTES="$(printf '## Установка\n\n```bash\ncurl -fsSL %s/%s/raw/branch/main/deploy/get.sh | sudo bash\n```\n\nОбновление — та же команда: конфиг, миры и учётные записи не трогаются.\n\n## Изменения\n\n%s\n' \ "${GITHUB_SERVER_URL}" "${GITHUB_REPOSITORY}" "${CHANGES}")" PAYLOAD="$(jq -n --arg tag "$TAG" --arg body "$NOTES" \ '{tag_name: $tag, name: $tag, body: $body, draft: false, prerelease: false}')" # Тег могли перевыпустить — тогда работаем с существующим релизом. ID="$(curl -sS -H "$AUTH" "${API}/releases/tags/${TAG}" | jq -r '.id // empty')" if [ -n "$ID" ]; then echo "==> Обновляю существующий релиз ${TAG} (id ${ID})" curl -sS -X PATCH -H "$AUTH" -H "Content-Type: application/json" \ -d "$PAYLOAD" "${API}/releases/${ID}" > /dev/null # Старые файлы удаляем: иначе загрузка упрётся в совпадающие имена. curl -sS -H "$AUTH" "${API}/releases/${ID}/assets" | jq -r '.[].id' \ | while read -r asset; do [ -n "$asset" ] || continue curl -sS -X DELETE -H "$AUTH" "${API}/releases/${ID}/assets/${asset}" > /dev/null done else echo "==> Создаю релиз ${TAG}" ID="$(curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \ -d "$PAYLOAD" "${API}/releases" | jq -r '.id')" fi if [ -z "$ID" ] || [ "$ID" = "null" ]; then echo "Не удалось получить id релиза — проверьте права токена" >&2 exit 1 fi for file in dist/*; do name="$(basename "$file")" echo "==> Загружаю ${name}" curl -sS -f -X POST -H "$AUTH" \ -F "attachment=@${file}" \ "${API}/releases/${ID}/assets?name=${name}" > /dev/null done echo "Готово: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${TAG}"