intial release

This commit is contained in:
2026-05-31 11:52:44 +02:00
commit ddc78dd5ba
5 changed files with 476 additions and 0 deletions
+336
View File
@@ -0,0 +1,336 @@
name: Maven Release (reusable)
on:
workflow_call:
inputs:
compose-repo:
description: "Repo docker-compose da aggiornare (es. Biters/bitwork). Vuoto = skip."
required: false
type: string
default: ""
maven-profiles:
description: "Profili Maven da attivare (es. bitwork,ci,git)"
required: false
type: string
default: ""
docker-registry:
description: "Registry Docker per il pattern sed nei docker-compose"
required: false
type: string
default: "artifacts.biters.it:8443"
jobs:
release:
runs-on: ubuntu-latest
container:
image: artifacts.biters.it:8443/biters/gitea-ci-maven:21
credentials:
username: ${{ secrets.MAVEN_USERNAME }}
password: ${{ secrets.MAVEN_PASSWORD }}
volumes:
- /opt/ci-cache/m2-repository:/root/.m2/repository
env:
RUNNER_TOOL_CACHE: /toolcache
MAVEN_REPO_URL: ${{ vars.MAVEN_REPO_URL }}
MAVEN_REPO_RELEASES_URL: ${{ vars.MAVEN_REPO_RELEASES_URL }}
MAVEN_REPO_SNAPSHOTS_URL: ${{ vars.MAVEN_REPO_SNAPSHOTS_URL }}
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
DOCKER_REPO_NEXUS_URL: ${{ vars.DOCKER_REPO_NEXUS_URL }}
DOCKER_HUB_REPO_URL: ${{ vars.DOCKER_HUB_REPO_URL }}
GITEA_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
MVN_PROFILES: ${{ inputs.maven-profiles }}
steps:
# ── Bootstrap ──────────────────────────────────────────────
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Checkout CI config
run: |
git clone --depth=1 "https://biters.gitea:${GITEA_TOKEN}@git.biters.it/Biters/ci-workflows.git" .ci-config
- name: Configura git
run: |
git config user.name "CI Release Bot"
git config user.email "ci@biters.it"
git remote set-url origin "https://biters.gitea:${GITEA_TOKEN}@git.biters.it/${{ github.repository }}.git"
- name: Verifica configurazione
run: |
missing=0
for v in MAVEN_REPO_URL MAVEN_REPO_RELEASES_URL MAVEN_REPO_SNAPSHOTS_URL \
MAVEN_USERNAME MAVEN_PASSWORD \
DOCKER_REPO_NEXUS_URL DOCKER_HUB_REPO_URL GITEA_TOKEN; do
eval "val=\${$v}"
if [ -z "$val" ]; then echo "MANCANTE: $v"; missing=1; else echo "OK: $v"; fi
done
[ "$missing" -eq 0 ] || { echo "Imposta le Variables/Secrets mancanti a livello org."; exit 1; }
# ── Versione ───────────────────────────────────────────────
- name: Promuovi a release (rimuovi -SNAPSHOT)
id: version
run: |
PROF=""
[ -n "$MVN_PROFILES" ] && PROF="-P$MVN_PROFILES"
mvn -B -s .ci-config/settings.xml $PROF versions:set \
-DremoveSnapshot=true -DgenerateBackupPoms=false
RELEASE_VERSION=$(mvn -q -s .ci-config/settings.xml $PROF help:evaluate \
-Dexpression=project.version -DforceStdout)
echo "RELEASE_VERSION=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"
ARTIFACT_ID=$(mvn -q -s .ci-config/settings.xml $PROF help:evaluate \
-Dexpression=project.artifactId -DforceStdout)
echo "ARTIFACT_ID=$ARTIFACT_ID" >> "$GITHUB_OUTPUT"
GROUP_ID=$(mvn -q -s .ci-config/settings.xml $PROF help:evaluate \
-Dexpression=project.groupId -DforceStdout)
echo "GROUP_ID=$GROUP_ID" >> "$GITHUB_OUTPUT"
PROJECT_NAME=$(mvn -q -s .ci-config/settings.xml $PROF help:evaluate \
-Dexpression=project.artifactId -DforceStdout)
echo "PROJECT_NAME=$PROJECT_NAME" >> "$GITHUB_OUTPUT"
MAJOR=$(echo "$RELEASE_VERSION" | cut -d. -f1)
MINOR=$(echo "$RELEASE_VERSION" | cut -d. -f2)
PATCH=$(echo "$RELEASE_VERSION" | cut -d. -f3)
NEXT_VERSION="$MAJOR.$MINOR.$((PATCH + 1))-SNAPSHOT"
echo "NEXT_VERSION=$NEXT_VERSION" >> "$GITHUB_OUTPUT"
echo "── Riepilogo ──"
echo " release : $RELEASE_VERSION"
echo " artifactId: $ARTIFACT_ID"
echo " groupId : $GROUP_ID"
echo " next : $NEXT_VERSION"
# ── Check Nexus ────────────────────────────────────────────
- name: Verifica che la versione non esista già su Nexus
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
ARTIFACT_ID="${{ steps.version.outputs.ARTIFACT_ID }}"
GROUP_PATH=$(echo "${{ steps.version.outputs.GROUP_ID }}" | tr '.' '/')
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-u "$MAVEN_USERNAME:$MAVEN_PASSWORD" \
"${MAVEN_REPO_RELEASES_URL}/${GROUP_PATH}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.pom")
if [ "$HTTP_CODE" = "200" ]; then
echo "ERRORE: la versione $VERSION esiste già su Nexus!"
exit 1
fi
echo "OK: versione $VERSION non presente su Nexus (HTTP $HTTP_CODE)"
# ── Build & Deploy ─────────────────────────────────────────
- name: Build + Deploy artifact + Push immagine Docker
run: |
PROF=""
[ -n "$MVN_PROFILES" ] && PROF="-P$MVN_PROFILES"
mvn -B -U $PROF -s .ci-config/settings.xml -DskipTests \
-Djib.to.auth.username="$MAVEN_USERNAME" \
-Djib.to.auth.password="$MAVEN_PASSWORD" \
-Djib.from.auth.username="$MAVEN_USERNAME" \
-Djib.from.auth.password="$MAVEN_PASSWORD" \
clean deploy
# ── Tag & Bump ─────────────────────────────────────────────
- name: Commit release e tag
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
git add pom.xml
git commit -m "release: ${VERSION} [skip ci]"
git tag -a "${VERSION}" -m "Release ${VERSION}"
- name: Avanza a prossima versione SNAPSHOT
run: |
PROF=""
[ -n "$MVN_PROFILES" ] && PROF="-P$MVN_PROFILES"
NEXT="${{ steps.version.outputs.NEXT_VERSION }}"
mvn -B -s .ci-config/settings.xml $PROF versions:set \
-DnewVersion="$NEXT" -DgenerateBackupPoms=false
git add pom.xml
git commit -m "chore: avanza versione a ${NEXT} [skip ci]"
- name: Push release + tag + versione successiva
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
git push origin HEAD "${VERSION}"
# ── Gitea Release ──────────────────────────────────────────
- name: Crea release su Gitea
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
ARTIFACT_ID="${{ steps.version.outputs.ARTIFACT_ID }}"
GROUP_PATH=$(echo "${{ steps.version.outputs.GROUP_ID }}" | tr '.' '/')
JAR_URL="${MAVEN_REPO_RELEASES_URL}/${GROUP_PATH}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.jar"
DOCKER_IMAGE="${{ inputs.docker-registry }}/biters/${ARTIFACT_ID}:${VERSION}"
BODY="## Artifacts
- **JAR**: [${ARTIFACT_ID}-${VERSION}.jar](${JAR_URL})
- **Docker**: \`${DOCKER_IMAGE}\`"
curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"https://git.biters.it/api/v1/repos/${{ github.repository }}/releases" \
-d "$(jq -n \
--arg tag "$VERSION" \
--arg name "v${VERSION}" \
--arg body "$BODY" \
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')"
# ── Rebase develop ─────────────────────────────────────────
- name: Rebase develop su master
run: |
git fetch origin develop
git checkout develop
git rebase origin/${{ github.ref_name }}
git push origin develop --force-with-lease
# ── Aggiorna docker-compose (opzionale) ────────────────────
- name: Clona repo compose e aggiorna versione immagine
if: ${{ inputs.compose-repo != '' }}
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
PROJECT_NAME="${{ steps.version.outputs.PROJECT_NAME }}"
REGISTRY="${{ inputs.docker-registry }}"
COMPOSE_REPO="${{ inputs.compose-repo }}"
git clone "https://biters.gitea:${GITEA_TOKEN}@git.biters.it/${COMPOSE_REPO}.git" /tmp/compose-repo
cd /tmp/compose-repo
git config user.name "CI Release Bot"
git config user.email "ci@biters.it"
ESCAPED_REGISTRY=$(echo "$REGISTRY" | sed 's/\./\\./g')
find . -name 'docker-compose*.yml' -exec \
sed -i "s|\(${ESCAPED_REGISTRY}/biters/${PROJECT_NAME}:\)[^ \"']*|\1${VERSION}|g" {} +
- name: Verifica variabili environment
if: ${{ inputs.compose-repo != '' }}
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
PROJECT_NAME="${{ steps.version.outputs.PROJECT_NAME }}"
COMPOSE_REPO="${{ inputs.compose-repo }}"
APP_YML="${GITHUB_WORKSPACE}/src/main/resources/application.yml"
if [ ! -f "$APP_YML" ]; then
echo "application.yml non trovato, skip verifica variabili."
exit 0
fi
ALL_PLACEHOLDERS=$(grep -oP '\$\{[^}]+\}' "$APP_YML" | sort -u)
APP_VARS_REQUIRED=""
APP_VARS_WITH_DEFAULT=""
for ph in $ALL_PLACEHOLDERS; do
var=$(echo "$ph" | sed 's/\${//;s/[:}].*//')
echo "$var" | grep -q '\.' && continue
if echo "$ph" | grep -q ':'; then
APP_VARS_WITH_DEFAULT=$(printf '%s\n%s' "$APP_VARS_WITH_DEFAULT" "$var")
else
APP_VARS_REQUIRED=$(printf '%s\n%s' "$APP_VARS_REQUIRED" "$var")
fi
done
APP_VARS_REQUIRED=$(echo "$APP_VARS_REQUIRED" | grep -v '^$' | sort -u)
APP_VARS_WITH_DEFAULT=$(echo "$APP_VARS_WITH_DEFAULT" | grep -v '^$' | sort -u)
APP_VARS_ALL=$(printf '%s\n%s' "$APP_VARS_REQUIRED" "$APP_VARS_WITH_DEFAULT" | grep -v '^$' | sort -u)
echo "Variabili application.yml:"
echo " Obbligatorie: $(echo "$APP_VARS_REQUIRED" | wc -w)"
echo " Con default: $(echo "$APP_VARS_WITH_DEFAULT" | wc -w)"
MISSING=""
cd /tmp/compose-repo
for compose_file in docker-compose-*.yml; do
[ -f "$compose_file" ] || continue
ENV_NAME=${compose_file#docker-compose-}
ENV_NAME=${ENV_NAME%.yml}
ENV_FILE=".env_${ENV_NAME}"
echo ""
echo "── ${compose_file} ──"
COMMON_VARS=$(yq '.services["common-env-hc"].environment // {} | keys | .[]' \
"$compose_file" 2>/dev/null || true)
SVC_VARS=$(yq ".services | to_entries[] |
select(.value.image // \"\" | test(\"${PROJECT_NAME}\")) |
.value.environment // {} | keys | .[]" \
"$compose_file" 2>/dev/null || true)
COMPOSE_VARS=$(printf '%s\n%s' "$COMMON_VARS" "$SVC_VARS" | grep -v '^$' | sort -u)
for var in $APP_VARS_ALL; do
if ! echo "$COMPOSE_VARS" | grep -qx "$var"; then
severity="REQUIRED"
echo "$APP_VARS_WITH_DEFAULT" | grep -qx "$var" && severity="HAS_DEFAULT"
MISSING="${MISSING}| \`${var}\` | \`${compose_file}\` | ${severity} |\n"
fi
done
if [ -f "$ENV_FILE" ]; then
ENV_REFS=$(grep -oP '\$\{\K\w+(?=\})' "$compose_file" | sort -u)
for ref in $ENV_REFS; do
if ! grep -q "^${ref}=" "$ENV_FILE"; then
MISSING="${MISSING}| \`${ref}\` | \`${ENV_FILE}\` | REQUIRED |\n"
fi
done
fi
done
if [ -n "$MISSING" ]; then
echo ""
echo "VARIABILI MANCANTI:"
printf '%b' "$MISSING"
ISSUE_BODY="## Variabili mancanti — ${PROJECT_NAME} v${VERSION}
La pipeline di release ha rilevato variabili non censite:
| Variabile | File | Severità |
|-----------|------|----------|
$(printf '%b' "$MISSING")
**REQUIRED** = nessun default, il servizio non parte senza.
**HAS_DEFAULT** = ha un default in application.yml, verificare se adeguato.
### Azione richiesta
Aggiungere le variabili mancanti nei rispettivi file e committare su ${COMPOSE_REPO}."
curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"https://git.biters.it/api/v1/repos/${COMPOSE_REPO}/issues" \
-d "$(jq -n \
--arg title "[CI] Variabili mancanti: ${PROJECT_NAME} v${VERSION}" \
--arg body "$ISSUE_BODY" \
'{title: $title, body: $body}')"
echo ""
echo "Issue creata su ${COMPOSE_REPO}. Push bloccato."
exit 1
fi
echo "Tutte le variabili sono correttamente censite."
- name: Push docker-compose aggiornato
if: ${{ inputs.compose-repo != '' }}
run: |
VERSION="${{ steps.version.outputs.RELEASE_VERSION }}"
PROJECT_NAME="${{ steps.version.outputs.PROJECT_NAME }}"
cd /tmp/compose-repo
if git diff --quiet; then
echo "Nessuna modifica necessaria ai docker-compose"
else
git add -A
git commit -m "chore(${PROJECT_NAME}): aggiorna immagine a ${VERSION}"
git push origin HEAD
echo "Docker-compose aggiornati con versione ${VERSION}"
fi