mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 05:13:40 +00:00
fix(release): add validation/lint checks before release and clean output
Added mandatory validation steps to release workflow: - Job 1: validate (hassfest + HACS) - runs before release - Job 2: lint (Ruff check + format) - runs before release - Job 3: sync-manifest - only runs if validation passes - Job 4: release-notes - only runs if all previous jobs pass This ensures no release is created if code doesn't pass validation. Fixed generate-release-notes script to suppress colored output in CI: - Added log_info() wrapper that sends output to stderr in CI - Keeps release notes clean (only markdown, no ANSI codes) - Local execution still shows colored output for better UX Impact: Release workflow now fails fast if validation fails. Release notes are clean without shell output artifacts.
This commit is contained in:
parent
900e77203a
commit
6614d225e3
2 changed files with 84 additions and 17 deletions
54
.github/workflows/release.yml
vendored
54
.github/workflows/release.yml
vendored
|
|
@ -4,12 +4,66 @@ on:
|
|||
push:
|
||||
tags:
|
||||
- 'v*.*.*' # Triggers on version tags like v1.0.0, v2.1.3, etc.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Tag version to release (e.g., v0.3.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write # Needed to create/update releases and push commits
|
||||
|
||||
jobs:
|
||||
# Run validation first - release only proceeds if this passes
|
||||
validate:
|
||||
name: Validate before release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
|
||||
|
||||
- name: Run hassfest validation
|
||||
uses: home-assistant/actions/hassfest@master
|
||||
|
||||
- name: Run HACS validation
|
||||
uses: hacs/action@main
|
||||
with:
|
||||
category: integration
|
||||
|
||||
# Run linting - release only proceeds if this passes
|
||||
lint:
|
||||
name: Lint before release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
with:
|
||||
version: "0.9.3"
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --frozen
|
||||
|
||||
- name: Run Ruff check
|
||||
run: uv run ruff check .
|
||||
|
||||
- name: Run Ruff format check
|
||||
run: uv run ruff format --check .
|
||||
|
||||
sync-manifest:
|
||||
needs: [validate, lint] # Only runs if validation and linting pass
|
||||
name: Sync manifest.json with tag version
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
|
|
|
|||
|
|
@ -30,6 +30,19 @@ YELLOW='\033[1;33m'
|
|||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Detect if running in CI (suppress colored output to stdout)
|
||||
if [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; then
|
||||
# In CI, send info messages to stderr to keep release notes clean
|
||||
log_info() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
else
|
||||
# Local execution, show colored output
|
||||
log_info() {
|
||||
echo "$@"
|
||||
}
|
||||
fi
|
||||
|
||||
# Configuration
|
||||
BACKEND="${RELEASE_NOTES_BACKEND:-auto}"
|
||||
USE_AI="${USE_AI:-true}"
|
||||
|
|
@ -40,13 +53,13 @@ FROM_TAG="${1:-$(git describe --tags --abbrev=0 2>/dev/null || echo "")}"
|
|||
TO_TAG="${2:-HEAD}"
|
||||
|
||||
if [ -z "$FROM_TAG" ]; then
|
||||
echo "${RED}Error: No tags found in repository${NC}"
|
||||
echo "Usage: $0 [FROM_TAG] [TO_TAG]"
|
||||
echo "${RED}Error: No tags found in repository${NC}" >&2
|
||||
echo "Usage: $0 [FROM_TAG] [TO_TAG]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "${BLUE}==> Generating release notes: ${FROM_TAG}..${TO_TAG}${NC}"
|
||||
echo ""
|
||||
log_info "${BLUE}==> Generating release notes: ${FROM_TAG}..${TO_TAG}${NC}"
|
||||
log_info ""
|
||||
|
||||
# Detect available backends
|
||||
detect_backend() {
|
||||
|
|
@ -82,20 +95,20 @@ detect_backend() {
|
|||
}
|
||||
|
||||
BACKEND=$(detect_backend)
|
||||
echo "${GREEN}Using backend: ${BACKEND}${NC}"
|
||||
echo ""
|
||||
log_info "${GREEN}Using backend: ${BACKEND}${NC}"
|
||||
log_info ""
|
||||
|
||||
# Backend: GitHub Copilot CLI (AI-powered)
|
||||
generate_with_copilot() {
|
||||
echo "${BLUE}==> Generating with GitHub Copilot CLI (AI-powered)${NC}"
|
||||
echo "${YELLOW}Note: This will use one premium request from your monthly quota${NC}"
|
||||
echo ""
|
||||
log_info "${BLUE}==> Generating with GitHub Copilot CLI (AI-powered)${NC}"
|
||||
log_info "${YELLOW}Note: This will use one premium request from your monthly quota${NC}"
|
||||
log_info ""
|
||||
|
||||
# Get commit log for the range
|
||||
COMMITS=$(git log --pretty=format:"%h | %s%n%b%n---" "${FROM_TAG}..${TO_TAG}")
|
||||
|
||||
if [ -z "$COMMITS" ]; then
|
||||
echo "${YELLOW}No commits found between ${FROM_TAG} and ${TO_TAG}${NC}"
|
||||
log_info "${YELLOW}No commits found between ${FROM_TAG} and ${TO_TAG}${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
@ -145,8 +158,8 @@ Generate the release notes now:"
|
|||
# Call copilot CLI (it will handle authentication interactively)
|
||||
copilot < "$TEMP_PROMPT" || {
|
||||
echo ""
|
||||
echo "${YELLOW}Warning: GitHub Copilot CLI failed or was not authenticated${NC}"
|
||||
echo "${YELLOW}Falling back to git-cliff${NC}"
|
||||
log_info "${YELLOW}Warning: GitHub Copilot CLI failed or was not authenticated${NC}"
|
||||
log_info "${YELLOW}Falling back to git-cliff${NC}"
|
||||
rm -f "$TEMP_PROMPT"
|
||||
if command -v git-cliff >/dev/null 2>&1; then
|
||||
generate_with_gitcliff
|
||||
|
|
@ -159,9 +172,9 @@ Generate the release notes now:"
|
|||
rm -f "$TEMP_PROMPT"
|
||||
}
|
||||
|
||||
# Backend: git-cliff (fast Rust tool)
|
||||
# Backend: git-cliff (template-based)
|
||||
generate_with_gitcliff() {
|
||||
echo "${BLUE}==> Generating with git-cliff${NC}"
|
||||
log_info "${BLUE}==> Generating with git-cliff${NC}"
|
||||
|
||||
# Create temporary cliff.toml if not exists
|
||||
if [ ! -f "cliff.toml" ]; then
|
||||
|
|
@ -210,12 +223,12 @@ EOF
|
|||
|
||||
# Backend: Manual parsing (fallback)
|
||||
generate_with_manual() {
|
||||
echo "${BLUE}==> Generating with manual parsing${NC}"
|
||||
log_info "${BLUE}==> Generating with manual parsing${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if we have commits
|
||||
if ! git log --oneline "${FROM_TAG}..${TO_TAG}" >/dev/null 2>&1; then
|
||||
echo "${YELLOW}No commits found between ${FROM_TAG} and ${TO_TAG}${NC}"
|
||||
log_info "${YELLOW}No commits found between ${FROM_TAG} and ${TO_TAG}${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
@ -351,4 +364,4 @@ case "$BACKEND" in
|
|||
esac
|
||||
|
||||
echo ""
|
||||
echo "${GREEN}==> Release notes generated successfully!${NC}"
|
||||
log_info "${GREEN}==> Release notes generated successfully!${NC}"
|
||||
|
|
|
|||
Loading…
Reference in a new issue