commit 374f421732c227156d0dcfaf1c077ff16e5f5a91 Author: Torsten Ueberschar Date: Sat Jan 17 15:50:37 2026 +0100 so, mal sehn diff --git a/.github/workflows/build-and-push-call-example.yml b/.github/workflows/build-and-push-call-example.yml new file mode 100644 index 0000000..1808468 --- /dev/null +++ b/.github/workflows/build-and-push-call-example.yml @@ -0,0 +1,13 @@ +name: Build and Push (via reusable workflow) +run-name: ${{ gitea.actor }} triggers build-and-push + +on: + workflow_dispatch: + +jobs: + build-and-push: + uses: tanztee/ci-cd/.github/workflows/build-and-push.yml@main + secrets: + REGISTRY: ${{ secrets.REGISTRY }} + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml new file mode 100644 index 0000000..3223cbe --- /dev/null +++ b/.github/workflows/build-and-push.yml @@ -0,0 +1,174 @@ +name: Build and Push Docker Image +run-name: ${{ gitea.actor }} builds and pushes image + +on: + workflow_call: + inputs: + registry: + description: Container registry hostname (defaults to secret REGISTRY) + type: string + default: "" + image_name: + description: Full image name including registry (defaults to REGISTRY/repo) + type: string + default: "" + dockerfile: + description: Path to Dockerfile + type: string + default: Dockerfile + context: + description: Build context + type: string + default: . + push: + description: Push image after build + type: boolean + default: true + secrets: + REGISTRY: + description: Container registry hostname + required: false + REGISTRY_USERNAME: + description: Registry username + required: true + REGISTRY_PASSWORD: + description: Registry password or token + required: true + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + env: + REGISTRY: ${{ inputs.registry != '' && inputs.registry || secrets.REGISTRY }} + IMAGE_NAME: ${{ inputs.image_name }} + REPO: ${{ gitea.repository }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Resolve image name + run: | + if [ -z "${IMAGE_NAME}" ]; then + IMAGE_NAME="${REGISTRY}/${REPO}" + fi + echo "IMAGE_NAME=${IMAGE_NAME}" >> "$GITHUB_ENV" + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Validate registry configuration + run: | + if [ -z "${REGISTRY}" ]; then + echo "::error::REGISTRY secret is missing or empty" + exit 1 + fi + if [ -z "${IMAGE_NAME}" ] || [[ "${IMAGE_NAME}" == */ ]]; then + echo "::error::IMAGE_NAME is empty or malformed (resolved to '${IMAGE_NAME}')" + exit 1 + fi + + - name: Derive image tags + id: vars + run: | + IMAGE="${IMAGE_NAME}" + TAG_NAME="" + REF="${GITHUB_REF:-${GITEA_REF}}" + SHA="${GITHUB_SHA:-${GITEA_SHA}}" + BRANCH="" + SHORT_SHA="$(git rev-parse --short=7 "${SHA}")" + TAGS=() + + # Extract tag name when we are on a tag ref (e.g. v1.4) + if [[ "${REF}" =~ refs/tags/(.+) ]]; then + TAG_NAME="${BASH_REMATCH[1]}" + fi + + if [[ "${REF}" =~ refs/heads/(.+) ]]; then + BRANCH="${BASH_REMATCH[1]}" + else + # Tag build: detect which branch contains the tagged commit + git fetch --no-tags --depth=1 origin main release develop || true + if git branch -r --contains "${SHA}" | grep -q "origin/main"; then + BRANCH="main" + elif git branch -r --contains "${SHA}" | grep -q "origin/release"; then + BRANCH="release" + elif git branch -r --contains "${SHA}" | grep -q "origin/develop"; then + BRANCH="develop" + fi + fi + + TAGS+=("${IMAGE}:${SHORT_SHA}") + [[ -n "${TAG_NAME}" ]] && TAGS+=("${IMAGE}:${TAG_NAME}") + + case "${BRANCH}" in + main) + TAGS+=("${IMAGE}:latest") + ;; + release*) + TAGS+=("${IMAGE}:latest-rc") + ;; + develop) + TAGS+=("${IMAGE}:latest-dev") + ;; + *) + TAGS+=("${IMAGE}:latest-snapshot") + ;; + esac + + echo "Computed tags:" + printf '%s\n' "${TAGS[@]}" + { + echo "tags<> "$GITHUB_OUTPUT" + + - name: Show build summary + run: | + echo "Commit: ${GITHUB_SHA:-${GITEA_SHA}}" + echo "Image: ${IMAGE_NAME}" + echo "Tags:" + printf '%s\n' "${{ steps.vars.outputs.tags }}" + + - name: Determine deploy target + id: deploy + run: | + REF="${GITHUB_REF:-${GITEA_REF}}" + SHA="${GITHUB_SHA:-${GITEA_SHA}}" + TARGET="dev" + if [[ "${REF}" == "refs/heads/main" ]]; then + TARGET="prod" + elif [[ "${REF}" =~ refs/tags/ ]]; then + # Tag builds deploy to prod only if the tagged commit is in main + git fetch --no-tags --depth=1 origin main || true + if git branch -r --contains "${SHA}" | grep -q "origin/main"; then + TARGET="prod" + fi + fi + echo "Deploy target: ${TARGET}" + echo "target=${TARGET}" >> "$GITHUB_OUTPUT" + + - name: Build and push image + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.context }} + file: ${{ inputs.dockerfile }} + push: ${{ inputs.push }} + tags: ${{ steps.vars.outputs.tags }} + build-args: | + VITE_KEYCLOAK_URL=${{ vars.VITE_KEYCLOAK_URL }} + VITE_KEYCLOAK_REALM=${{ vars.VITE_KEYCLOAK_REALM }} + VITE_KEYCLOAK_CLIENT_ID=${{ vars.VITE_KEYCLOAK_CLIENT_ID }} diff --git a/.github/workflows/bump-version-call-example.yaml b/.github/workflows/bump-version-call-example.yaml new file mode 100644 index 0000000..93d2800 --- /dev/null +++ b/.github/workflows/bump-version-call-example.yaml @@ -0,0 +1,17 @@ +name: Bump Version (via reusable workflow) +run-name: ${{ gitea.actor }} triggers bump-version + +on: + workflow_dispatch: + push: + branches: + - main + - develop + +jobs: + bump-version: + uses: tanztee/ci-cd/.github/workflows/bump-version.yaml@main + with: + node_version: "24" + secrets: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} diff --git a/.github/workflows/bump-version.yaml b/.github/workflows/bump-version.yaml new file mode 100644 index 0000000..1844e87 --- /dev/null +++ b/.github/workflows/bump-version.yaml @@ -0,0 +1,80 @@ +name: Bump Version +run-name: ${{ gitea.actor }} runs patch update + +on: + workflow_call: + inputs: + node_version: + description: Node.js version to use + type: string + default: "24" + secrets: + GITEA_TOKEN: + description: Token for checkout/push (optional) + required: false + +jobs: + bump-version: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + fetch-tags: true + token: ${{ secrets.GITEA_TOKEN }} + + - name: Setup Git + run: | + git config user.name "CI Bot" + git config user.email "ci@git.uesome.de" + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ inputs.node_version }} + + - name: Bump patch version and tag + run: | + REF="${GITHUB_REF:-${GITEA_REF}}" + BRANCH="${REF#refs/heads/}" + git fetch origin "${BRANCH}" --tags + git checkout "${BRANCH}" + git pull --ff-only origin "${BRANCH}" + BRANCH_SAFE="$(echo "${BRANCH}" | tr '/[:space:].' '-' | tr -cd '[:alnum:]_-')" + BRANCH_SAFE="$(echo "${BRANCH_SAFE}" | sed 's/^-*//;s/-*$//')" + BRANCH_SAFE="${BRANCH_SAFE:-unknown}" + case "${BRANCH}" in + main) + COMMIT_MSG="$(git log -1 --pretty=%B)" + TARGET_VERSION="" + if [[ "${COMMIT_MSG}" =~ release/([0-9]+)\.([0-9]+) ]]; then + TARGET_VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.0" + elif [[ "${COMMIT_MSG}" =~ hotfix/([0-9]+\.[0-9]+\.[0-9]+) ]]; then + TARGET_VERSION="${BASH_REMATCH[1]}" + fi + + if [[ -n "${TARGET_VERSION}" ]]; then + if git rev-parse -q --verify "refs/tags/v${TARGET_VERSION}" >/dev/null; then + echo "Tag v${TARGET_VERSION} already exists; skipping version bump." + exit 0 + fi + TAG="$(npm version "${TARGET_VERSION}" -m "update version: %s")" + else + TAG="$(npm version patch -m "update version: %s")" + fi + ;; + develop) + TAG="$(npm version prerelease --preid=dev -m "update version: %s")" + ;; + release*) + TAG="$(npm version prerelease --preid=rc-${BRANCH_SAFE} -m "update version: %s")" + ;; + *) + TAG="$(npm version prerelease --preid=nightly-${BRANCH_SAFE} -m "update version: %s")" + ;; + esac + + git push origin HEAD + git push origin "${TAG}" diff --git a/.github/workflows/deploy-k8s-call-example.yml b/.github/workflows/deploy-k8s-call-example.yml new file mode 100644 index 0000000..61d02a8 --- /dev/null +++ b/.github/workflows/deploy-k8s-call-example.yml @@ -0,0 +1,19 @@ +name: Deploy to Kubernetes (via reusable workflow) +run-name: ${{ gitea.actor }} triggers deploy-k8s + +on: + workflow_dispatch: + inputs: + tag: + description: Image tag to deploy (e.g. v1.2.3) + required: true + type: string + +jobs: + deploy: + uses: tanztee/ci-cd/.github/workflows/deploy-k8s.yml@main + with: + tag: ${{ inputs.tag }} + secrets: + KUBECONFIG: ${{ secrets.KUBECONFIG }} + REGISTRY: ${{ secrets.REGISTRY }} diff --git a/.github/workflows/deploy-k8s.yml b/.github/workflows/deploy-k8s.yml new file mode 100644 index 0000000..5ccb2df --- /dev/null +++ b/.github/workflows/deploy-k8s.yml @@ -0,0 +1,76 @@ +name: Deploy Image to Kubernetes +run-name: ${{ gitea.actor }} deploys to k8s + +on: + workflow_call: + inputs: + tag: + description: Image tag to deploy (e.g. v1.2.3) + type: string + required: true + deployment: + description: Kubernetes Deployment name + type: string + default: oumta-app + container: + description: Container name in the Deployment to update + type: string + default: app + namespace: + description: Kubernetes namespace + type: choice + default: oumta-dev + options: + - oumta-dev + - oumta-beta + - oumta-app + registry: + description: Container registry hostname (defaults to secret REGISTRY) + type: string + default: "" + image_name: + description: Full image name including registry (defaults to REGISTRY/repo) + type: string + default: "" + secrets: + KUBECONFIG: + description: Kubeconfig content + required: true + REGISTRY: + description: Container registry hostname + required: false + +jobs: + deploy: + runs-on: ubuntu-latest + env: + REGISTRY: ${{ inputs.registry != '' && inputs.registry || secrets.REGISTRY }} + IMAGE_NAME: ${{ inputs.image_name }} + REPO: ${{ gitea.repository }} + steps: + - name: Install kubectl + uses: azure/setup-kubectl@v4 + + - name: Resolve image name + run: | + if [ -z "${IMAGE_NAME}" ]; then + IMAGE_NAME="${REGISTRY}/${REPO}" + fi + echo "IMAGE_NAME=${IMAGE_NAME}" >> "$GITHUB_ENV" + + - name: Configure kubeconfig + env: + KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }} + run: | + mkdir -p ~/.kube + printf '%s' "$KUBECONFIG_CONTENT" > ~/.kube/config + chmod 600 ~/.kube/config + + - name: Update deployment image + run: | + IMAGE="${IMAGE_NAME}:${{ inputs.tag }}" + kubectl set image deployment/${{ inputs.deployment }} \ + ${{ inputs.container }}=${IMAGE} \ + --namespace ${{ inputs.namespace }} + kubectl rollout status deployment/${{ inputs.deployment }} \ + --namespace ${{ inputs.namespace }} diff --git a/README.md b/README.md new file mode 100644 index 0000000..df46257 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +## Reusable Workflows + +This repo provides reusable Gitea Actions workflows that can be referenced with `uses:`. + +### Bump Version + +Example: + +```yaml +jobs: + bump-version: + uses: tanztee/ci-cd/.github/workflows/bump-version.yaml@main + secrets: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} +``` + +### Build and Push Docker Image + +Example: + +```yaml +jobs: + build-and-push: + uses: tanztee/ci-cd/.github/workflows/build-and-push.yml@main + secrets: + REGISTRY: ${{ secrets.REGISTRY }} + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} +``` + +### Deploy Image to Kubernetes + +Example: + +```yaml +on: + workflow_dispatch: + inputs: + tag: + description: Image tag to deploy (e.g. v1.2.3) + required: true + type: string + +jobs: + deploy: + uses: tanztee/ci-cd/.github/workflows/deploy-k8s.yml@main + with: + tag: ${{ inputs.tag }} + namespace: oumta-dev + secrets: + KUBECONFIG: ${{ secrets.KUBECONFIG }} + REGISTRY: ${{ secrets.REGISTRY }} +```