name: CI on: release: types: [published] pull_request: branches: '**' paths-ignore: - '**.md' merge_group: 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 }')-v9 # 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 # Docker tags cannot contain '/'; merge queue refs do (e.g. gh-readonly-queue/develop/pr-123-sha) DOCKER_TAG="${DOCKER_TAG//\//-}" 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\": [\"8.0\"], \"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@v5 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@v5 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/caching-for-turbo@v1.8 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)**/.turbo/*' ':(exclude).turbo/*' ':(exclude)**/.yarn/*' ':(exclude).yarn/*' ':(exclude).git/*') - name: Upload packages build artifact uses: actions/upload-artifact@v7 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@v7 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: - 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, 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 - uses: ./.github/actions/restore-packages # 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.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 }} publish-image: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' }} - name: Image ${{ matrix.service[1] || '"skipped"' }} uses: ./.github/actions/build-docker if: matrix.service[1] && 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 }} publish-image: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' }} setup-docker: false - name: Image ${{ matrix.service[2] || '"skipped"' }} uses: ./.github/actions/build-docker if: matrix.service[2] && 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 }} publish-image: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' }} setup-docker: false - name: Image ${{ matrix.service[3] || '"skipped"' }} uses: ./.github/actions/build-docker if: matrix.service[3] && 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 }} publish-image: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' }} 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@v8 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 if: github.actor != 'dependabot[bot]' && (github.ref == 'refs/heads/develop' || github.event.pull_request.head.repo.full_name == github.repository) 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 size-thresholds: '{"rocketchat":{"mb":11}}' 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-api-livechat: name: 🔨 Test API Livechat (CE) needs: [checks, build-gh-docker-publish, release-versions] uses: ./.github/workflows/ci-test-e2e.yml with: type: api-livechat 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: "['8.0']" coverage: '8.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 }} secrets: CR_USER: ${{ secrets.CR_USER }} CR_PAT: ${{ secrets.CR_PAT }} test-api-livechat-ee: name: 🔨 Test API Livechat (EE) needs: [checks, build-gh-docker-publish, release-versions] uses: ./.github/workflows/ci-test-e2e.yml with: type: api-livechat release: ee transporter: 'nats://nats:4222' enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} mongodb-version: "['8.0']" coverage: '8.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 }} 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: "['8.0']" coverage: '8.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-federation-matrix: name: 🔨 Test Federation Matrix needs: [checks, build-gh-docker-publish, packages-build, release-versions] runs-on: ubuntu-24.04 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/caching-for-turbo@v1.8 - name: Restore turbo build uses: actions/download-artifact@v8 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" # Download Docker images from build artifacts - name: Download Docker images uses: actions/download-artifact@v8 if: github.event.pull_request.head.repo.full_name != github.repository && github.event_name != 'release' && github.ref != 'refs/heads/develop' with: pattern: 'docker-image-rocketchat-amd64-coverage' path: /tmp/docker-images merge-multiple: true # Load Docker images - name: Load Docker images if: github.event.pull_request.head.repo.full_name != github.repository && github.event_name != 'release' && github.ref != 'refs/heads/develop' shell: bash run: | set -o xtrace # Load all downloaded images for image_file in /tmp/docker-images/*.tar; do if [ -f "$image_file" ]; then echo "Loading image from $image_file" docker load -i "$image_file" rm "$image_file" fi done # List loaded images docker images - name: Start federation services 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 }}-amd64 ENTERPRISE_LICENSE_RC1: ZAikY+LLaal7mT6RNYxpyWEmMQyucrl50/7pYBXqHczc90j+RLwF+T0xuCT2pIpKMC5DxcZ1TtkV6MYJk5whrwmap+mQ0FV+VpILJlL0i4T21K4vMfzZXTWm/pzcAy2fMTUNH+mUA9HTBD6lYYh40KnbGXPAd80VbZk0MO/WbWBm2dOT0YCwfvlRyurRqkDAQrftLaffzCNUsMKk0fh+MKs73UDHZQDp1yvs7WoGpPu5ZVi5mTBOt3ZKVz5KjGfClLwJptFPmW1w6nKelAiJBDPpjcX1ylfjxpnBoixko7uN52zlyaeoAYwfRcdDLnZ8k0Ou6tui/vTQUXjGIjHw2AhMaKwonn4E9LYpuA1KEXt08qJL5J3ZtjSCV1T+A9Z3zFhhLgp5dxP/PPUbxDn/P8XKp7nXM9duIfcCMlnea7V8ixEyCHwwvKQaXVVidcsUGtB8CwS0GlsAEBLOzqMehuQUK2rdQ4WgEz3AYveikeVvSzgBHvyXsxssWAThc0Mht0eEJqdDhUB2QeZ2WmPsaSSD639Z4WgjSUoR0zh8bfqepH+2XRcUryXe2yN+iU+3POzi9wfg0k65MxXT8pBg3PD5RHnR8oflEP0tpZts33JiBhYRxX3MKplAFm4dMuphTsDJTh+e534pT7IPuZF79QSVaLEWZfVVVb7nGFtmMwA= QASE_TESTOPS_JEST_API_TOKEN: ${{ secrets.QASE_TESTOPS_JEST_API_TOKEN }} PR_NUMBER: ${{ github.event.number }} run: yarn test:integration --start-containers-only --image "${ROCKETCHAT_IMAGE}" - name: Run federation integration tests working-directory: ./ee/packages/federation-matrix env: QASE_TESTOPS_JEST_API_TOKEN: ${{ secrets.QASE_TESTOPS_JEST_API_TOKEN }} PR_NUMBER: ${{ github.event.number }} run: yarn test:integration --ci - name: Show federation integration tests logs if: failure() working-directory: ./ee/packages/federation-matrix run: yarn test:integration --logs - name: Show mongo logs if tests failed if: failure() working-directory: ./ee/packages/federation-matrix run: docker compose -f docker-compose.test.yml logs mongo report-coverage: name: 📊 Report Coverage runs-on: ubuntu-24.04 needs: [release-versions, test-api-ee, test-api-livechat-ee, test-ui-ee] steps: - uses: actions/checkout@v6 - name: Use Node.js uses: actions/setup-node@v6.2.0 with: node-version: ${{ needs.release-versions.outputs.node-version }} - name: Restore coverage folder uses: actions/download-artifact@v8 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@v7 with: name: reports-coverage path: /tmp/coverage_report include-hidden-files: true - name: Report API coverage uses: codecov/codecov-action@v5 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@v5 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-api-livechat, test-api-livechat-ee, 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-api-livechat.result }}' != 'success' ]]; then exit 1 fi if [[ '${{ needs.test-api-livechat-ee.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@v8 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@v8 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 DOCKER_TAG="${DOCKER_TAG//\//-}" 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\": [\"8.0\"], \"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 }}