Continuous Integration #4401
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Continuous Integration | |
env: | |
DOCKER_IMAGE: wyrihaximusnet/php | |
DOCKER_BUILDKIT: 1 | |
DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING: '{"ghcr.io":"GHCR_TOKEN","docker.io":"HUB_PASSCODE"}' | |
DOCKER_CLI_EXPERIMENTAL: enabled | |
on: | |
workflow_dispatch: | |
push: | |
branches: | |
- master | |
pull_request: | |
schedule: | |
- cron: '13 4 * * *' | |
jobs: | |
supported-alpine-versions: | |
name: Supported Alpine versions | |
runs-on: ubuntu-latest | |
outputs: | |
alpine: ${{ steps.supported-alpine-versions.outputs.versions }} | |
steps: | |
- id: supported-alpine-versions | |
name: Generate Alpine | |
uses: wyrihaximus/github-action-supported-alpine-linux-versions@v1 | |
with: | |
maxVersions: 2 | |
supported-debian-versions: | |
name: Supported Debian versions | |
runs-on: ubuntu-latest | |
outputs: | |
debian: ${{ steps.supported-debian-versions.outputs.versions }} | |
steps: | |
- id: supported-debian-versions | |
name: Generate Debian | |
uses: wyrihaximus/github-action-supported-debian-linux-versions@v1 | |
supported-php-versions: | |
name: Supported PHP versions | |
runs-on: ubuntu-latest | |
outputs: | |
php: ${{ steps.supported-php-versions.outputs.versions }} | |
steps: | |
- id: supported-php-versions | |
name: Generate PHP | |
uses: wyrihaximus/github-action-supported-php-versions@v1 | |
with: | |
upcomingReleases: true | |
supported-arch-matrix: | |
name: Supported processor architectures | |
runs-on: ubuntu-latest | |
outputs: | |
arch: ${{ steps.supported-arch-matrix.outputs.arch }} | |
steps: | |
- uses: actions/checkout@v4 | |
- id: supported-arch-matrix | |
name: Generate Arch | |
run: | | |
echo "arch=[\\\"amd64\\\",\\\"arm64\\\"]" >> $GITHUB_OUTPUT | |
image-type-matrix: | |
name: Create Image Type Matrix | |
runs-on: ubuntu-latest | |
outputs: | |
type: ${{ steps.image-type-matrix.outputs.type }} | |
steps: | |
- uses: actions/checkout@v4 | |
- id: image-type-matrix | |
name: Generate Type | |
run: | | |
ls Dockerfile-* | jq -csR '. | rtrimstr("\n") | split("\n")' | php -r "echo str_replace('Dockerfile-', '', stream_get_contents(STDIN));" > types.list | |
cat types.list | |
echo "type=$(cat types.list)" >> $GITHUB_OUTPUT | |
exclude-matrix: | |
name: Create Exclude Matrix | |
runs-on: ubuntu-latest | |
outputs: | |
exclude: ${{ steps.exclude-matrix.outputs.exclude }} | |
exclude-push: ${{ steps.exclude-matrix.outputs.exclude-push }} | |
steps: | |
- uses: actions/checkout@v4 | |
- id: exclude-matrix | |
name: Generate Exclude | |
run: | | |
php utils/exclude-list.php | |
image-matrix: | |
name: Create Image Matrix | |
runs-on: ubuntu-latest | |
needs: | |
- lint | |
- supported-alpine-versions | |
- supported-debian-versions | |
- supported-php-versions | |
outputs: | |
image: ${{ steps.image-matrix.outputs.image }} | |
steps: | |
- uses: actions/checkout@v4 | |
- id: image-matrix | |
name: Generate Combined Image Matrix | |
run: | | |
echo "Generate full image list" | |
php utils/all-images.php | |
if [ "${{ github.event_name }}" == "schedule" ] ; then | |
echo "This is a scheduled run, scanning for CVE's" | |
touch trivy.output | |
php utils/all-image-tags.php | grep -v debian | xargs -I % sh -c 'docker pull -q $(php -r "echo explode(\"#\", \"%\")[0];") && echo "%|" || true' >> pullable.list | |
cat pullable.list | xargs -I % sh -c 'docker run -v /tmp/trivy:/var/lib/trivy -v /var/run/docker.sock:/var/run/docker.sock -t aquasec/trivy:latest --cache-dir /var/lib/trivy image --exit-code 1 --no-progress $(php -r "echo explode(\"#\", \"%\")[0];") >> trivy.output || echo "%|"' >> images_with.cves | |
cat trivy.output | |
if [ -s "images_with.cves" ] | |
then | |
echo "Found images with CVE's in them" | |
cat images_with.cves | xargs -I % php -r 'echo implode(PHP_EOL, explode("|", "%")), PHP_EOL;' | xargs -I % php -r 'echo explode("#", "%")[1], PHP_EOL;' >> images-that-need-updating.list | |
fi | |
echo "Looking for newer upstream images" | |
php utils/newer-upstream-images.php >> images-that-need-updating.list | |
echo "Building the following images:" | |
php utils/deduplicate-list.php | jq '.[]' | |
printf "image=%s" $(php utils/deduplicate-list.php) >> $GITHUB_OUTPUT | |
exit 0 | |
fi | |
echo "Not in a scheduled run, building all images" | |
echo "Building the following images:" | |
cat all-images.list | jq '.[]' | |
printf "image=%s" $(cat all-images.list) >> $GITHUB_OUTPUT | |
exit 0 | |
env: | |
ALPINE: ${{ needs.supported-alpine-versions.outputs.alpine }} | |
DEBIAN: ${{ needs.supported-debian-versions.outputs.debian }} | |
PHP: ${{ needs.supported-php-versions.outputs.php }} | |
lint: | |
name: Linting Dockerfile-${{ matrix.type }} | |
runs-on: ubuntu-latest | |
needs: | |
- image-type-matrix | |
strategy: | |
fail-fast: false | |
matrix: | |
type: ${{ fromJson(needs.image-type-matrix.outputs.type) }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Lint Dockerfile-${{ matrix.type }} | |
uses: docker://hadolint/hadolint:latest-debian | |
with: | |
entrypoint: hadolint | |
args: Dockerfile-${{ matrix.type }} | |
build: | |
name: Building "${{ matrix.image }}" | |
needs: | |
- lint | |
- image-matrix | |
- supported-arch-matrix | |
- exclude-matrix | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
image: ${{ fromJson(needs.image-matrix.outputs.image) }} | |
exclude: ${{ fromJson(needs.exclude-matrix.outputs.exclude) }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dbhi/qus/action@main | |
- run: mkdir ./docker-image/ | |
- uses: nick-invision/retry@v3 | |
with: | |
timeout_minutes: 120 | |
retry_wait_seconds: 30 | |
max_attempts: 5 | |
command: (echo "${{ needs.supported-arch-matrix.outputs.arch }}" | jq -r '.[]') | xargs -I % ./build-php.sh $(echo "${{ matrix.image }}" | tr '-' ' ') % | |
- run: cat ./docker-image/image.tags | xargs -I % docker inspect --format='%={{.Id}}:{{index .Config.Env 7}}' % | |
- run: docker save "${DOCKER_IMAGE}" | gzip -9 > ./docker-image/image.tar | |
- run: docker images | |
- name: Upload Images | |
uses: actions/upload-artifact@v2 | |
with: | |
name: docker-image-${{ matrix.image }} | |
path: ./docker-image | |
scan-vulnerability: | |
name: Scanning "${{ matrix.image }}" for vulnerabilities | |
needs: | |
- build | |
- image-matrix | |
- supported-arch-matrix | |
- exclude-matrix | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
image: ${{ fromJson(needs.image-matrix.outputs.image) }} | |
exclude: ${{ fromJson(needs.exclude-matrix.outputs.exclude) }} | |
steps: | |
- uses: actions/checkout@v4 | |
if: contains(matrix.image, 'alpine') | |
- uses: dbhi/qus/action@main | |
if: contains(matrix.image, 'alpine') | |
- name: Download Images | |
if: contains(matrix.image, 'alpine') | |
uses: actions/download-artifact@v3 | |
with: | |
name: docker-image-${{ matrix.image }} | |
path: ./docker-image | |
- run: docker load --input ./docker-image/image.tar | |
if: contains(matrix.image, 'alpine') | |
- run: mkdir -p "./clair/${DOCKER_IMAGE}" | |
if: contains(matrix.image, 'alpine') | |
- run: make ci-scan-vulnerability | |
if: contains(matrix.image, 'alpine') | |
test: | |
name: Testing "${{ matrix.image }}" | |
needs: | |
- build | |
- image-matrix | |
- supported-arch-matrix | |
- exclude-matrix | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
image: ${{ fromJson(needs.image-matrix.outputs.image) }} | |
exclude: ${{ fromJson(needs.exclude-matrix.outputs.exclude) }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dbhi/qus/action@main | |
- name: Download Images | |
uses: actions/download-artifact@v3 | |
with: | |
name: docker-image-${{ matrix.image }} | |
path: ./docker-image | |
- run: ls -lasth ./docker-image/ | |
- run: docker load --input ./docker-image/image.tar | |
- run: | | |
export IMAGE_BASE_VERSION=$(php -r 'echo explode("-", "${{ matrix.image }}")[2];') | |
(echo "${{ needs.supported-arch-matrix.outputs.arch }}" | jq -r '.[]') | xargs -I % make $(php -r 'echo "test-", explode("-", str_replace(["zts-zts", "cli-nts"], ["zts", "nts"], "${{ matrix.image }}"))[0];') IMAGE_ARCH=% | |
- run: rm -Rf ./docker-image/ | |
check-mark: | |
name: ✔️ | |
needs: | |
- lint | |
- build | |
- scan-vulnerability | |
- test | |
runs-on: ubuntu-latest | |
steps: | |
- run: echo "✔️" | |
push: | |
name: Pushing "${{ matrix.image }}" | |
if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/master' | |
needs: | |
- check-mark | |
- image-matrix | |
- supported-arch-matrix | |
- exclude-matrix | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
image: ${{ fromJson(needs.image-matrix.outputs.image) }} | |
exclude: ${{ fromJson(needs.exclude-matrix.outputs.exclude) }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Set up Docker Buildx | |
id: buildx | |
uses: docker/setup-buildx-action@v2 | |
with: | |
install: true | |
- name: Inspect builder | |
run: | | |
echo "Name: ${{ steps.buildx.outputs.name }}" | |
echo "Endpoint: ${{ steps.buildx.outputs.endpoint }}" | |
echo "Status: ${{ steps.buildx.outputs.status }}" | |
echo "Flags: ${{ steps.buildx.outputs.flags }}" | |
echo "Platforms: ${{ steps.buildx.outputs.platforms }}" | |
- name: Download Images | |
uses: actions/download-artifact@v3 | |
with: | |
name: docker-image-${{ matrix.image }} | |
path: ./docker-image | |
- run: ls -lasthR ./docker-image | |
- run: find ./docker-image/ | grep "image.tar" | |
- run: find ./docker-image/ | grep "image.tags" | |
- run: docker images | |
- run: find ./docker-image/ | grep "image.tar" | xargs -I % sh -c 'docker load --input % && rm %' | |
- run: docker images | |
- name: Login to container registries | |
uses: nick-invision/retry@v3 | |
with: | |
timeout_minutes: 120 | |
retry_wait_seconds: 30 | |
max_attempts: 5 | |
command: | | |
(jq -r 'to_entries | map("echo \"$" + .value + "\" | docker login " + .key + " --username \"${{ env.DOCKER_USER }}\" --password-stdin") | .[]' <<<"$DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING") | sh | |
env: | |
DOCKER_USER: ${{ secrets.HUB_USERNAME }} | |
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} | |
HUB_PASSCODE: ${{ secrets.HUB_PASSCODE }} | |
- name: Docker info | |
run: docker info | |
- name: Retag | |
uses: nick-invision/retry@v3 | |
with: | |
timeout_minutes: 120 | |
retry_wait_seconds: 30 | |
max_attempts: 5 | |
command: | | |
(jq -r 'to_entries | map("(find ./docker-image/ | grep image.tags | xargs -I $ cat $) | xargs -I % docker tag % " + .key + "/%") | .[]' <<<"$DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING") | sh | |
(jq -r 'to_entries | map("(find ./docker-image/ | grep image.tags | xargs -I $ cat $) | xargs -I % docker push " + .key + "/%") | .[]' <<<"$DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING") | sh | |
- run: docker images | |
- name: Push all images to registries | |
uses: nick-invision/retry@v3 | |
with: | |
timeout_minutes: 120 | |
retry_wait_seconds: 30 | |
max_attempts: 5 | |
command: | | |
find ./docker-image/ | grep image.tags | xargs -I $ cat $ > tags-to-push.list | |
touch command.sh | |
(jq -r 'to_entries | map("php utils/create-manifest-command.php " + .key) | .[]' <<<"$DOCKER_IMAGE_REGISTRIES_SECRET_MAPPING") | sh | |
chmod +x command.sh | |
cat ./command.sh | |
./command.sh | |
env: | |
TARGET_ARCHS: ${{ needs.supported-arch-matrix.outputs.arch }} | |
- run: docker images |