diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6dbe635..934f4eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,9 +7,9 @@ on: workflow_dispatch: inputs: version: - description: 'Semantic Version Tag (e.g. v0.1.0)' + description: 'Semantic Version Tag (e.g. v1.0.0-rc.26)' required: true - default: 'v0.1.0' + default: 'v1.0.0-rc.26' jobs: release: @@ -20,19 +20,35 @@ jobs: packages: write steps: - - name: Determine Release Tag + - name: Determine Release Tag & Type id: release_tag + env: + EVENT_NAME: ${{ github.event_name }} + INPUT_VERSION: ${{ inputs.version }} + REF_NAME: ${{ github.ref_name }} run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - TAG="${{ inputs.version }}" + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + TAG="$INPUT_VERSION" else - TAG="${{ github.ref_name }}" + TAG="$REF_NAME" fi - if ! echo "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then - echo "Error: Tag '$TAG' does not match semver format vX.Y.Z" + + if [[ "$TAG" == *$'\n'* || "$TAG" == *$'\r'* ]]; then + echo "Error: Tag must be a single line" + exit 1 + fi + + if ! printf '%s\n' "$TAG" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-rc\.(0|[1-9][0-9]*))?$'; then + echo "Error: Tag '$TAG' does not match semver format vX.Y.Z or vX.Y.Z-rc.N" exit 1 fi - echo "tag=$TAG" >> $GITHUB_OUTPUT + + printf 'tag=%s\n' "$TAG" >> "$GITHUB_OUTPUT" + if echo "$TAG" | grep -q '\-rc'; then + printf 'is_prerelease=true\n' >> "$GITHUB_OUTPUT" + else + printf 'is_prerelease=false\n' >> "$GITHUB_OUTPUT" + fi - name: Checkout repository uses: actions/checkout@v4 @@ -59,9 +75,8 @@ jobs: with: images: ghcr.io/${{ github.repository }} tags: | - type=semver,pattern={{version}},value=${{ steps.release_tag.outputs.tag }} - type=semver,pattern={{major}}.{{minor}},value=${{ steps.release_tag.outputs.tag }} - type=raw,value=latest + type=raw,value=${{ steps.release_tag.outputs.tag }} + type=raw,value=latest,enable=${{ steps.release_tag.outputs.is_prerelease == 'false' }} - name: Build & Push Multi-Arch Container Image uses: docker/build-push-action@v6 @@ -90,6 +105,7 @@ jobs: with: tag_name: ${{ steps.release_tag.outputs.tag }} name: Release ${{ steps.release_tag.outputs.tag }} + prerelease: ${{ steps.release_tag.outputs.is_prerelease == 'true' }} generate_release_notes: true body: | ## 🚀 InfraMap Single Binary Container Release diff --git a/Makefile b/Makefile index 659e83c..a983920 100644 --- a/Makefile +++ b/Makefile @@ -48,9 +48,9 @@ docker-run: docker-build ## Start production Docker Compose environment @echo "Starting production Docker Compose environment..." docker compose up -d -release: ## Create and push semantic version git tag (usage: make release VERSION=v0.1.0) - @if [ -z "$(VERSION)" ]; then echo "Error: VERSION is required (e.g. make release VERSION=v0.1.0)"; exit 1; fi - @if ! echo "$(VERSION)" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$$'; then echo "Error: VERSION must match semver pattern vX.Y.Z (e.g. v0.1.0)"; exit 1; fi +release: ## Create and push semantic version git tag (usage: make release VERSION=v1.0.0-rc.26) + @if [ -z "$(VERSION)" ]; then echo "Error: VERSION is required (e.g. make release VERSION=v1.0.0-rc.26)"; exit 1; fi + @if ! echo "$(VERSION)" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-rc\.(0|[1-9][0-9]*))?$$'; then echo "Error: VERSION must match semver pattern vX.Y.Z or vX.Y.Z-rc.N (e.g. v1.0.0-rc.26)"; exit 1; fi @echo "Creating and pushing tag $(VERSION)..." git tag -a $(VERSION) -m "Release $(VERSION)" git push origin $(VERSION) diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 35bcaeb..a35d0ac 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -8,35 +8,40 @@ This document outlines the versioning policy, automated release workflow, and ro InfraMap adheres strictly to **Semantic Versioning (SemVer 2.0.0)**: -- `v{MAJOR}.{MINOR}.{PATCH}` (e.g. `v0.1.0`) +- `v{MAJOR}.{MINOR}.{PATCH}` (e.g. `v1.0.0`) +- `v{MAJOR}.{MINOR}.{PATCH}-rc.{N}` (e.g. `v1.0.0-rc.26` for Release Candidates) - **MAJOR**: Incompatible API changes or breaking architecture refactors. - **MINOR**: Backward-compatible new features (e.g. new integration discovery provider). - **PATCH**: Backward-compatible bug fixes and security patches. + - **RELEASE CANDIDATES (`-rc.N`)**: Pre-releases published to GHCR for validation before stable release. Pre-releases are tagged on GHCR as `:vX.Y.Z-rc.N` (the `:latest` tag is only updated on stable releases). --- ## 2. Triggering an Automated Release -To initiate a release: +To initiate a release candidate or stable release: ```bash # Ensure you are on develop with all PRs merged and quality gates passing git checkout develop git pull origin develop -# Create and push the release tag (e.g. v0.1.0) -make release VERSION=v0.1.0 +# Trigger release candidate build +make release VERSION=v1.0.0-rc.26 + +# Or trigger stable release build +make release VERSION=v1.0.0 ``` ### What GitHub Actions Pipeline Does Automatically Upon receiving a tag matching `v*.*.*`: -1. **Tag Format Validation**: Validates exact SemVer `vX.Y.Z` structure. +1. **Tag Format Validation**: Validates exact SemVer `vX.Y.Z` or `vX.Y.Z-rc.N` structure. 2. **Multi-Architecture Container Build**: Builds `linux/amd64` and `linux/arm64` container images with Docker Buildx. -3. **Container Registry Tagging**: Tags images on `ghcr.io/matheus-souza/inframap` with `:v0.1.0`, `:v0.1`, and `:latest`. +3. **Container Registry Tagging**: Tags images on `ghcr.io/matheus-souza/inframap` with `:vX.Y.Z-rc.N` (and updates `:latest` tag only for stable releases). 4. **Vulnerability Scanning**: Runs Trivy security scanner against `CRITICAL` and `HIGH` CVEs. -5. **GitHub Release Generation**: Creates a GitHub Release with auto-generated release notes and installation instructions. +5. **GitHub Release Generation**: Creates a GitHub Release (marked as Pre-release for `-rc.N` tags) with auto-generated release notes and quick-start guides. --- @@ -45,8 +50,8 @@ Upon receiving a tag matching `v*.*.*`: Before deploying a new version to production homelab nodes: ```bash -# Pull the newly published container image -docker pull ghcr.io/matheus-souza/inframap:v0.1.0 +# Pull the newly published release candidate container image +docker pull ghcr.io/matheus-souza/inframap:v1.0.0-rc.26 # Verify health status curl -f http://localhost:8055/api/v1/health @@ -58,9 +63,9 @@ curl -f http://localhost:8055/api/v1/health If a release candidate exhibits issues in your environment: -1. Update your `docker-compose.yml` image tag to the previous stable release: +1. Update your `docker-compose.yml` image tag to the previous stable release or working RC: ```yaml - image: ghcr.io/matheus-souza/inframap:v0.0.9 + image: ghcr.io/matheus-souza/inframap:v1.0.0-rc.25 ``` 2. Restart the stack: ```bash