From 00907363d4b290df1c755df1a2494b95265e40b4 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 21 Feb 2025 11:15:04 +0000 Subject: [PATCH] DEV: Drop ember-cli-based SCSS and locale compilation (#31407) This totally separate SCSS and i18n compilation pipelines only existed so that we could run `ember exam` in CI without starting Rails. Now that our CI has such heavy caching of Ruby dependencies and database migrations, the speed benefit of this is not worth the cost of maintaining these separate pipelines. Therefore, this commit removes that system, and updates CI to use `bin/rake qunit:test`. That will start up a Rails server and proxy stylesheet/locale requests to it. This strategy was already used for our theme and plugin qunit test runs. --- .github/workflows/tests.yml | 75 ++----- .../javascripts/discourse/ember-cli-build.js | 11 - .../discourse/lib/discourse-scss.js | 64 ------ .../discourse/lib/translation-plugin.js | 137 ------------- app/assets/javascripts/discourse/package.json | 1 - app/assets/javascripts/discourse/testem.js | 21 +- .../javascripts/discourse/tests/index.html | 9 +- app/assets/stylesheets/qunit.scss | 11 - app/controllers/bootstrap_controller.rb | 24 ++- app/controllers/extra_locales_controller.rb | 3 +- config/routes.rb | 1 + lib/tasks/docker.rake | 5 +- pnpm-lock.yaml | 192 ------------------ .../requests/extra_locales_controller_spec.rb | 3 +- 14 files changed, 65 insertions(+), 492 deletions(-) delete mode 100644 app/assets/javascripts/discourse/lib/discourse-scss.js delete mode 100644 app/assets/javascripts/discourse/lib/translation-plugin.js delete mode 100644 app/assets/stylesheets/qunit.scss diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 143aab2ab4c..48620686c46 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,7 +28,7 @@ permissions: jobs: build: if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror' - name: ${{ matrix.target }} ${{ matrix.build_type }} # Update fetch-job-id step if changing this + name: ${{ matrix.target }} ${{ matrix.build_type }}${{ (matrix.target == 'core' && matrix.build_type == 'frontend' && format(' ({0})', matrix.browser)) || '' }} # Update fetch-job-id step if changing this runs-on: ${{ (github.repository_owner == 'discourse' && 'debian-12') || 'ubuntu-latest' }} container: discourse/discourse_test:release timeout-minutes: 20 @@ -42,8 +42,9 @@ jobs: MINIO_RUNNER_LOG_LEVEL: DEBUG DISCOURSE_TURBO_RSPEC_RETRY_AND_LOG_FLAKY_TESTS: ${{ (matrix.build_type == 'system' || matrix.build_type == 'backend') && '1' }} CHEAP_SOURCE_MAPS: "1" - TESTEM_DEFAULT_BROWSER: Chrome MINIO_RUNNER_INSTALL_DIR: /home/discourse/.minio_runner + TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }} + TESTEM_FIREFOX_PATH: ${{ (matrix.browser == 'Firefox Evergreen') && '/opt/firefox-evergreen/firefox' }} strategy: fail-fast: false @@ -51,6 +52,7 @@ jobs: matrix: build_type: [backend, frontend, system, annotations] target: [core, plugins, themes] + browser: [Chrome] exclude: - build_type: annotations target: plugins @@ -58,11 +60,15 @@ jobs: target: themes - build_type: backend target: themes - - build_type: frontend - target: core # Handled by core_frontend_tests job (below) include: - build_type: system target: chat + - build_type: frontend + target: core + browser: Firefox Evergreen + - build_type: frontend + target: core + browser: Firefox ESR steps: - name: Set working directory owner @@ -233,6 +239,11 @@ jobs: if: matrix.build_type == 'backend' && matrix.target == 'plugins' run: bin/rake plugin:turbo_spec['*','--verbose --format=documentation --use-runtime-info --profile=50'] + - name: Core QUnit + if: matrix.build_type == 'frontend' && matrix.target == 'core' + run: QUNIT_WRITE_EXECUTION_FILE=1 bin/rake qunit:test + timeout-minutes: 30 + - name: Plugin QUnit if: matrix.build_type == 'frontend' && matrix.target == 'plugins' run: QUNIT_WRITE_EXECUTION_FILE=1 bin/rake plugin:qunit['*'] @@ -244,9 +255,9 @@ jobs: timeout-minutes: 10 - uses: actions/upload-artifact@v4 - if: always() && matrix.build_type == 'frontend' && matrix.target == 'plugins' + if: always() && matrix.build_type == 'frontend' with: - name: ember-exam-execution-plugins-frontend-${{ hashFiles('./app/assets/javascripts/discourse/test-execution-*.json') }} + name: ember-exam-execution-${{ matrix.target }}-${{ matrix.browser }}-frontend-${{ hashFiles('./app/assets/javascripts/discourse/test-execution-*.json') }} path: ./app/assets/javascripts/discourse/test-execution-*.json - name: Ember Build for System Tests @@ -322,7 +333,7 @@ jobs: id: fetch-job-id if: steps.check-flaky-spec-report.outputs.exists == 'true' run: | - job_id=$(ruby script/get_github_workflow_run_job_id.rb ${{ github.run_id }} ${{ github.run_attempt }} '${{ matrix.target }} ${{ matrix.build_type }}') + job_id=$(ruby script/get_github_workflow_run_job_id.rb ${{ github.run_id }} ${{ github.run_attempt }} '${{ matrix.target }} ${{ matrix.build_type }}${{ (matrix.target == 'core' && matrix.build_type == 'frontend' && format(' ({0})', matrix.browser)) || '' }}') echo "job_id=$job_id" >> $GITHUB_OUTPUT - name: Create flaky tests report artifact @@ -353,56 +364,6 @@ jobs: fi timeout-minutes: 30 - core_frontend_tests: - if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror' - name: core frontend (${{ matrix.browser }}) - runs-on: ${{ (github.repository_owner == 'discourse' && 'debian-12') || 'ubuntu-latest' }} - container: - image: discourse/discourse_test:release - 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' }} - CHEAP_SOURCE_MAPS: "1" - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Setup Git - run: | - git config --global user.email "ci@ci.invalid" - git config --global user.name "Discourse CI" - - - name: pnpm install - run: pnpm install --frozen-lockfile - - - name: Ember Build - working-directory: ./app/assets/javascripts/discourse - run: | - mkdir /tmp/emberbuild - pnpm ember build --environment=test -o /tmp/emberbuild - - - name: Core QUnit - working-directory: ./app/assets/javascripts/discourse - run: | - pnpm ember exam --path /tmp/emberbuild --load-balance --parallel=$(($(nproc) / 2)) --launch "${{ env.TESTEM_BROWSER }}" --write-execution-file --random - timeout-minutes: 15 - - - uses: actions/upload-artifact@v4 - if: ${{ always() }} - with: - name: ember-exam-execution-${{ matrix.browser }}-${{ hashFiles('./app/assets/javascripts/discourse/test-execution-*.json') }} - path: ./app/assets/javascripts/discourse/test-execution-*.json merge: if: github.repository == 'discourse/discourse' && github.ref == 'refs/heads/main' diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index dd1cfaf6368..44cac1ad74b 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -4,9 +4,7 @@ const EmberApp = require("ember-cli/lib/broccoli/ember-app"); const path = require("path"); const mergeTrees = require("broccoli-merge-trees"); const concat = require("broccoli-concat"); -const { createI18nTree } = require("./lib/translation-plugin"); const { parsePluginClientSettings } = require("./lib/site-settings-plugin"); -const discourseScss = require("./lib/discourse-scss"); const generateScriptsTree = require("./lib/scripts"); const funnel = require("broccoli-funnel"); const DeprecationSilencer = require("deprecation-silencer"); @@ -96,20 +94,12 @@ module.exports = function (defaults) { const adminTree = app.project.findAddonByName("admin").treeForAddonBundle(); - const testStylesheetTree = mergeTrees([ - discourseScss(`${discourseRoot}/app/assets/stylesheets`, "qunit.scss"), - discourseScss( - `${discourseRoot}/app/assets/stylesheets`, - "qunit-custom.scss" - ), - ]); app.project.liveReloadFilterPatterns = [/.*\.scss/]; const terserPlugin = app.project.findAddonByName("ember-cli-terser"); const applyTerser = (tree) => terserPlugin.postprocessTree("all", tree); let extraPublicTrees = [ - createI18nTree(discourseRoot, vendorJs), parsePluginClientSettings(discourseRoot, vendorJs, app), funnel(`${discourseRoot}/public/javascripts`, { destDir: "javascripts" }), applyTerser( @@ -120,7 +110,6 @@ module.exports = function (defaults) { ), applyTerser(generateScriptsTree(app)), applyTerser(discoursePluginsTree), - testStylesheetTree, ]; const assetCachebuster = process.env["DISCOURSE_ASSET_URL_SALT"] || ""; diff --git a/app/assets/javascripts/discourse/lib/discourse-scss.js b/app/assets/javascripts/discourse/lib/discourse-scss.js deleted file mode 100644 index a96881dafe7..00000000000 --- a/app/assets/javascripts/discourse/lib/discourse-scss.js +++ /dev/null @@ -1,64 +0,0 @@ -const Plugin = require("broccoli-plugin"); -const sass = require("sass"); -const fs = require("fs"); -const concat = require("broccoli-concat"); - -let builtSet = new Set(); - -class DiscourseScss extends Plugin { - constructor(inputNodes, inputFile, options) { - super(inputNodes, { - ...options, - persistentOutput: true, - }); - - this.inputFile = inputFile; - } - - build() { - let file = this.inputPaths[0] + "/" + this.inputFile; - - // We could get fancy eventually and do this based on whether the css changes - // but this is just used for tests right now. - if (builtSet.has(file)) { - return; - } - - let deprecationCount = 0; - let result = sass.renderSync({ - file, - includePaths: this.inputPaths, - silenceDeprecations: ["color-functions", "import", "global-builtin"], - verbose: true, // call warn() for all deprecations - logger: { - warn(message, options) { - if (options.deprecation) { - deprecationCount += 1; - } else { - // eslint-disable-next-line no-console - console.warn(`\nWARNING: ${message}`); - } - }, - }, - }); - if (deprecationCount > 0) { - // eslint-disable-next-line no-console - console.warn( - `\nWARNING: ${deprecationCount} deprecations encountered while compiling scss. (we cannot correct these until the Ruby SCSS pipeline is updated)` - ); - } - - fs.writeFileSync( - `${this.outputPath}/` + this.inputFile.replace(".scss", ".css"), - result.css - ); - - builtSet.add(file); - } -} - -module.exports = function scss(path, file) { - return concat(new DiscourseScss([path], file), { - outputFile: `assets/${file.replace(".scss", ".css")}`, - }); -}; diff --git a/app/assets/javascripts/discourse/lib/translation-plugin.js b/app/assets/javascripts/discourse/lib/translation-plugin.js deleted file mode 100644 index ef626bdf1be..00000000000 --- a/app/assets/javascripts/discourse/lib/translation-plugin.js +++ /dev/null @@ -1,137 +0,0 @@ -const Plugin = require("broccoli-plugin"); -const Yaml = require("js-yaml"); -const fs = require("fs"); -const concat = require("broccoli-concat"); -const mergeTrees = require("broccoli-merge-trees"); -const MessageFormat = require("@messageformat/core"); -const deepmerge = require("deepmerge"); -const glob = require("glob"); -const { shouldLoadPlugins } = require("discourse-plugins"); - -let built = false; - -class TranslationPlugin extends Plugin { - constructor(inputNodes, inputFile, options) { - super(inputNodes, { - ...options, - persistentOutput: true, - }); - - this.inputFile = inputFile; - } - - replaceMF(formats, input, path = []) { - if (!input) { - return; - } - - Object.keys(input).forEach((key) => { - let value = input[key]; - - let subpath = path.concat(key); - if (typeof value === "object") { - this.replaceMF(formats, value, subpath); - } else if (key.endsWith("_MF")) { - // omit locale.js - let mfPath = subpath.slice(2).join("."); - formats[mfPath] = this.mf.compile(value); - } - }); - } - - build() { - // We could get fancy eventually and do this based on whether the yaml - // or vendor files change but in practice we shouldn't need exact up to date - // translations in admin. - if (built) { - return; - } - - let parsed = {}; - - this.inputPaths.forEach((path) => { - let file = path + "/" + this.inputFile; - let yaml = fs.readFileSync(file, { encoding: "UTF-8" }); - let loaded = Yaml.load(yaml, { json: true }); - parsed = deepmerge(parsed, loaded); - }); - - let extras = { - en: { - admin: parsed.en.admin_js.admin, - wizard: parsed.en.wizard_js.wizard, - }, - }; - - delete parsed.en.admin_js; - delete parsed.en.wizard_js; - - let formats = {}; - this.mf = new MessageFormat("en"); - this.replaceMF(formats, parsed); - this.replaceMF(formats, extras); - - formats = Object.entries(formats).map(([k, v]) => `"${k}": ${v}`); - - let contents = ` - (function() { - I18n.locale = 'en'; - I18n.translations = ${JSON.stringify(parsed)}; - I18n.extras = ${JSON.stringify(extras)}; - - const Messages = require("@messageformat/runtime/messages").default; - const { number, plural, select } = require("@messageformat/runtime"); - const { en } = require("@messageformat/runtime/lib/cardinals"); - const msgData = { en: { ${formats.join(",\n")} } }; - const messages = new Messages(msgData, "en"); - messages.defaultLocale = "en"; - I18n._mfMessages = messages; - })() - `; - - fs.writeFileSync( - `${this.outputPath}/` + this.inputFile.replace(".yml", ".js"), - contents - ); - built = true; - } -} - -module.exports = function translatePlugin(...params) { - return new TranslationPlugin(...params); -}; - -module.exports.createI18nTree = function (discourseRoot, vendorJs) { - let translations = [discourseRoot + "/config/locales"]; - - if (shouldLoadPlugins()) { - translations = translations.concat( - glob - .sync(discourseRoot + "/plugins/*/config/locales/client.en.yml") - .map((f) => f.replace(/\/client\.en\.yml$/, "")) - ); - } - - let en = new TranslationPlugin(translations, "client.en.yml"); - - return concat( - mergeTrees([ - vendorJs, - discourseRoot + "/app/assets/javascripts/locales", - en, - ]), - { - inputFiles: [ - "i18n.js", - "moment.js", - "moment-timezone-with-data.js", - "client.en.js", - ], - headerFiles: ["i18n.js", "moment.js", "moment-timezone-with-data.js"], - footerFiles: ["client.en.js"], - outputFile: `assets/test-i18n.js`, - } - ); -}; - -module.exports.TranslationPlugin = TranslationPlugin; diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json index bf8070e2716..55374884ff7 100644 --- a/app/assets/javascripts/discourse/package.json +++ b/app/assets/javascripts/discourse/package.json @@ -127,7 +127,6 @@ "pretender": "^3.4.7", "qunit": "^2.24.1", "qunit-dom": "^3.4.0", - "sass": "^1.85.0", "select-kit": "workspace:1.0.0", "sinon": "^19.0.2", "source-map": "^0.7.4", diff --git a/app/assets/javascripts/discourse/testem.js b/app/assets/javascripts/discourse/testem.js index d30c4910057..ac54dc31423 100644 --- a/app/assets/javascripts/discourse/testem.js +++ b/app/assets/javascripts/discourse/testem.js @@ -1,5 +1,4 @@ const TapReporter = require("testem/lib/reporters/tap_reporter"); -const { shouldLoadPlugins } = require("discourse-plugins"); const fs = require("fs"); const displayUtils = require("testem/lib/utils/displayutils"); const colors = require("@colors/colors/safe"); @@ -177,6 +176,16 @@ if (process.env.TESTEM_FIREFOX_PATH) { } const target = `http://127.0.0.1:${process.env.UNICORN_PORT || "3000"}`; + +fetch(`${target}/about.json`).catch(() => { + // eslint-disable-next-line no-console + console.error( + colors.red( + `Error connecting to Rails server on ${target}. Is it running? Use 'bin/rake qunit:test' or 'plugin:qunit' to start automatically.` + ) + ); +}); + const themeTestPages = process.env.THEME_TEST_PAGES; if (themeTestPages) { @@ -204,20 +213,26 @@ if (themeTestPages) { }); }, ]; -} else if (shouldLoadPlugins()) { +} else { // Running with ember cli, but we want to pass through plugin request to Rails module.exports.proxies = { + "/assets/locales/*.js": { + target, + }, "/assets/plugins/*_extra.js": { target, }, "/plugins/": { target, }, - "/bootstrap/plugin-css-for-tests.css": { + "/bootstrap/": { target, }, "/stylesheets/": { target, }, + "/extra-locales/": { + target, + }, }; } diff --git a/app/assets/javascripts/discourse/tests/index.html b/app/assets/javascripts/discourse/tests/index.html index 3ff46ac2e85..3d88c4a1340 100644 --- a/app/assets/javascripts/discourse/tests/index.html +++ b/app/assets/javascripts/discourse/tests/index.html @@ -20,7 +20,7 @@ - + {{content-for "head-footer"}} {{content-for "test-head-footer"}} @@ -53,7 +53,10 @@ - + + + + @@ -72,6 +75,6 @@ - + diff --git a/app/assets/stylesheets/qunit.scss b/app/assets/stylesheets/qunit.scss deleted file mode 100644 index cd79425feb8..00000000000 --- a/app/assets/stylesheets/qunit.scss +++ /dev/null @@ -1,11 +0,0 @@ -// Styles for Ember CLI test environment -:root { - --font-family: "Arial"; -} - -@import "common/foundation/colors"; -@import "common/foundation/variables"; -@import "common/foundation/mixins"; -@import "desktop"; -@import "color_definitions"; -@import "admin"; diff --git a/app/controllers/bootstrap_controller.rb b/app/controllers/bootstrap_controller.rb index 4770ee17cc2..cb4eadc6dd6 100644 --- a/app/controllers/bootstrap_controller.rb +++ b/app/controllers/bootstrap_controller.rb @@ -4,16 +4,26 @@ class BootstrapController < ApplicationController skip_before_action :redirect_to_login_if_required, :check_xhr def plugin_css_for_tests + targets = Discourse.find_plugin_css_assets(include_disabled: true, desktop_view: true) + render_css_for_tests(targets) + end + + def core_css_for_tests + targets = %w[color_definitions desktop admin] + render_css_for_tests(targets) + end + + private + + def render_css_for_tests(targets) urls = - Discourse - .find_plugin_css_assets(include_disabled: true, desktop_view: true) - .map do |target| - details = Stylesheet::Manager.new().stylesheet_details(target, "all") - details[0][:new_href] - end + targets.map do |target| + details = Stylesheet::Manager.new().stylesheet_details(target, "all") + details[0][:new_href] + end stylesheet = <<~CSS - /* For use in tests only - `@import`s all plugin stylesheets */ + /* For use in tests only */ #{urls.map { |url| "@import \"#{url}\";" }.join("\n")} CSS diff --git a/app/controllers/extra_locales_controller.rb b/app/controllers/extra_locales_controller.rb index df2768e8099..1b5fc059514 100644 --- a/app/controllers/extra_locales_controller.rb +++ b/app/controllers/extra_locales_controller.rb @@ -85,6 +85,7 @@ class ExtraLocalesController < ApplicationController private def valid_bundle?(bundle) - bundle.in?(BUNDLES) || (bundle =~ /\A(admin|wizard)\z/ && current_user&.staff?) + return true if bundle.in?(BUNDLES) + bundle =~ /\A(admin|wizard)\z/ && (current_user&.staff? || Rails.env.local?) end end diff --git a/config/routes.rb b/config/routes.rb index 5ab67c8d219..75e5ed6bfbb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -29,6 +29,7 @@ Discourse::Application.routes.draw do if Rails.env.test? || Rails.env.development? get "/bootstrap/plugin-css-for-tests.css" => "bootstrap#plugin_css_for_tests" + get "/bootstrap/core-css-for-tests.css" => "bootstrap#core_css_for_tests" end # This is not a valid production route and is causing routing errors to be raised in diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake index cb1a6021dcd..4269a6e0ac6 100644 --- a/lib/tasks/docker.rake +++ b/lib/tasks/docker.rake @@ -300,10 +300,7 @@ task "docker:test" do unless ENV["RUBY_ONLY"] unless ENV["SKIP_CORE"] - @good &&= - run_or_fail( - "cd app/assets/javascripts/discourse && CI=1 pnpm ember exam --load-balance --parallel=#{qunit_concurrency} --random", - ) + @good &&= run_or_fail("CI=1 QUNIT_PARALLEL=#{qunit_concurrency} bin/rake qunit:test") end unless ENV["SKIP_PLUGINS"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7603dfc39c6..ae5188c1cfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -597,9 +597,6 @@ importers: qunit-dom: specifier: ^3.4.0 version: 3.4.0 - sass: - specifier: ^1.85.0 - version: 1.85.0 select-kit: specifier: workspace:1.0.0 version: link:../select-kit @@ -2423,88 +2420,6 @@ packages: resolution: {integrity: sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==} engines: {node: ^16.14.0 || >=18.0.0} - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} - engines: {node: '>= 10.0.0'} - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -3612,10 +3527,6 @@ packages: peerDependencies: chart.js: '>=3.0.0' - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -4238,11 +4149,6 @@ packages: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - detect-newline@4.0.1: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5515,9 +5421,6 @@ packages: immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} - immutable@5.0.3: - resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} - import-cwd@3.0.0: resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} engines: {node: '>=8'} @@ -6594,9 +6497,6 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -7325,10 +7225,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - recast@0.18.10: resolution: {integrity: sha512-XNvYvkfdAN9QewbrxeTOjgINkdY/odTgTS56ZNEWL9Ml0weT4T3sFtvnTuF+Gxyu46ANcRm1ntrF6F5LAJPAaQ==} engines: {node: '>= 4'} @@ -7592,11 +7488,6 @@ packages: engines: {node: 10.* || >= 12.*} hasBin: true - sass@1.85.0: - resolution: {integrity: sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==} - engines: {node: '>=14.0.0'} - hasBin: true - saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -10598,67 +10489,6 @@ snapshots: - bluebird - supports-color - '@parcel/watcher-android-arm64@2.5.1': - optional: true - - '@parcel/watcher-darwin-arm64@2.5.1': - optional: true - - '@parcel/watcher-darwin-x64@2.5.1': - optional: true - - '@parcel/watcher-freebsd-x64@2.5.1': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-arm-musl@2.5.1': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-arm64-musl@2.5.1': - optional: true - - '@parcel/watcher-linux-x64-glibc@2.5.1': - optional: true - - '@parcel/watcher-linux-x64-musl@2.5.1': - optional: true - - '@parcel/watcher-win32-arm64@2.5.1': - optional: true - - '@parcel/watcher-win32-ia32@2.5.1': - optional: true - - '@parcel/watcher-win32-x64@2.5.1': - optional: true - - '@parcel/watcher@2.5.1': - dependencies: - detect-libc: 1.0.3 - is-glob: 4.0.3 - micromatch: 4.0.8 - node-addon-api: 7.1.1 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - optional: true - '@pkgjs/parseargs@0.11.0': optional: true @@ -12139,10 +11969,6 @@ snapshots: dependencies: chart.js: 3.5.1 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - chownr@2.0.0: {} chrome-launcher@1.1.2: @@ -12580,9 +12406,6 @@ snapshots: detect-indent@7.0.1: {} - detect-libc@1.0.3: - optional: true - detect-newline@4.0.1: {} devtools-protocol@0.0.1402036: {} @@ -14665,8 +14488,6 @@ snapshots: immer@10.1.1: {} - immutable@5.0.3: {} - import-cwd@3.0.0: dependencies: import-from: 3.0.0 @@ -15768,9 +15589,6 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 - node-addon-api@7.1.1: - optional: true - node-domexception@1.0.0: {} node-fetch@2.7.0(encoding@0.1.13): @@ -16566,8 +16384,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@4.1.2: {} - recast@0.18.10: dependencies: ast-types: 0.13.3 @@ -16838,14 +16654,6 @@ snapshots: minimist: 1.2.8 walker: 1.0.8 - sass@1.85.0: - dependencies: - chokidar: 4.0.3 - immutable: 5.0.3 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.1 - saxes@6.0.0: dependencies: xmlchars: 2.2.0 diff --git a/spec/requests/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb index c240c293f74..be4c910b2ee 100644 --- a/spec/requests/extra_locales_controller_spec.rb +++ b/spec/requests/extra_locales_controller_spec.rb @@ -14,7 +14,8 @@ RSpec.describe ExtraLocalesController do expect(response.status).to eq(403) end - it "requires staff access" do + it "requires staff access in production" do + Rails.env.stubs(:local?).returns(false) get "/extra-locales/admin" expect(response.status).to eq(403)