Chore: Run tests on docker (#25556)
Co-authored-by: Guilherme Gazzo <guilhermegazzo@gmail.com>pull/25888/head
parent
391bb8cc20
commit
eedc18b3d9
@ -0,0 +1,69 @@ |
||||
name: 'Build Micro Services Docker image' |
||||
description: 'Build Rocket.Chat Micro Services Docker images' |
||||
|
||||
inputs: |
||||
docker-tag: |
||||
required: true |
||||
service: |
||||
required: true |
||||
username: |
||||
required: false |
||||
password: |
||||
required: false |
||||
|
||||
outputs: |
||||
image-name: |
||||
value: ${{ steps.build-image.outputs.image-name }} |
||||
|
||||
runs: |
||||
using: "composite" |
||||
steps: |
||||
# - shell: bash |
||||
# name: Free disk space |
||||
# run: | |
||||
# sudo swapoff -a |
||||
# sudo rm -f /swapfile |
||||
# sudo apt clean |
||||
# docker rmi $(docker image ls -aq) |
||||
# df -h |
||||
|
||||
- shell: bash |
||||
id: build-image |
||||
run: | |
||||
LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") |
||||
|
||||
IMAGE_TAG="${{ inputs.docker-tag }}" |
||||
|
||||
IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/${{ inputs.service }}-service:${IMAGE_TAG}" |
||||
|
||||
echo "Building Docker image for service: ${{ inputs.service }}:${IMAGE_TAG}" |
||||
|
||||
if [[ "${{ inputs.service }}" == "ddp-streamer" ]]; then |
||||
DOCKERFILE_PATH="./ee/apps/ddp-streamer/Dockerfile" |
||||
else |
||||
DOCKERFILE_PATH="./apps/meteor/ee/server/services/Dockerfile" |
||||
fi |
||||
|
||||
docker build \ |
||||
--build-arg SERVICE=${{ inputs.service }} \ |
||||
-t ${IMAGE_NAME} \ |
||||
-f ${DOCKERFILE_PATH} \ |
||||
. |
||||
|
||||
echo "::set-output name=image-name::${IMAGE_NAME}" |
||||
|
||||
- name: Login to GitHub Container Registry |
||||
if: github.event.pull_request.head.repo.full_name == github.repository || github.ref == 'refs/heads/develop' |
||||
uses: docker/login-action@v2 |
||||
with: |
||||
registry: ghcr.io |
||||
username: ${{ inputs.username }} |
||||
password: ${{ inputs.password }} |
||||
|
||||
- name: Publish image |
||||
shell: bash |
||||
if: github.event.pull_request.head.repo.full_name == github.repository || github.ref == 'refs/heads/develop' |
||||
run: | |
||||
echo "Push Docker image: ${{ steps.build-image.outputs.image-name }}" |
||||
|
||||
docker push ${{ steps.build-image.outputs.image-name }} |
||||
@ -0,0 +1,85 @@ |
||||
name: 'Build Docker image' |
||||
description: 'Build Rocket.Chat Docker image' |
||||
|
||||
inputs: |
||||
root-dir: |
||||
required: true |
||||
docker-tag: |
||||
required: true |
||||
release: |
||||
required: true |
||||
username: |
||||
required: false |
||||
password: |
||||
required: false |
||||
|
||||
outputs: |
||||
image-name: |
||||
value: ${{ steps.build-image.outputs.image-name }} |
||||
|
||||
runs: |
||||
using: composite |
||||
steps: |
||||
# - shell: bash |
||||
# name: Free disk space |
||||
# run: | |
||||
# sudo swapoff -a |
||||
# sudo rm -f /swapfile |
||||
# sudo apt clean |
||||
# docker rmi $(docker image ls -aq) |
||||
# df -h |
||||
|
||||
- shell: bash |
||||
id: build-image |
||||
run: | |
||||
cd ${{ inputs.root-dir }} |
||||
|
||||
LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") |
||||
IMAGE_NAME="rocket.chat" |
||||
if [[ '${{ inputs.release }}' = 'preview' ]]; then |
||||
IMAGE_NAME="${IMAGE_NAME}.preview" |
||||
fi; |
||||
|
||||
IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/${IMAGE_NAME}:${{ inputs.docker-tag }}" |
||||
if [[ '${{ inputs.release }}' = 'alpine' ]]; then |
||||
IMAGE_NAME="${IMAGE_NAME}.${{ inputs.release }}" |
||||
fi; |
||||
|
||||
echo "Build Docker image ${IMAGE_NAME}" |
||||
|
||||
DOCKER_PATH="${GITHUB_WORKSPACE}/apps/meteor/.docker" |
||||
if [[ '${{ inputs.release }}' = 'preview' ]]; then |
||||
DOCKER_PATH="${DOCKER_PATH}-mongo" |
||||
fi; |
||||
|
||||
DOCKERFILE_PATH="${DOCKER_PATH}/Dockerfile" |
||||
if [[ '${{ inputs.release }}' = 'alpine' ]]; then |
||||
DOCKERFILE_PATH="${DOCKERFILE_PATH}.${{ inputs.release }}" |
||||
fi; |
||||
|
||||
echo "Copy Dockerfile for release: ${{ inputs.release }}" |
||||
cp $DOCKERFILE_PATH ./Dockerfile |
||||
if [ -e ${DOCKER_PATH}/entrypoint.sh ]; then |
||||
cp ${DOCKER_PATH}/entrypoint.sh . |
||||
fi; |
||||
|
||||
echo "Build ${{ inputs.release }} Docker image" |
||||
docker build -t $IMAGE_NAME . |
||||
|
||||
echo "::set-output name=image-name::${IMAGE_NAME}" |
||||
|
||||
- name: Login to GitHub Container Registry |
||||
if: github.event.pull_request.head.repo.full_name == github.repository && (github.event_name == 'release' || github.ref == 'refs/heads/develop') |
||||
uses: docker/login-action@v2 |
||||
with: |
||||
registry: ghcr.io |
||||
username: ${{ inputs.username }} |
||||
password: ${{ inputs.password }} |
||||
|
||||
- name: Publish image |
||||
shell: bash |
||||
if: github.event.pull_request.head.repo.full_name == github.repository && (github.event_name == 'release' || github.ref == 'refs/heads/develop') |
||||
run: | |
||||
echo "Push Docker image: ${{ steps.build-image.outputs.image-name }}" |
||||
|
||||
docker push ${{ steps.build-image.outputs.image-name }} |
||||
File diff suppressed because it is too large
Load Diff
@ -1,196 +0,0 @@ |
||||
#!/usr/bin/env node
|
||||
|
||||
const path = require('path'); |
||||
const fs = require('fs'); |
||||
const { spawn } = require('child_process'); |
||||
const net = require('net'); |
||||
|
||||
const processes = []; |
||||
|
||||
const baseDir = path.resolve(__dirname, '..'); |
||||
const srcDir = path.resolve(baseDir); |
||||
|
||||
const isPortTaken = (port) => |
||||
new Promise((resolve, reject) => { |
||||
const tester = net |
||||
.createServer() |
||||
.once('error', (err) => (err.code === 'EADDRINUSE' ? resolve(true) : reject(err))) |
||||
.once('listening', () => tester.once('close', () => resolve(false)).close()) |
||||
.listen(port); |
||||
}); |
||||
|
||||
const waitPortRelease = (port, count = 0) => |
||||
new Promise((resolve, reject) => { |
||||
isPortTaken(port).then((taken) => { |
||||
if (!taken) { |
||||
return resolve(); |
||||
} |
||||
if (count > 60) { |
||||
return reject(); |
||||
} |
||||
console.log('Port', port, 'not released, waiting 1s...'); |
||||
setTimeout(() => { |
||||
waitPortRelease(port, ++count) |
||||
.then(resolve) |
||||
.catch(reject); |
||||
}, 1000); |
||||
}); |
||||
}); |
||||
|
||||
const appOptions = { |
||||
env: { |
||||
PORT: 3000, |
||||
ROOT_URL: 'http://localhost:3000', |
||||
}, |
||||
}; |
||||
|
||||
let killingAllProcess = false; |
||||
function killAllProcesses(mainExitCode) { |
||||
if (killingAllProcess) { |
||||
return; |
||||
} |
||||
killingAllProcess = true; |
||||
|
||||
processes.forEach((p) => { |
||||
console.log('Killing process', p.pid); |
||||
p.kill(); |
||||
}); |
||||
|
||||
waitPortRelease(appOptions.env.PORT) |
||||
.then(() => { |
||||
console.log(`Port ${appOptions.env.PORT} was released, exiting with code ${mainExitCode}`); |
||||
process.exit(mainExitCode); |
||||
}) |
||||
.catch((error) => { |
||||
console.error(`Error waiting port ${appOptions.env.PORT} to be released, exiting with code ${mainExitCode}`); |
||||
console.error(error); |
||||
process.exit(mainExitCode); |
||||
}); |
||||
} |
||||
|
||||
function startProcess(opts) { |
||||
console.log('Starting process', opts.name, opts.command, opts.params, opts.options.cwd); |
||||
const proc = spawn(opts.command, opts.params, opts.options); |
||||
processes.push(proc); |
||||
|
||||
if (opts.onData) { |
||||
proc.stdout.on('data', opts.onData); |
||||
} |
||||
|
||||
if (!opts.silent) { |
||||
proc.stdout.pipe(process.stdout); |
||||
proc.stderr.pipe(process.stderr); |
||||
} |
||||
|
||||
if (opts.logFile) { |
||||
const logStream = fs.createWriteStream(opts.logFile, { flags: 'a' }); |
||||
proc.stdout.pipe(logStream); |
||||
proc.stderr.pipe(logStream); |
||||
} |
||||
|
||||
proc.on('exit', function (code, signal) { |
||||
processes.splice(processes.indexOf(proc), 1); |
||||
|
||||
if (code != null) { |
||||
console.log(opts.name, `exited with code ${code}`); |
||||
} else { |
||||
console.log(opts.name, `exited with signal ${signal}`); |
||||
} |
||||
|
||||
killAllProcesses(code); |
||||
}); |
||||
} |
||||
|
||||
function startRocketChat() { |
||||
return new Promise((resolve) => { |
||||
const waitServerRunning = (message) => { |
||||
if (message.toString().match('SERVER RUNNING')) { |
||||
return resolve(); |
||||
} |
||||
}; |
||||
|
||||
startProcess({ |
||||
name: 'Meteor App', |
||||
command: 'node', |
||||
params: ['/tmp/build-test/bundle/main.js'], |
||||
onData: waitServerRunning, |
||||
options: { |
||||
cwd: srcDir, |
||||
env: { |
||||
...appOptions.env, |
||||
...process.env, |
||||
}, |
||||
}, |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
async function startMicroservices() { |
||||
const waitStart = (resolve) => (message) => { |
||||
if (message.toString().match('NetworkBroker started successfully')) { |
||||
return resolve(); |
||||
} |
||||
}; |
||||
const startService = (name) => { |
||||
return new Promise((resolve) => { |
||||
const cwd = |
||||
name === 'ddp-streamer' |
||||
? path.resolve(srcDir, '..', '..', 'ee', 'apps', name, 'dist', 'ee', 'apps', name) |
||||
: path.resolve(srcDir, 'ee', 'server', 'services', 'dist', 'ee', 'server', 'services', name); |
||||
|
||||
startProcess({ |
||||
name: `${name} service`, |
||||
command: 'node', |
||||
params: [name === 'ddp-streamer' ? 'src/service.js' : 'service.js'], |
||||
onData: waitStart(resolve), |
||||
options: { |
||||
cwd, |
||||
env: { |
||||
...appOptions.env, |
||||
...process.env, |
||||
PORT: 4000, |
||||
}, |
||||
}, |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
await Promise.all([ |
||||
startService('account'), |
||||
startService('authorization'), |
||||
startService('ddp-streamer'), |
||||
startService('presence'), |
||||
startService('stream-hub'), |
||||
]); |
||||
} |
||||
|
||||
function startTests(options = []) { |
||||
const testOption = options.find((i) => i.startsWith('--test=')); |
||||
const testParam = testOption ? testOption.replace('--test=', '') : 'test'; |
||||
|
||||
console.log(`Running test "npm run ${testParam}"`); |
||||
|
||||
startProcess({ |
||||
name: 'Tests', |
||||
command: 'npm', |
||||
params: ['run', testParam], |
||||
options: { |
||||
env: { |
||||
...process.env, |
||||
NODE_PATH: `${process.env.NODE_PATH + path.delimiter + srcDir + path.delimiter + srcDir}/node_modules`, |
||||
}, |
||||
}, |
||||
}); |
||||
} |
||||
|
||||
(async () => { |
||||
const [, , ...options] = process.argv; |
||||
|
||||
await startRocketChat(); |
||||
|
||||
if (options.includes('--enterprise')) { |
||||
await startMicroservices(); |
||||
} |
||||
|
||||
startTests(options); |
||||
})(); |
||||
Loading…
Reference in new issue