Files
rpm-changelog/scripts/generate-rpm-changelog.sh
rob thijssen 328101f247 feat: add source-dir and repo-url inputs for external repo support
Allow changelog generation from upstream repositories instead of only
the current working directory. Supports packaging repos that contain
only rpm spec files while the source lives in an external git repo.

- source-dir: point at an existing local checkout
- repo-url: action clones a bare copy automatically
- source-dir takes precedence if both are set

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 10:36:00 +03:00

122 lines
3.4 KiB
Bash
Executable File

#!/bin/bash
# Generate an rpm %changelog entry for this release and prepend it to
# the spec's existing %changelog section.
#
# Usage: generate-rpm-changelog.sh <spec-file> <version>
#
# Environment overrides:
# CHANGELOG_AUTHOR — "Name <email>", default "Gitea Actions <actions@git.lair.cafe>"
# RELEASE — release suffix, default "1"
# TAG_PATTERN — glob for release tags, default "v*"
# EXCLUDE_PATTERNS — newline-separated grep -E patterns to drop
# SOURCE_DIR — path to an external git checkout to read history from
# REPO_URL — URL of a remote repo to clone (bare) for history
#
# If SOURCE_DIR or REPO_URL is set, commits are collected from that
# repository instead of the current working directory. SOURCE_DIR
# takes precedence over REPO_URL.
#
# Collects commits since the previous matching tag, drops filtered
# lines (bump-version chore commits, merges, etc.), and writes a
# dated entry.
set -euo pipefail
SPEC="$1"
VERSION="$2"
AUTHOR="${CHANGELOG_AUTHOR:-Gitea Actions <actions@git.lair.cafe>}"
RELEASE="${RELEASE:-1}"
TAG_PATTERN="${TAG_PATTERN:-v*}"
EXCLUDE_PATTERNS="${EXCLUDE_PATTERNS:-$'^- chore: bump version\n^- Merge'}"
SOURCE_DIR="${SOURCE_DIR:-}"
REPO_URL="${REPO_URL:-}"
# Resolve the git directory to collect commits from.
# Priority: SOURCE_DIR > REPO_URL > current working directory.
CLEANUP_DIR=""
GIT_ARGS=()
if [ -n "$SOURCE_DIR" ]; then
if [ ! -d "$SOURCE_DIR/.git" ] && ! git -C "$SOURCE_DIR" rev-parse --git-dir >/dev/null 2>&1; then
printf 'error: source-dir is not a git repository: %s\n' "$SOURCE_DIR" >&2
exit 1
fi
GIT_ARGS=(-C "$SOURCE_DIR")
printf 'Using source-dir for commit history: %s\n' "$SOURCE_DIR"
elif [ -n "$REPO_URL" ]; then
CLONE_DIR=$(mktemp -d)
CLEANUP_DIR="$CLONE_DIR"
printf 'Cloning %s (bare) for commit history…\n' "$REPO_URL"
git clone --bare --filter=blob:none "$REPO_URL" "$CLONE_DIR/repo.git"
GIT_ARGS=(-C "$CLONE_DIR/repo.git")
fi
cleanup() {
if [ -n "$CLEANUP_DIR" ] && [ -d "$CLEANUP_DIR" ]; then
rm -rf "$CLEANUP_DIR"
fi
}
trap cleanup EXIT
if [ ! -f "$SPEC" ]; then
echo "error: spec file not found: $SPEC" >&2
exit 1
fi
if ! grep -q '^%changelog' "$SPEC"; then
echo "error: no %changelog section in $SPEC — refusing to mangle" >&2
exit 1
fi
# Find the previous release tag (exclude the current tag at HEAD).
PREV_TAG=$(git "${GIT_ARGS[@]}" describe --tags --abbrev=0 --match="$TAG_PATTERN" HEAD^ 2>/dev/null || echo "")
if [ -n "$PREV_TAG" ]; then
RAW=$(git "${GIT_ARGS[@]}" log --no-merges --pretty=format:'- %s' "${PREV_TAG}..HEAD")
# Build a combined grep -E pattern from the exclude list; drop blanks.
COMBINED=""
while IFS= read -r pat; do
[ -z "$pat" ] && continue
if [ -z "$COMBINED" ]; then
COMBINED="$pat"
else
COMBINED="${COMBINED}|${pat}"
fi
done <<< "$EXCLUDE_PATTERNS"
if [ -n "$COMBINED" ]; then
LOG=$(printf '%s\n' "$RAW" | grep -Ev "$COMBINED" || true)
else
LOG="$RAW"
fi
else
LOG=""
fi
if [ -z "$LOG" ]; then
LOG="- No user-visible changes"
fi
DATE=$(LC_ALL=C date -u +'%a %b %d %Y')
ENTRY="* ${DATE} ${AUTHOR} - ${VERSION}-${RELEASE}
${LOG}
"
# Prepend the entry to the %changelog section.
TMP=$(mktemp)
awk -v entry="$ENTRY" '
inserted == 0 && /^%changelog[[:space:]]*$/ {
print
print entry
inserted = 1
next
}
{ print }
' "$SPEC" > "$TMP"
mv "$TMP" "$SPEC"
echo "Added changelog entry for ${VERSION}-${RELEASE}:"
echo "$ENTRY"