|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -euo pipefail |
| 4 | + |
| 5 | +# Shared script for Renovate to bump version and update CHANGELOG |
| 6 | +# Can be downloaded and executed in any repo with version and changelog files |
| 7 | +# Auto-detects changed dependencies from git diff |
| 8 | + |
| 9 | +# Use current working directory as repo root (where Renovate executes the script) |
| 10 | +# Override these via environment variables if your repo has different paths |
| 11 | +REPO_ROOT="${REPO_ROOT:-$(pwd)}" |
| 12 | +VERSION_FILE="${VERSION_FILE:-$REPO_ROOT/unstructured/__version__.py}" |
| 13 | +CHANGELOG_FILE="${CHANGELOG_FILE:-$REPO_ROOT/CHANGELOG.md}" |
| 14 | + |
| 15 | +echo "=== Renovate Security Version Bump ===" |
| 16 | + |
| 17 | +# Read current version from __version__.py |
| 18 | +CURRENT_VERSION=$(grep -o -E "(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-dev[0-9]+)?" "$VERSION_FILE") |
| 19 | +echo "Current version: $CURRENT_VERSION" |
| 20 | + |
| 21 | +# Determine release version based on current version format |
| 22 | +if [[ "$CURRENT_VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-dev.*)?$ ]]; then |
| 23 | + MAJOR="${BASH_REMATCH[1]}" |
| 24 | + MINOR="${BASH_REMATCH[2]}" |
| 25 | + PATCH="${BASH_REMATCH[3]}" |
| 26 | + DEV_SUFFIX="${BASH_REMATCH[4]}" |
| 27 | + |
| 28 | + if [[ -n "$DEV_SUFFIX" ]]; then |
| 29 | + # Strip -dev suffix to release current version |
| 30 | + RELEASE_VERSION="$MAJOR.$MINOR.$PATCH" |
| 31 | + echo "Stripping dev suffix: $CURRENT_VERSION → $RELEASE_VERSION" |
| 32 | + else |
| 33 | + # Already a release version, bump to next patch |
| 34 | + NEW_PATCH=$((PATCH + 1)) |
| 35 | + RELEASE_VERSION="$MAJOR.$MINOR.$NEW_PATCH" |
| 36 | + echo "Bumping patch version: $CURRENT_VERSION → $RELEASE_VERSION" |
| 37 | + fi |
| 38 | +else |
| 39 | + echo "Error: Could not parse version: $CURRENT_VERSION" |
| 40 | + exit 1 |
| 41 | +fi |
| 42 | + |
| 43 | +# Update __version__.py |
| 44 | +echo "Updating $VERSION_FILE to version $RELEASE_VERSION" |
| 45 | + |
| 46 | +# Detect quote style used in the file |
| 47 | +if grep -q "__version__ = ['\"]" "$VERSION_FILE"; then |
| 48 | + if grep -q "__version__ = \"" "$VERSION_FILE"; then |
| 49 | + # Double quotes |
| 50 | + sed -i.bak -E "s/__version__ = \"[^\"]+\"/__version__ = \"$RELEASE_VERSION\"/" "$VERSION_FILE" |
| 51 | + else |
| 52 | + # Single quotes |
| 53 | + sed -i.bak -E "s/__version__ = '[^']+'/__version__ = '$RELEASE_VERSION'/" "$VERSION_FILE" |
| 54 | + fi |
| 55 | +else |
| 56 | + echo "Error: Could not detect quote style in $VERSION_FILE" |
| 57 | + exit 1 |
| 58 | +fi |
| 59 | + |
| 60 | +# Verify the update succeeded |
| 61 | +if ! grep -q "__version__ = ['\"]$RELEASE_VERSION['\"]" "$VERSION_FILE"; then |
| 62 | + echo "Error: Failed to update version in $VERSION_FILE" |
| 63 | + exit 1 |
| 64 | +fi |
| 65 | + |
| 66 | +rm -f "$VERSION_FILE.bak" |
| 67 | + |
| 68 | +# Detect changed packages from git diff (best effort, not critical) |
| 69 | +echo "Detecting changed dependencies..." |
| 70 | +CHANGED_PACKAGES=$(git diff --cached requirements/*.txt 2>/dev/null | grep -E "^[-+][a-zA-Z0-9_-]+==" | sed 's/^[+-]//' | sort -u | head -20 || true) |
| 71 | + |
| 72 | +if [ -z "$CHANGED_PACKAGES" ]; then |
| 73 | + # Try without --cached |
| 74 | + CHANGED_PACKAGES=$(git diff requirements/*.txt 2>/dev/null | grep -E "^[-+][a-zA-Z0-9_-]+==" | sed 's/^[+-]//' | sort -u | head -20 || true) |
| 75 | +fi |
| 76 | + |
| 77 | +# Build changelog entry (generic for now, can be manually edited) |
| 78 | +if [ -n "$CHANGED_PACKAGES" ]; then |
| 79 | + PACKAGE_COUNT=$(echo "$CHANGED_PACKAGES" | wc -l | tr -d ' ') |
| 80 | + echo "Found $PACKAGE_COUNT changed package(s)" |
| 81 | + CHANGELOG_ENTRY="- **Security update**: Bumped dependencies to address security vulnerabilities" |
| 82 | +else |
| 83 | + echo "Could not auto-detect packages, using generic entry" |
| 84 | + CHANGELOG_ENTRY="- **Security update**: Bumped dependencies to address security vulnerabilities" |
| 85 | +fi |
| 86 | +echo "Changelog entry: $CHANGELOG_ENTRY" |
| 87 | + |
| 88 | +# Update CHANGELOG.md |
| 89 | +echo "Updating CHANGELOG..." |
| 90 | + |
| 91 | +# Only look for -dev version to rename if CURRENT_VERSION had -dev suffix |
| 92 | +if [[ -n "$DEV_SUFFIX" ]]; then |
| 93 | + # Look for -dev version header in CHANGELOG that matches our version |
| 94 | + DEV_VERSION_HEADER=$(grep -m 1 -F "## $CURRENT_VERSION" "$CHANGELOG_FILE" || true) |
| 95 | + |
| 96 | + if [[ -n "$DEV_VERSION_HEADER" ]]; then |
| 97 | + echo "Found dev version in CHANGELOG: $DEV_VERSION_HEADER" |
| 98 | + |
| 99 | + # Extract the -dev version number from header |
| 100 | + DEV_VERSION=$(echo "$DEV_VERSION_HEADER" | grep -o -E "[0-9]+\.[0-9]+\.[0-9]+-dev[0-9]*") |
| 101 | + |
| 102 | + echo "Renaming CHANGELOG header: $DEV_VERSION → $RELEASE_VERSION" |
| 103 | + |
| 104 | + # Create awk script to: |
| 105 | + # 1. Rename the -dev version header |
| 106 | + # 2. Find or create Fixes section |
| 107 | + # 3. Append security entry |
| 108 | + awk -v dev_version="$DEV_VERSION" \ |
| 109 | + -v release_version="$RELEASE_VERSION" \ |
| 110 | + -v security_entry="$CHANGELOG_ENTRY" ' |
| 111 | + BEGIN { |
| 112 | + in_target_version = 0 |
| 113 | + found_fixes = 0 |
| 114 | + added_entry = 0 |
| 115 | + } |
| 116 | +
|
| 117 | + # Match the dev version header and rename it |
| 118 | + /^## / { |
| 119 | + if ($0 ~ "^## " dev_version) { |
| 120 | + print "## " release_version |
| 121 | + in_target_version = 1 |
| 122 | + next |
| 123 | + } else { |
| 124 | + # Hit a different version header, stop being in target version |
| 125 | + if (in_target_version && !found_fixes && !added_entry) { |
| 126 | + # We never found Fixes section, add it before this new version |
| 127 | + print "" |
| 128 | + print "### Fixes" |
| 129 | + print security_entry |
| 130 | + print "" |
| 131 | + added_entry = 1 |
| 132 | + } |
| 133 | + in_target_version = 0 |
| 134 | + found_fixes = 0 |
| 135 | + } |
| 136 | + } |
| 137 | +
|
| 138 | + # Found Fixes section in target version |
| 139 | + /^### Fixes/ && in_target_version { |
| 140 | + print |
| 141 | + print security_entry |
| 142 | + found_fixes = 1 |
| 143 | + added_entry = 1 |
| 144 | + next |
| 145 | + } |
| 146 | +
|
| 147 | + { print } |
| 148 | +
|
| 149 | + END { |
| 150 | + # Handle case where target dev version is last entry and has no Fixes section |
| 151 | + if (in_target_version && !found_fixes && !added_entry) { |
| 152 | + print "" |
| 153 | + print "### Fixes" |
| 154 | + print security_entry |
| 155 | + } |
| 156 | + } |
| 157 | + ' "$CHANGELOG_FILE" > "$CHANGELOG_FILE.tmp" |
| 158 | + |
| 159 | + mv "$CHANGELOG_FILE.tmp" "$CHANGELOG_FILE" |
| 160 | + else |
| 161 | + # Dev version in __version__.py but no dev header found in CHANGELOG |
| 162 | + # This shouldn't happen, but create new entry as fallback |
| 163 | + echo "Warning: Current version has -dev suffix but no matching dev header in CHANGELOG" |
| 164 | + echo "Creating new entry for $RELEASE_VERSION" |
| 165 | + |
| 166 | + cat > /tmp/new_changelog_section.tmp <<EOF |
| 167 | +## $RELEASE_VERSION |
| 168 | +
|
| 169 | +### Fixes |
| 170 | +$CHANGELOG_ENTRY |
| 171 | +
|
| 172 | +EOF |
| 173 | + |
| 174 | + cat /tmp/new_changelog_section.tmp "$CHANGELOG_FILE" > "$CHANGELOG_FILE.tmp" |
| 175 | + mv "$CHANGELOG_FILE.tmp" "$CHANGELOG_FILE" |
| 176 | + rm -f /tmp/new_changelog_section.tmp |
| 177 | + fi |
| 178 | +else |
| 179 | + # Current version was already a release, so we bumped to next patch |
| 180 | + # Create new release entry at top |
| 181 | + echo "Current version was already released, creating new entry for $RELEASE_VERSION" |
| 182 | + |
| 183 | + cat > /tmp/new_changelog_section.tmp <<EOF |
| 184 | +## $RELEASE_VERSION |
| 185 | +
|
| 186 | +### Fixes |
| 187 | +$CHANGELOG_ENTRY |
| 188 | +
|
| 189 | +EOF |
| 190 | + |
| 191 | + cat /tmp/new_changelog_section.tmp "$CHANGELOG_FILE" > "$CHANGELOG_FILE.tmp" |
| 192 | + mv "$CHANGELOG_FILE.tmp" "$CHANGELOG_FILE" |
| 193 | + rm -f /tmp/new_changelog_section.tmp |
| 194 | +fi |
| 195 | + |
| 196 | +echo "" |
| 197 | +echo "✓ Successfully updated version to $RELEASE_VERSION" |
| 198 | +echo "✓ Updated CHANGELOG with security fix entry" |
| 199 | +echo "" |
| 200 | +echo "Modified files:" |
| 201 | +echo " - $VERSION_FILE" |
| 202 | +echo " - $CHANGELOG_FILE" |
0 commit comments