From 048b96420488bae599ea8f2f7765a2e576b9f718 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Sat, 14 Jun 2025 18:36:15 +0200 Subject: [PATCH] feat(scripts): add CI utilities for versioning and changelog - Add scripts to detect version changes and generate changelogs - Include setup for installing and configuring git-cliff - Automate release creation and changelog updates for CI workflows - Improve Git author setup for consistent commits --- scripts/detect-version-change.sh | 32 ++++++++ scripts/generate-unreleased-changelog.sh | 27 +++++++ scripts/install-git-cliff.sh | 50 ++++++++++++ scripts/read-cliff-version.sh | 21 +++++ scripts/release-from-version.sh | 97 ++++++++++++++++++++++++ scripts/setup-git.sh | 13 ++++ 6 files changed, 240 insertions(+) create mode 100755 scripts/detect-version-change.sh create mode 100644 scripts/generate-unreleased-changelog.sh create mode 100755 scripts/install-git-cliff.sh create mode 100644 scripts/read-cliff-version.sh create mode 100644 scripts/release-from-version.sh create mode 100644 scripts/setup-git.sh diff --git a/scripts/detect-version-change.sh b/scripts/detect-version-change.sh new file mode 100755 index 0000000..7dbc54e --- /dev/null +++ b/scripts/detect-version-change.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +# === Inputs from GitHub/Gitea Action environment === +GIT_REF="${GITHUB_REF:-}" +COMMIT_BEFORE="${GITHUB_EVENT_BEFORE:-}" +COMMIT_AFTER="${GITHUB_SHA:-}" +VERSION_FILE="VERSION" + +echo "πŸ” Comparing commits:" +echo "Before: $COMMIT_BEFORE" +echo "After: $COMMIT_AFTER" + +# === Check branch condition === +if [[ "$GIT_REF" != "refs/heads/main" ]]; then + echo "Not on 'main' branch – skipping version check." + echo "version_changed=false" >> "$GITHUB_OUTPUT" + exit 0 +fi + +echo "πŸ“„ Changed files:" +git diff --name-only "$COMMIT_BEFORE" "$COMMIT_AFTER" || echo "(diff failed)" + +if git diff --name-only "$COMMIT_BEFORE" "$COMMIT_AFTER" | grep -q "^$VERSION_FILE$"; then + echo "βœ… VERSION file was changed" + echo "VERSION_CHANGED=true" >> "$GITHUB_ENV" + echo "version_changed=true" >> "$GITHUB_OUTPUT" +else + echo "ℹ️ VERSION file not changed" + echo "VERSION_CHANGED=false" >> "$GITHUB_ENV" + echo "version_changed=false" >> "$GITHUB_OUTPUT" +fi diff --git a/scripts/generate-unreleased-changelog.sh b/scripts/generate-unreleased-changelog.sh new file mode 100644 index 0000000..6019b50 --- /dev/null +++ b/scripts/generate-unreleased-changelog.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +CHANGELOG_FILE="CHANGELOG.md" +CLIFF_CONFIG="cliff.toml" +GIT_BRANCH="${GITHUB_REF##refs/heads/}" + +# === Step 1: Generate Changelog (only if file exists or on main) === +if [[ -f "$CHANGELOG_FILE" || "$GIT_BRANCH" == "main" ]]; then + echo "πŸ“„ Generating $CHANGELOG_FILE using git-cliff..." + git-cliff -c "$CLIFF_CONFIG" -o "$CHANGELOG_FILE" +else + echo "ℹ️ $CHANGELOG_FILE does not exist and branch is not 'main'. Skipping generation." + exit 0 +fi + +# === Step 2: Commit and push changes if any === +git add "$CHANGELOG_FILE" + +if git diff --cached --quiet; then + echo "βœ… No changes to commit – changelog is up to date." +else + echo "✍️ Committing updated $CHANGELOG_FILE..." + git commit -m "chore(changelog): update unreleased changelog" + echo "πŸš€ Pushing to origin/$GIT_BRANCH..." + git push origin "$GIT_BRANCH" +fi diff --git a/scripts/install-git-cliff.sh b/scripts/install-git-cliff.sh new file mode 100755 index 0000000..b04c71c --- /dev/null +++ b/scripts/install-git-cliff.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# install-git-cliff.sh – holt neueste oder gewΓΌnschte git-cliff-Binary (x86_64) +# Usage: sudo ./install-git-cliff.sh # neueste Version +# sudo ./install-git-cliff.sh 2.9.0 # bestimmte Version +set -euo pipefail + +REPO="orhun/git-cliff" +ARCH_OS="x86_64-unknown-linux-gnu" +INSTALL_DIR="/usr/local/bin" +VERSION="${1:-latest}" + +need() { command -v "$1" >/dev/null || { echo "$1 fehlt"; exit 1; }; } +need curl; need tar; need grep; need sed; need awk + +# 1 Version ermitteln β†’ Release-JSON abrufen +if [[ "$VERSION" == "latest" ]]; then + API_URL="https://api.github.com/repos/${REPO}/releases/latest" +else + API_URL="https://api.github.com/repos/${REPO}/releases/tags/v${VERSION}" +fi + +echo "πŸ” Hole Release-Info ($API_URL)…" +JSON=$(curl -sL "$API_URL") + +VERSION=$(echo "$JSON" | grep -m1 '"tag_name":' | sed -E 's/.*"v?([^"]+)".*/\1/') +ASSET_URL=$(echo "$JSON" | + grep -Eo '"browser_download_url": *"[^"]+' | + cut -d'"' -f4 | + grep "${ARCH_OS}\\.tar" | head -n1) + +[[ -z "$ASSET_URL" ]] && { echo "❌ passender Asset nicht gefunden"; exit 1; } + +ASSET_FILE=$(basename "$ASSET_URL") +echo "πŸ“¦ Lade git-cliff v${VERSION} (${ASSET_FILE}) …" +TMP=$(mktemp -d) +curl -#L -o "${TMP}/${ASSET_FILE}" "$ASSET_URL" + +# 2 Entpacken je nach Endung +case "$ASSET_FILE" in + *.tar.gz|*.tgz) tar -C "$TMP" -xzf "${TMP}/${ASSET_FILE}" ;; + *.tar.xz) tar -C "$TMP" -xJf "${TMP}/${ASSET_FILE}" ;; + *.zip) need unzip; unzip -q "${TMP}/${ASSET_FILE}" -d "$TMP" ;; + *) echo "❌ Unbekanntes Archivformat: $ASSET_FILE"; exit 1 ;; +esac + +BIN_PATH=$(find "$TMP" -type f -name git-cliff -perm -u+x | head -n1) +[[ -z "$BIN_PATH" ]] && { echo "❌ Binary nicht gefunden"; exit 1; } + +sudo install -m755 "$BIN_PATH" "${INSTALL_DIR}/git-cliff" +echo "βœ… git-cliff $(git-cliff --version) installiert unter ${INSTALL_DIR}" diff --git a/scripts/read-cliff-version.sh b/scripts/read-cliff-version.sh new file mode 100644 index 0000000..c9a4df7 --- /dev/null +++ b/scripts/read-cliff-version.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +CLIFF_TOML="${1:-cliff.toml}" + +if [[ ! -f "$CLIFF_TOML" ]]; then + echo "❌ File not found: $CLIFF_TOML" >&2 + echo "version=" >> "$GITHUB_OUTPUT" + exit 0 +fi + +VERSION_LINE=$(awk -F '=' '/^# CLIFF_VERSION=/ { gsub(/[" ]/, "", $2); print $2 }' "$CLIFF_TOML" || true) + +if [[ -n "$VERSION_LINE" ]]; then + echo "βœ… Extracted CLIFF_VERSION: $VERSION_LINE" +else + echo "⚠️ No CLIFF_VERSION found in $CLIFF_TOML" +fi + +# Output fΓΌr GitHub Actions / Composite Action +echo "version=${VERSION_LINE:-}" >> "$GITHUB_OUTPUT" diff --git a/scripts/release-from-version.sh b/scripts/release-from-version.sh new file mode 100644 index 0000000..a83fc4d --- /dev/null +++ b/scripts/release-from-version.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +set -euo pipefail + +VERSION_FILE="VERSION" +CHANGELOG_FILE="CHANGELOG.md" +CLIFF_CONFIG="cliff.toml" +RELEASE_BODY_TMP="$(mktemp)" +BODY_OUTPUT_VAR="changelog_body_path" + +# === Schritt 1: Read version from VERSION === +if [[ ! -f "$VERSION_FILE" ]]; then + echo "❌ VERSION file not found" + exit 1 +fi +VERSION="$(<"$VERSION_FILE")" +echo "πŸ“¦ Version: $VERSION" + +# === Schritt 2: Generate changelog for release === +echo "πŸ“„ Generating changelog for tag v$VERSION" +git-cliff -c "$CLIFF_CONFIG" -t "v$VERSION" -o "$CHANGELOG_FILE" + +ESCAPED_VERSION="$(echo "$VERSION" | sed 's/\./\\./g')" + +awk -v ver="$ESCAPED_VERSION" ' + $0 ~ "^## \\[" ver "\\]" { + print_flag=1 + line = $0 + sub(/^## /, "", line) + sub(/\\s*\\(.*\\)/, "", line) # entfernt z.β€―B. "(...)" oder "(*)" + print line + next + } + $0 ~ "^## \\[" && $0 !~ "^## \\[" ver "\\]" { + print_flag=0 + } + print_flag +' "$CHANGELOG_FILE" > "$RELEASE_BODY_TMP" + +# === Schritt 3: Commit updated changelog === +git add "$CHANGELOG_FILE" +if git diff --cached --quiet; then + echo "βœ… No changes to commit" +else + echo "πŸ“ Committing updated changelog" + git commit -m "chore(changelog): update changelog for v$VERSION" + git push origin main +fi + +# === Schritt 4: Create tag if not exists === +if git rev-parse "v$VERSION" >/dev/null 2>&1; then + echo "πŸ” Tag v$VERSION already exists, skipping." +else + echo "🏷️ Creating annotated tag v$VERSION" + export GIT_AUTHOR_DATE="$(date --iso-8601=seconds)" + export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" + git tag -a "v$VERSION" -F "$RELEASE_BODY_TMP" --cleanup=verbatim + git push origin "v$VERSION" +fi + +# === Schritt 5: Create Gitea release === +OWNER="$(echo "$GITHUB_REPOSITORY" | cut -d/ -f1)" +REPO="$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)" +TOKEN="${RELEASE_PUBLISH_TOKEN:-$ACTIONS_RUNTIME_TOKEN}" + +if [[ -z "${RELEASE_PUBLISH_TOKEN:-}" ]]; then + echo "::warning title=Limited Release Propagation::" + echo "RELEASE_PUBLISH_TOKEN is not set. Using ACTIONS_RUNTIME_TOKEN instead." + echo "⚠️ Release events may not trigger other workflows if created with the runtime token." + echo +fi + +# PrΓΌfen, ob Release bereits existiert +if curl -sf "$GITHUB_API_URL/repos/$OWNER/$REPO/releases/tags/v$VERSION" \ + -H "Authorization: token $TOKEN" > /dev/null; then + echo "πŸ” Release for tag v$VERSION already exists, skipping." + exit 0 +fi + +echo "πŸš€ Creating Gitea release for v$VERSION" + +RELEASE_BODY=$(tail -n +2 "$RELEASE_BODY_TMP" | jq -Rs .) + +curl -X POST "$GITHUB_API_URL/repos/$OWNER/$REPO/releases" \ + -H "Authorization: token $TOKEN" \ + -H "Content-Type: application/json" \ + -d @- <