From a04badd6d6144351b9bcc9690ff618e586444006 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 25 Nov 2024 16:25:48 -0300 Subject: [PATCH] ci: test images on PR and push (#216) --- .github/workflows/build-test.yml | 98 ++++++++++++++++++++++++++++++++ compose.yml | 2 +- genMatrix.js | 68 ++++++++++++++++++++++ 3 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-test.yml create mode 100644 genMatrix.js diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000..0fba59b --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,98 @@ +name: build-test + +on: + push: + paths: + - "**/Dockerfile" + - genMatrix.js + - compose.yml + - ".github/workflows/build-test.yml" + + pull_request: + paths: + - "**/Dockerfile" + - genMatrix.js + - compose.yml + - ".github/workflows/build-test.yml" + +jobs: + gen-matrix: + name: generate-matrix + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Calculate file differences + id: diff + uses: tj-actions/changed-files@v45 + with: + json: true + escape_json: false + + - name: Generate testing matrix + uses: actions/github-script@v7 + id: generator + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const script = require(`${process.env.GITHUB_WORKSPACE}/genMatrix.js`) + return script( + ${{ steps.diff.outputs.added_files }}, + ${{ steps.diff.outputs.modified_files }}, + ${{ steps.diff.outputs.renamed_files }}, + ); + + outputs: + matrix: ${{ steps.generator.outputs.result }} + + build: + if: ${{ fromJson(needs.gen-matrix.outputs.matrix) }} + needs: gen-matrix + name: build + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.gen-matrix.outputs.matrix) }} + + steps: + - name: Get short node version + uses: actions/github-script@v7 + id: short-version + with: + result-encoding: string + script: | + const version = "${{ matrix.version }}".split('.'); + return `${version[0]}.${version[1]}` + + - name: Checkout + uses: actions/checkout@v4 + + - name: Build image + uses: docker/build-push-action@v6 + with: + push: false + load: true + context: . + file: ./${{ steps.short-version.outputs.result }}/Dockerfile + tags: rocket.chat:${{ matrix.version }} + + - name: Run Image + env: + IMAGE: rocket.chat + RELEASE: ${{ matrix.version }} + run: docker compose up -d + + - name: Wait for Rocket.Chat to start up + uses: cygnetdigital/wait_for_response@v2.0.0 + with: + url: 'http://localhost:3000/health' + responseCode: '200' + timeout: 60000 + interval: 1000 + + - name: Show logs if failed + if: failure() + run: docker compose logs diff --git a/compose.yml b/compose.yml index 2cd9548..b16f9c7 100644 --- a/compose.yml +++ b/compose.yml @@ -3,7 +3,7 @@ volumes: services: rocketchat: - image: registry.rocket.chat/rocketchat/rocket.chat:${RELEASE:-latest} + image: ${IMAGE:-registry.rocket.chat/rocketchat/rocket.chat}:${RELEASE:-latest} restart: always labels: traefik.enable: "true" diff --git a/genMatrix.js b/genMatrix.js new file mode 100644 index 0000000..cb6531f --- /dev/null +++ b/genMatrix.js @@ -0,0 +1,68 @@ +'use strict'; +const path = require('path'); +const fs = require('fs'); + +const testFiles = [ + 'genMatrix.js', + '.github/workflows/build-test.yml', + 'compose.yml', +]; + +const rcDirRegex = /^\d+\.\d+$/; + +const areTestFilesChanged = (changedFiles) => changedFiles + .some((file) => testFiles.includes(file)); + +// Returns a list of the child directories in the given path +const getChildDirectories = (parent) => fs.readdirSync(parent, { withFileTypes: true }) + .filter((dirent) => dirent.isDirectory()) + .map(({ name }) => path.resolve(parent, name)); + +const getRocketChatVersionDirs = (base) => getChildDirectories(base) + .filter((childPath) => rcDirRegex.test(path.basename(childPath))); + +// Returns the paths of Dockerfiles that are at: base/*/Dockerfile +const getDockerfilesInChildDirs = (base) => path.resolve(base, 'Dockerfile'); + +const getAllDockerfiles = (base) => getRocketChatVersionDirs(base) + .flatMap(getDockerfilesInChildDirs); + +const getAffectedDockerfiles = (filesAdded, filesModified, filesRenamed) => { + const files = [ + ...filesAdded, + ...filesModified, + ...filesRenamed, + ]; + + // If the test files were changed, include everything + if (areTestFilesChanged(files)) { + console.log('Test files changed so scheduling all Dockerfiles'); + return getAllDockerfiles(__dirname); + } + + return files.filter((file) => file.endsWith('/Dockerfile')); +}; + +const getFullRocketChatVersionFromDockerfile = (file) => fs.readFileSync(file, 'utf8') + .match(/^ENV RC_VERSION (\d*\.*\d*\.\d*)/m)[1]; + +const getDockerfileMatrixEntry = (file) => { + const version = getFullRocketChatVersionFromDockerfile(file); + + return { + version, + }; +}; + +const generateBuildMatrix = (filesAdded, filesModified, filesRenamed) => { + const dockerfiles = [...new Set(getAffectedDockerfiles(filesAdded, filesModified, filesRenamed))]; + + const entries = dockerfiles.map(getDockerfileMatrixEntry); + + // Return null if there are no entries so we can skip the matrix step + return entries.length + ? { include: entries } + : null; +}; + +module.exports = generateBuildMatrix;