DEV: Upgrade dependencies to Ember 5.12 (#30131)

This commit is contained in:
Sérgio Saquetim 2024-12-11 11:09:25 -03:00 committed by GitHub
parent 6ef0b5d508
commit 1505978586
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 572 additions and 1238 deletions

View File

@ -19,7 +19,6 @@ plugins/**/lib/javascripts/locale
public/
!/app/assets/javascripts/discourse/public
vendor/
!app/assets/javascripts/ember-production-deprecations/vendor/
app/assets/javascripts/discourse/tests/fixtures
spec/
node_modules/

View File

@ -36,7 +36,7 @@
"ember-disable-prototype-extensions": "^1.1.3",
"ember-load-initializers": "^3.0.1",
"ember-resolver": "^13.1.0",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-source-channel-url": "^3.0.0",
"loader.js": "^4.7.0",
"webpack": "^5.97.1"

View File

@ -1,4 +1,6 @@
const DEPRECATION_WORKFLOW = [
{ handler: "silence", matchId: "template-action" }, // will be removed in Ember 6.0
{ handler: "silence", matchId: "deprecate-array-prototype-extensions" }, // will be removed in Ember 6.0
{ handler: "silence", matchId: "discourse.select-kit" },
{
handler: "silence",

View File

@ -38,7 +38,7 @@
"ember-cli-terser": "^4.0.2",
"ember-disable-prototype-extensions": "^1.1.3",
"ember-load-initializers": "^3.0.1",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-source-channel-url": "^3.0.0",
"loader.js": "^4.7.0",
"webpack": "^5.97.1"

View File

@ -33,7 +33,7 @@
"ember-disable-prototype-extensions": "^1.1.3",
"ember-load-initializers": "^3.0.1",
"ember-resolver": "^13.1.0",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-source-channel-url": "^3.0.0",
"loader.js": "^4.7.0",
"webpack": "^5.97.1"

View File

@ -12,6 +12,7 @@ export default {
registerDeprecationHandler((message, options, next) => {
if (options.id !== "ember-this-fallback.this-property-fallback") {
next(message, options);
return;
}

View File

@ -4,8 +4,6 @@ import { isTesting } from "discourse-common/config/environment";
import deprecated from "discourse-common/lib/deprecated";
import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
const COLOCATED_TEMPLATE_OVERRIDES = new Map();
let THROW_GJS_ERROR = isTesting();
/** For use in tests/integration/component-templates-test only */
@ -13,16 +11,9 @@ export function overrideThrowGjsError(value) {
THROW_GJS_ERROR = value;
}
// We're using a patched version of Ember with a modified GlimmerManager to make the code below work.
// This patch is not ideal, but Ember does not allow us to change a component template after initial association
// https://github.com/glimmerjs/glimmer-vm/blob/03a4b55c03/packages/%40glimmer/manager/lib/public/template.ts#L14-L20
const originalGetTemplate = GlimmerManager.getComponentTemplate;
// eslint-disable-next-line no-import-assign
GlimmerManager.getComponentTemplate = (component) => {
return (
COLOCATED_TEMPLATE_OVERRIDES.get(component) ??
originalGetTemplate(component)
);
};
export default {
after: ["populate-template-map", "mobile"],
@ -60,7 +51,9 @@ export default {
return;
}
const originalTemplate = originalGetTemplate(component);
// patched function: Ember's OG won't return overridden templates. This version will.
// it's safe to call it original template here because the override wasn't set yet.
const originalTemplate = GlimmerManager.getComponentTemplate(component);
const isStrictMode = originalTemplate?.()?.parsedLayout?.isStrictMode;
const finalOverrideModuleName = moduleNames[moduleNames.length - 1];
@ -85,7 +78,8 @@ export default {
const overrideTemplate = require(finalOverrideModuleName).default;
COLOCATED_TEMPLATE_OVERRIDES.set(component, overrideTemplate);
// patched function: Ember's OG does not allow overriding a component template
GlimmerManager.setComponentTemplate(overrideTemplate, component);
}
});
},
@ -112,6 +106,7 @@ export default {
},
teardown() {
COLOCATED_TEMPLATE_OVERRIDES.clear();
// patched function: doesn't exist on og GlimmerManager
GlimmerManager.clearTemplateOverrides();
},
};

View File

@ -1,4 +1,4 @@
import DEBUG from "@glimmer/env";
import { DEBUG } from "@glimmer/env";
import PreloadStore from "discourse/lib/preload-store";
import getURL from "discourse-common/lib/get-url";

View File

@ -128,6 +128,7 @@ module.exports = function (defaults) {
.slice(0, 8);
const appTree = compatBuild(app, Webpack, {
staticEmberSource: true,
splitAtRoutes: ["wizard"],
staticAppPaths: ["static"],
packagerOptions: {

View File

@ -97,9 +97,8 @@
"ember-load-initializers": "^3.0.1",
"ember-modifier": "^4.2.0",
"ember-on-resize-modifier": "^2.0.2",
"ember-production-deprecations": "workspace:1.0.0",
"ember-qunit": "^8.1.1",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-template-imports": "^4.2.0",
"ember-test-selectors": "^7.0.0",
"float-kit": "workspace:1.0.0",

View File

@ -16,6 +16,7 @@ function silenceMobileAndOverrideDeprecations(hooks) {
const promise = new Promise((resolve) => (unsilenceCallback = resolve));
withSilencedDeprecationsAsync(
[
"component-template-resolving", // silence ember's template resolving deprecation
"discourse.mobile-templates",
"discourse.resolver-template-overrides",
"discourse.component-template-overrides",

View File

@ -1,3 +1,4 @@
import { setComponentTemplate } from "@glimmer/manager";
import ClassicComponent from "@ember/component";
import { click, doubleClick, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
@ -76,31 +77,6 @@ module("Unit | Lib | ember-action-modifier", function (hooks) {
});
module("used on a classic component", function (innerHooks) {
class ExampleClassicButton extends ClassicComponent {
tagName = "";
onDoSomething = null;
doSomething() {
this.onDoSomething?.("doSomething");
}
}
// eslint-disable-next-line ember/no-classic-classes
const ExampleClassicButtonWithActions = ClassicComponent.extend({
tagName: "",
onDoSomething: null,
doSomething() {
this.onDoSomething?.("doSomething");
},
actions: {
doSomething() {
this.onDoSomething?.("actions.doSomething");
},
},
});
const exampleClassicButtonTemplate = hbs`
<a
href
@ -112,23 +88,46 @@ module("Unit | Lib | ember-action-modifier", function (hooks) {
</a>
`;
const ExampleClassicButton = setComponentTemplate(
exampleClassicButtonTemplate,
class extends ClassicComponent {
tagName = "";
onDoSomething = null;
doSomething() {
this.onDoSomething?.("doSomething");
}
}
);
const ExampleClassicButtonWithActions = setComponentTemplate(
exampleClassicButtonTemplate,
// eslint-disable-next-line ember/no-classic-classes
ClassicComponent.extend({
tagName: "",
onDoSomething: null,
doSomething() {
this.onDoSomething?.("doSomething");
},
actions: {
doSomething() {
this.onDoSomething?.("actions.doSomething");
},
},
})
);
innerHooks.beforeEach(function () {
this.owner.register(
"component:example-classic-button",
ExampleClassicButton
);
this.owner.register(
"template:components/example-classic-button",
exampleClassicButtonTemplate
);
this.owner.register(
"component:example-classic-button-with-actions",
ExampleClassicButtonWithActions
);
this.owner.register(
"template:components/example-classic-button-with-actions",
exampleClassicButtonTemplate
);
});
test("it can target a listener on the context", async function (assert) {

View File

@ -1,7 +1,7 @@
/* eslint-disable ember/no-classic-classes */
import GlimmerComponent from "@glimmer/component";
import ClassicComponent from "@ember/component";
import ClassicComponent, { setComponentTemplate } from "@ember/component";
import { action } from "@ember/object";
import { click, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
@ -10,38 +10,42 @@ import { module, test } from "qunit";
// Configure test-local Classic and Glimmer components that
// will be immune from upgrades to actual Discourse components.
const ExampleClassicButton = ClassicComponent.extend({
tagName: "button",
type: "button",
preventEventPropagation: false,
onClick: null,
onMouseDown: null,
const ExampleClassicButton = setComponentTemplate(
hbs`{{! template-lint-disable no-yield-only }}{{yield}}`,
ClassicComponent.extend({
tagName: "button",
type: "button",
preventEventPropagation: false,
onClick: null,
onMouseDown: null,
click(event) {
event.preventDefault();
if (this.preventEventPropagation) {
event.stopPropagation();
}
this.onClick?.(event);
},
});
const exampleClassicButtonTemplate = hbs`{{! template-lint-disable no-yield-only }}{{yield}}`;
click(event) {
event.preventDefault();
if (this.preventEventPropagation) {
event.stopPropagation();
}
this.onClick?.(event);
},
})
);
class ExampleGlimmerButton extends GlimmerComponent {
@action
click(event) {
event.preventDefault();
if (this.args.preventEventPropagation) {
event.stopPropagation();
const ExampleGlimmerButton = setComponentTemplate(
hbs`
<button {{on 'click' this.click}} type='button' ...attributes>
{{yield}}
</button>
`,
class extends GlimmerComponent {
@action
click(event) {
event.preventDefault();
if (this.args.preventEventPropagation) {
event.stopPropagation();
}
this.args.onClick?.(event);
}
this.args.onClick?.(event);
}
}
const exampleGlimmerButtonTemplate = hbs`
<button {{on 'click' this.click}} type='button' ...attributes>
{{yield}}
</button>
`;
);
module("Unit | Lib | ember-events", function (hooks) {
setupRenderingTest(hooks);
@ -51,19 +55,10 @@ module("Unit | Lib | ember-events", function (hooks) {
"component:example-classic-button",
ExampleClassicButton
);
this.owner.register(
"template:components/example-classic-button",
exampleClassicButtonTemplate
);
this.owner.register(
"component:example-glimmer-button",
ExampleGlimmerButton
);
this.owner.register(
"template:components/example-glimmer-button",
exampleGlimmerButtonTemplate
);
});
module("classic component event configuration", function () {

View File

@ -1,25 +0,0 @@
"use strict";
/**
* Ember's deprecation and registerDeprecationHandler APIs are stripped from production
* builds via the DEBUG flag. This file provides a minimal reimplementation of them
* to be used in production.
*
* Designed to be used alongside our fork of babel-plugin-debug-macros, which maintains
* deprecate calls in production builds. This fork is introduced via a custom yarn resolution
* in app/assets/javascripts/package.json.
*
* https://github.com/discourse/babel-plugin-debug-macros/commit/d179d613bf
*/
module.exports = {
name: require("./package").name,
included() {
this._super.included.apply(this, arguments);
this.app.import("vendor/ember-production-deprecations/deprecate-shim.js");
},
isDevelopingAddon() {
return true;
},
};

View File

@ -1,14 +0,0 @@
{
"name": "ember-production-deprecations",
"version": "1.0.0",
"description": "Prevents ember-cli from stripping deprecations in the production build",
"author": "Discourse",
"license": "GPL-2.0-only",
"keywords": [
"ember-addon"
],
"ember-addon": {
"after": "ember-cli-babel",
"before": "ember-cli-deprecation-workflow"
}
}

View File

@ -1,42 +0,0 @@
// Ember's deprecation and registerDeprecationHandler APIs are stripped from production
// builds via the DEBUG flag. This file provides a minimal reimplementation of them
// to be used in production
define("discourse/lib/deprecate-shim", ["exports"], function (exports) {
exports.applyShim = function () {
let handler = () => {};
require("@ember/debug/lib/deprecate").registerHandler = (fn) => {
const next = handler;
handler = (message, options) => fn(message, options, next);
};
require("@ember/debug").deprecate = (message, test, options) => {
if (test) {
return;
}
handler(message, options);
};
function formatMessage(message, options) {
if (options && options.id) {
message = message + ` [deprecation id: ${options.id}]`;
}
if (options && options.url) {
message += ` See ${options.url} for more details.`;
}
return message;
}
require("@ember/debug").registerDeprecationHandler(
function shimLogDeprecationToConsole(message, options) {
const updatedMessage = formatMessage(message, options);
// eslint-disable-next-line no-console
console.warn(`DEPRECATION: ${updatedMessage}`);
}
);
};
});
if (!require("@glimmer/env").DEBUG) {
require("discourse/lib/deprecate-shim").applyShim();
}

View File

@ -36,7 +36,7 @@
"ember-disable-prototype-extensions": "^1.1.3",
"ember-load-initializers": "^3.0.1",
"ember-resolver": "^13.1.0",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-source-channel-url": "^3.0.0",
"loader.js": "^4.7.0",
"webpack": "^5.97.1"

View File

@ -37,7 +37,7 @@
"ember-disable-prototype-extensions": "^1.1.3",
"ember-load-initializers": "^3.0.1",
"ember-resolver": "^13.1.0",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-source-channel-url": "^3.0.0",
"loader.js": "^4.7.0",
"webpack": "^5.97.1"

View File

@ -37,7 +37,7 @@
"ember-disable-prototype-extensions": "^1.1.3",
"ember-load-initializers": "^3.0.1",
"ember-resolver": "^13.1.0",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-source-channel-url": "^3.0.0",
"loader.js": "^4.7.0",
"webpack": "^5.97.1"

View File

@ -15,7 +15,7 @@
"discourse-common": "workspace:1.0.0",
"discourse-widget-hbs": "workspace:1.0.0",
"ember-cli-htmlbars": "^6.3.0",
"ember-source": "~5.5.0",
"ember-source": "~5.12.0",
"ember-this-fallback": "^0.4.0",
"handlebars": "^4.7.8",
"path-browserify": "^1.0.1",

View File

@ -6,7 +6,7 @@ require "json_schemer"
class Theme < ActiveRecord::Base
include GlobalPath
BASE_COMPILER_VERSION = 85
BASE_COMPILER_VERSION = 86
class SettingsMigrationError < StandardError
end

View File

@ -67,7 +67,8 @@
"virtual-dom@2.1.1": "patches/virtual-dom@2.1.1.patch",
"licensee@11.1.1": "patches/licensee@11.1.1.patch",
"content-tag@3.0.0": "patches/content-tag@3.0.0.patch",
"@ember-compat/tracked-built-ins@0.9.1": "patches/@ember-compat__tracked-built-ins@0.9.1.patch"
"@ember-compat/tracked-built-ins@0.9.1": "patches/@ember-compat__tracked-built-ins@0.9.1.patch",
"ember-source@5.12.0": "patches/ember-source@5.12.0.patch"
},
"peerDependencyRules": {
"allowedVersions": {

View File

@ -0,0 +1,97 @@
diff --git a/dist/ember-template-compiler.js b/dist/ember-template-compiler.js
index 01999af0c4c125af3c713318db7eb85fa492f72d..edadab049d4e5959b4d33ddcbe59bcaec9641e61 100644
--- a/dist/ember-template-compiler.js
+++ b/dist/ember-template-compiler.js
@@ -9485,10 +9485,20 @@ var define, require;
return Object.defineProperty(node, "escaped", {
enumerable: !1,
get() {
- return deprecate$1("The escaped property on mustache nodes is deprecated, use trusting instead"), !this.trusting;
+ // when upgrading Ember check if this patch is still necessary
+ // Ember 5.12 still shipped with the template-compiler generating a ton of warnings but the fix is already commited
+ // to glimmervm/syntax
+ // See https://github.com/glimmerjs/glimmer-vm/commit/02313376f21a606841b00a7789fd6128a1b292af
+ // return deprecate$1("The escaped property on mustache nodes is deprecated, use trusting instead"), !this.trusting;
+ return !this.trusting;
},
set(value) {
- deprecate$1("The escaped property on mustache nodes is deprecated, use trusting instead"), this.trusting = !value;
+ // when upgrading Ember check if this patch is still necessary
+ // Ember 5.12 still shipped with the template-compiler generating a ton of warnings but the fix is already commited
+ // to glimmervm/syntax
+ // See https://github.com/glimmerjs/glimmer-vm/commit/02313376f21a606841b00a7789fd6128a1b292af
+ // deprecate$1("The escaped property on mustache nodes is deprecated, use trusting instead"), this.trusting = !value;
+ this.trusting = !value;
}
}), node;
}({
diff --git a/dist/packages/@ember/-internals/deprecations/index.js b/dist/packages/@ember/-internals/deprecations/index.js
index a6390a7c14f78c4876f97695e057231c1c7ecef0..f62f2d4efbdbf3fb01cd9d1235ac5dc0967a8756 100644
--- a/dist/packages/@ember/-internals/deprecations/index.js
+++ b/dist/packages/@ember/-internals/deprecations/index.js
@@ -142,7 +142,7 @@ function deprecateUntil(message, deprecation) {
if (deprecation.isRemoved) {
throw new Error(`The API deprecated by ${options.id} was removed in ember-source ${options.until}. The message was: ${message}. Please see ${options.url} for more details.`);
}
- (isDevelopingApp() && !(deprecation.test) && deprecate(message, deprecation.test, options));
+ (true && !(deprecation.test) && deprecate(message, deprecation.test, options));
}
const {
EXTEND_PROTOTYPES
diff --git a/dist/packages/@ember/debug/lib/deprecate.js b/dist/packages/@ember/debug/lib/deprecate.js
index bd48673cc5a4416b492daded7e1ca4ff5b1a8d8d..9cf7b80e7308dd4b34b5d6a980294de43ce21bd5 100644
--- a/dist/packages/@ember/debug/lib/deprecate.js
+++ b/dist/packages/@ember/debug/lib/deprecate.js
@@ -50,7 +50,7 @@ let missingOptionsDeprecation;
let missingOptionsIdDeprecation;
let missingOptionDeprecation = () => '';
let deprecate = () => {};
-if (isDevelopingApp()) {
+if (true) {
registerHandler = function registerHandler(handler) {
registerHandler$1('deprecate', handler);
};
diff --git a/dist/packages/@ember/debug/lib/handlers.js b/dist/packages/@ember/debug/lib/handlers.js
index cd68afe479229ed77b4e4c93759aa90913cdc49c..6e7d71bbeb28f18259fa8afb48ef78279f25c531 100644
--- a/dist/packages/@ember/debug/lib/handlers.js
+++ b/dist/packages/@ember/debug/lib/handlers.js
@@ -3,7 +3,7 @@ import { isDevelopingApp } from '@embroider/macros';
let HANDLERS = {};
let registerHandler = function registerHandler(_type, _callback) {};
let invoke = () => {};
-if (isDevelopingApp()) {
+if (true) {
registerHandler = function registerHandler(type, callback) {
let nextHandler = HANDLERS[type] || (() => {});
HANDLERS[type] = (message, options) => {
diff --git a/dist/packages/@glimmer/manager/index.js b/dist/packages/@glimmer/manager/index.js
index ca6ac88fe0fcc7ad335b19fafa039fb6c5ebd14a..462672f9c1cdcca76e9e6713606c1b8d8797eff3 100644
--- a/dist/packages/@glimmer/manager/index.js
+++ b/dist/packages/@glimmer/manager/index.js
@@ -546,20 +546,23 @@ function setModifierManager(factory, obj) {
function setHelperManager(factory, obj) {
return setInternalHelperManager(new CustomHelperManager(factory), obj);
}
+let TEMPLATE_OVERRIDES = new WeakMap();
const TEMPLATES = new WeakMap(),
getPrototypeOf = Object.getPrototypeOf;
function setComponentTemplate(factory, obj) {
if (isDevelopingApp() && (null === obj || "object" != typeof obj && "function" != typeof obj)) throw new Error(`Cannot call \`setComponentTemplate\` on \`${debugToString$1(obj)}\``);
- if (isDevelopingApp() && TEMPLATES.has(obj)) throw new Error(`Cannot call \`setComponentTemplate\` multiple times on the same class (\`${debugToString$1(obj)}\`)`);
+ // if (isDevelopingApp() && TEMPLATES.has(obj)) throw new Error(`Cannot call \`setComponentTemplate\` multiple times on the same class (\`${debugToString$1(obj)}\`)`);
+ if (TEMPLATES.has(obj)) return TEMPLATE_OVERRIDES.set(obj, factory), obj;
return TEMPLATES.set(obj, factory), obj;
}
function getComponentTemplate(obj) {
let pointer = obj;
for (; null !== pointer;) {
- let template = TEMPLATES.get(pointer);
+ let template = TEMPLATE_OVERRIDES.get(pointer) ?? TEMPLATES.get(pointer);
if (void 0 !== template) return template;
pointer = getPrototypeOf(pointer);
}
}
+function clearTemplateOverrides() { TEMPLATE_OVERRIDES = new WeakMap() };
-export { CustomComponentManager, CustomHelperManager, CustomModifierManager, capabilityFlagsFrom, componentCapabilities, getComponentTemplate, getCustomTagFor, getInternalComponentManager, getInternalHelperManager, getInternalModifierManager, hasCapability, hasDestroyable, hasInternalComponentManager, hasInternalHelperManager, hasInternalModifierManager, hasValue, helperCapabilities, managerHasCapability, modifierCapabilities, setComponentManager, setComponentTemplate, setCustomTagFor, setHelperManager, setInternalComponentManager, setInternalHelperManager, setInternalModifierManager, setModifierManager };
+export { CustomComponentManager, CustomHelperManager, CustomModifierManager, capabilityFlagsFrom, componentCapabilities, getComponentTemplate, clearTemplateOverrides, getCustomTagFor, getInternalComponentManager, getInternalHelperManager, getInternalModifierManager, hasCapability, hasDestroyable, hasInternalComponentManager, hasInternalHelperManager, hasInternalModifierManager, hasValue, helperCapabilities, managerHasCapability, modifierCapabilities, setComponentManager, setComponentTemplate, setCustomTagFor, setHelperManager, setInternalComponentManager, setInternalHelperManager, setInternalModifierManager, setModifierManager };

View File

@ -73,11 +73,7 @@
class="-{{button.id}}"
disabled={{or this.disabled button.disabled}}
tabindex={{if button.disabled -1 0}}
{{on
"click"
(fn this.handleInlineButtonAction button.action)
bubbles=false
}}
{{on "click" (fn this.handleInlineButtonAction button.action)}}
{{on "focus" (fn this.computeIsFocused true)}}
{{on "blur" (fn this.computeIsFocused false)}}
/>

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ packages:
- "app/assets/javascripts/discourse-plugins"
- "app/assets/javascripts/discourse-widget-hbs"
- "app/assets/javascripts/ember-cli-progress-ci"
- "app/assets/javascripts/ember-production-deprecations"
- "app/assets/javascripts/float-kit"
- "app/assets/javascripts/pretty-text"
- "app/assets/javascripts/select-kit"

View File

@ -128,7 +128,7 @@ RSpec.describe DiscourseJsProcessor do
*/
{
"id": null,
"block": "[[[1,[34,0]]],[],false,[\\"somevalue\\"]]",
"block": "[[[1,[35,0]]],[],false,[\\"somevalue\\"]]",
"moduleName": "/blah/mymodule",
"isStrictMode": false
});

View File

@ -11,25 +11,17 @@ describe "JS Deprecation Handling", type: :system do
console.warn = (msg) => window.intercepted_warnings.push([msg, (new Error()).stack])
JS
# Apply deprecate shims. These are applied automatically in production
# builds, but running a full production build for system specs would be
# too slow
page.execute_script <<~JS
require("discourse/lib/deprecate-shim").applyShim();
JS
# Trigger a deprecation, then return the console.warn calls
warn_calls = page.execute_script <<~JS
const { deprecate } = require('@ember/debug');
deprecate("Some message", false, { id: "some.id" })
deprecate("Some message", false, { id: "some.id", for: "discourse", since: "3.4.0", until: "3.5.0" });
return window.intercepted_warnings
JS
expect(warn_calls.size).to eq(1)
call, backtrace = warn_calls[0]
expect(call).to eq("DEPRECATION: Some message [deprecation id: some.id]")
expect(backtrace).to include("shimLogDeprecationToConsole")
expect(call).to start_with("DEPRECATION: Some message [deprecation id: some.id]")
end
it "shows warnings to admins for critical deprecations" do