All checks were successful
CI Pipeline / build (push) Successful in 40s
CI Pipeline / security-scan (push) Successful in 1m29s
CI Pipeline / autotag (push) Successful in 18s
CI Pipeline / push (push) Successful in 21s
CI Pipeline / update-cd (push) Successful in 17s
CI Pipeline / lint (push) Successful in 19s
CI Pipeline / test (push) Successful in 56s
Gitea doesn't trigger new workflows when tags are pushed by the workflow itself. Modified push job to: - Depend on autotag job - Use autotag outputs for version when not triggered by tag ref - Run when autotag succeeds OR when triggered by tag push
296 lines
9.4 KiB
YAML
296 lines
9.4 KiB
YAML
name: CI Pipeline
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- 'v*'
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
|
|
env:
|
|
REGISTRY: ${{ vars.REGISTRY_URL }}
|
|
IMAGE_NAME: enterprise-openldap
|
|
|
|
jobs:
|
|
# Stage 1: Lint Dockerfile
|
|
lint:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Lint Dockerfile with hadolint
|
|
run: |
|
|
docker run --rm -i hadolint/hadolint < Dockerfile || {
|
|
echo "::warning::Dockerfile linting found issues (non-blocking)"
|
|
}
|
|
|
|
# Stage 2: Build image
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
needs: lint
|
|
outputs:
|
|
image_tag: ${{ steps.version.outputs.VERSION }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Determine version tag
|
|
id: version
|
|
run: |
|
|
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
|
|
VERSION="${GITHUB_REF#refs/tags/v}"
|
|
else
|
|
VERSION="$(echo "$GITHUB_SHA" | cut -c1-7)"
|
|
fi
|
|
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "Building version: $VERSION"
|
|
|
|
- name: Build Docker image
|
|
run: |
|
|
docker build -t ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} .
|
|
docker tag ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} ${{ env.IMAGE_NAME }}:test
|
|
|
|
- name: Save image for subsequent jobs
|
|
run: |
|
|
mkdir -p /tmp/images
|
|
docker save ${{ env.IMAGE_NAME }}:test -o /tmp/images/image.tar
|
|
|
|
- name: Upload image artifact
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: docker-image
|
|
path: /tmp/images/image.tar
|
|
retention-days: 1
|
|
|
|
# Stage 3: Integration tests
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download image artifact
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: docker-image
|
|
path: /tmp/images
|
|
|
|
- name: Load Docker image
|
|
run: |
|
|
docker load -i /tmp/images/image.tar
|
|
|
|
- name: Run integration tests
|
|
run: |
|
|
chmod +x tests/test-container.sh
|
|
./tests/test-container.sh
|
|
env:
|
|
IMAGE_NAME: ${{ env.IMAGE_NAME }}:test
|
|
CONTAINER_NAME: openldap-ci-test
|
|
|
|
# Stage 4: Security scan
|
|
security-scan:
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
steps:
|
|
- name: Download image artifact
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: docker-image
|
|
path: /tmp/images
|
|
|
|
- name: Load Docker image
|
|
run: |
|
|
docker load -i /tmp/images/image.tar
|
|
|
|
- name: Scan image with Trivy
|
|
run: |
|
|
docker run --rm \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
aquasec/trivy:latest image \
|
|
--severity HIGH,CRITICAL \
|
|
--exit-code 0 \
|
|
--no-progress \
|
|
${{ env.IMAGE_NAME }}:test
|
|
|
|
- name: Scan for critical vulnerabilities (blocking)
|
|
run: |
|
|
docker run --rm \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
aquasec/trivy:latest image \
|
|
--severity CRITICAL \
|
|
--exit-code 1 \
|
|
--no-progress \
|
|
--ignore-unfixed \
|
|
${{ env.IMAGE_NAME }}:test || {
|
|
echo "::error::Critical vulnerabilities found!"
|
|
exit 1
|
|
}
|
|
|
|
# Stage 5: Auto-tag (only on main branch, not on tags or PRs)
|
|
autotag:
|
|
runs-on: ubuntu-latest
|
|
needs: [test, security-scan]
|
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
outputs:
|
|
new_tag: ${{ steps.autotag.outputs.new_tag }}
|
|
version: ${{ steps.autotag.outputs.version }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Need full history for autotag
|
|
|
|
- name: Configure git
|
|
run: |
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
- name: Run autotag
|
|
id: autotag
|
|
run: |
|
|
# Check if any tags exist
|
|
CURRENT_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
|
|
if [ -z "$CURRENT_TAG" ]; then
|
|
echo "No existing tags found, starting at v0.1.0"
|
|
NEW_TAG="v0.1.0"
|
|
else
|
|
echo "Current tag: $CURRENT_TAG"
|
|
|
|
# Download autotag
|
|
AUTOTAG_VERSION="1.3.9"
|
|
curl -sL "https://github.com/autotag-dev/autotag/releases/download/v${AUTOTAG_VERSION}/autotag_linux_amd64" -o /tmp/autotag
|
|
chmod +x /tmp/autotag
|
|
|
|
# Calculate next version based on commits
|
|
# autotag looks for #major, #minor in commit messages, defaults to patch
|
|
NEW_TAG=$(/tmp/autotag -n -b main 2>&1 || echo "")
|
|
|
|
# Check if autotag returned an error or empty result
|
|
if [ -z "$NEW_TAG" ] || echo "$NEW_TAG" | grep -qi "error"; then
|
|
echo "Autotag failed or returned error, using fallback"
|
|
# Fallback: increment patch version
|
|
CURRENT_VERSION="${CURRENT_TAG#v}"
|
|
MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
|
|
MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
|
|
PATCH=$(echo $CURRENT_VERSION | cut -d. -f3)
|
|
NEW_PATCH=$((PATCH + 1))
|
|
NEW_TAG="v${MAJOR}.${MINOR}.${NEW_PATCH}"
|
|
fi
|
|
fi
|
|
|
|
echo "New tag will be: $NEW_TAG"
|
|
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT
|
|
echo "version=${NEW_TAG#v}" >> $GITHUB_OUTPUT
|
|
|
|
- name: Create and push tag
|
|
run: |
|
|
NEW_TAG="${{ steps.autotag.outputs.new_tag }}"
|
|
|
|
# Check if tag already exists
|
|
if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then
|
|
echo "Tag $NEW_TAG already exists, skipping"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Creating tag: $NEW_TAG"
|
|
git tag -a "$NEW_TAG" -m "Release $NEW_TAG (auto-generated)"
|
|
git push origin "$NEW_TAG"
|
|
echo "Successfully pushed tag: $NEW_TAG"
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# Stage 6: Push to registry
|
|
# Runs after autotag (on main) or after tests (on tag push)
|
|
push:
|
|
runs-on: ubuntu-latest
|
|
needs: [test, security-scan, autotag]
|
|
if: |
|
|
always() &&
|
|
needs.test.result == 'success' &&
|
|
needs.security-scan.result == 'success' &&
|
|
github.event_name == 'push' &&
|
|
(needs.autotag.result == 'success' || startsWith(github.ref, 'refs/tags/v'))
|
|
outputs:
|
|
version: ${{ steps.version.outputs.VERSION }}
|
|
full_image: ${{ steps.version.outputs.FULL_IMAGE }}
|
|
steps:
|
|
- name: Download image artifact
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: docker-image
|
|
path: /tmp/images
|
|
|
|
- name: Load Docker image
|
|
run: |
|
|
docker load -i /tmp/images/image.tar
|
|
|
|
- name: Determine version and tags
|
|
id: version
|
|
run: |
|
|
# Get version from autotag output or from git ref
|
|
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
|
|
VERSION="${GITHUB_REF#refs/tags/v}"
|
|
else
|
|
# Use version from autotag job
|
|
VERSION="${{ needs.autotag.outputs.version }}"
|
|
fi
|
|
|
|
if [ -z "$VERSION" ]; then
|
|
echo "::error::No version determined"
|
|
exit 1
|
|
fi
|
|
|
|
# For releases, tag with version, major.minor, and latest
|
|
MAJOR=$(echo $VERSION | cut -d. -f1)
|
|
MINOR=$(echo $VERSION | cut -d. -f2)
|
|
TAGS="${VERSION},${MAJOR}.${MINOR},latest"
|
|
|
|
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "TAGS=$TAGS" >> $GITHUB_OUTPUT
|
|
echo "FULL_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}" >> $GITHUB_OUTPUT
|
|
echo "Pushing version: $VERSION"
|
|
|
|
- name: Log in to Docker Registry
|
|
run: |
|
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
|
|
|
- name: Tag and push images
|
|
run: |
|
|
IFS=',' read -ra TAGS <<< "${{ steps.version.outputs.TAGS }}"
|
|
for TAG in "${TAGS[@]}"; do
|
|
docker tag ${{ env.IMAGE_NAME }}:test ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$TAG
|
|
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$TAG
|
|
echo "Pushed: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$TAG"
|
|
done
|
|
|
|
- name: Logout from registry
|
|
if: always()
|
|
run: docker logout ${{ env.REGISTRY }} || true
|
|
|
|
# Stage 7: Update CD pipeline (trigger deployment)
|
|
update-cd:
|
|
runs-on: ubuntu-latest
|
|
needs: push
|
|
if: needs.push.result == 'success'
|
|
steps:
|
|
- name: Trigger CD pipeline
|
|
run: |
|
|
echo "=============================================="
|
|
echo " Ready to update CD pipeline"
|
|
echo "=============================================="
|
|
echo "New version: ${{ needs.push.outputs.version }}"
|
|
echo "Full image: ${{ needs.push.outputs.full_image }}"
|
|
echo ""
|
|
echo "TODO: Add step to update version in CD repository"
|
|
echo "This could be:"
|
|
echo " - Update docker-compose.yml in infra repo"
|
|
echo " - Update Helm values"
|
|
echo " - Trigger ArgoCD sync"
|
|
echo "=============================================="
|