hass.tibber_prices/scripts/suggest-version
Julian Pawlowski ddc718aabd feat(release): add semantic versioning workflow automation
Added intelligent version suggestion system based on Conventional Commits
analysis to support proper semantic versioning.

New scripts:
- check-if-released: Verify if commit exists in any version tag
  - Helps decide if legacy migration code is needed
  - Shows guidance for breaking changes vs simple migrations

- suggest-version: Analyze commits and suggest next version
  - Counts breaking changes, features, and bug fixes
  - Applies pre-1.0 rules: breaking→MINOR, feat→MINOR, fix→PATCH
  - Applies post-1.0 rules: breaking→MAJOR, feat→MINOR, fix→PATCH
  - Checks manifest.json and suggests alternatives (MAJOR/MINOR/PATCH)
  - Provides preview and release commands

Updated scripts:
- prepare-release: Now calls suggest-version when no argument provided
  - Shows suggested version before prompting
  - Maintains manual override capability

Impact: Developers get intelligent version suggestions based on actual
commit content, reducing versioning mistakes and following semver correctly.
2025-11-09 15:32:44 +00:00

194 lines
6.2 KiB
Bash
Executable file

#!/bin/bash
# Analyze commits since last release and suggest next version number
#
# Usage:
# ./scripts/suggest-version [--from TAG]
#
# Examples:
# ./scripts/suggest-version
# ./scripts/suggest-version --from v0.2.0
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${SCRIPT_DIR}/.."
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'
# Parse arguments
FROM_TAG="${2:-}"
# Get current version from manifest.json
MANIFEST="custom_components/tibber_prices/manifest.json"
if [[ ! -f "$MANIFEST" ]]; then
echo -e "${RED}Error: Manifest file not found: $MANIFEST${NC}"
exit 1
fi
# Require jq for JSON parsing
if ! command -v jq >/dev/null 2>&1; then
echo -e "${RED}Error: jq is not installed${NC}"
echo "Please install jq: apt-get install jq (or brew install jq)"
exit 1
fi
MANIFEST_VERSION=$(jq -r '.version' "$MANIFEST")
MANIFEST_TAG="v${MANIFEST_VERSION}"
# Get latest version tag
if [ -z "$FROM_TAG" ]; then
FROM_TAG=$(git tag -l 'v*.*.*' --sort=-version:refname | head -1)
if [ -z "$FROM_TAG" ]; then
echo -e "${RED}Error: No version tags found${NC}"
exit 1
fi
fi
# Check if manifest version already has a tag
if git rev-parse "$MANIFEST_TAG" >/dev/null 2>&1; then
# Manifest version is already tagged - analyze from that tag
FROM_TAG="$MANIFEST_TAG"
echo -e "${YELLOW}Note: manifest.json version ${MANIFEST_VERSION} already tagged as ${MANIFEST_TAG}${NC}"
echo ""
fi
echo -e "${BOLD}Analyzing commits since $FROM_TAG${NC}"
echo ""
# Parse current version (from the tag we're analyzing from)
CURRENT_VERSION="${FROM_TAG#v}"
MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1)
MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f2)
PATCH=$(echo "$CURRENT_VERSION" | cut -d. -f3)
echo "Current released version: v${MAJOR}.${MINOR}.${PATCH}"
if [[ "$MANIFEST_VERSION" != "$CURRENT_VERSION" ]]; then
echo -e "${YELLOW}Manifest.json version: ${MANIFEST_VERSION} (not yet tagged)${NC}"
fi
echo ""
# Analyze commits (exclude version bump commits)
COMMITS=$(git log "$FROM_TAG"..HEAD --format="%s" --no-merges | grep -v "^chore(release):" || true)
if [ -z "$COMMITS" ]; then
echo -e "${YELLOW}No new commits since last release${NC}"
# Check if manifest.json needs to be tagged
if [[ "$MANIFEST_VERSION" != "$CURRENT_VERSION" ]]; then
echo ""
echo -e "${BLUE}Manifest.json has version ${MANIFEST_VERSION} but no tag exists yet.${NC}"
echo "Create tag with:"
echo " git tag -a v${MANIFEST_VERSION} -m \"Release ${MANIFEST_VERSION}\""
echo " git push origin v${MANIFEST_VERSION}"
fi
exit 0
fi
# Count commit types
BREAKING_COUNT=$(echo "$COMMITS" | grep -c "^[^:]*!:" || true)
FEAT_COUNT=$(echo "$COMMITS" | grep -cE "^feat(\(.+\))?:" || true)
FIX_COUNT=$(echo "$COMMITS" | grep -cE "^fix(\(.+\))?:" || true)
REFACTOR_COUNT=$(echo "$COMMITS" | grep -cE "^refactor(\(.+\))?:" || true)
DOCS_COUNT=$(echo "$COMMITS" | grep -cE "^docs(\(.+\))?:" || true)
OTHER_COUNT=$(echo "$COMMITS" | grep -vcE "^(feat|fix|refactor|docs)(\(.+\))?:" || true)
# Check for breaking changes in commit messages or Impact sections
BREAKING_IN_BODY=$(git log "$FROM_TAG"..HEAD --format="%b" --no-merges | grep -ci "BREAKING CHANGE:" || true)
TOTAL_BREAKING=$((BREAKING_COUNT + BREAKING_IN_BODY))
echo -e "${BOLD}Commit Analysis:${NC}"
echo ""
if [ $TOTAL_BREAKING -gt 0 ]; then
echo -e " ${RED}⚠ Breaking changes:${NC} $TOTAL_BREAKING"
fi
echo -e " ${GREEN}✨ New features:${NC} $FEAT_COUNT"
echo -e " ${BLUE}🐛 Bug fixes:${NC} $FIX_COUNT"
if [ $REFACTOR_COUNT -gt 0 ]; then
echo -e " ${YELLOW}🔧 Refactorings:${NC} $REFACTOR_COUNT"
fi
if [ $DOCS_COUNT -gt 0 ]; then
echo -e " 📚 Documentation: $DOCS_COUNT"
fi
if [ $OTHER_COUNT -gt 0 ]; then
echo -e " 📦 Other: $OTHER_COUNT"
fi
echo ""
# Determine version bump
SUGGESTED_MAJOR=$MAJOR
SUGGESTED_MINOR=$MINOR
SUGGESTED_PATCH=$PATCH
if [ $TOTAL_BREAKING -gt 0 ]; then
# Before v1.0.0: Breaking changes bump minor
# After v1.0.0: Breaking changes bump major
if [ $MAJOR -eq 0 ]; then
SUGGESTED_MINOR=$((MINOR + 1))
SUGGESTED_PATCH=0
BUMP_TYPE="MINOR (breaking changes in 0.x)"
BUMP_REASON="Breaking changes detected (before v1.0.0 → bump minor)"
else
SUGGESTED_MAJOR=$((MAJOR + 1))
SUGGESTED_MINOR=0
SUGGESTED_PATCH=0
BUMP_TYPE="MAJOR (breaking)"
BUMP_REASON="Breaking changes detected"
fi
elif [ $FEAT_COUNT -gt 0 ]; then
SUGGESTED_MINOR=$((MINOR + 1))
SUGGESTED_PATCH=0
BUMP_TYPE="MINOR (features)"
BUMP_REASON="New features added"
elif [ $FIX_COUNT -gt 0 ]; then
SUGGESTED_PATCH=$((PATCH + 1))
BUMP_TYPE="PATCH (fixes)"
BUMP_REASON="Bug fixes only"
else
SUGGESTED_PATCH=$((PATCH + 1))
BUMP_TYPE="PATCH (other)"
BUMP_REASON="Documentation/refactoring changes"
fi
SUGGESTED_VERSION="v${SUGGESTED_MAJOR}.${SUGGESTED_MINOR}.${SUGGESTED_PATCH}"
echo -e "${BOLD}${GREEN}Suggested Version: $SUGGESTED_VERSION${NC}"
echo -e " Bump type: ${BUMP_TYPE}"
echo -e " Reason: ${BUMP_REASON}"
echo ""
# Show alternative versions
echo -e "${BOLD}Alternative Versions:${NC}"
echo -e " ${YELLOW}MAJOR:${NC} v$((MAJOR + 1)).0.0 (if you want to release v1.0.0 or have breaking changes)"
echo -e " ${GREEN}MINOR:${NC} v${MAJOR}.$((MINOR + 1)).0 (if adding features)"
echo -e " ${BLUE}PATCH:${NC} v${MAJOR}.${MINOR}.$((PATCH + 1)) (if only fixes/docs)"
echo ""
# Show preview command
echo -e "${BOLD}Preview Release Notes:${NC}"
echo " ./scripts/generate-release-notes $FROM_TAG HEAD"
echo ""
echo -e "${BOLD}Create Release:${NC}"
echo " ./scripts/prepare-release ${SUGGESTED_MAJOR}.${SUGGESTED_MINOR}.${SUGGESTED_PATCH}"
echo ""
# Show warning if breaking changes detected
if [ $TOTAL_BREAKING -gt 0 ]; then
echo -e "${RED}${BOLD}⚠ WARNING: Breaking changes detected!${NC}"
echo -e "${RED}Make sure to document migration steps in release notes.${NC}"
echo ""
fi
# Show note about pre-1.0 versioning
if [ $MAJOR -eq 0 ]; then
echo -e "${YELLOW}Note: Pre-1.0 versioning (0.x.y)${NC}"
echo " - Breaking changes bump MINOR (0.x.0)"
echo " - Features bump MINOR (0.x.0)"
echo " - Fixes bump PATCH (0.0.x)"
echo " - After v1.0.0: Breaking changes bump MAJOR (x.0.0)"
fi