Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .docker-hub/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:
frontend-image:
image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-frontend:${VERSION:-latest}
build:
context: ../
dockerfile: .docker-hub/frontend/Dockerfile
# they have to be registered in GitHub under exactly this name in secrets or vars
args:
SENTRY_AUTH_TOKEN: ${SENTRY_AUTH_TOKEN:-}
SENTRY_ORG: ${SENTRY_ORG:-}
SENTRY_FRONTEND_PROJECT: ${SENTRY_FRONTEND_PROJECT:-}
SENTRY_RELEASE_NAME: ${RELEASE_NAME:-}
print-image:
image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-print:${VERSION:-latest}
build:
context: ../
dockerfile: .docker-hub/print/Dockerfile
# they have to be registered in GitHub under exactly this name in secrets or vars
args:
SENTRY_AUTH_TOKEN: ${SENTRY_AUTH_TOKEN:-}
SENTRY_ORG: ${SENTRY_ORG:-}
SENTRY_PRINT_PROJECT: ${SENTRY_PRINT_PROJECT:-}
SENTRY_RELEASE_NAME: ${RELEASE_NAME:-}
varnish-image:
image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-varnish:${VERSION:-latest}
build:
context: ../
dockerfile: .docker-hub/varnish/Dockerfile
Comment on lines +2 to +28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the api and the db-backup-restore images which we were building before?

292 changes: 224 additions & 68 deletions .github/workflows/reusable-build-and-push.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: '[reusable only] Build images and push to registry'
name: "[reusable only] Build images and push to registry"

on:
workflow_dispatch:
workflow_call:
inputs:
tag:
Expand All @@ -17,91 +18,246 @@ on:
required: true
SENTRY_AUTH_TOKEN:

env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1

jobs:
build-info:
runs-on: ubuntu-latest
outputs:
repo-owner: ${{ steps.repo-owner.outputs.result }}
tags: ${{ steps.image-tags.outputs.image-tags }}
build-config: ${{ steps.build-info.outputs.result }}
steps:
#github forces lower case for the image name
- name: Get lowercase repo owner name
uses: actions/github-script@v7
id: repo-owner
with:
result-encoding: string
script: |
return context.repo.owner.toLowerCase()

- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Set nightly tag if commit was on main
id: add-nightly-tag
if: startsWith(github.ref, 'refs/heads/devel')
run: |
echo "nightly-tag=nightly" | tr -d "\n" >> $GITHUB_OUTPUT

- name: Set latest tag if its a tag
id: add-latest-tag
if: startsWith(github.ref, 'refs/tags/')
run: |
echo "latest-tag=latest" | tr -d "\n" >> $GITHUB_OUTPUT

- uses: actions/github-script@v7
id: get-tag
if: startsWith(github.ref, 'refs/tags/')
with:
result-encoding: string
script: |
return context.payload.ref.replace('refs/tags/', '')

- name: concat tags to list
id: image-tags
run: |
TAGS=$(cat <<-END
[
"${{ inputs.sha || github.sha }}",
"${{ steps.add-nightly-tag.outputs.nightly-tag }}",
"${{ steps.add-latest-tag.outputs.latest-tag }}",
"${{ steps.get-tag.outputs.result }}"
]
END
)
TAGS=$(echo $TAGS | jq -c 'map(select(length > 0))')
echo "image-tags=$TAGS" | tr -d "\n" >> $GITHUB_OUTPUT

- name: Get build info
id: build-info
run: |
set -x
sudo snap install yq

export REPO_NAME=$(basename $(pwd))
echo "services:" > /tmp/docker-compose.yml
for i in $(find . -name docker-compose.yml); do
docker compose -f $i config | yq '.services | select(.[].build != null and .[].image != null)' | sed 's/^/ /' >> /tmp/docker-compose.yml
done

cat /tmp/docker-compose.yml

yq_pipe='.services'
yq_pipe=$yq_pipe'| to_entries[]'
yq_pipe=$yq_pipe'| select(.value.build != null and .value.image != null)'
yq_pipe=$yq_pipe'| .value.build.image=.value.image'
yq_pipe=$yq_pipe'| .value.build.service=.key'
yq_pipe=$yq_pipe'| .value.build'
yq_pipe=$yq_pipe'| .dockerfile=.context + "/" + .dockerfile'
yq_pipe=$yq_pipe'| [.]'
cat /tmp/docker-compose.yml | yq "$yq_pipe"
BUILD_INFO=$(cat /tmp/docker-compose.yml | yq "$yq_pipe" -o=json)
BUILD_INFO=$(echo $BUILD_INFO | jq -c -s add | sed "s|:local||g")
echo $BUILD_INFO
echo "result=$BUILD_INFO" | tr -d "\n" >> $GITHUB_OUTPUT
env:
REPO_OWNER: ${{ vars.DOCKER_HUB_USERNAME || steps.repo-owner.outputs.result }}
VERSION: local

build-and-push:
name: Build images and push
runs-on: ubuntu-latest
name: "Build and push image ${{ matrix.build-config.service }}"
needs:
- build-info
strategy:
fail-fast: false
matrix:
build-config: ${{ fromJSON(needs.build-info.outputs.build-config) }}
env:
tags: ${{ needs.build-info.outputs.tags }}
repo-owner: ${{ needs.build-info.outputs.repo-owner }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
ref: ${{ inputs.sha }}
fetch-depth: 100
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fail


- run: |
echo "inputs:"
cat <<-HEREDOC
${{ toJSON(inputs) }}
HEREDOC

echo "build config:"
cat <<-HEREDOC
${{ toJSON(matrix.build-config) }}
HEREDOC

echo "build tags:"
cat <<-HEREDOC
${{ env.tags }}
HEREDOC

echo "build repo owner:"
cat <<-HEREDOC
${{ env.repo-owner }}
HEREDOC

if [ ! echo "${{ matrix.build-config.image }}" | grep -Eq '^[a-zA-Z0-9._/-]+$' ]; then
echo "Error: Invalid Docker image name '${{ matrix.build-config.image }}'."
exit 1
fi

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKER_HUB_USERNAME }}
username: ${{ vars.DOCKER_HUB_USERNAME || env.repo-owner }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}

- name: Build and push frontend docker image
uses: docker/build-push-action@v6
with:
push: true
file: .docker-hub/frontend/Dockerfile
tags: |
${{ ((inputs.tag != '') && format('{0}/ecamp3-frontend:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }}
${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-frontend:${{ inputs.sha }}
context: .
build-args: |
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG=${{ vars.SENTRY_ORG }}
SENTRY_FRONTEND_PROJECT=${{ vars.SENTRY_FRONTEND_PROJECT }}
SENTRY_RELEASE_NAME=${{ inputs.sha }}
cache-from: type=gha,scope=frontend
cache-to: type=gha,scope=frontend,mode=max

- name: Build and push api docker image
uses: docker/build-push-action@v6
- name: find latest commit for image tag
id: get-latest-commit
run: |
set -x
context=$( echo '${{ toJSON(matrix.build-config) }}' | jq -r '.context' | sed "s|$PWD|.|g")
echo "context: $context"
dockerfile=$( echo '${{ toJSON(matrix.build-config) }}' | jq -r '.dockerfile' | sed "s|$PWD|.|g")
echo "dockerfile: $dockerfile"
git log --stat -n 1 $context $dockerfile
latest_commit=$(git log --pretty=format:"%H" -n 1 $context $dockerfile)
echo "latest_commit: $latest_commit"
echo "result=$latest_commit" | tr -d "\n" >> $GITHUB_OUTPUT

- name: check if image already exists
id: check-image
run: |
set +e
docker pull ${{ matrix.build-config.image }}:${{ steps.get-latest-commit.outputs.result }}
image_exists=$?
set -e
if ([ $image_exists -eq 0 ]); then
echo "image already exists"
echo "result=true" | tr -d "\n" >> $GITHUB_OUTPUT
else
echo "image does not exist"
echo "result=false" | tr -d "\n" >> $GITHUB_OUTPUT
fi

- name: Add latest commit to image tag if image does not exist
id: add-latest-commit-to-tags-if-image-does-not-exist
uses: actions/github-script@v7
with:
push: true
file: api/Dockerfile
tags: |
${{ ((inputs.tag != '') && format('{0}/ecamp3-api:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }}
${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-api:${{ inputs.sha }}
context: './api'
target: frankenphp_prod
cache-from: type=gha,scope=api
cache-to: type=gha,scope=api,mode=max

- name: Build and push print docker image
uses: docker/build-push-action@v6
script: |
if (!${{ steps.check-image.outputs.result }}) {
return [...JSON.parse('${{ env.tags }}'), '${{ steps.get-latest-commit.outputs.result }}']
}
return JSON.parse('${{ env.tags }}')

- uses: actions/github-script@v7
id: expand-tags
with:
push: true
file: .docker-hub/print/Dockerfile
tags: |
${{ ((inputs.tag != '') && format('{0}/ecamp3-print:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }}
${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-print:${{ inputs.sha }}
context: .
build-args: |
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG=${{ vars.SENTRY_ORG }}
SENTRY_PRINT_PROJECT=${{ vars.SENTRY_PRINT_PROJECT }}
SENTRY_RELEASE_NAME=${{ inputs.sha }}
cache-from: type=gha,scope=print
cache-to: type=gha,scope=print,mode=max

- name: Build and push varnish docker image
uses: docker/build-push-action@v6
script: |
return JSON.parse('${{ steps.add-latest-commit-to-tags-if-image-does-not-exist.outputs.result }}').map(tag => `${{ matrix.build-config.image }}:${ tag }`)

- name: populate build args from secrets/vars
if: steps.check-image.outputs.result == 'false'
id: populate-build-args
uses: actions/github-script@v7
with:
push: true
file: .docker-hub/varnish/Dockerfile
tags: |
${{ ((inputs.tag != '') && format('{0}/ecamp3-varnish:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }}
${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-varnish:${{ inputs.sha }}
context: .
cache-from: type=gha,scope=varnish
cache-to: type=gha,scope=varnish,mode=max

- name: Build and push db-backup-restore docker image
script: |
const buildArgValues = {
"SENTRY_AUTH_TOKEN" : "${{ secrets.SENTRY_AUTH_TOKEN }}",
"SENTRY_FRONTEND_PROJECT" : "${{ vars.SENTRY_FRONTEND_PROJECT }}",
"SENTRY_ORG" : "${{ vars.SENTRY_ORG }}",
"SENTRY_PRINT_PROJECT" : "${{ vars.SENTRY_PRINT_PROJECT }}",
"SENTRY_RELEASE_NAME" : "${{ inputs.sha }}",
Comment on lines +213 to +217
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to change in this PR, but can you explain why the sentry settings are build args instead of environment variables? This way they're baked into the images, right? Why is that beneficial for the sentry settings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was too lazy until now to split sentry release bundle generation and docker build.

}
const args = JSON.parse(`${{ toJSON(matrix.build-config.args) }}`)
let result = ""
for (const arg in args) {
if (buildArgValues[arg]) {
args[arg] = buildArgValues[arg]
}
}
Comment on lines +221 to +225
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have an override mechanism for these? As far as I can tell, the variable values should be populated in the new docker-compose.yml already, no? Why overwrite them again here with the same values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not really an override, its more filling in the build-args from the secret.

return args

- name: transform build args
if: steps.check-image.outputs.result == 'false'
id: transform-build-args
run: |
set -x
echo 'result<<EOF' >> $GITHUB_OUTPUT
echo '${{ steps.populate-build-args.outputs.result }}' | yq -p json >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
cat $GITHUB_OUTPUT

- name: debug transform build args output
if: steps.check-image.outputs.result == 'false'
run: |
echo "result: ${{ steps.transform-build-args.outputs.result }}"
echo "result: ${{ toJSON(steps.transform-build-args.outputs) }}"

- name: Build and push image
uses: docker/build-push-action@v6
if: steps.check-image.outputs.result == 'false'
with:
push: true
file: .helm/ecamp3/files/db-backup-restore-image/Dockerfile
tags: |
${{ ((inputs.tag != '') && format('{0}/ecamp3-db-backup-restore:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }}
${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-db-backup-restore:${{ inputs.sha }}
context: .
cache-from: type=gha,scope=db-backup-restore
cache-to: type=gha,scope=db-backup-restore,mode=max
file: ${{ matrix.build-config.dockerfile }}
tags: ${{ join(fromJSON(steps.expand-tags.outputs.result)) }}
context: ${{ matrix.build-config.context }}
build-args: |
${{ steps.transform-build-args.outputs.result }}
cache-from: type=gha,scope=${{ matrix.build-config.image }}
cache-to: type=gha,scope=${{ matrix.build-config.image }},mode=max

- name: Retag and push images
if: steps.check-image.outputs.result == 'true'
run: |
for tag in $(echo '${{ env.tags }}' | jq -r '.[]'); do
docker tag ${{ matrix.build-config.image }}:${{ steps.get-latest-commit.outputs.result }} ${{ matrix.build-config.image }}:${tag}
docker push ${{ matrix.build-config.image }}:${tag}
done
2 changes: 1 addition & 1 deletion .github/workflows/reusable-e2e-tests-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
load: true
target: frankenphp_prod
builder: ${{ steps.buildx.outputs.name }}
tags: ecamp/ecamp3-dev-api
tags: docker.io/ecamp/ecamp3-api:latest
cache-from: type=gha,scope=api
cache-to: type=gha,scope=api,mode=max
outputs: type=docker,dest=/tmp/ecamp3-dev-api.tar
Expand Down
1 change: 1 addition & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
services:
api:
image: ''
build:
target: frankenphp_dev
volumes:
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ services:
- pdf

api:
image: ecamp/ecamp3-dev-api
image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-api:${VERSION:-latest}
build:
context: ./api
target: frankenphp_prod
Expand Down