Skip to content

Continuous Delivery #1429

Continuous Delivery

Continuous Delivery #1429

Workflow file for this run

name: Continuous Delivery
on:
push:
branches:
- main
paths-ignore:
- 'image-catalogs/**'
workflow_dispatch:
env:
IMAGE_GHCR_DEV: ghcr.io/enterprisedb/postgresql-testing
IMAGE_GHCR: ghcr.io/enterprisedb/postgresql
IMAGE_QUAY_DEV: quay.io/enterprisedb/postgresql-testing
IMAGE_QUAY: quay.io/enterprisedb/postgresql
jobs:
generate-jobs:
name: Generate Jobs
runs-on: ubuntu-22.04
outputs:
strategy: ${{ steps.generate-jobs.outputs.strategy }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Generate Jobs
id: generate-jobs
shell: bash
run: |
bash .github/generate-strategy.sh
build:
needs: generate-jobs
strategy: ${{ fromJson(needs.generate-jobs.outputs.strategy) }}
name: ${{ matrix.name }}
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Docker meta
env:
TAGS: ${{ toJson(matrix.tags) }}
run: |
RESULT=""
for tag in $(jq -r '.[]' <<< "${TAGS}")
do
# dev tags
RESULT="${RESULT},${IMAGE_GHCR_DEV}:${tag}"
RESULT="${RESULT},${IMAGE_QUAY_DEV}:${tag}"
# If we are running the pipeline in the main branch images are pushed in both -testing and PROD repo
if [ "${GITHUB_REF#refs/heads/}" == main ]
then
# prod tags
RESULT="${RESULT},${IMAGE_GHCR}:${tag}"
RESULT="${RESULT},${IMAGE_QUAY}:${tag}"
fi
done
echo "TAGS=${RESULT%,}" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to quay.io
uses: docker/login-action@v3
with:
registry: quay.io/enterprisedb
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}
- name: Log in to the GitHub Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# When publishing new images from main, we should not overwrite an existing
# tag in order to guarantee the tag's SHA digest consistency.
- name: Verify primary tag is not overwritten
run: |
echo "MISSING_TAG=false" >> $GITHUB_ENV
# if we are not on the main branch, always push
if [ "${GITHUB_REF#refs/heads/}" != main ]; then
echo "MISSING_TAG=true" >> $GITHUB_ENV
exit 0
fi
IMAGE="${IMAGE_GHCR}:${{ matrix.fullTag }}"
# If the primary tag already exists, skip the building phase
if skopeo inspect docker://${IMAGE} >/dev/null 2>/dev/null; then
echo "Image ${IMAGE} already exists"
# We still need to grab the digest to build the imageCatalog
echo "OLD_DIGEST=$(skopeo inspect docker://${IMAGE} --format '{{ .Digest }}')" >> $GITHUB_ENV
else
echo "MISSING_TAG=true" >> $GITHUB_ENV
fi
- name: Build and load
uses: docker/build-push-action@v6
if: ${{ env.MISSING_TAG == 'true' }}
with:
context: ${{ matrix.dir }}
provenance: false
file: ${{ matrix.file }}
secrets: |
"cs_token=${{ secrets.CS_TOKEN }}"
"subscription=${{ secrets.SUBSCRIPTION }}"
push: false
load: true
tags: ${{ env.TAGS }}
build-args: |
SUBSCRIPTION_NAME=docker-postgresql-build-${{ github.run_number }}
- name: Dockle scan
uses: erzz/dockle-action@v1
if: ${{ env.MISSING_TAG == 'true' }}
env:
DOCKLE_IGNORES: CIS-DI-0009
with:
image: "${{ env.IMAGE_GHCR_DEV }}:${{ matrix.tags[0] }}"
exit-code: '1'
failure-threshold: WARN
accept-keywords: key
accept-filenames: usr/share/cmake/Templates/Windows/Windows_TemporaryKey.pfx,etc/trusted-key.key,usr/share/doc/perl-IO-Socket-SSL/certs/server_enc.p12,usr/share/doc/perl-IO-Socket-SSL/certs/server.p12,usr/share/postgresql-common/pgdg/apt.postgresql.org.asc,etc/ssl/private/ssl-cert-snakeoil.key,usr/local/lib/python3.11/site-packages/azure/core/settings.py
- name: Build and push
id: build
uses: docker/build-push-action@v6
if: ${{ env.MISSING_TAG == 'true' }}
with:
context: ${{ matrix.dir }}
file: ${{ matrix.file }}
secrets: |
"cs_token=${{ secrets.CS_TOKEN }}"
"subscription=${{ secrets.SUBSCRIPTION }}"
# Available architecture on UBI8 are: linux/amd64, linux/s390x, linux/ppc64le, linux/arm64
platforms: ${{ matrix.platforms }}
provenance: false
push: true
tags: ${{ env.TAGS }}
labels: ${{ github.ref != 'refs/heads/main' && 'quay.expires-after=7d' || '' }}
build-args: |
SUBSCRIPTION_NAME=docker-postgresql-cicd-${{ github.run_number }}
# Send a notification on release failure
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2
if: ${{ failure() && github.ref == 'refs/heads/main' }}
env:
SLACK_COLOR: ${{ job.status }}
SLACK_ICON: https://avatars.githubusercontent.com/u/44036562?size=48
SLACK_USERNAME: ghBot
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_MESSAGE: "Failure releasing PostgreSQL ${{ matrix.name }} image"
- name: Create artifact
run: |
# set a flavor suffix
FLAVOR_SUFFIX=""
FLAVOR=${{ matrix.flavor }}
if [ -n "${FLAVOR}" ]; then
FLAVOR_SUFFIX="-${FLAVOR}"
fi
echo FLAVOR_SUFFIX=${FLAVOR_SUFFIX} >> $GITHUB_ENV
# set the image name
CATALOG_NAME="postgresql"
if [[ "${FLAVOR}" =~ "postgis" ]]; then
CATALOG_NAME="postgis"
fi
# set the base images
BASE_IMAGE=${IMAGE_GHCR_DEV}
if [ "${GITHUB_REF#refs/heads/}" == main ]; then
BASE_IMAGE=${IMAGE_QUAY}
fi
# set a default registry suffix
REGISTRY_SUFFIX=""
# extract the registry
if [[ "$image" =~ "quay.io" ]]; then
REGISTRY_SUFFIX="-quay"
fi
if [[ "$image" =~ "ghcr.io" ]]; then
REGISTRY_SUFFIX="-ghcr"
fi
DIGEST="${{ steps.build.outputs.digest }}"
if [[ "${{ env.MISSING_TAG }}" == "false" ]]; then
DIGEST="${{ env.OLD_DIGEST }}"
fi
IMAGE=${BASE_IMAGE}:${{ matrix.fullTag }}@${DIGEST} \
MAJOR=${{ matrix.version }} \
NAME=${CATALOG_NAME} \
yq --null-input '{
"apiVersion": "postgresql.k8s.enterprisedb.io/v1",
"kind": "ClusterImageCatalog",
"metadata": {"name": env(NAME)},
"spec": {
"images": [
{
"major": env(MAJOR),
"image": env(IMAGE)
}
]
}
}' > "${{ matrix.version }}${FLAVOR_SUFFIX}${REGISTRY_SUFFIX}".yaml
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.version }}${{ env.FLAVOR_SUFFIX }}-clusterimagecatalog
path: ${{ matrix.version }}*.yaml
image-catalog:
name: Generate ClusterImageCatalog
runs-on: ubuntu-22.04
needs: build
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
token: ${{ secrets.REPO_GHA_PAT }}
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: '*-clusterimagecatalog'
path: clusterimagecatalog
merge-multiple: true
- name: Update ClusterImageCatalog
run: |
shopt -s extglob
mkdir -p image-catalogs/
for ubiVersion in 8 9; do
# standard
yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/[0-9][0-9]-ubi${ubiVersion}.yaml > image-catalogs/ClusterImageCatalog-ubi${ubiVersion}.yaml
# multilang
yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/[0-9][0-9]-ubi${ubiVersion}-multilang.yaml > image-catalogs/ClusterImageCatalog-ubi${ubiVersion}-multilang.yaml
# multiarch
yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/[0-9][0-9]-ubi${ubiVersion}-multiarch.yaml > image-catalogs/ClusterImageCatalog-ubi${ubiVersion}-multiarch.yaml
# postgis
yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/[0-9][0-9]-ubi${ubiVersion}-postgis.yaml > image-catalogs/ClusterImageCatalog-ubi${ubiVersion}-postgis.yaml
# postgis multilang
yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/[0-9][0-9]-ubi${ubiVersion}-postgis-multilang.yaml > image-catalogs/ClusterImageCatalog-ubi${ubiVersion}-postgis-multilang.yaml
# postgis multiarch
yq eval-all '. as $item ireduce ({}; . *+ $item )' clusterimagecatalog/[0-9][0-9]-ubi${ubiVersion}-postgis-multiarch.yaml > image-catalogs/ClusterImageCatalog-ubi${ubiVersion}-postgis-multiarch.yaml
done
cat image-catalogs/*.yaml
- name: Temporarily disable "include administrators" branch protection
if: ${{ always() && github.ref == 'refs/heads/main' }}
id: disable_include_admins
uses: benjefferies/[email protected]
with:
access_token: ${{ secrets.REPO_GHA_PAT }}
branch: main
enforce_admins: false
- name: Push ClusterImageCatalog updates
uses: EndBug/add-and-commit@v9
if: ${{ github.ref == 'refs/heads/main' }}
with:
author_name: EnterpriseDB Automated Updates
author_email: [email protected]
message: 'Automatic ClusterImageCatalog update'
add: 'image-catalogs/*'
- name: Enable "include administrators" branch protection
uses: benjefferies/[email protected]
if: ${{ always() && github.ref == 'refs/heads/main' }}
with:
access_token: ${{ secrets.REPO_GHA_PAT }}
branch: main
enforce_admins: ${{ steps.disable_include_admins.outputs.initial_status }}