From 0f5d493d2a2d2c22bdc512da41105d0cb0f1f287 Mon Sep 17 00:00:00 2001 From: Matheus Henrique de Souza Date: Thu, 6 Aug 2026 11:11:22 -0300 Subject: [PATCH 1/5] fix(release): support release candidate tags (vX.Y.Z-rc.N) and mark prereleases --- .github/workflows/release.yml | 18 ++++++++++++------ Makefile | 6 +++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6dbe635..8b6e9bd 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,7 +20,7 @@ jobs: packages: write steps: - - name: Determine Release Tag + - name: Determine Release Tag & Type id: release_tag run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then @@ -28,11 +28,16 @@ jobs: else TAG="${{ github.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 ! echo "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[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 + if echo "$TAG" | grep -q '\-rc'; then + echo "is_prerelease=true" >> $GITHUB_OUTPUT + else + echo "is_prerelease=false" >> $GITHUB_OUTPUT + fi - name: Checkout repository uses: actions/checkout@v4 @@ -60,7 +65,7 @@ jobs: 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=${{ steps.release_tag.outputs.tag }} type=raw,value=latest - name: Build & Push Multi-Arch Container Image @@ -90,6 +95,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..148f43d 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-9]+\.[0-9]+\.[0-9]+(-rc\.[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) From 15dbc5ef0df54c7c632c89841e72dda22c1b4f22 Mon Sep 17 00:00:00 2001 From: Matheus Henrique de Souza Date: Thu, 6 Aug 2026 13:42:44 -0300 Subject: [PATCH 2/5] fix(release): address CodeRabbit review feedback for release candidates and docs --- .github/workflows/release.yml | 17 +++++++++++------ Makefile | 2 +- docs/RELEASE.md | 27 ++++++++++++++++----------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8b6e9bd..9cc89b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,16 +22,22 @@ jobs: steps: - 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]+(-rc\.[0-9]+)?$'; then + + if ! echo "$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 if echo "$TAG" | grep -q '\-rc'; then echo "is_prerelease=true" >> $GITHUB_OUTPUT @@ -64,9 +70,8 @@ jobs: with: images: ghcr.io/${{ github.repository }} tags: | - type=semver,pattern={{version}},value=${{ steps.release_tag.outputs.tag }} type=raw,value=${{ steps.release_tag.outputs.tag }} - type=raw,value=latest + 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 diff --git a/Makefile b/Makefile index 148f43d..a983920 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ docker-run: docker-build ## Start production Docker Compose environment 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-9]+\.[0-9]+\.[0-9]+(-rc\.[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 + @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 From bccb571535f8776b9fdd6dbbdcca300e2d31605c Mon Sep 17 00:00:00 2001 From: Matheus Henrique de Souza Date: Thu, 6 Aug 2026 13:59:22 -0300 Subject: [PATCH 3/5] ci: trigger fresh build for release candidate PR #65 From 5ac1b52eab9f9de8352bb85a077d7cfa460bf222 Mon Sep 17 00:00:00 2001 From: Matheus Henrique de Souza Date: Thu, 6 Aug 2026 14:33:07 -0300 Subject: [PATCH 4/5] fix(release): reject multiline tag input in release workflow --- .github/workflows/release.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9cc89b0..934f4eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,16 +33,21 @@ jobs: TAG="$REF_NAME" fi - if ! echo "$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 + 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 - echo "is_prerelease=true" >> $GITHUB_OUTPUT + printf 'is_prerelease=true\n' >> "$GITHUB_OUTPUT" else - echo "is_prerelease=false" >> $GITHUB_OUTPUT + printf 'is_prerelease=false\n' >> "$GITHUB_OUTPUT" fi - name: Checkout repository From 5575282774cb0b60690fcf0e244089dc2163b8e9 Mon Sep 17 00:00:00 2001 From: Matheus Henrique de Souza Date: Fri, 7 Aug 2026 08:38:56 -0300 Subject: [PATCH 5/5] ci: trigger fresh build for release candidate PR #65