# NOTE: This workflow name is referenced by other workflows: # - server-ci-artifacts.yml # - server-ci-report.yml # - sentry.yaml # If you rename this workflow, be sure to update those workflows as well. name: Server CI on: workflow_dispatch: # Allow manual/API triggering for linked plugin CI push: branches: - master - release-* pull_request: concurrency: group: ${{ github.event_name == 'pull_request' && format('{0}-{1}', github.workflow, github.ref) || github.run_id }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} permissions: contents: read jobs: buildenv: name: Build Environment runs-on: ubuntu-22.04 permissions: contents: read pull-requests: read actions: write id-token: write # for chainguard (FIPS base image pull) outputs: build-server-tag: ${{ steps.calculate.outputs.BUILD_SERVER_TAG }} gomod-changed: ${{ steps.changed-files.outputs.any_changed }} # Individual jobs below use this to skip via `if:` rather # than the workflow being skipped entirely, # so required status checks always get reported. relevant-changed: ${{ github.event_name != 'pull_request' || steps.changed-relevant.outputs.any_changed == 'true' }} steps: - name: Checkout mattermost project uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Calculate build image tag id: calculate working-directory: server/ run: | tag=$(./build/buildenv-tag.sh) echo "BUILD_SERVER_TAG=${tag}" >> "${GITHUB_OUTPUT}" - name: Check for go.mod changes id: changed-files uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | **/go.mod - name: Check for relevant Server CI path changes id: changed-relevant if: github.event_name == 'pull_request' uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | server/** .github/workflows/server-ci.yml .github/workflows/server-test-template.yml .github/workflows/server-test-merge-template.yml .github/workflows/mmctl-test-template.yml .github/actions/setup-buildenv/** .github/actions/load-buildenv/** .github/actions/run-in-buildenv/** tools/mattermost-govet/** files_ignore: | server/**/*.md server/NOTICE.txt server/CHANGELOG.md - name: Setup build environment env: CHAINCTL_IDENTITY: ee399b4c72dd4e58e3d617f78fc47b74733c9557/922f2d48307d6f5f DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} uses: ./.github/actions/setup-buildenv with: build-server-tag: ${{ steps.calculate.outputs.BUILD_SERVER_TAG }} check-generated: name: Check generated files needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' runs-on: ubuntu-22.04 services: # make default-roles-permissions snapshots a live database. postgres: image: postgres:15 env: POSTGRES_USER: mmuser POSTGRES_PASSWORD: mostest_password POSTGRES_DB: mattermost_test ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 5s --health-timeout 5s --health-retries 5 steps: - name: Checkout mattermost project uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Restore Go cache uses: ./.github/actions/restore-go-cache - uses: ./.github/actions/run-in-buildenv with: run: | export IS_CI=true export TEST_DATABASE_POSTGRESQL_DSN="postgres://mmuser:mostest_password@localhost:5432/mattermost_test?sslmode=disable&connect_timeout=10" make generated - name: Check generated files run: | if [ -n "$(git status --porcelain)" ]; then echo "Generated files are out of date. Please run 'make generated' and commit the result." git status --porcelain git diff exit 1 fi check-backport-migrations: name: Check backport migrations needs: buildenv # Only backports (release-* base) must keep a migration's version+name; new master migrations are expected. if: needs.buildenv.outputs.relevant-changed == 'true' && startsWith(github.base_ref, 'release-') runs-on: ubuntu-22.04 steps: - name: Checkout mattermost project uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Restore Go cache uses: ./.github/actions/restore-go-cache - name: Check for renumbered or renamed migrations uses: ./.github/actions/run-in-buildenv with: run: | git fetch --no-tags --depth=1 origin master "${{ github.base_ref }}" export MM_MIGRATION_CHECK_BASE_REF="origin/${{ github.base_ref }}" export MM_MIGRATION_CHECK_CANONICAL_REF="origin/master" make check-backport-migrations check-style: name: check-style needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' runs-on: ubuntu-22.04 steps: - name: Checkout mattermost project uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Restore Go cache uses: ./.github/actions/restore-go-cache - uses: ./.github/actions/run-in-buildenv with: run: make check-style check-mattermost-vet-api: name: Vet API needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' runs-on: ubuntu-22.04 steps: - name: Checkout mattermost project uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Restore Go cache uses: ./.github/actions/restore-go-cache - uses: ./.github/actions/run-in-buildenv with: run: make vet-api # NOTE: Postgres with binary parameters has been moved to server-ci-weekly.yml # (runs Monday 1am EST / 5am UTC). Low regression risk doesn't justify # consuming 8-core runners on every push. # -- Sharded into 4 parallel runners for ~88% wall-time improvement -- test-postgres-normal: name: Postgres (shard ${{ matrix.shard }}) needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' strategy: fail-fast: false # Let all shards complete so we get full test results matrix: shard: [0, 1, 2, 3] permissions: contents: read actions: write uses: ./.github/workflows/server-test-template.yml secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: name: "Postgres (shard ${{ matrix.shard }})" datasource: postgres://mmuser:mostest_password@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10 drivername: postgres # Each shard gets a unique artifact name so they don't collide logsartifact: "postgres-server-test-logs-shard-${{ matrix.shard }}" enablecoverage: ${{ github.event_name != 'pull_request' || !startsWith(github.event.pull_request.base.ref, 'release-') }} build-server-tag: ${{ needs.buildenv.outputs.build-server-tag }} fips-enabled: false shard-index: ${{ matrix.shard }} shard-total: 4 # -- Merge test results (handles both single-run and future sharded runs) -- merge-postgres-test-results: name: Merge Postgres Test Results needs: test-postgres-normal if: always() && needs.test-postgres-normal.result != 'skipped' permissions: contents: read actions: write uses: ./.github/workflows/server-test-merge-template.yml with: artifact-pattern: postgres-server-test-logs-shard-* artifact-name: postgres-server-test-logs save-timing-cache: true all-shards-passed: ${{ needs.test-postgres-normal.result == 'success' }} test-elasticsearch-v8: name: Elasticsearch v8 Compatibility needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' permissions: contents: read actions: write uses: ./.github/workflows/server-test-template.yml with: name: Elasticsearch v8 Compatibility datasource: postgres://mmuser:mostest_password@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10 drivername: postgres logsartifact: elasticsearch-v8-server-test-logs build-server-tag: ${{ needs.buildenv.outputs.build-server-tag }} fips-enabled: false elasticsearch-version: "8.9.0" test-target: "test-server-elasticsearch" test-opensearch-v2: name: OpenSearch v2 Compatibility needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' permissions: contents: read actions: write uses: ./.github/workflows/server-test-template.yml with: name: OpenSearch v2 Compatibility datasource: postgres://mmuser:mostest_password@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10 drivername: postgres logsartifact: opensearch-v2-server-test-logs build-server-tag: ${{ needs.buildenv.outputs.build-server-tag }} fips-enabled: false opensearch-version: "2.19.0" test-target: "test-server-opensearch" # FIPS tests: run on PRs when go.mod changed or branch name contains "fips". # Sharded for fast iteration. Weekly workflow provides regular full coverage. test-postgres-normal-fips: if: >- needs.buildenv.outputs.relevant-changed == 'true' && (contains(github.head_ref, 'fips') || needs.buildenv.outputs.gomod-changed == 'true') name: "Postgres FIPS (shard ${{ matrix.shard }})" needs: buildenv strategy: fail-fast: false matrix: shard: [0, 1, 2, 3] permissions: contents: read actions: write uses: ./.github/workflows/server-test-template.yml secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} with: name: "Postgres FIPS (shard ${{ matrix.shard }})" datasource: postgres://mmuser:mostest_password@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10 drivername: postgres logsartifact: "postgres-server-fips-test-logs-shard-${{ matrix.shard }}" build-server-tag: ${{ needs.buildenv.outputs.build-server-tag }} fips-enabled: true shard-index: ${{ matrix.shard }} shard-total: 4 merge-postgres-fips-test-results: name: Merge Postgres FIPS Test Results needs: test-postgres-normal-fips if: needs.test-postgres-normal-fips.result != 'skipped' permissions: contents: read actions: write uses: ./.github/workflows/server-test-merge-template.yml with: artifact-pattern: postgres-server-fips-test-logs-shard-* artifact-name: postgres-server-fips-test-logs test-mmctl: name: Run mmctl tests needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' permissions: contents: read actions: write uses: ./.github/workflows/mmctl-test-template.yml secrets: MM_E2E_ZEPHYR_API_KEY: ${{ secrets.MM_E2E_ZEPHYR_API_KEY }} with: name: mmctl datasource: postgres://mmuser:mostest_password@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10 drivername: postgres logsartifact: mmctl-test-logs build-server-tag: ${{ needs.buildenv.outputs.build-server-tag }} fips-enabled: false test-mmctl-fips: if: >- needs.buildenv.outputs.relevant-changed == 'true' && (contains(github.head_ref, 'fips') || needs.buildenv.outputs.gomod-changed == 'true') name: Run mmctl tests (FIPS) needs: buildenv permissions: contents: read actions: write uses: ./.github/workflows/mmctl-test-template.yml secrets: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} MM_E2E_ZEPHYR_API_KEY: ${{ secrets.MM_E2E_ZEPHYR_API_KEY }} with: name: mmctl datasource: postgres://mmuser:mostest_password@postgres:5432/mattermost_test?sslmode=disable&connect_timeout=10 drivername: postgres logsartifact: mmctl-fips-test-logs build-server-tag: ${{ needs.buildenv.outputs.build-server-tag }} fips-enabled: true build-mattermost-server: name: Build mattermost server app needs: buildenv if: needs.buildenv.outputs.relevant-changed == 'true' permissions: contents: read actions: write runs-on: ubuntu-22.04 steps: - name: Checkout mattermost project uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Restore Go cache uses: ./.github/actions/restore-go-cache - name: Build uses: ./.github/actions/run-in-buildenv with: run: | export BUILD_NUMBER="$(printf '%s' "${HEAD_REF:-${REF_NAME}}" | tr -c 'A-Za-z0-9._-' '-')-${RUN_ID}" export FIPS_ENABLED=false make config-reset make build-cmd make package - name: Persist dist artifacts if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: server-dist-artifact path: server/dist/ if-no-files-found: error compression-level: 0 retention-days: 2 - name: Persist build artifacts if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: server-build-artifact path: server/build/ retention-days: 2 # ci-complete is used to determine if the Server CI is complete since # fips steps are optional and can be skipped. When we build with fips, # we want to ensure that the Server CI is complete before running the # artifacts upload workflow. ci-complete: name: Server CI Complete if: >- always() && (needs.test-mmctl-fips.result == 'success' || needs.test-mmctl-fips.result == 'skipped' || needs.test-mmctl-fips.result == 'failure') && (needs.merge-postgres-fips-test-results.result == 'success' || needs.merge-postgres-fips-test-results.result == 'skipped' || needs.merge-postgres-fips-test-results.result == 'failure') permissions: {} runs-on: ubuntu-22.04 needs: - buildenv - merge-postgres-test-results - test-elasticsearch-v8 - test-opensearch-v2 - test-mmctl - test-mmctl-fips - build-mattermost-server - merge-postgres-fips-test-results steps: - name: Server CI Complete run: | # Explicitly fail here rather than relying on `if:`, since a job # skipped via `if:` is reported as "Success" by GitHub. if [ "${{ needs.buildenv.result }}" != "success" ]; then echo "::error::'buildenv' job did not succeed (result: ${{ needs.buildenv.result }}); relevant-changed could not be computed reliably. Failing Server CI Complete." exit 1 fi echo "Server CI Complete" ci-report: name: Server CI Report # Skip cleanly (rather than fail) when no relevant Server CI paths # changed, since none of the test jobs it reports on will have run. if: always() && needs.buildenv.outputs.relevant-changed == 'true' permissions: contents: read actions: read checks: write pull-requests: write issues: write needs: - buildenv - ci-complete uses: ./.github/workflows/server-ci-report.yml secrets: WEBHOOK_URL_FLAKY_TEST: ${{ secrets.WEBHOOK_URL_FLAKY_TEST }} WEBHOOK_AUTH_TOKEN_FLAKY_TEST: ${{ secrets.WEBHOOK_AUTH_TOKEN_FLAKY_TEST }} WEBHOOK_URL_FLAKY_TEST_MM: ${{ secrets.WEBHOOK_URL_FLAKY_TEST_MM }} with: source-run-id: ${{ github.run_id }} source-event: ${{ github.event_name }} head-commit-id: ${{ github.event.pull_request.head.sha || github.sha }} head-repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} workflow-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} ci-artifacts: name: Server CI Artifacts # Skip when no relevant Server CI paths changed, since build-mattermost-server # (and thus server-dist-artifact) will not have run. if: >- success('ci-complete') && needs.buildenv.outputs.relevant-changed == 'true' && github.repository_owner == 'mattermost' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository permissions: contents: read actions: read statuses: write needs: - buildenv - ci-complete uses: ./.github/workflows/server-ci-artifacts.yml secrets: PR_BUILDS_BUCKET_AWS_ACCESS_KEY_ID: ${{ secrets.PR_BUILDS_BUCKET_AWS_ACCESS_KEY_ID }} PR_BUILDS_BUCKET_AWS_SECRET_ACCESS_KEY: ${{ secrets.PR_BUILDS_BUCKET_AWS_SECRET_ACCESS_KEY }} DOCKERHUB_DEV_TOKEN: ${{ secrets.DOCKERHUB_DEV_TOKEN }} WIZ_DEVOPS_CLIENT_ID: ${{ secrets.WIZ_DEVOPS_CLIENT_ID }} WIZ_DEVOPS_CLIENT_SECRET: ${{ secrets.WIZ_DEVOPS_CLIENT_SECRET }} with: source-run-id: ${{ github.run_id }} source-event: ${{ github.event_name }} head-sha: ${{ github.event.pull_request.head.sha }} head-repository: ${{ github.event.pull_request.head.repo.full_name }} ci-sentry: name: Sentry Upload # Only run Sentry upload for master branch as mentioned in old workflow title. if: >- always() && github.repository_owner == 'mattermost' && github.event_name == 'push' && github.ref == 'refs/heads/master' permissions: contents: read needs: - ci-complete uses: ./.github/workflows/sentry.yaml secrets: SENTRY_AUTH_TOKEN: ${{ secrets.MM_SERVER_SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ secrets.MM_SERVER_SENTRY_ORG }} SENTRY_PROJECT: ${{ secrets.MM_SERVER_SENTRY_PROJECT }}