name: Tests on: pull_request: push: branches: - main - beta - stable concurrency: group: tests-${{ format('{0}-{1}', github.head_ref || github.run_number, github.job) }} cancel-in-progress: true permissions: contents: read jobs: build: if: "!(github.event_name == 'push' && github.repository == 'discourse/discourse-private-mirror')" name: ${{ matrix.target }} ${{ matrix.build_type }} ${{ matrix.ruby }} runs-on: ${{ (matrix.build_type == 'annotations') && 'ubuntu-latest' || 'ubuntu-20.04-8core' }} container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }}${{ (matrix.ruby == '3.1') && '-ruby-3.1.0' || '' }} timeout-minutes: 20 env: DISCOURSE_HOSTNAME: www.example.com RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072 RAILS_ENV: test PGUSER: discourse PGPASSWORD: discourse USES_PARALLEL_DATABASES: ${{ matrix.build_type == 'backend' || matrix.build_type == 'system' }} CAPBYARA_DEFAULT_MAX_WAIT_TIME: 4 strategy: fail-fast: false matrix: build_type: [backend, frontend, system, annotations] target: [core, plugins] ruby: ['3.2'] exclude: - build_type: annotations target: plugins - build_type: frontend target: core # Handled by core_frontend_tests job (below) steps: - name: Set working directory owner run: chown root:root . - uses: actions/checkout@v3 with: fetch-depth: 1 - name: Setup Git run: | git config --global user.email "ci@ci.invalid" git config --global user.name "Discourse CI" - name: Start redis run: | redis-server /etc/redis/redis.conf & - name: Start Postgres run: | chown -R postgres /var/run/postgresql sudo -E -u postgres script/start_test_db.rb sudo -u postgres psql -c "CREATE ROLE $PGUSER LOGIN SUPERUSER PASSWORD '$PGPASSWORD';" - name: Bundler cache uses: actions/cache@v3 with: path: vendor/bundle key: ${{ runner.os }}-${{ matrix.ruby }}-gem-${{ hashFiles('**/Gemfile.lock') }} restore-keys: | ${{ runner.os }}-${{ matrix.ruby }}-gem- - name: Setup gems run: | gem install bundler --conservative -v $(awk '/BUNDLED WITH/ { getline; gsub(/ /,""); print $0 }' Gemfile.lock) bundle config --local path vendor/bundle bundle config --local deployment true bundle config --local without development bundle install --jobs 4 bundle clean - name: Get yarn cache directory id: yarn-cache-dir run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Yarn cache uses: actions/cache@v3 id: yarn-cache with: path: ${{ steps.yarn-cache-dir.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - name: Yarn install run: yarn install - name: Checkout official plugins if: matrix.target == 'plugins' run: bin/rake plugin:install_all_official - name: Pull compatible versions of plugins if: matrix.target == 'plugins' run: bin/rake plugin:pull_compatible_all - name: Fetch app state cache uses: actions/cache@v3 id: app-cache with: path: tmp/app-cache key: >- # postgres version, hash of migrations, "parallel?" ${{ runner.os }}- ${{ hashFiles('.github/workflows/tests.yml') }}- ${{ matrix.postgres }}- ${{ hashFiles('db/**/*', 'plugins/**/db/**/*') }}- ${{ env.USES_PARALLEL_DATABASES }} - name: Restore database from cache if: steps.app-cache.outputs.cache-hit == 'true' run: psql -f tmp/app-cache/cache.sql postgres - name: Restore uploads from cache if: steps.app-cache.outputs.cache-hit == 'true' run: rm -rf public/uploads && cp -r tmp/app-cache/uploads public/uploads - name: Create and migrate database if: steps.app-cache.outputs.cache-hit != 'true' run: | bin/rake db:create bin/rake db:migrate - name: Create and migrate parallel databases if: >- env.USES_PARALLEL_DATABASES == 'true' && steps.app-cache.outputs.cache-hit != 'true' run: | bin/rake parallel:create bin/rake parallel:migrate - name: Dump database for cache if: steps.app-cache.outputs.cache-hit != 'true' run: mkdir -p tmp/app-cache && pg_dumpall > tmp/app-cache/cache.sql - name: Dump uploads for cache if: steps.app-cache.outputs.cache-hit != 'true' run: rm -rf tmp/app-cache/uploads && cp -r public/uploads tmp/app-cache/uploads - name: Fetch turbo_rspec_runtime.log cache uses: actions/cache@v3 id: test-runtime-cache if: matrix.build_type == 'backend' && matrix.target == 'core' with: path: tmp/turbo_rspec_runtime.log key: rspec-runtime-backend-core - name: Run Zeitwerk check if: matrix.build_type == 'backend' env: LOAD_PLUGINS: ${{ (matrix.target == 'plugins') && '1' || '0' }} run: | if ! bin/rails zeitwerk:check --trace; then echo echo "---------------------------------------------" echo echo "::error::'bin/rails zeitwerk:check' failed - the app will fail to boot with 'eager_load=true' (e.g. in production)." echo "To reproduce locally, run 'bin/rails zeitwerk:check'." echo "Alternatively, you can run your local server/tests with the 'DISCOURSE_ZEITWERK_EAGER_LOAD=1' environment variable." echo exit 1 fi - name: Core RSpec if: matrix.build_type == 'backend' && matrix.target == 'core' run: bin/turbo_rspec --verbose - name: Plugin RSpec if: matrix.build_type == 'backend' && matrix.target == 'plugins' run: bin/rake plugin:turbo_spec - name: Plugin QUnit if: matrix.build_type == 'frontend' && matrix.target == 'plugins' run: QUNIT_PARALLEL=3 bin/rake plugin:qunit['*','1200000'] timeout-minutes: 30 - name: Ember Build for System Tests if: matrix.build_type == 'system' run: bin/ember-cli --build - name: Setup Webdriver if: matrix.build_type == 'system' run: bin/rails runner "require 'webdrivers'; Webdrivers::Chromedriver.update" - name: Core System Tests if: matrix.build_type == 'system' && matrix.target == 'core' run: bin/rspec spec/system --format documentation - name: Plugin System Tests if: matrix.build_type == 'system' && matrix.target == 'plugins' run: LOAD_PLUGINS=1 bin/rspec plugins/*/spec/system --format documentation - name: Upload failed system test screenshots uses: actions/upload-artifact@v3 if: matrix.build_type == 'system' && failure() with: name: failed-system-test-screenshots path: tmp/capybara/*.png - name: Check Annotations if: matrix.build_type == 'annotations' run: | bin/rake annotate:ensure_all_indexes bin/annotate --models --model-dir app/models if [ ! -z "$(git status --porcelain app/models/)" ]; then echo "Core annotations are not up to date. To resolve, run:" echo " bin/rake annotate:clean" echo echo "Or manually apply the diff printed below:" echo "---------------------------------------------" git -c color.ui=always diff app/models/ exit 1 fi timeout-minutes: 30 core_frontend_tests: if: "!(github.event_name == 'push' && github.repository == 'discourse/discourse-private-mirror')" name: core frontend (${{ matrix.browser }}) runs-on: ubuntu-20.04-8core container: image: discourse/discourse_test:slim-browsers options: --user discourse timeout-minutes: 35 strategy: fail-fast: false matrix: browser: ["Chrome", "Firefox ESR", "Firefox Evergreen"] env: TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }} TESTEM_FIREFOX_PATH: ${{ (matrix.browser == 'Firefox Evergreen') && '/opt/firefox-evergreen/firefox' }} steps: - uses: actions/checkout@v3 with: fetch-depth: 1 - name: Setup Git run: | git config --global user.email "ci@ci.invalid" git config --global user.name "Discourse CI" - name: Get yarn cache directory id: yarn-cache-dir run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - name: Yarn cache uses: actions/cache@v3 id: yarn-cache with: path: ${{ steps.yarn-cache-dir.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - name: Yarn install working-directory: ./app/assets/javascripts/discourse run: yarn install - name: Ember Build working-directory: ./app/assets/javascripts/discourse run: | mkdir /tmp/emberbuild yarn ember build --environment=test -o /tmp/emberbuild - name: Core QUnit working-directory: ./app/assets/javascripts/discourse run: yarn ember exam --path /tmp/emberbuild --load-balance --parallel=5 --launch "${{ env.TESTEM_BROWSER }}" --write-execution-file --random timeout-minutes: 15 - uses: actions/upload-artifact@v3 if: ${{ always() }} with: name: ember-exam-execution-${{matrix.browser}} path: ./app/assets/javascripts/discourse/test-execution-*.json