Skip to content

fix(presence): update connections on heartbeat and remove them when stale #47134

fix(presence): update connections on heartbeat and remove them when stale

fix(presence): update connections on heartbeat and remove them when stale #47134

Workflow file for this run

name: CI
on:
release:
types: [published]
pull_request:
branches: '**'
paths-ignore:
- '**.md'
push:
branches:
- develop
paths-ignore:
- '**.md'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }}
jobs:
release-versions:
name: ⚙️ Variables Setup
runs-on: ubuntu-24.04-arm
outputs:
release: ${{ steps.by-tag.outputs.release }}
latest-release: ${{ steps.latest.outputs.latest-release }}
gh-docker-tag: ${{ steps.docker.outputs.gh-docker-tag }}
lowercase-repo: ${{ steps.var.outputs.lowercase-repo }}
node-version: ${{ steps.var.outputs.node-version }}
deno-version: ${{ steps.var.outputs.deno-version }}
source-hash: ${{ steps.source.outputs.hash }}
# this is 100% intentional, secrets are not available for forks, so ee-tests will always fail
# to avoid this, we are using a dummy license, expiring at 2026-07-01
enterprise-license: Uo7Jcr6WW0XYA8ydHd+Sk6pZ9/0V6dIASnyTwvUrNym/zJg2Ma3eYNKkC8osXLCc72y1ahohnWY7/+7IYkvono3GYXQR+IGvYbbrVgNR6OjMahd9P/odHZL1GFTm2qHrEL5Hh/XEOG+YluFeRdWPzCizQlp4zGGOi0+PkQo096TR9NVCLrsErVl2MW1WM6ZM1W5EUJG9pKly4BQnaOTUAlor1im6i8qPTDCKrISZfLiZEWuQKaPW/GE3mRKjQNjDh0CabX1N2S880pRRGoozBYAnp2NmFfrQW0+5ihKisBTIeMbMZ7K5NE5PkYU1nhQDcc+rpDHtwG9Ceg5X0J+oea3UfrPTmDON2aSI0iO22kvL6G7QI3fyrEIvJrMbxcNKxAFeQYgnjisw/b06+chWSG4jG686Fx58XrVS87dFhWL9WoGltsk1dJCntUQvI1sX6zOfpvyg1iWRnHfYDOrwoWlX57XMm29fWineEoqnOOTOVnA/uP+DKEhercQ9Xuo7Cr6zJxpQpwd03e7ODVjiEbTDqlkZE687rmxRCD4Wmu8L86WIl2xSEIajKLX301Ww5mz/FdLqk+Mg32lkW66W3azQKvJ1440NBrYxhpJ+dl9vSFMb3s1+xnz1cYUbjUcq9mARvORcgy5mLwKulmqT6Sq0Uvbv10YCO0TW0beXYW8=
steps:
- name: Github Info
run: |
echo "GITHUB_ACTION: $GITHUB_ACTION"
echo "GITHUB_ACTOR: $GITHUB_ACTOR"
echo "GITHUB_REF: $GITHUB_REF"
echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
echo "github.event_name: ${{ github.event_name }}"
cat $GITHUB_EVENT_PATH
- uses: actions/checkout@v6
# with:
# sparse-checkout: |
# package.json
# .tool-versions
# sparse-checkout-cone-mode: false
# ref: ${{ github.ref }}
- id: source
run: |
ls -la
tar -cf /tmp/RocketChat-source.tar \
--sort=name \
--owner=0 --group=0 \
--mtime='1970-01-01' \
--exclude='.github' \
--exclude='.git' \
.
SOURCE_HASH=$(sha256sum /tmp/RocketChat-source.tar | awk '{ print $1 }')-v8
# Uncomment the following line to include the run ID in the hash and disable caching between runs
# SOURCE_HASH=$(sha256sum /tmp/RocketChat-source.tar | awk '{ print $1 }')-${{ github.run_id }}
echo hash=${SOURCE_HASH}
echo hash=${SOURCE_HASH} >> $GITHUB_OUTPUT
- id: var
run: |
LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]")
echo "LOWERCASE_REPOSITORY: ${LOWERCASE_REPOSITORY}"
echo "lowercase-repo=${LOWERCASE_REPOSITORY}" >> $GITHUB_OUTPUT
NODE_VERSION=$(node -p "require('./package.json').engines.node")
echo "NODE_VERSION: ${NODE_VERSION}"
echo "node-version=${NODE_VERSION}" >> $GITHUB_OUTPUT
DENO_VERSION=$(awk '$1=="deno"{ print $2 }' .tool-versions)
echo "DENO_VERSION: ${DENO_VERSION}"
echo "deno-version=${DENO_VERSION}" >> $GITHUB_OUTPUT
- id: by-tag
run: |
if echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then
RELEASE="latest"
elif echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then
RELEASE="release-candidate"
fi
echo "RELEASE: ${RELEASE}"
echo "release=${RELEASE}" >> $GITHUB_OUTPUT
- id: latest
run: |
LATEST_RELEASE="$(
git -c 'versionsort.suffix=-' ls-remote -t --exit-code --refs --sort=-v:refname "https://github.com/$GITHUB_REPOSITORY" '*' |
awk -F/ '$NF !~ /rc|beta/ { print $NF; exit }'
)"
echo "LATEST_RELEASE: ${LATEST_RELEASE}"
echo "latest-release=${LATEST_RELEASE}" >> $GITHUB_OUTPUT
- id: docker
run: |
if [[ '${{ github.event_name }}' == 'pull_request' ]]; then
DOCKER_TAG="pr-${{ github.event.number }}"
else
DOCKER_TAG=$GITHUB_REF_NAME
fi
echo "DOCKER_TAG: ${DOCKER_TAG}"
echo "gh-docker-tag=${DOCKER_TAG}" >> $GITHUB_OUTPUT
notify-draft-services:
name: 🚀 Notify external services - draft
runs-on: ubuntu-24.04-arm
needs: [release-versions]
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: |
package.json
sparse-checkout-cone-mode: false
ref: ${{ github.ref }}
- name: Register release on cloud as Draft
if: github.event_name == 'release'
env:
UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }}
run: |
REPO_VERSION=$(node -p "require('./package.json').version")
if [[ '${{ github.event_name }}' = 'release' ]]; then
GIT_TAG="${GITHUB_REF#*tags/}"
GIT_BRANCH=""
ARTIFACT_NAME="${REPO_VERSION}"
RC_VERSION=$GIT_TAG
if [[ '${{ needs.release-versions.outputs.release }}' = 'release-candidate' ]]; then
RC_RELEASE=candidate
elif [[ '${{ needs.release-versions.outputs.release }}' = 'latest' ]]; then
RC_RELEASE=stable
fi
else
GIT_TAG=""
GIT_BRANCH="${GITHUB_REF#*heads/}"
ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA"
RC_VERSION="${REPO_VERSION}"
RC_RELEASE=develop
fi;
curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \
"{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"denoVersion\": \"${{ needs.release-versions.outputs.deno-version }}\", \"compatibleMongoVersions\": [\"5\", \"6\", \"7\", \"8\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"draft\", \"draftAs\": \"$RC_RELEASE\"}" \
https://releases.rocket.chat/update
packages-build:
name: 📦 Build Packages
needs: [release-versions, notify-draft-services]
runs-on: ubuntu-24.04-arm
steps:
- name: Cache build
uses: actions/cache@v4
id: packages-cache-build
with:
path: |
/tmp/RocketChat-packages-build.tar.gz
key: ${{ runner.arch }}-${{ runner.os }}-packages-build-${{ needs.release-versions.outputs.source-hash }}
- name: Debug cache-hit
run: echo "cache-hit=${{ steps.packages-cache-build.outputs.cache-hit }}"
- name: Set Swap Space
uses: pierotofy/set-swap-space@master
if: steps.packages-cache-build.outputs.cache-hit != 'true'
with:
swap-size-gb: 4
- uses: actions/checkout@v6
if: steps.packages-cache-build.outputs.cache-hit != 'true'
- name: Setup NodeJS
uses: ./.github/actions/setup-node
if: steps.packages-cache-build.outputs.cache-hit != 'true'
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
cache-modules: true
install: true
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
HARDENED_MODE: '1'
- name: Cache vite
uses: actions/cache@v4
if: steps.packages-cache-build.outputs.cache-hit != 'true'
with:
path: ./node_modules/.vite
key: vite-local-cache-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('package.json') }}
restore-keys: |
vite-local-cache-${{ runner.arch }}-${{ runner.os }}-
- uses: rharkor/[email protected]
if: steps.packages-cache-build.outputs.cache-hit != 'true'
- name: Build Rocket.Chat Packages
if: steps.packages-cache-build.outputs.cache-hit != 'true'
run: yarn build
- name: Archive packages build output
if: steps.packages-cache-build.outputs.cache-hit != 'true'
run: |
tar -czf /tmp/RocketChat-packages-build.tar.gz \
$(git ls-files -oi --exclude-standard -- ':(exclude)node_modules/*' ':(exclude)**/node_modules/*' ':(exclude)**/.meteor/*' ':(exclude)**/.deno-cache/*' ':(exclude)**/.turbo/*' ':(exclude).turbo/*' ':(exclude)**/.yarn/*' ':(exclude).yarn/*' ':(exclude).git/*')
- name: Upload packages build artifact
uses: actions/upload-artifact@v5
with:
name: packages-build
path: /tmp/RocketChat-packages-build.tar.gz
retention-days: 5
- name: Store turbo build
if: steps.packages-cache-build.outputs.cache-hit != 'true'
uses: actions/upload-artifact@v5
with:
name: turbo-build
path: .turbo/cache
overwrite: true
include-hidden-files: true
build:
name: 📦 Meteor Build (${{ matrix.type }})
needs: [release-versions, packages-build]
runs-on: ubuntu-24.04-arm
strategy:
fail-fast: false
matrix:
type:
- production
- coverage
exclude:
- type: ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'production' || '' }}
steps:
- name: Collect Workflow Telemetry
uses: catchpoint/workflow-telemetry-action@v2
with:
theme: dark
job_summary: true
comment_on_pr: false
- uses: actions/checkout@v6
- uses: ./.github/actions/meteor-build
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
source-hash: ${{ needs.release-versions.outputs.source-hash }}
type: ${{ matrix.type }}
build-gh-docker:
name: 🚢 Build Docker
needs: [build, release-versions]
runs-on: ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }}
env:
DOCKER_TAG: ${{ needs.release-versions.outputs.gh-docker-tag }}-${{ matrix.arch }}
LOWERCASE_REPOSITORY: ${{ needs.release-versions.outputs.lowercase-repo }}
strategy:
fail-fast: false
matrix:
arch: [arm64, amd64]
service:
[
[authorization-service, queue-worker-service, ddp-streamer-service],
[account-service, presence-service, stream-hub-service, omnichannel-transcript-service],
[rocketchat],
]
type:
# if running in a PR build with coverage
- ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}
include:
# if not, build with coverage for tests
- arch: amd64
service: [rocketchat]
type: coverage
- arch: arm64
service: [rocketchat]
type: coverage
steps:
- uses: actions/checkout@v6
- name: Restore packages build
uses: actions/download-artifact@v6
with:
name: packages-build
path: /tmp
- name: Unpack packages build
shell: bash
run: |
tar -xzf /tmp/RocketChat-packages-build.tar.gz -C .
# we only build and publish the actual docker images if not a PR from a fork
- name: Image ${{ matrix.service[0] }}
uses: ./.github/actions/build-docker
if: (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') && github.actor != 'dependabot[bot]'
env:
# add suffix for the extra images with coverage if building for production
DOCKER_TAG_SUFFIX_ROCKETCHAT: ${{ matrix.type == 'coverage' && (github.event_name == 'release' || github.ref == 'refs/heads/develop') && '-cov' || '' }}
with:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
arch: ${{ matrix.arch }}
service: ${{ matrix.service[0] }}
type: ${{ matrix.type }}
- name: Image ${{ matrix.service[1] || '"skipped"' }}
uses: ./.github/actions/build-docker
if: matrix.service[1] && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') && github.actor != 'dependabot[bot]'
env:
DOCKER_TAG_SUFFIX_ROCKETCHAT: ${{ matrix.type == 'coverage' && '-cov' || '' }}
with:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
arch: ${{ matrix.arch }}
service: ${{ matrix.service[1] }}
type: ${{ matrix.type }}
setup-docker: false
- name: Image ${{ matrix.service[2] || '"skipped"' }}
uses: ./.github/actions/build-docker
if: matrix.service[2] && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') && github.actor != 'dependabot[bot]'
env:
DOCKER_TAG_SUFFIX_ROCKETCHAT: ${{ matrix.type == 'coverage' && '-cov' || '' }}
with:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
arch: ${{ matrix.arch }}
service: ${{ matrix.service[2] }}
type: ${{ matrix.type }}
setup-docker: false
- name: Image ${{ matrix.service[3] || '"skipped"' }}
uses: ./.github/actions/build-docker
if: matrix.service[3] && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') && github.actor != 'dependabot[bot]'
env:
DOCKER_TAG_SUFFIX_ROCKETCHAT: ${{ matrix.type == 'coverage' && '-cov' || '' }}
with:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
arch: ${{ matrix.arch }}
service: ${{ matrix.service[3] }}
type: ${{ matrix.type }}
setup-docker: false
build-gh-docker-publish:
name: 🚢 Publish Docker Images (ghcr.io)
needs: [build-gh-docker, release-versions]
runs-on: ubuntu-24.04-arm
env:
DOCKER_TAG: ${{ needs.release-versions.outputs.gh-docker-tag }}
LOWERCASE_REPOSITORY: ${{ needs.release-versions.outputs.lowercase-repo }}
steps:
- uses: actions/checkout@v6
if: github.actor != 'dependabot[bot]' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop')
with:
sparse-checkout: |
docker-compose-ci.yml
sparse-checkout-cone-mode: false
ref: ${{ github.ref }}
- name: Login to GitHub Container Registry
if: github.actor != 'dependabot[bot]' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop')
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.CR_USER }}
password: ${{ secrets.CR_PAT }}
- name: Download manifests
if: github.actor != 'dependabot[bot]' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop')
uses: actions/download-artifact@v6
with:
pattern: manifests-*
path: /tmp/manifests
merge-multiple: true
- name: Create and push multi-arch manifests
if: github.actor != 'dependabot[bot]' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop')
run: |
set -o xtrace
shopt -s nullglob
for service_dir in /tmp/manifests/*; do
[[ -d "$service_dir" ]] || continue
service="$(basename "$service_dir")"
echo "Creating manifest for $service"
# Extract digests from manifest.json files
mapfile -t refs < <(
find "$service_dir" -type f -name 'manifest.json' -print0 \
| xargs -0 -I{} jq -r '.Descriptor.digest as $digest | .Ref | split("@")[0] + "@" + $digest' {}
)
echo "Digest for ${service}: ${refs[@]}"
# Get image name from docker-compose-ci.yml since rocketchat image is different from service name (rocket.chat)
if [ "$service" == "rocketchat-cov" ]; then
IMAGE=$(docker compose -f docker-compose-ci.yml config --format json 2>/dev/null | jq -r --arg s "rocketchat" '.services[$s].image')-cov
else
IMAGE=$(docker compose -f docker-compose-ci.yml config --format json 2>/dev/null | jq -r --arg s "$service" '.services[$s].image')
fi
echo $IMAGE
docker buildx imagetools create \
--debug \
--annotation "manifest-descriptor:org.opencontainers.image.description=Build run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--tag "${IMAGE}" \
--tag "${IMAGE}-gha-run-${{ github.run_id }}" \
${refs[@]}
done
track-image-sizes:
name: 📦 Track Image Sizes
needs: [build-gh-docker-publish, release-versions]
runs-on: ubuntu-24.04-arm
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/develop'
permissions:
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v6
- name: Track Docker image sizes
uses: ./.github/actions/docker-image-size-tracker
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
ci-pat: ${{ secrets.CI_PAT }}
registry: ghcr.io
repository: ${{ needs.release-versions.outputs.lowercase-repo }}
tag: ${{ needs.release-versions.outputs.gh-docker-tag }}
baseline-tag: develop
checks:
needs: [release-versions, packages-build]
name: 🔎 Code Check
uses: ./.github/workflows/ci-code-check.yml
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
test-storybook:
name: 🔨 Test Storybook
needs: [packages-build, release-versions]
uses: ./.github/workflows/ci-test-storybook.yml
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-unit:
name: 🔨 Test Unit
needs: [packages-build, release-versions]
uses: ./.github/workflows/ci-test-unit.yml
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }}
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-api:
name: 🔨 Test API (CE)
needs: [checks, build-gh-docker-publish, release-versions]
uses: ./.github/workflows/ci-test-e2e.yml
with:
type: api
release: ce
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }}
gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }}
secrets:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
test-ui:
name: 🔨 Test UI (CE)
needs: [checks, build-gh-docker-publish, release-versions]
uses: ./.github/workflows/ci-test-e2e.yml
with:
type: ui
release: ce
transporter: 'nats://nats:4222'
enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }}
shard: '[1, 2, 3, 4]'
total-shard: 4
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }}
gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }}
retries: ${{ (github.event_name == 'release' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') && 2 || 0 }}
secrets:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }}
REPORTER_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_ROCKETCHAT_API_KEY }}
REPORTER_ROCKETCHAT_URL: ${{ secrets.REPORTER_ROCKETCHAT_URL }}
REPORTER_JIRA_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_JIRA_ROCKETCHAT_API_KEY }}
test-api-ee:
name: 🔨 Test API (EE)
needs: [checks, build-gh-docker-publish, release-versions]
uses: ./.github/workflows/ci-test-e2e.yml
with:
type: api
release: ee
transporter: 'nats://nats:4222'
enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }}
mongodb-version: "['5.0', '8.2']"
coverage: '8.2'
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }}
gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }}
secrets:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
test-ui-ee:
name: 🔨 Test UI (EE)
needs: [checks, build-gh-docker-publish, release-versions]
uses: ./.github/workflows/ci-test-e2e.yml
with:
type: ui
release: ee
transporter: 'nats://nats:4222'
enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }}
shard: '[1, 2, 3, 4, 5]'
total-shard: 5
mongodb-version: "['5.0']"
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }}
gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }}
retries: ${{ (github.event_name == 'release' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') && 2 || 0 }}
secrets:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }}
REPORTER_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_ROCKETCHAT_API_KEY }}
REPORTER_ROCKETCHAT_URL: ${{ secrets.REPORTER_ROCKETCHAT_URL }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
REPORTER_JIRA_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_JIRA_ROCKETCHAT_API_KEY }}
test-ui-ee-watcher:
name: 🔨 Test UI (EE)
needs: [checks, build-gh-docker-publish, release-versions]
uses: ./.github/workflows/ci-test-e2e.yml
with:
type: ui
release: ee
transporter: 'nats://nats:4222'
enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }}
shard: '[1, 2, 3, 4, 5]'
total-shard: 5
mongodb-version: "['8.2']"
coverage: '8.2'
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }}
gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }}
retries: ${{ (github.event_name == 'release' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') && 2 || 0 }}
db-watcher-disabled: 'false'
secrets:
CR_USER: ${{ secrets.CR_USER }}
CR_PAT: ${{ secrets.CR_PAT }}
QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }}
REPORTER_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_ROCKETCHAT_API_KEY }}
REPORTER_ROCKETCHAT_URL: ${{ secrets.REPORTER_ROCKETCHAT_URL }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
REPORTER_JIRA_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_JIRA_ROCKETCHAT_API_KEY }}
test-federation-matrix:
name: 🔨 Test Federation Matrix
needs: [checks, build-gh-docker-publish, packages-build, release-versions]
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v6
- name: Setup NodeJS
uses: ./.github/actions/setup-node
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
deno-version: ${{ needs.release-versions.outputs.deno-version }}
cache-modules: true
install: true
- uses: rharkor/[email protected]
- name: Restore turbo build
uses: actions/download-artifact@v6
continue-on-error: true
with:
name: turbo-build
path: .turbo/cache
- name: Build packages
run: yarn build
- 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') && github.actor != 'dependabot[bot]'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.CR_USER }}
password: ${{ secrets.CR_PAT }}
- name: Configure /etc/hosts for federation services
run: |
sudo -- sh -c "echo '127.0.0.1 hs1' >> /etc/hosts"
sudo -- sh -c "echo '127.0.0.1 rc1' >> /etc/hosts"
- name: Run federation integration tests with pre-built image
working-directory: ./ee/packages/federation-matrix
env:
ROCKETCHAT_IMAGE: ghcr.io/${{ needs.release-versions.outputs.lowercase-repo }}/rocket.chat:${{ needs.release-versions.outputs.gh-docker-tag }}
ENTERPRISE_LICENSE_RC1: ${{ secrets.ENTERPRISE_LICENSE_RC1 }}
QASE_TESTOPS_JEST_API_TOKEN: ${{ secrets.QASE_TESTOPS_JEST_API_TOKEN }}
run: yarn test:integration --image "${ROCKETCHAT_IMAGE}"
report-coverage:
name: 📊 Report Coverage
runs-on: ubuntu-24.04
needs: [release-versions, test-api-ee, test-ui-ee, test-ui-ee-watcher]
steps:
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/[email protected]
with:
node-version: ${{ needs.release-versions.outputs.node-version }}
- name: Restore coverage folder
uses: actions/download-artifact@v6
with:
pattern: coverage-*
path: /tmp/coverage
merge-multiple: true
- name: Generate lcov report
run: |
set -o xtrace
npx nyc report --reporter=lcovonly --report-dir=/tmp/coverage_report/api --temp-dir=/tmp/coverage/api
npx nyc report --reporter=lcovonly --report-dir=/tmp/coverage_report/ui --temp-dir=/tmp/coverage/ui
- name: Store coverage-reports
uses: actions/upload-artifact@v5
with:
name: reports-coverage
path: /tmp/coverage_report
include-hidden-files: true
- name: Report API coverage
uses: codecov/codecov-action@v3
with:
files: /tmp/coverage_report/api/lcov.info
working-directory: .
flags: e2e-api
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
- name: Report UI coverage
uses: codecov/codecov-action@v3
with:
files: /tmp/coverage_report/ui/lcov.info
working-directory: .
flags: e2e
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
tests-done:
name: ✅ Tests Done
runs-on: ubuntu-24.04-arm
needs: [checks, test-unit, test-api, test-ui, test-api-ee, test-ui-ee, test-ui-ee-watcher, test-federation-matrix]
if: always()
steps:
- name: Test finish aggregation
run: |
if [[ '${{ needs.checks.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-unit.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-api.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-ui.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-api-ee.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-ui-ee.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-ui-ee-watcher.result }}' != 'success' ]]; then
exit 1
fi
if [[ '${{ needs.test-federation-matrix.result }}' != 'success' ]]; then
exit 1
fi
echo finished
deploy:
name: 🚀 Publish build assets
runs-on: ubuntu-24.04-arm
if: github.event_name == 'release' || github.ref == 'refs/heads/develop'
needs: [build-gh-docker-publish, release-versions]
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: |
package.json
sparse-checkout-cone-mode: false
ref: ${{ github.ref }}
- name: Restore build
uses: actions/download-artifact@v6
with:
name: build-production
path: /tmp/build
- name: Publish assets
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: 'us-east-1'
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
run: |
REPO_VERSION=$(node -p "require('./package.json').version")
if [[ '${{ github.event_name }}' = 'release' ]]; then
GIT_TAG="${GITHUB_REF#*tags/}"
ARTIFACT_NAME="${REPO_VERSION}"
else
GIT_TAG=""
ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA"
fi;
ROCKET_DEPLOY_DIR="/tmp/deploy"
FILENAME="$ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.tgz";
aws s3 cp s3://rocketchat/sign.key.gpg .github/sign.key.gpg
mkdir -p $ROCKET_DEPLOY_DIR
cp .github/sign.key.gpg /tmp
gpg --yes --batch --passphrase=$GPG_PASSWORD /tmp/sign.key.gpg
gpg --allow-secret-key-import --import /tmp/sign.key
rm /tmp/sign.key
ln -s /tmp/build/Rocket.Chat.tar.gz "$FILENAME"
gpg --armor --detach-sign "$FILENAME"
aws s3 cp $ROCKET_DEPLOY_DIR/ s3://download.rocket.chat/build/ --recursive
docker-image-publish:
name: 🚀 Publish Docker Images (DockerHub)
runs-on: ubuntu-24.04-arm
needs: [deploy, release-versions]
env:
DOCKER_TAG: ${{ needs.release-versions.outputs.gh-docker-tag }}
LOWERCASE_REPOSITORY: ${{ needs.release-versions.outputs.lowercase-repo }}
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: |
docker-compose-ci.yml
sparse-checkout-cone-mode: false
ref: ${{ github.ref }}
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.CR_USER }}
password: ${{ secrets.CR_PAT }}
- name: Download manifests
if: github.actor != 'dependabot[bot]' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop')
uses: actions/download-artifact@v6
with:
pattern: manifests-*
path: /tmp/manifests
merge-multiple: true
- name: Publish Docker images
run: |
set -euo pipefail
set -o xtrace
shopt -s nullglob
# sudo apt-get update -y
# sudo apt-get install -y skopeo
# 'develop' or 'tag'
DOCKER_TAG=$GITHUB_REF_NAME
declare -a TAGS=()
# tag specific tag version
TAGS+=("$DOCKER_TAG")
if [[ $GITHUB_REF == refs/tags/* ]]; then
RELEASE="${{ needs.release-versions.outputs.release }}"
echo "RELEASE: $RELEASE"
if [[ $RELEASE == 'latest' ]]; then
if [[ '${{ needs.release-versions.outputs.latest-release }}' == $GITHUB_REF_NAME ]]; then
TAGS+=("$RELEASE")
fi
else
TAGS+=("$RELEASE")
fi
fi
# commit hash
COMMIT_SHA="sha-${GITHUB_SHA:0:7}"
echo "COMMIT_SHA: ${COMMIT_SHA}"
TAGS+=("${COMMIT_SHA}")
echo "Tags: ${TAGS[*]}"
# get first tag as primary
PRIMARY="${TAGS[0]}"
for service_dir in /tmp/manifests/*; do
[[ -d "$service_dir" ]] || continue
service="$(basename "$service_dir")"
if [ "$service" == "rocketchat-cov" ]; then
continue
fi
echo "Promoting $service"
if [[ "${service}" == 'rocketchat' ]]; then
IMAGE_NAME="${{ needs.release-versions.outputs.lowercase-repo }}/rocket.chat"
else
IMAGE_NAME="${{ needs.release-versions.outputs.lowercase-repo }}/${service}"
fi
# Get image name from docker-compose-ci.yml since rocketchat image is different from service name (rocket.chat)
SRC=$(docker compose -f docker-compose-ci.yml config --format json 2>/dev/null | jq -r --arg s "${service}" '.services[$s].image')
DEST_REPO="docker.io/${IMAGE_NAME}"
echo "Copying $SRC to ${DEST_REPO}:${PRIMARY}"
skopeo copy --all \
"docker://${SRC}" \
"docker://${DEST_REPO}:${PRIMARY}"
# copy additional tags
if (( ${#TAGS[@]} > 1 )); then
for t in "${TAGS[@]:1}"; do
echo "Copying $SRC to ${DEST_REPO}:${t}"
skopeo copy --all \
"docker://${SRC}" \
"docker://${DEST_REPO}:${t}"
done
fi
done
notify-services:
name: 🚀 Notify external services
runs-on: ubuntu-24.04-arm
needs:
- docker-image-publish
- release-versions
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: |
package.json
sparse-checkout-cone-mode: false
ref: ${{ github.ref }}
- name: Releases service
env:
UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }}
run: |
REPO_VERSION=$(node -p "require('./package.json').version")
if [[ '${{ github.event_name }}' = 'release' ]]; then
GIT_TAG="${GITHUB_REF#*tags/}"
GIT_BRANCH=""
ARTIFACT_NAME="${REPO_VERSION}"
RC_VERSION=$GIT_TAG
if [[ '${{ needs.release-versions.outputs.release }}' = 'release-candidate' ]]; then
RC_RELEASE=candidate
elif [[ '${{ needs.release-versions.outputs.release }}' = 'latest' ]]; then
RC_RELEASE=stable
fi
else
GIT_TAG=""
GIT_BRANCH="${GITHUB_REF#*heads/}"
ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA"
RC_VERSION="${REPO_VERSION}"
RC_RELEASE=develop
fi;
curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \
"{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"denoVersion\": \"${{ needs.release-versions.outputs.deno-version }}\", \"compatibleMongoVersions\": [\"5\", \"6\", \"7\", \"8\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \
https://releases.rocket.chat/update
# Makes build fail if the release isn't there
curl --fail https://releases.rocket.chat/$RC_VERSION/info
docs-update:
name: Update Version Durability
if: github.event_name == 'release'
needs:
- docker-image-publish
uses: ./.github/workflows/update-version-durability.yml
with:
LTS_VERSIONS: ${{ vars.LTS_VERSIONS }}
secrets:
CI_PAT: ${{ secrets.CI_PAT }}
D360_TOKEN: ${{ secrets.D360_TOKEN }}