Skip to content

fix: production ready docker build with ci workflow #1

fix: production ready docker build with ci workflow

fix: production ready docker build with ci workflow #1

name: Docker CI Pull Request Target
on:
# pull_request_target:
# branches:
# - main
# types: [opened, synchronize, reopened]
jobs:
# FIRST JOB #######################################################################
build-test-image:
name: Build Image for Testing
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ghcr.io registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for the Docker image
id: docker_meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: ${{ github.run_id }}
- name: Build and Push to GHCR
uses: docker/build-push-action@v5
with:
file: infra/docker/web/Dockerfile
push: true
tags: ${{ steps.docker_meta.outputs.tags }}
cache-to: type=gha,scope=base,mode=max
cache-from: type=gha,scope=base
platforms: linux/amd64
# NEXT JOB #######################################################################
unit-test:
name: Unit Test in Docker
needs: [build-test-image]
runs-on: ubuntu-latest
permissions:
packages: read
contents: read
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ghcr.io registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Unit-Test
uses: docker/build-push-action@v5
with:
file: infra/docker/web/Dockerfile
target: unit-test
push: false
cache-to: type=gha,scope=test,mode=max
cache-from: |
type=gha,scope=base
type=gha,scope=test
platforms: linux/amd64
# NEXT JOB #######################################################################
integration-test:
name: Integration Test in Compose
needs: [build-test-image]
runs-on: ubuntu-latest
permissions:
packages: read
contents: read
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ghcr.io registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Downcase repo name
run: |
echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Test healthcheck in Docker Compose
run: |
export TESTING_IMAGE=ghcr.io/${REPO}:"$GITHUB_RUN_ID"
echo Testing image: "$TESTING_IMAGE"
docker compose -f ./infra/docker/web/integration-test/compose.yml up -d calcom
echo "Waiting for the server to be healthy..."
sleep 60s
curl --fail http://localhost:3000 || exit 1
# NEXT JOB #######################################################################
scan-image:
name: Scan Image with Trivy
needs: [build-test-image]
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
security-events: write
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ghcr.io registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Downcase repo name
run: |
echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Run Trivy for HIGH,CRITICAL CVEs and report (non-blocking)
uses: aquasecurity/[email protected]
with:
image-ref: ghcr.io/${{env.REPO}}:${{ github.run_id }}
format: sarif
exit-code: 0
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'HIGH,CRITICAL'
timeout: 10m0s
output: 'trivy-results.sarif'
env:
TRIVY_USERNAME: ${{ github.repository_owner }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
# NEXT JOB #######################################################################
changelog:
name: Automated Changelog using Conventional Commit
needs: [build-test-image, unit-test, integration-test, scan-image]
runs-on: ubuntu-latest
outputs:
TAG: ${{ steps.docker_tag.outputs.TAG }}
permissions:
contents: write
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Check out the repository with all releases
uses: actions/checkout@v4
with:
persist-credentials: 'false'
ref: ${{github.event.repository.default_branch}}
- name: Conventional Changelog Action
id: changelog
uses: TriPSs/[email protected]
with:
github-token: ${{ secrets.RELEASE_MAIN }}
version-file: "./apps/web/package.json"
git-branch: ${{github.event.repository.default_branch}}
preset: "conventionalcommits"
input-file: "./apps/web/CHANGELOG.md"
output-file: "./apps/web/CHANGELOG.md"
tag-prefix: "v"
pre-release: "${{github.event_name == 'pull_request_target'}}"
pre-release-identifier: "alpha"
skip-on-empty: 'false'
skip-git-pull: true
- name: Create Release
uses: actions/create-release@v1
if: ${{ steps.changelog.outputs.skipped == 'false' }}
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_MAIN }}
with:
tag_name: ${{ steps.changelog.outputs.tag }}
release_name: ${{ steps.changelog.outputs.tag }}
body: ${{ steps.changelog.outputs.clean_changelog }}
- name: Export tag for final build
id: docker_tag
run: |
echo "TAG=${{ steps.changelog.outputs.tag }}" >> $GITHUB_OUTPUT
# NEXT JOB #######################################################################
build-final-image:
name: Build Final Image
needs: [unit-test, integration-test, scan-image, changelog]
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
pull-requests: write
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ghcr.io registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Metadata for Final Image Build
id: docker_meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/cal.com
tags: |
type=raw,value=${{needs.changelog.outputs.TAG}}
- name: Comment on pull request
uses: marocchino/sticky-pull-request-comment@v2
with:
header: final-image
message: |
image tag: ${{ steps.docker_meta.outputs.tags }}
image label: ${{ steps.docker_meta.outputs.labels }}
- name: Add labels
uses: actions-ecosystem/action-add-labels@v1
if: github.event_name == 'pull_request_target'
with:
labels: preview
- name: Docker Build and Push to Docker Hub
uses: docker/build-push-action@v5
with:
file: infra/docker/web/Dockerfile
push: true
tags: |
${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=gha,scope=base
platforms: linux/amd64
# NEXT JOB #######################################################################
tag-manifest-update-compose:
name: Tag Kubernetes Manifest and Update Compose
needs: [unit-test, integration-test, scan-image, changelog, build-final-image]
runs-on: ubuntu-latest
permissions:
contents: write
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened'
steps:
- name: Set default values for manifest tag
run: |
echo "PUSH_MANIFEST_TAG='false'" >> $GITHUB_ENV
echo "ENABLE_PREVIEW='false'" >> $GITHUB_ENV
echo "REMOTE_REPO=''" >> $GITHUB_ENV
echo "REMOTE_WORKFLOW=''" >> $GITHUB_ENV
echo "PREVIEW_WORKFLOW=''" >> $GITHUB_ENV
- name: Trigger Deployment Workflow
if: github.event_name == 'pull_request_target' && github.base_ref == 'refs/heads/main' && env.PUSH_MANIFEST_TAG == 'true' && env.ENABLE_PREVIEW == 'true'
uses: benc-uk/workflow-dispatch@v1
with:
workflow: ${{env.PREVIEW_WORKFLOW}}
repo: ${{ env.REMOTE_REPO }}
inputs: '{"image": "${{ secrets.DOCKERHUB_USERNAME }}/calcom:${{ needs.changelog.outputs.TAG }}" }'
token: "${{ secrets.RELEASE_MAIN }}"