├── tests
├── unit
│ ├── .gitkeep
│ ├── deprecation-collector-test.js
│ ├── flush-deprecations-test.js
│ └── handle-deprecation-workflow-test.js
├── helpers
│ └── debug-test.js
├── index.html
├── test-helper.js
├── deprecation-workflow.js
└── acceptance
│ ├── flush-deprecations-test.js
│ └── workflow-config-test.js
├── addon-main.cjs
├── demo-app
├── templates
│ └── application.gts
├── styles.css
└── app.gts
├── .prettierignore
├── .gitignore
├── .prettierrc.mjs
├── .env.development
├── pnpm-workspace.yaml
├── .editorconfig
├── src
├── index.d.ts
└── index.js
├── config
└── ember-cli-update.json
├── index.html
├── vite.config.mjs
├── CONTRIBUTING.md
├── testem.cjs
├── LICENSE.md
├── babel.config.cjs
├── .github
└── workflows
│ ├── publish.yml
│ ├── plan-release.yml
│ └── ci.yml
├── .release-plan.json
├── RELEASE.md
├── .try.mjs
├── eslint.config.mjs
├── package.json
├── README.md
└── CHANGELOG.md
/tests/unit/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addon-main.cjs:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { addonV1Shim } = require('@embroider/addon-shim');
4 | module.exports = addonV1Shim(__dirname);
5 |
--------------------------------------------------------------------------------
/demo-app/templates/application.gts:
--------------------------------------------------------------------------------
1 | import { pageTitle } from 'ember-page-title';
2 |
3 | const greeting = 'hello';
4 |
5 |
6 | {{pageTitle "Demo App"}}
7 |
8 | Welcome to ember!
9 |
10 | {{greeting}}, world!
11 |
12 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # unconventional js
2 | /blueprints/*/files/
3 |
4 | # compiled output
5 | /dist/
6 | /dist-*/
7 | /declarations/
8 |
9 | # misc
10 | /coverage/
11 | pnpm-lock.yaml
12 | config/ember-cli-update.json
13 | *.yaml
14 | *.yml
15 | *.md
16 | *.html
17 |
--------------------------------------------------------------------------------
/demo-app/styles.css:
--------------------------------------------------------------------------------
1 | /**
2 | * See: https://vite.dev/guide/features.html#css
3 | * for features beyond normal CSS that are available to you.
4 | *
5 | * This CSS is meant for the demo-app only, and will not be included in the published assets for this library.
6 | */
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | dist/
3 | dist-tests/
4 | declarations/
5 |
6 | # from scenarios
7 | tmp/
8 | config/optional-features.json
9 | ember-cli-build.cjs
10 |
11 | # npm/pnpm/yarn pack output
12 | *.tgz
13 |
14 | # deps & caches
15 | node_modules/
16 | .eslintcache
17 | .prettiercache
18 |
--------------------------------------------------------------------------------
/.prettierrc.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: ['prettier-plugin-ember-template-tag'],
3 | overrides: [
4 | {
5 | files: '*.{js,gjs,ts,gts,mjs,mts,cjs,cts}',
6 | options: {
7 | singleQuote: true,
8 | templateSingleQuote: false,
9 | },
10 | },
11 | ],
12 | };
13 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | # This file is committed to git and should not contain any secrets.
2 | #
3 | # Vite recommends using .env.local or .env.[mode].local if you need to manage secrets
4 | # SEE: https://vite.dev/guide/env-and-mode.html#env-files for more information.
5 |
6 |
7 | # Default NODE_ENV with vite build --mode=test is production
8 | NODE_ENV=development
9 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "."
3 |
4 | # Docs: https://pnpm.io/settings
5 | # https://github.com/emberjs/rfcs/pull/907
6 |
7 | # we don't want addons to be bad citizens of the ecosystem
8 | autoInstallPeers: false
9 |
10 | # we want true isolation,
11 | # if a dependency is not declared, we want an error
12 | resolvePeersFromWorkspaceRoot: false
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.hbs]
16 | insert_final_newline = false
17 |
18 | [*.{diff,md}]
19 | trim_trailing_whitespace = false
20 |
--------------------------------------------------------------------------------
/tests/helpers/debug-test.js:
--------------------------------------------------------------------------------
1 | import { DEBUG } from '@glimmer/env';
2 | import { test } from 'qunit';
3 |
4 | export default function debugTest(description, callback) {
5 | return test(description, function (assert) {
6 | if (!DEBUG) {
7 | assert.pushResult({
8 | result: true,
9 | message: 'debug functions are disabled',
10 | });
11 | return;
12 | }
13 |
14 | return callback.apply(this, arguments);
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | interface WorkflowMatchId {
2 | handler?: 'log' | 'silence' | 'throw';
3 | matchId: string | RegExp;
4 | }
5 |
6 | interface WorkflowMatchMessage {
7 | handler?: 'log' | 'silence' | 'throw';
8 | matchMessage: string | RegExp;
9 | }
10 |
11 | type Workflow = WorkflowMatchId | WorkflowMatchMessage;
12 |
13 | export default function setupDeprecationWorkflow(config?: {
14 | throwOnUnhandled?: boolean;
15 | workflow?: Workflow[];
16 | }): void;
17 |
--------------------------------------------------------------------------------
/config/ember-cli-update.json:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": "1.0.0",
3 | "projectName": "ember-cli-deprecation-workflow",
4 | "packages": [
5 | {
6 | "name": "@ember/addon-blueprint",
7 | "version": "0.16.1",
8 | "blueprints": [
9 | {
10 | "name": "@ember/addon-blueprint",
11 | "isBaseBlueprint": true,
12 | "options": [
13 | "--ci-provider=github",
14 | "--pnpm"
15 | ]
16 | }
17 | ]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Demo App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/vite.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import { extensions, ember, classicEmberSupport } from '@embroider/vite';
3 | import { babel } from '@rollup/plugin-babel';
4 |
5 | // For scenario testing
6 | const isCompat = Boolean(process.env.ENABLE_COMPAT_BUILD);
7 |
8 | export default defineConfig({
9 | plugins: [
10 | ...(isCompat ? [classicEmberSupport()] : []),
11 | ember(),
12 | babel({
13 | babelHelpers: 'inline',
14 | extensions,
15 | }),
16 | ],
17 | build: {
18 | rollupOptions: {
19 | input: {
20 | tests: 'tests/index.html',
21 | },
22 | },
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How To Contribute
2 |
3 | ## Installation
4 |
5 | - `git clone `
6 | - `cd ember-cli-deprecation-workflow`
7 | - `pnpm install`
8 |
9 | ## Linting
10 |
11 | - `pnpm lint`
12 | - `pnpm lint:fix`
13 |
14 | ## Building the addon
15 |
16 | - `pnpm build`
17 |
18 | ## Running tests
19 |
20 | - `pnpm test` – Runs the test suite on the current Ember version
21 | - `pnpm test:watch` – Runs the test suite in "watch mode"
22 |
23 | ## Running the test application
24 |
25 | - `pnpm start`
26 | - Visit the test application at [http://localhost:4200](http://localhost:4200).
27 |
28 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/).
29 |
--------------------------------------------------------------------------------
/testem.cjs:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | if (typeof module !== 'undefined') {
4 | module.exports = {
5 | test_page: 'tests/index.html?hidepassed',
6 | cwd: 'dist-tests',
7 | disable_watching: true,
8 | launch_in_ci: ['Chrome'],
9 | launch_in_dev: ['Chrome'],
10 | browser_start_timeout: 120,
11 | browser_args: {
12 | Chrome: {
13 | ci: [
14 | // --no-sandbox is needed when running Chrome inside a container
15 | process.env.CI ? '--no-sandbox' : null,
16 | '--headless=new',
17 | '--disable-dev-shm-usage',
18 | '--disable-software-rasterizer',
19 | '--mute-audio',
20 | '--remote-debugging-port=0',
21 | '--window-size=1440,900',
22 | ].filter(Boolean),
23 | },
24 | },
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ember-cli-deprecation-workflow Tests
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
21 |
22 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/test-helper.js:
--------------------------------------------------------------------------------
1 | import EmberApp from 'ember-strict-application-resolver';
2 | import EmberRouter from '@ember/routing/router';
3 | import * as QUnit from 'qunit';
4 | import { setApplication } from '@ember/test-helpers';
5 | import { setup } from 'qunit-dom';
6 | import { start as qunitStart, setupEmberOnerrorValidation } from 'ember-qunit';
7 | import './deprecation-workflow';
8 |
9 | class Router extends EmberRouter {
10 | location = 'none';
11 | rootURL = '/';
12 | }
13 |
14 | class TestApp extends EmberApp {
15 | modules = {
16 | './router': Router,
17 | // add any custom services here
18 | // import.meta.glob('./services/*', { eager: true }),
19 | };
20 | }
21 |
22 | Router.map(function () {});
23 |
24 | export function start() {
25 | setApplication(
26 | TestApp.create({
27 | autoboot: false,
28 | rootElement: '#ember-testing',
29 | }),
30 | );
31 | setup(QUnit.assert);
32 | setupEmberOnerrorValidation();
33 | qunitStart();
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/babel.config.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | * This babel.config is not used for publishing.
3 | * It's only for the local editing experience
4 | * (and linting)
5 | */
6 | const { buildMacros } = require('@embroider/macros/babel');
7 |
8 | const {
9 | babelCompatSupport,
10 | templateCompatSupport,
11 | } = require('@embroider/compat/babel');
12 |
13 | const macros = buildMacros();
14 |
15 | // For scenario testing
16 | const isCompat = Boolean(process.env.ENABLE_COMPAT_BUILD);
17 |
18 | module.exports = {
19 | plugins: [
20 | [
21 | 'babel-plugin-ember-template-compilation',
22 | {
23 | transforms: [
24 | ...(isCompat ? templateCompatSupport() : macros.templateMacros),
25 | ],
26 | },
27 | ],
28 | [
29 | 'module:decorator-transforms',
30 | {
31 | runtime: {
32 | import: require.resolve('decorator-transforms/runtime-esm'),
33 | },
34 | },
35 | ],
36 | ...(isCompat ? babelCompatSupport() : macros.babelMacros),
37 | ],
38 |
39 | generatorOpts: {
40 | compact: false,
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/tests/deprecation-workflow.js:
--------------------------------------------------------------------------------
1 | import setupDeprecationWorkflow from '#src/index.js';
2 |
3 | // We export this here to be able to import from our own tests
4 | export const config = {
5 | throwOnUnhandled: true,
6 | workflow: [
7 | /*
8 | * Actual controlled deprecations
9 | *
10 | * The ember-global log configuration is only required for
11 | * ember-3.28-with-jquery. All other ember-try scenarios pass with that
12 | * handler removed (and defaulting to a throw).
13 | */
14 | { matchId: 'ember-global', handler: 'log' },
15 | { matchMessage: /ember-test-waiters/, handler: 'log' },
16 |
17 | /*
18 | * Deprecation setup for tests
19 | */
20 | { matchId: 'silence-strict', handler: 'silence' },
21 | { matchMessage: 'silence-strict', handler: 'silence' },
22 | { matchMessage: /silence-match/, handler: 'silence' },
23 |
24 | { matchId: 'log-strict', handler: 'log' },
25 | { matchMessage: 'log-strict', handler: 'log' },
26 | { matchMessage: /log-match/, handler: 'log' },
27 |
28 | { matchMessage: 'throw-strict', handler: 'throw' },
29 | ],
30 | };
31 |
32 | setupDeprecationWorkflow(config);
33 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | # For every push to the primary branch with .release-plan.json modified,
2 | # runs release-plan.
3 |
4 | name: Publish Stable
5 |
6 | on:
7 | workflow_dispatch:
8 | push:
9 | branches:
10 | - main
11 | - master
12 | paths:
13 | - ".release-plan.json"
14 |
15 | concurrency:
16 | group: publish-${{ github.head_ref || github.ref }}
17 | cancel-in-progress: true
18 |
19 | jobs:
20 | publish:
21 | name: "NPM Publish"
22 | runs-on: ubuntu-latest
23 | permissions:
24 | contents: write
25 | id-token: write
26 | attestations: write
27 |
28 | steps:
29 | - uses: actions/checkout@v6
30 | - uses: pnpm/action-setup@v4
31 | - uses: actions/setup-node@v6
32 | with:
33 | node-version: 22
34 | registry-url: "https://registry.npmjs.org"
35 | cache: pnpm
36 | - run: pnpm install --frozen-lockfile
37 | - run: npm install -g npm@latest # ensure that the globally installed npm is new enough to support OIDC
38 | - name: Publish to NPM
39 | run: NPM_CONFIG_PROVENANCE=true pnpm release-plan publish
40 | env:
41 | GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}
42 |
--------------------------------------------------------------------------------
/demo-app/app.gts:
--------------------------------------------------------------------------------
1 | import EmberApp from 'ember-strict-application-resolver';
2 | import EmberRouter from '@ember/routing/router';
3 | import PageTitleService from 'ember-page-title/services/page-title';
4 |
5 | class Router extends EmberRouter {
6 | location = 'history';
7 | rootURL = '/';
8 | }
9 |
10 | export class App extends EmberApp {
11 | /**
12 | * Any services or anything from the addon that needs to be in the app-tree registry
13 | * will need to be manually specified here.
14 | *
15 | * Techniques to avoid needing this:
16 | * - private services
17 | * - require the consuming app import and configure themselves
18 | * (which is what we're emulating here)
19 | */
20 | modules = {
21 | './router': Router,
22 | './services/page-title': PageTitleService,
23 | /**
24 | * NOTE: this glob will import everything matching the glob,
25 | * and includes non-services in the services directory.
26 | */
27 | ...import.meta.glob('./services/**/*', { eager: true }),
28 | /**
29 | * These imports are not magic, but we do require that all entries in the
30 | * modules object match a ./[type]/[name] pattern.
31 | *
32 | * See: https://rfcs.emberjs.com/id/1132-default-strict-resolver
33 | */
34 | ...import.meta.glob('./templates/**/*', { eager: true }),
35 | };
36 | }
37 |
38 | Router.map(function () {});
39 |
--------------------------------------------------------------------------------
/.release-plan.json:
--------------------------------------------------------------------------------
1 | {
2 | "solution": {
3 | "ember-cli-deprecation-workflow": {
4 | "impact": "major",
5 | "oldVersion": "3.4.0",
6 | "newVersion": "4.0.0",
7 | "tagName": "latest",
8 | "constraints": [
9 | {
10 | "impact": "major",
11 | "reason": "Appears in changelog section :boom: Breaking Change"
12 | },
13 | {
14 | "impact": "patch",
15 | "reason": "Appears in changelog section :house: Internal"
16 | }
17 | ],
18 | "pkgJSONPath": "./package.json"
19 | }
20 | },
21 | "description": "## Release (2025-12-18)\n \n* ember-cli-deprecation-workflow 4.0.0 (major)\n\n#### :boom: Breaking Change\n* `ember-cli-deprecation-workflow`\n * [#222](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/222) Convert to v2 Addon - classic apps (using ember-cli for build) will want to remain on v3 ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### :house: Internal\n* `ember-cli-deprecation-workflow`\n * [#223](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/223) Update release plan ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#220](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/220) chore: Test latest LTS versions ([@TSenter](https://github.com/TSenter))\n\n#### Committers: 2\n- Tyler Senter ([@TSenter](https://github.com/TSenter))\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n"
22 | }
23 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Release Process
2 |
3 | Releases in this repo are mostly automated using [release-plan](https://github.com/embroider-build/release-plan/). Once you label all your PRs correctly (see below) you will have an automatically generated PR that updates your CHANGELOG.md file and a `.release-plan.json` that is used to prepare the release once the PR is merged.
4 |
5 | ## Preparation
6 |
7 | Since the majority of the actual release process is automated, the remaining tasks before releasing are:
8 |
9 | - correctly labeling **all** pull requests that have been merged since the last release
10 | - updating pull request titles so they make sense to our users
11 |
12 | Some great information on why this is important can be found at [keepachangelog.com](https://keepachangelog.com/en/1.1.0/), but the overall
13 | guiding principle here is that changelogs are for humans, not machines.
14 |
15 | When reviewing merged PR's the labels to be used are:
16 |
17 | - breaking - Used when the PR is considered a breaking change.
18 | - enhancement - Used when the PR adds a new feature or enhancement.
19 | - bug - Used when the PR fixes a bug included in a previous release.
20 | - documentation - Used when the PR adds or updates documentation.
21 | - internal - Internal changes or things that don't fit in any other category.
22 |
23 | **Note:** `release-plan` requires that **all** PRs are labeled. If a PR doesn't fit in a category it's fine to label it as `internal`
24 |
25 | ## Release
26 |
27 | Once the prep work is completed, the actual release is straight forward: you just need to merge the open [Plan Release](https://github.com/ember-cli/ember-cli-deprecation-workflow/pulls?q=is%3Apr+is%3Aopen+%22Prepare+Release%22+in%3Atitle) PR
28 |
--------------------------------------------------------------------------------
/tests/acceptance/flush-deprecations-test.js:
--------------------------------------------------------------------------------
1 | import { deprecate } from '@ember/debug';
2 | import { module } from 'qunit';
3 | import test from '../helpers/debug-test';
4 | import { config } from '../deprecation-workflow';
5 |
6 | let originalWarn;
7 |
8 | module('flushDeprecations', function (hooks) {
9 | hooks.beforeEach(function () {
10 | originalWarn = window.Testem.handleConsoleMessage;
11 | });
12 |
13 | hooks.afterEach(function () {
14 | window.deprecationWorkflow.deprecationLog = { messages: new Set() };
15 | window.Testem.handleConsoleMessage = originalWarn;
16 | });
17 |
18 | test('works', function (assert) {
19 | deprecate('silence-strict', false, {
20 | since: '2.0.0',
21 | until: 'forever',
22 | id: 'test',
23 | for: 'testing',
24 | });
25 |
26 | deprecate('log-strict', false, {
27 | since: '2.0.0',
28 | until: 'forever',
29 | id: 'test',
30 | for: 'testing',
31 | });
32 |
33 | deprecate(' foo log-match foo', false, {
34 | since: 'now',
35 | until: 'forever',
36 | id: 'test',
37 | for: 'testing',
38 | });
39 |
40 | deprecate(' foo foo', false, {
41 | since: 'now',
42 | until: 'forever',
43 | id: 'log-strict',
44 | for: 'testing',
45 | });
46 |
47 | deprecate('arbitrary-unmatched-message', false, {
48 | id: 'log-strict',
49 | since: '2.0.0',
50 | until: '3.0.0',
51 | for: 'testing',
52 | });
53 |
54 | const deprecationsPayload = self.deprecationWorkflow.flushDeprecations();
55 |
56 | assert.strictEqual(
57 | deprecationsPayload,
58 | `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
59 |
60 | setupDeprecationWorkflow(${JSON.stringify(
61 | {
62 | ...config,
63 | workflow: [
64 | ...config.workflow,
65 | { handler: 'silence', matchId: 'test' },
66 | // this one is already present in the existing config, so don't expect another entry, as we deduplicate
67 | // { handler: 'silence', matchId: 'log-strict' },
68 | ],
69 | },
70 | undefined,
71 | 2,
72 | )});`,
73 | );
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/.github/workflows/plan-release.yml:
--------------------------------------------------------------------------------
1 | name: Plan Release
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 | - master
8 | pull_request_target: # This workflow has permissions on the repo, do NOT run code from PRs in this workflow. See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
9 | types:
10 | - labeled
11 | - unlabeled
12 |
13 | concurrency:
14 | group: plan-release # only the latest one of these should ever be running
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | should-run-release-plan-prepare:
19 | name: Should we run release-plan prepare?
20 | runs-on: ubuntu-latest
21 | outputs:
22 | should-prepare: ${{ steps.should-prepare.outputs.should-prepare }}
23 | steps:
24 | - uses: release-plan/actions/should-prepare-release@v1
25 | with:
26 | ref: 'main'
27 | id: should-prepare
28 |
29 | create-prepare-release-pr:
30 | name: Create Prepare Release PR
31 | runs-on: ubuntu-latest
32 | timeout-minutes: 5
33 | needs: should-run-release-plan-prepare
34 | permissions:
35 | contents: write
36 | issues: read
37 | pull-requests: write
38 | if: needs.should-run-release-plan-prepare.outputs.should-prepare == 'true'
39 | steps:
40 | - uses: release-plan/actions/prepare@v1
41 | name: Run release-plan prepare
42 | with:
43 | ref: 'main'
44 | env:
45 | GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}
46 | id: explanation
47 |
48 | - uses: peter-evans/create-pull-request@v7
49 | name: Create Prepare Release PR
50 | with:
51 | commit-message: "Prepare Release ${{ steps.explanation.outputs.new-version}} using 'release-plan'"
52 | labels: "internal"
53 | sign-commits: true
54 | branch: release-preview
55 | title: Prepare Release ${{ steps.explanation.outputs.new-version }}
56 | body: |
57 | This PR is a preview of the release that [release-plan](https://github.com/embroider-build/release-plan) has prepared. To release you should just merge this PR 👍
58 |
59 | -----------------------------------------
60 |
61 | ${{ steps.explanation.outputs.text }}
62 |
--------------------------------------------------------------------------------
/.try.mjs:
--------------------------------------------------------------------------------
1 | // When building your addon for older Ember versions you need to have the required files
2 | const compatFiles = {
3 | 'ember-cli-build.cjs': `const EmberApp = require('ember-cli/lib/broccoli/ember-app');
4 | const { compatBuild } = require('@embroider/compat');
5 | module.exports = async function (defaults) {
6 | const { buildOnce } = await import('@embroider/vite');
7 | let app = new EmberApp(defaults);
8 | return compatBuild(app, buildOnce);
9 | };`,
10 | 'config/optional-features.json': JSON.stringify({
11 | 'application-template-wrapper': false,
12 | 'default-async-observers': true,
13 | 'jquery-integration': false,
14 | 'template-only-glimmer-components': true,
15 | 'no-implicit-route-model': true,
16 | }),
17 | };
18 |
19 | const compatDeps = {
20 | '@embroider/compat': '^4.0.3',
21 | 'ember-cli': '^5.12.0',
22 | 'ember-auto-import': '^2.10.0',
23 | '@ember/optional-features': '^2.2.0',
24 | };
25 |
26 | const ancientDeps = {
27 | 'ember-cli': '^4.12.0',
28 | };
29 |
30 | function compatLTS(version, options = {}) {
31 | return {
32 | name: `ember-lts-${version}`,
33 | npm: {
34 | devDependencies: {
35 | 'ember-source': `~${version}`,
36 | ...compatDeps,
37 | ...options?.deps,
38 | },
39 | },
40 | env: {
41 | ENABLE_COMPAT_BUILD: true,
42 | },
43 | files: compatFiles,
44 | };
45 | }
46 |
47 | export default {
48 | scenarios: [
49 | compatLTS('3.28', { deps: ancientDeps }),
50 | compatLTS('4.4'),
51 | compatLTS('4.8'),
52 | compatLTS('4.12'),
53 | compatLTS('5.4'),
54 | compatLTS('5.8'),
55 | compatLTS('5.12'),
56 | {
57 | name: 'ember-lts-6.4',
58 | npm: {
59 | devDependencies: {
60 | 'ember-source': 'npm:ember-source@~6.4.0',
61 | },
62 | },
63 | },
64 | {
65 | name: 'ember-latest',
66 | npm: {
67 | devDependencies: {
68 | 'ember-source': 'npm:ember-source@latest',
69 | },
70 | },
71 | },
72 | {
73 | name: 'ember-beta',
74 | npm: {
75 | devDependencies: {
76 | 'ember-source': 'npm:ember-source@beta',
77 | },
78 | },
79 | },
80 | {
81 | name: 'ember-alpha',
82 | npm: {
83 | devDependencies: {
84 | 'ember-source': 'npm:ember-source@alpha',
85 | },
86 | },
87 | },
88 | ],
89 | };
90 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - master
8 | pull_request: {}
9 |
10 | concurrency:
11 | group: ci-${{ github.head_ref || github.ref }}
12 | cancel-in-progress: true
13 |
14 | jobs:
15 | lint:
16 | name: "Lints"
17 | runs-on: ubuntu-latest
18 | timeout-minutes: 10
19 |
20 | steps:
21 | - uses: actions/checkout@v6
22 | - uses: pnpm/action-setup@v4
23 | - uses: actions/setup-node@v6
24 | with:
25 | node-version: 22
26 | cache: pnpm
27 | - name: Install Dependencies
28 | run: pnpm install --frozen-lockfile
29 | - name: Lint
30 | run: pnpm lint
31 |
32 | test:
33 | name: "Tests"
34 | runs-on: ubuntu-latest
35 | timeout-minutes: 10
36 | outputs:
37 | matrix: ${{ steps.set-matrix.outputs.matrix }}
38 |
39 | steps:
40 | - uses: actions/checkout@v6
41 | - uses: pnpm/action-setup@v4
42 | - uses: actions/setup-node@v6
43 | with:
44 | node-version: 22
45 | cache: pnpm
46 | - name: Install Dependencies
47 | run: pnpm install --frozen-lockfile
48 | - name: Run Tests
49 | run: pnpm test
50 | # For the Try Scenarios
51 | - id: set-matrix
52 | run: |
53 | echo "matrix=$(pnpm -s dlx @embroider/try list)" >> $GITHUB_OUTPUT
54 |
55 | floating:
56 | name: "Floating Dependencies"
57 | runs-on: ubuntu-latest
58 | timeout-minutes: 10
59 |
60 | steps:
61 | - uses: actions/checkout@v6
62 | - uses: pnpm/action-setup@v4
63 | - uses: actions/setup-node@v6
64 | with:
65 | node-version: 22
66 | cache: pnpm
67 | - name: Install Dependencies
68 | run: pnpm install --no-lockfile
69 | - name: Run Tests
70 | run: pnpm test
71 |
72 | try-scenarios:
73 | name: ${{ matrix.name }}
74 | runs-on: ubuntu-latest
75 | needs: "test"
76 | timeout-minutes: 10
77 | strategy:
78 | fail-fast: false
79 | matrix: ${{fromJson(needs.test.outputs.matrix)}}
80 |
81 | steps:
82 | - uses: actions/checkout@v6
83 | - uses: pnpm/action-setup@v4
84 | - uses: actions/setup-node@v6
85 | with:
86 | node-version: 22
87 | cache: pnpm
88 | - name: Apply Scenario
89 | run: |
90 | pnpm dlx @embroider/try apply ${{ matrix.name }}
91 |
92 | - name: Install Dependencies
93 | run: pnpm install --no-lockfile
94 | - name: Run Tests
95 | run: |
96 | pnpm test
97 |
98 | env: ${{ matrix.env }}
99 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Debugging:
3 | * https://eslint.org/docs/latest/use/configure/debug
4 | * ----------------------------------------------------
5 | *
6 | * Print a file's calculated configuration
7 | *
8 | * npx eslint --print-config path/to/file.js
9 | *
10 | * Inspecting the config
11 | *
12 | * npx eslint --inspect-config
13 | *
14 | */
15 |
16 | import babelParser from '@babel/eslint-parser/experimental-worker';
17 | import js from '@eslint/js';
18 | import { defineConfig, globalIgnores } from 'eslint/config';
19 | import prettier from 'eslint-config-prettier';
20 | import ember from 'eslint-plugin-ember/recommended';
21 | import importPlugin from 'eslint-plugin-import';
22 | import n from 'eslint-plugin-n';
23 | import globals from 'globals';
24 |
25 | const esmParserOptions = {
26 | ecmaFeatures: { modules: true },
27 | ecmaVersion: 'latest',
28 | };
29 |
30 | export default defineConfig([
31 | globalIgnores([
32 | 'dist/',
33 | 'dist-*/',
34 | 'declarations/',
35 | 'coverage/',
36 | '!**/.*',
37 | 'src/index.d.ts',
38 | ]),
39 | js.configs.recommended,
40 | prettier,
41 | ember.configs.base,
42 | ember.configs.gjs,
43 | /**
44 | * https://eslint.org/docs/latest/use/configure/configuration-files#configuring-linter-options
45 | */
46 | {
47 | linterOptions: {
48 | reportUnusedDisableDirectives: 'error',
49 | },
50 | },
51 | {
52 | files: ['**/*.js'],
53 | languageOptions: {
54 | parser: babelParser,
55 | },
56 | },
57 | {
58 | files: ['**/*.{js,gjs}'],
59 | languageOptions: {
60 | parserOptions: esmParserOptions,
61 | globals: {
62 | ...globals.browser,
63 | },
64 | },
65 | },
66 | {
67 | files: ['src/**/*'],
68 | plugins: {
69 | import: importPlugin,
70 | },
71 | rules: {
72 | // require relative imports use full extensions
73 | 'import/extensions': ['error', 'always', { ignorePackages: true }],
74 | },
75 | },
76 | /**
77 | * CJS node files
78 | */
79 | {
80 | files: ['**/*.cjs'],
81 | plugins: {
82 | n,
83 | },
84 |
85 | languageOptions: {
86 | sourceType: 'script',
87 | ecmaVersion: 'latest',
88 | globals: {
89 | ...globals.node,
90 | },
91 | },
92 | },
93 | /**
94 | * ESM node files
95 | */
96 | {
97 | files: ['**/*.mjs'],
98 | plugins: {
99 | n,
100 | },
101 |
102 | languageOptions: {
103 | sourceType: 'module',
104 | ecmaVersion: 'latest',
105 | parserOptions: esmParserOptions,
106 | globals: {
107 | ...globals.node,
108 | },
109 | },
110 | },
111 | ]);
112 |
--------------------------------------------------------------------------------
/tests/unit/deprecation-collector-test.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 |
3 | import { module } from 'qunit';
4 | import test from '../helpers/debug-test';
5 | import { deprecationCollector } from '#src/index.js';
6 |
7 | let originalWarn, originalConfig;
8 |
9 | module('deprecationCollector', function (hooks) {
10 | hooks.beforeEach(function () {
11 | originalWarn = console.warn;
12 |
13 | /*
14 | * Clear config for these tests
15 | */
16 | originalConfig = self.deprecationWorkflow = {
17 | config: null,
18 | deprecationLog: {
19 | messages: new Set(),
20 | },
21 | };
22 | });
23 |
24 | hooks.afterEach(function () {
25 | self.deprecationWorkflow.config = originalConfig;
26 | self.deprecationWorkflow.deprecationLog = { messages: {} };
27 | console.warn = originalWarn;
28 | });
29 |
30 | test('it collects deprecations', function (assert) {
31 | deprecationCollector(
32 | 'First deprecation',
33 | {
34 | id: 'first',
35 | since: 'the beginning',
36 | until: 'forever',
37 | for: 'testing',
38 | },
39 | () => {},
40 | );
41 | deprecationCollector(
42 | 'Second deprecation',
43 | {
44 | id: 'second',
45 | since: 'the beginning',
46 | until: 'forever',
47 | for: 'testing',
48 | },
49 | () => {},
50 | );
51 |
52 | assert.deepEqual(
53 | self.deprecationWorkflow.deprecationLog.messages,
54 | new Set(['first', 'second']),
55 | );
56 | });
57 |
58 | test('should call next', function (assert) {
59 | assert.expect(1);
60 |
61 | function next() {
62 | assert.ok(true, 'next has been called');
63 | }
64 |
65 | deprecationCollector(
66 | 'First deprecation',
67 | {
68 | id: 'first',
69 | since: 'the beginning',
70 | until: 'forever',
71 | for: 'testing',
72 | },
73 | next,
74 | );
75 | });
76 |
77 | test('deprecations are not duplicated', function (assert) {
78 | deprecationCollector(
79 | 'First deprecation',
80 | {
81 | id: 'first',
82 | since: 'the beginning',
83 | until: 'forever',
84 | for: 'testing',
85 | },
86 | () => {},
87 | );
88 | deprecationCollector(
89 | 'Second deprecation',
90 | {
91 | id: 'second',
92 | since: 'the beginning',
93 | until: 'forever',
94 | for: 'testing',
95 | },
96 | () => {},
97 | );
98 |
99 | // do it again
100 | deprecationCollector(
101 | 'First deprecation',
102 | {
103 | id: 'first',
104 | since: 'the beginning',
105 | until: 'forever',
106 | for: 'testing',
107 | },
108 | () => {},
109 | );
110 | deprecationCollector(
111 | 'Second deprecation',
112 | {
113 | id: 'second',
114 | since: 'the beginning',
115 | until: 'forever',
116 | for: 'testing',
117 | },
118 | () => {},
119 | );
120 |
121 | assert.deepEqual(
122 | self.deprecationWorkflow.deprecationLog.messages,
123 | new Set(['first', 'second']),
124 | );
125 | });
126 | });
127 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ember-cli-deprecation-workflow",
3 | "version": "4.0.0",
4 | "description": "Provides a much needed workflow to managing deprecations.",
5 | "keywords": [
6 | "ember-addon"
7 | ],
8 | "repository": "https://github.com/ember-cli/ember-cli-deprecation-workflow/",
9 | "license": "MIT",
10 | "author": "",
11 | "imports": {
12 | "#src/*": "./src/*"
13 | },
14 | "exports": {
15 | ".": {
16 | "types": "./src/index.d.ts",
17 | "default": "./src/index.js"
18 | },
19 | "./addon-main.js": "./addon-main.cjs"
20 | },
21 | "files": [
22 | "addon-main.cjs",
23 | "src"
24 | ],
25 | "scripts": {
26 | "format": "prettier . --cache --write",
27 | "lint": "concurrently \"pnpm:lint:*(!fix)\" --names \"lint:\" --prefixColors auto",
28 | "lint:fix": "concurrently \"pnpm:lint:*:fix\" --names \"fix:\" --prefixColors auto && pnpm run format",
29 | "lint:format": "prettier . --cache --check",
30 | "lint:js": "eslint . --cache",
31 | "lint:js:fix": "eslint . --fix",
32 | "start": "vite dev",
33 | "test": "vite build --mode=development --out-dir dist-tests && testem --file testem.cjs ci --port 0"
34 | },
35 | "dependencies": {
36 | "@embroider/addon-shim": "^1.8.9",
37 | "decorator-transforms": "^2.2.2"
38 | },
39 | "devDependencies": {
40 | "@babel/core": "^7.25.2",
41 | "@babel/eslint-parser": "^7.25.1",
42 | "@babel/runtime": "^7.25.6",
43 | "@ember/app-tsconfig": "^2.0.0",
44 | "@ember/library-tsconfig": "^2.0.0",
45 | "@ember/test-helpers": "^5.2.1",
46 | "@ember/test-waiters": "^4.1.1",
47 | "@embroider/compat": "^4.1.0",
48 | "@embroider/core": "^4.1.0",
49 | "@embroider/macros": "^1.18.0",
50 | "@embroider/vite": "^1.1.5",
51 | "@eslint/js": "^9.17.0",
52 | "@glimmer/component": "^2.0.0",
53 | "@rollup/plugin-babel": "^6.0.4",
54 | "babel-plugin-ember-template-compilation": "^3.0.1",
55 | "concurrently": "^9.0.1",
56 | "ember-page-title": "^9.0.3",
57 | "ember-qunit": "^9.0.2",
58 | "ember-source": "^6.7.0",
59 | "ember-strict-application-resolver": "^0.1.0",
60 | "eslint": "^9.17.0",
61 | "eslint-config-prettier": "^10.1.5",
62 | "eslint-plugin-ember": "^12.3.3",
63 | "eslint-plugin-import": "^2.31.0",
64 | "eslint-plugin-n": "^17.15.1",
65 | "globals": "^16.1.0",
66 | "prettier": "^3.4.2",
67 | "prettier-plugin-ember-template-tag": "^2.0.4",
68 | "qunit": "^2.24.1",
69 | "qunit-dom": "^3.4.0",
70 | "release-plan": "^0.17.0",
71 | "testem": "^3.15.1",
72 | "vite": "^7.1.9"
73 | },
74 | "packageManager": "pnpm@10.26.0",
75 | "volta": {
76 | "node": "22",
77 | "pnpm": "10.26.0"
78 | },
79 | "publishConfig": {
80 | "registry": "https://registry.npmjs.org"
81 | },
82 | "changelog": {
83 | "repo": "mixonic/ember-cli-deprecation-workflow",
84 | "labels": {
85 | "breaking": ":boom: Breaking Change",
86 | "enhancement": ":rocket: Enhancement",
87 | "bug": ":bug: Bug Fix",
88 | "documentation": ":memo: Documentation",
89 | "internal": ":house: Internal"
90 | }
91 | },
92 | "ember": {
93 | "edition": "octane"
94 | },
95 | "ember-addon": {
96 | "version": 2,
97 | "type": "addon",
98 | "main": "addon-main.cjs"
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { registerDeprecationHandler } from '@ember/debug';
2 |
3 | const LOG_LIMIT = 100;
4 |
5 | export default function setupDeprecationWorkflow(config) {
6 | self.deprecationWorkflow = self.deprecationWorkflow || {};
7 | self.deprecationWorkflow.deprecationLog = {
8 | messages: new Set(),
9 | };
10 |
11 | registerDeprecationHandler((message, options, next) =>
12 | handleDeprecationWorkflow(config, message, options, next),
13 | );
14 |
15 | registerDeprecationHandler(deprecationCollector);
16 |
17 | self.deprecationWorkflow.flushDeprecations = (options) =>
18 | flushDeprecations({ config, ...options });
19 | }
20 |
21 | function matchesWorkflow(matcher, value) {
22 | return (
23 | (typeof matcher === 'string' && matcher === value) ||
24 | (matcher instanceof RegExp && matcher.exec(value))
25 | );
26 | }
27 |
28 | export function detectWorkflow(config, message, options) {
29 | if (!config || !config.workflow) {
30 | return;
31 | }
32 |
33 | let i, workflow, matcher, idMatcher;
34 | for (i = 0; i < config.workflow.length; i++) {
35 | workflow = config.workflow[i];
36 | matcher = workflow.matchMessage;
37 | idMatcher = workflow.matchId;
38 |
39 | if (
40 | matchesWorkflow(idMatcher, options?.id) ||
41 | matchesWorkflow(matcher, message)
42 | ) {
43 | return workflow;
44 | }
45 | }
46 | }
47 |
48 | export function flushDeprecations({ handler = 'silence', config = {} } = {}) {
49 | let messages = self.deprecationWorkflow.deprecationLog.messages;
50 | let existing = config.workflow ?? [];
51 | let collected = messages
52 | .values()
53 | .filter((matchId) => !existing.some((entry) => entry.matchId === matchId))
54 | .map((matchId) => ({
55 | handler,
56 | matchId,
57 | }));
58 |
59 | let mergedConfig = {
60 | ...config,
61 | workflow: [...existing, ...collected],
62 | };
63 |
64 | return `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
65 |
66 | setupDeprecationWorkflow(${JSON.stringify(mergedConfig, undefined, 2)});`;
67 | }
68 |
69 | export function handleDeprecationWorkflow(config, message, options, next) {
70 | let matchingWorkflow = detectWorkflow(config, message, options);
71 | if (!matchingWorkflow) {
72 | if (config && config.throwOnUnhandled) {
73 | throw new Error(message);
74 | } else {
75 | next(message, options);
76 | }
77 | } else {
78 | switch (matchingWorkflow.handler) {
79 | case 'silence':
80 | // no-op
81 | break;
82 | case 'log': {
83 | let key = (options && options.id) || message;
84 |
85 | if (!self.deprecationWorkflow.logCounts) {
86 | self.deprecationWorkflow.logCounts = {};
87 | }
88 |
89 | let count = self.deprecationWorkflow.logCounts[key] || 0;
90 | self.deprecationWorkflow.logCounts[key] = ++count;
91 |
92 | if (count <= LOG_LIMIT) {
93 | console.warn('DEPRECATION: ' + message);
94 | if (count === LOG_LIMIT) {
95 | console.warn(
96 | 'To avoid console overflow, this deprecation will not be logged any more in this run.',
97 | );
98 | }
99 | }
100 |
101 | break;
102 | }
103 | case 'throw':
104 | throw new Error(message + ` (id: ${options?.id || 'unknown'})`);
105 | default:
106 | next(message, options);
107 | break;
108 | }
109 | }
110 | }
111 |
112 | export function deprecationCollector(message, options, next) {
113 | self.deprecationWorkflow.deprecationLog.messages.add(options.id);
114 |
115 | next(message, options);
116 | }
117 |
--------------------------------------------------------------------------------
/tests/unit/flush-deprecations-test.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 |
3 | import { module } from 'qunit';
4 | import test from '../helpers/debug-test';
5 | import { flushDeprecations } from '#src/index.js';
6 |
7 | let originalWarn, originalConfig;
8 |
9 | module('flushDeprecations', function (hooks) {
10 | hooks.beforeEach(function () {
11 | originalWarn = console.warn;
12 |
13 | /*
14 | * Clear config for these tests
15 | */
16 | originalConfig = self.deprecationWorkflow = {
17 | config: null,
18 | deprecationLog: {
19 | messages: new Set(),
20 | },
21 | };
22 | });
23 |
24 | hooks.afterEach(function () {
25 | self.deprecationWorkflow.config = originalConfig;
26 | self.deprecationWorkflow.deprecationLog = { messages: new Set() };
27 | console.warn = originalWarn;
28 | });
29 |
30 | test('calling flushDeprecations returns workflow config', function (assert) {
31 | self.deprecationWorkflow.deprecationLog.messages = new Set([
32 | 'first',
33 | 'second',
34 | ]);
35 |
36 | let deprecationsPayload = flushDeprecations();
37 | let expectedConfig = {
38 | workflow: [
39 | { handler: 'silence', matchId: 'first' },
40 | { handler: 'silence', matchId: 'second' },
41 | ],
42 | };
43 |
44 | assert.strictEqual(
45 | deprecationsPayload,
46 | `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
47 |
48 | setupDeprecationWorkflow(${JSON.stringify(expectedConfig, undefined, 2)});`,
49 | );
50 | });
51 |
52 | test('calling flushDeprecations with custom handler returns workflow config', function (assert) {
53 | self.deprecationWorkflow.deprecationLog.messages = new Set([
54 | 'first',
55 | 'second',
56 | ]);
57 |
58 | let deprecationsPayload = flushDeprecations({ handler: 'log' });
59 | let expectedConfig = {
60 | workflow: [
61 | { handler: 'log', matchId: 'first' },
62 | { handler: 'log', matchId: 'second' },
63 | ],
64 | };
65 |
66 | assert.strictEqual(
67 | deprecationsPayload,
68 | `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
69 |
70 | setupDeprecationWorkflow(${JSON.stringify(expectedConfig, undefined, 2)});`,
71 | );
72 | });
73 |
74 | test('calling flushDeprecations with existing config and no deprecations returns original config', function (assert) {
75 | let config = {
76 | throwOnUnhandled: true,
77 | workflow: [{ handler: 'log', matchId: 'existing' }],
78 | };
79 | self.deprecationWorkflow.deprecationLog.messages = new Set([]);
80 |
81 | let deprecationsPayload = flushDeprecations({ config });
82 | assert.strictEqual(
83 | deprecationsPayload,
84 | `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
85 |
86 | setupDeprecationWorkflow(${JSON.stringify(config, undefined, 2)});`,
87 | );
88 | });
89 |
90 | test('calling flushDeprecations with existing config returns augmented config', function (assert) {
91 | let config = {
92 | throwOnUnhandled: true,
93 | workflow: [{ handler: 'log', matchId: 'existing' }],
94 | };
95 | self.deprecationWorkflow.deprecationLog.messages = new Set([
96 | 'first',
97 | 'second',
98 | ]);
99 |
100 | let deprecationsPayload = flushDeprecations({ config });
101 | let expectedConfig = {
102 | throwOnUnhandled: true,
103 | workflow: [
104 | { handler: 'log', matchId: 'existing' },
105 | { handler: 'silence', matchId: 'first' },
106 | { handler: 'silence', matchId: 'second' },
107 | ],
108 | };
109 | assert.strictEqual(
110 | deprecationsPayload,
111 | `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
112 |
113 | setupDeprecationWorkflow(${JSON.stringify(expectedConfig, undefined, 2)});`,
114 | );
115 | });
116 |
117 | test('calling flushDeprecations with existing config does not override existing deprecations', function (assert) {
118 | let config = {
119 | throwOnUnhandled: true,
120 | workflow: [{ handler: 'log', matchId: 'existing' }],
121 | };
122 | self.deprecationWorkflow.deprecationLog.messages = new Set([
123 | 'first',
124 | 'second',
125 | 'existing',
126 | ]);
127 |
128 | let deprecationsPayload = flushDeprecations({ config });
129 | let expectedConfig = {
130 | throwOnUnhandled: true,
131 | workflow: [
132 | { handler: 'log', matchId: 'existing' },
133 | { handler: 'silence', matchId: 'first' },
134 | { handler: 'silence', matchId: 'second' },
135 | ],
136 | };
137 | assert.strictEqual(
138 | deprecationsPayload,
139 | `import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
140 |
141 | setupDeprecationWorkflow(${JSON.stringify(expectedConfig, undefined, 2)});`,
142 | );
143 | });
144 | });
145 |
--------------------------------------------------------------------------------
/tests/acceptance/workflow-config-test.js:
--------------------------------------------------------------------------------
1 | import { deprecate } from '@ember/debug';
2 | import { module } from 'qunit';
3 | import test from '../helpers/debug-test';
4 |
5 | let originalWarn;
6 |
7 | module('workflow config', function (hooks) {
8 | hooks.beforeEach(function () {
9 | originalWarn = window.Testem.handleConsoleMessage;
10 | });
11 |
12 | hooks.afterEach(function () {
13 | window.deprecationWorkflow.deprecationLog = { messages: new Set() };
14 | window.Testem.handleConsoleMessage = originalWarn;
15 | });
16 |
17 | test('deprecation silenced with string matcher', function (assert) {
18 | deprecate('silence-strict', false, {
19 | since: '2.0.0',
20 | until: 'forever',
21 | id: 'test',
22 | for: 'testing',
23 | });
24 | assert.ok(true, 'Deprecation did not raise');
25 | });
26 |
27 | test('deprecation logs with message matcher', function (assert) {
28 | assert.expect(1);
29 |
30 | let message = 'log-strict';
31 | window.Testem.handleConsoleMessage = function (passedMessage) {
32 | assert.strictEqual(
33 | passedMessage.indexOf('DEPRECATION: ' + message),
34 | 0,
35 | 'deprecation logs',
36 | );
37 | };
38 | deprecate(message, false, {
39 | since: '2.0.0',
40 | until: 'forever',
41 | id: 'test',
42 | for: 'testing',
43 | });
44 | });
45 |
46 | test('deprecation logs with message matcher by regex', function (assert) {
47 | assert.expect(1);
48 |
49 | let message = ' foo log-match foo';
50 | window.Testem.handleConsoleMessage = function (passedMessage) {
51 | assert.strictEqual(
52 | passedMessage.indexOf('DEPRECATION: ' + message),
53 | 0,
54 | 'deprecation logs',
55 | );
56 | };
57 | deprecate(message, false, {
58 | since: 'now',
59 | until: 'forever',
60 | id: 'test',
61 | for: 'testing',
62 | });
63 | });
64 |
65 | test('deprecation logs with id matcher', function (assert) {
66 | assert.expect(1);
67 |
68 | let message = ' foo foo';
69 | window.Testem.handleConsoleMessage = function (passedMessage) {
70 | assert.strictEqual(
71 | passedMessage.indexOf('DEPRECATION: ' + message),
72 | 0,
73 | 'deprecation logs',
74 | );
75 | };
76 | deprecate(message, false, {
77 | since: 'now',
78 | until: 'forever',
79 | id: 'log-strict',
80 | for: 'testing',
81 | });
82 | });
83 |
84 | test('deprecation thrown with string matcher', function (assert) {
85 | assert.throws(function () {
86 | deprecate('throw-strict', false, {
87 | since: '2.0.0',
88 | until: 'forever',
89 | id: 'test',
90 | for: 'testing',
91 | });
92 | }, 'deprecation throws');
93 | });
94 |
95 | test('deprecation logs with id matcher and options', function (assert) {
96 | assert.expect(1);
97 |
98 | let message = 'arbitrary-unmatched-message';
99 | let id = 'log-strict';
100 | let options = {
101 | id,
102 | since: '2.0.0',
103 | until: '3.0.0',
104 | for: 'testing',
105 | };
106 | let expected = `DEPRECATION: ${message}`;
107 | window.Testem.handleConsoleMessage = function (passedMessage) {
108 | assert.strictEqual(
109 | passedMessage.substr(0, expected.length),
110 | expected,
111 | 'deprecation logs',
112 | );
113 | };
114 | deprecate(message, false, options);
115 | });
116 |
117 | test('deprecation limits each id to 100 console.logs', function (assert) {
118 | assert.expect(104);
119 | let limit = 100;
120 |
121 | let message = 'log-match';
122 | let id = 'first-and-unique-to-limit-test';
123 | let options = {
124 | id,
125 | since: '2.0.0',
126 | until: '3.0.0',
127 | for: 'testing',
128 | };
129 | let expected = `DEPRECATION: ${message}`;
130 |
131 | let count = 0;
132 | window.Testem.handleConsoleMessage = function (passedMessage) {
133 | count++;
134 | if (count <= limit) {
135 | assert.strictEqual(
136 | passedMessage.substr(0, expected.length),
137 | expected,
138 | 'deprecation logs',
139 | );
140 | }
141 | if (count === limit) {
142 | window.Testem.handleConsoleMessage = function (passedMessage) {
143 | assert.strictEqual(
144 | passedMessage,
145 | 'To avoid console overflow, this deprecation will not be logged any more in this run.',
146 | );
147 | };
148 | }
149 | };
150 |
151 | // Run one more time than the limit
152 | for (let i = 0; i <= limit; i++) {
153 | deprecate(message, false, options);
154 | }
155 |
156 | assert.strictEqual(
157 | count,
158 | limit,
159 | 'logged 100 times, including final notice',
160 | );
161 |
162 | let secondMessage = 'log-strict';
163 | let secondId = 'second-and-unique-to-limit-test';
164 | let secondOptions = {
165 | id: secondId,
166 | since: '2.0.0',
167 | until: '3.0.0',
168 | for: 'testing',
169 | };
170 | let secondExpected = `DEPRECATION: ${secondMessage}`;
171 |
172 | let secondCount = 0;
173 | window.Testem.handleConsoleMessage = function (passedMessage) {
174 | secondCount++;
175 | assert.strictEqual(
176 | passedMessage.substr(0, secondExpected.length),
177 | secondExpected,
178 | 'second deprecation logs',
179 | );
180 | window.Testem.handleConsoleMessage = function () {
181 | assert.ok(false, 'No further logging expected');
182 | };
183 | };
184 |
185 | deprecate(secondMessage, false, secondOptions);
186 |
187 | assert.strictEqual(secondCount, 1, 'logged deprecation with different id');
188 | });
189 | });
190 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ember-cli-deprecation-workflow
2 |
3 | An addon geared towards making Ember upgrades easier by allowing you to work
4 | through deprecations without massive console noise.
5 |
6 | ## History
7 |
8 | Upgrading Ember versions can be very daunting. One of the largest factors is the
9 | massive `console.log` noise that the deprecations introduced in those versions
10 | (to help us know what we need to do to stay up to date) is so overwhelming that
11 | we quite literally have no idea what to do.
12 |
13 | The "deprecation spew" issue became very obvious as we progressed into the later
14 | 1.13 beta releases. At that point, [@mixonic](https://twitter.com/mixonic) and
15 | [@rwjblue](https://twitter.com/rwjblue) came up with a wild scheme.
16 |
17 | The scheme was to build tooling which made dealing with deprecations an
18 | incremental process. ember-cli-deprecation-workflow allows you to focus on
19 | addressing a single deprecation at a time, and prevents backsliding
20 | (re-introduction of a deprecated API use) in a codebase.
21 |
22 | ## Usage
23 |
24 | ### Compatibility
25 |
26 | 3.x
27 |
28 | - Ember.js 3.28 until at least 5.4
29 | - Ember CLI 4.12 or above
30 | - Node.js 16 or above
31 |
32 | 2.x
33 |
34 | - Ember.js 2.12 until at least 4.12
35 | - Ember CLI 3.16 or above
36 | - Node.js 12 and 14 or above
37 |
38 | 1.x
39 |
40 | - Ember.js 1.13 until at least 3.4
41 | - Ember CLI 3.4 as well as many versions before and after
42 | - Node.js 6, 8, and 10 until at least 14
43 |
44 | ### Getting started
45 |
46 | 1. Install the ember-cli-deprecation-workflow addon (`ember install ember-cli-deprecation-workflow`).
47 | 2. Create an `app/deprecation-workflow.js` file with the following content:
48 |
49 | ```js
50 | import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
51 |
52 | setupDeprecationWorkflow();
53 | ```
54 |
55 | 3. In your `app/app.js`, do:
56 |
57 | ```js
58 | import './deprecation-workflow';
59 | ```
60 |
61 | 4. Run your test suite\* with `ember test --server`.
62 | 5. Navigate to your tests (default: http://localhost:7357/)
63 | 6. Run `deprecationWorkflow.flushDeprecations()` in your browsers console. Or `flushDeprecations({ handler: 'log' })` if you want a different [handler](#handlers) than the default of `silence`.
64 | 7. Copy the string output and overwrite the content of `app/deprecation-workflow.js`.
65 |
66 | In Chrome, use right click → "Copy string contents" to avoid escape characters.
67 |
68 | Once this initial setup is completed the "deprecation spew" should be largely
69 | "fixed". Only unhandled deprecations will be displayed in your console.
70 |
71 | \*Note: Unless your test coverage is amazing (>90%), it's likely that running
72 | the test suite alone will not reveal _every_ deprecation. It may be prudent to
73 | run through the app's workflows live and flush deprecations a second time,
74 | merging the resulting output list with that generated from your test suite.
75 |
76 | Now that the spew has settled down, you can process one deprecation at a time while ensuring that no new deprecations are introduced.
77 |
78 | ### Workflow
79 |
80 | What does that individual deprecation workflow look like?
81 |
82 | 1. Change one entry in `app/deprecation-workflow.js` from `silence` to `throw`.
83 | 2. Run your tests or use your application.
84 | 3. Errors will be thrown for just that one deprecation, and you can track down the fixes needed in relative isolation of the rest of the deprecations.
85 | 4. Once the deprecation has been dealt with, remove its entry from `app/deprecation-workflow.js`.
86 | 5. Lather and repeat.
87 |
88 | ### Handlers
89 |
90 | There are 3 defined handlers that have different behaviors
91 |
92 | | Handler | Behavior |
93 | | --------- | ---------------------------------------------------------------------------------------------------------------- |
94 | | `silence` | Keeps this deprecation from spewing all over the console |
95 | | `log` | Normal deprecation behavior runs for this deprecation and messages are logged to the console |
96 | | `throw` | The error is thrown instead of allowing the deprecated behavior to run. **_WARNING: APPLICATION MAY GO :boom:_** |
97 |
98 | ### Matchers
99 |
100 | the output from running `deprecationWorkflow.flushDeprecations()` gives you a
101 | nice Json like JS object with all the deprecations in your app. The
102 | `matchMessage` property determines what to filter out of the console. You can
103 | pass a string that must match the console message exactly or a `RegExp` for
104 | `ember-cli-deprecation-workflow` filter the log by.
105 |
106 | ### Production builds
107 |
108 | By default, production ember-cli builds already remove deprecation warnings. Any
109 | deprecations configured to `throw` or `log` will only do so in non-production
110 | builds.
111 |
112 | ### Enable / Disable through configuration
113 |
114 | If your app has disabled test files in development environment you can force enabling this addon through configuration in `ember-cli-build.js` instead:
115 | ```javascript
116 | 'ember-cli-deprecation-workflow': {
117 | enabled: true,
118 | },
119 | ```
120 |
121 | ### Catch-all
122 |
123 | To force all deprecations to throw (can be useful in larger teams to prevent
124 | accidental introduction of deprecations), update your
125 | `app/deprecation-workflow.js`:
126 |
127 | ```javascript
128 | window.deprecationWorkflow.config = {
129 | throwOnUnhandled: true,
130 | };
131 | ```
132 |
133 | ### Template Deprecations
134 |
135 | By default, the console based deprecations that occur during template
136 | compilation are suppressed in favor of browser deprecations ran during the test
137 | suite. If you would prefer to still have the deprecations in the console, add
138 | the following to your `app/environment.js`:
139 |
140 | ```javascript
141 | module.exports = function (env) {
142 | var ENV = {};
143 |
144 | // normal things here
145 |
146 | ENV.logTemplateLintToConsole = true;
147 | };
148 | ```
149 |
150 | ### Configuration
151 |
152 | In some cases, it may be necessary to indicate a different `config` directory
153 | from the default one (`/config`). For example, you may want the flushed
154 | deprecations file to be referenced in a config directory like `my-config`.
155 |
156 | Adjust the `configPath` in your `package.json` file. The `/` will automatically
157 | be prefixed.
158 |
159 | ```javascript
160 | {
161 | 'ember-addon': {
162 | configPath: 'my-config'
163 | }
164 | }
165 | ```
166 |
167 | ## Contributing
168 |
169 | Details on contributing to the addon itself (not required for normal usage).
170 |
171 | See the [Contributing](CONTRIBUTING.md) guide for details.
172 |
173 | ## License
174 |
175 | This project is licensed under the [MIT License](LICENSE.md).
176 |
--------------------------------------------------------------------------------
/tests/unit/handle-deprecation-workflow-test.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 |
3 | import { module } from 'qunit';
4 | import test from '../helpers/debug-test';
5 | import { handleDeprecationWorkflow } from '#src/index.js';
6 |
7 | let originalWarn, originalConfig;
8 |
9 | module('handleDeprecationWorkflow', function (hooks) {
10 | hooks.beforeEach(function () {
11 | originalWarn = console.warn;
12 |
13 | /*
14 | * Clear config for these tests
15 | */
16 | originalConfig = self.deprecationWorkflow = {
17 | config: null,
18 | deprecationLog: {
19 | messages: {},
20 | },
21 | };
22 | });
23 |
24 | hooks.afterEach(function () {
25 | self.deprecationWorkflow.config = originalConfig;
26 | self.deprecationWorkflow.deprecationLog = { messages: {} };
27 | console.warn = originalWarn;
28 | });
29 |
30 | test('specifying `throwOnUnhandled` as true raises', function (assert) {
31 | const config = {
32 | throwOnUnhandled: true,
33 | workflow: [{ handler: 'silence', matchMessage: 'Sshhhhh!!' }],
34 | };
35 |
36 | assert.throws(
37 | function () {
38 | handleDeprecationWorkflow(
39 | config,
40 | 'Foobarrrzzzz',
41 | {
42 | since: 'the beginning',
43 | until: 'forever',
44 | id: 'foobar',
45 | for: 'testing',
46 | },
47 | () => {},
48 | );
49 | },
50 | /Foobarrrzzzz/,
51 | 'setting raiseOnUnhandled throws for unknown workflows',
52 | );
53 |
54 | handleDeprecationWorkflow(
55 | config,
56 | 'Sshhhhh!!',
57 | {
58 | id: 'quiet',
59 | since: 'the beginning',
60 | until: 'forever',
61 | for: 'testing',
62 | },
63 | () => {},
64 | );
65 | assert.ok(true, 'did not throw when silenced');
66 | });
67 |
68 | test('specifying `throwOnUnhandled` as false does nothing', function (assert) {
69 | const config = {
70 | throwOnUnhandled: false,
71 | };
72 |
73 | handleDeprecationWorkflow(
74 | config,
75 | 'Sshhhhh!!',
76 | {
77 | id: 'quiet',
78 | since: 'the beginning',
79 | until: 'forever',
80 | for: 'testing',
81 | },
82 | () => {},
83 | );
84 |
85 | assert.ok(true, 'does not die when throwOnUnhandled is false');
86 | });
87 |
88 | test('deprecation silenced with string matcher', function (assert) {
89 | const config = {
90 | throwOnUnhandled: true,
91 | workflow: [{ matchMessage: 'Interesting', handler: 'silence' }],
92 | };
93 |
94 | handleDeprecationWorkflow(config, 'Interesting', {
95 | id: 'interesting',
96 | since: 'the beginning',
97 | until: 'forever',
98 | for: 'testing',
99 | });
100 | assert.ok(true, 'Deprecation did not raise');
101 | });
102 |
103 | test('deprecation logs with string matcher', function (assert) {
104 | assert.expect(1);
105 |
106 | let message = 'Interesting';
107 | console.warn = function (passedMessage) {
108 | assert.strictEqual(
109 | passedMessage.indexOf('DEPRECATION: ' + message),
110 | 0,
111 | 'deprecation logs',
112 | );
113 | };
114 |
115 | const config = {
116 | throwOnUnhandled: true,
117 | workflow: [{ matchMessage: message, handler: 'log' }],
118 | };
119 |
120 | handleDeprecationWorkflow(
121 | config,
122 | message,
123 | {
124 | since: 'the beginning',
125 | until: 'forever',
126 | id: 'interesting',
127 | for: 'testing',
128 | },
129 | () => {},
130 | );
131 | });
132 |
133 | test('deprecation thrown with string matcher', function (assert) {
134 | const config = {
135 | workflow: [{ matchMessage: 'Interesting', handler: 'throw' }],
136 | };
137 |
138 | assert.throws(function () {
139 | handleDeprecationWorkflow(
140 | config,
141 | 'Interesting',
142 | {
143 | id: 'interesting',
144 | since: 'the beginning',
145 | until: 'forever',
146 | for: 'testing',
147 | },
148 | () => {},
149 | );
150 | }, 'deprecation throws');
151 | });
152 |
153 | test('deprecation silenced with regex matcher', function (assert) {
154 | const config = {
155 | throwOnUnhandled: true,
156 | workflow: [{ matchMessage: /Inter/, handler: 'silence' }],
157 | };
158 |
159 | handleDeprecationWorkflow(
160 | config,
161 | 'Interesting',
162 | {
163 | id: 'interesting',
164 | since: 'the beginning',
165 | until: 'forever',
166 | for: 'testing',
167 | },
168 | () => {},
169 | );
170 |
171 | assert.ok(true, 'Deprecation did not raise');
172 | });
173 |
174 | test('deprecation logs with regex matcher', function (assert) {
175 | assert.expect(1);
176 |
177 | let message = 'Interesting';
178 |
179 | console.warn = function (passedMessage) {
180 | assert.strictEqual(
181 | passedMessage,
182 | 'DEPRECATION: ' + message,
183 | 'deprecation logs',
184 | );
185 | };
186 |
187 | const config = {
188 | throwOnUnhandled: true,
189 | workflow: [{ matchMessage: /Inter/, handler: 'log' }],
190 | };
191 |
192 | handleDeprecationWorkflow(
193 | config,
194 | message,
195 | {
196 | id: 'interesting',
197 | since: 'the beginning',
198 | until: 'forever',
199 | for: 'testing',
200 | },
201 | () => {},
202 | );
203 | });
204 |
205 | test('deprecation thrown with regex matcher', function (assert) {
206 | const config = {
207 | workflow: [{ matchMessage: /Inter/, handler: 'throw' }],
208 | };
209 |
210 | assert.throws(function () {
211 | handleDeprecationWorkflow(
212 | config,
213 | 'Interesting',
214 | {
215 | id: 'interesting',
216 | since: 'the beginning',
217 | until: 'forever',
218 | for: 'testing',
219 | },
220 | () => {},
221 | );
222 | }, 'deprecation throws');
223 | });
224 |
225 | test('deprecation thrown with string matcher with parens', function (assert) {
226 | let message =
227 | 'Some string that includes (). If treated like a regexp this will not match.';
228 |
229 | const config = {
230 | workflow: [{ matchMessage: message, handler: 'throw' }],
231 | };
232 |
233 | assert.throws(function () {
234 | handleDeprecationWorkflow(
235 | config,
236 | message,
237 | {
238 | id: 'throws',
239 | since: 'the beginning',
240 | until: 'forever',
241 | for: 'testing',
242 | },
243 | () => {},
244 | );
245 | }, 'deprecation throws');
246 | });
247 |
248 | test('deprecation silenced with id matcher', function (assert) {
249 | const config = {
250 | throwOnUnhandled: true,
251 | workflow: [{ matchId: 'ember.deprecation-workflow', handler: 'silence' }],
252 | };
253 |
254 | handleDeprecationWorkflow(
255 | config,
256 | 'Slightly interesting',
257 | {
258 | id: 'ember.deprecation-workflow',
259 | since: 'the beginning',
260 | until: '3.0.0',
261 | for: 'testing',
262 | },
263 | () => {},
264 | );
265 |
266 | assert.ok(true, 'Deprecation did not raise');
267 | });
268 |
269 | test('deprecation logs with id matcher', function (assert) {
270 | assert.expect(1);
271 |
272 | let message = 'Slightly interesting';
273 |
274 | console.warn = function (passedMessage) {
275 | assert.strictEqual(
276 | passedMessage,
277 | 'DEPRECATION: ' + message,
278 | 'deprecation logs',
279 | );
280 | };
281 |
282 | const config = {
283 | throwOnUnhandled: true,
284 | workflow: [{ matchId: 'ember.deprecation-workflow', handler: 'log' }],
285 | };
286 |
287 | handleDeprecationWorkflow(
288 | config,
289 | 'Slightly interesting',
290 | {
291 | id: 'ember.deprecation-workflow',
292 | since: 'the beginning',
293 | until: '3.0.0',
294 | for: 'testing',
295 | },
296 | () => {},
297 | );
298 | });
299 |
300 | test('deprecation thrown with id matcher', function (assert) {
301 | const config = {
302 | workflow: [{ matchId: 'ember.deprecation-workflow', handler: 'throw' }],
303 | };
304 | assert.throws(function () {
305 | handleDeprecationWorkflow(
306 | config,
307 | 'Slightly interesting',
308 | {
309 | id: 'ember.deprecation-workflow',
310 | since: 'the beginning',
311 | until: '3.0.0',
312 | for: 'testing',
313 | },
314 | () => {},
315 | );
316 | }, 'deprecation throws');
317 | });
318 |
319 | test('deprecation silenced with id regex', function (assert) {
320 | const config = {
321 | throwOnUnhandled: true,
322 | workflow: [{ matchId: /^ember\..*/, handler: 'silence' }],
323 | };
324 |
325 | handleDeprecationWorkflow(
326 | config,
327 | 'Slightly interesting',
328 | {
329 | id: 'ember.deprecation-workflow',
330 | since: 'the beginning',
331 | until: '3.0.0',
332 | for: 'testing',
333 | },
334 | () => {},
335 | );
336 |
337 | assert.ok(true, 'Deprecation did not raise');
338 | });
339 |
340 | test('deprecation logs with id regex', function (assert) {
341 | assert.expect(1);
342 |
343 | let message = 'Slightly interesting';
344 |
345 | console.warn = function (passedMessage) {
346 | assert.strictEqual(
347 | passedMessage,
348 | 'DEPRECATION: ' + message,
349 | 'deprecation logs',
350 | );
351 | };
352 |
353 | const config = {
354 | throwOnUnhandled: true,
355 | workflow: [{ matchId: /^ember\..*/, handler: 'log' }],
356 | };
357 |
358 | handleDeprecationWorkflow(
359 | config,
360 | 'Slightly interesting',
361 | {
362 | id: 'ember.deprecation-workflow',
363 | since: 'the beginning',
364 | until: '3.0.0',
365 | for: 'testing',
366 | },
367 | () => {},
368 | );
369 | });
370 |
371 | test('deprecation thrown with id regex', function (assert) {
372 | const config = {
373 | workflow: [{ matchId: /^ember\..*/, handler: 'throw' }],
374 | };
375 | assert.throws(function () {
376 | handleDeprecationWorkflow(
377 | config,
378 | 'Slightly interesting',
379 | {
380 | id: 'ember.deprecation-workflow',
381 | since: 'the beginning',
382 | until: '3.0.0',
383 | for: 'testing',
384 | },
385 | () => {},
386 | );
387 | }, 'deprecation throws');
388 | });
389 | });
390 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## Release (2025-12-18)
4 |
5 | * ember-cli-deprecation-workflow 4.0.0 (major)
6 |
7 | #### :boom: Breaking Change
8 | * `ember-cli-deprecation-workflow`
9 | * [#222](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/222) Convert to v2 Addon - classic projects (not yet using embroider for builds) will want to remain on v3 ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
10 |
11 | #### :house: Internal
12 | * `ember-cli-deprecation-workflow`
13 | * [#223](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/223) Update release plan ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
14 | * [#220](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/220) chore: Test latest LTS versions ([@TSenter](https://github.com/TSenter))
15 |
16 | #### Committers: 2
17 | - Tyler Senter ([@TSenter](https://github.com/TSenter))
18 | - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
19 |
20 | ## Release (2025-07-03)
21 |
22 | ember-cli-deprecation-workflow 3.4.0 (minor)
23 |
24 | #### :rocket: Enhancement
25 | * `ember-cli-deprecation-workflow`
26 | * [#217](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/217) Throw Deprecation ID ([@jrjohnson](https://github.com/jrjohnson))
27 |
28 | #### :bug: Bug Fix
29 | * `ember-cli-deprecation-workflow`
30 | * [#215](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/215) Relax ember-source peerDependency for 3.28 support ([@apellerano-pw](https://github.com/apellerano-pw))
31 |
32 | #### :house: Internal
33 | * `ember-cli-deprecation-workflow`
34 | * [#219](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/219) fix CI for Ember 6.x ([@mansona](https://github.com/mansona))
35 |
36 | #### Committers: 3
37 | - Andrew Pellerano ([@apellerano-pw](https://github.com/apellerano-pw))
38 | - Chris Manson ([@mansona](https://github.com/mansona))
39 | - Jon Johnson ([@jrjohnson](https://github.com/jrjohnson))
40 |
41 | ## Release (2025-03-21)
42 |
43 | ember-cli-deprecation-workflow 3.3.0 (minor)
44 |
45 | #### :rocket: Enhancement
46 | * `ember-cli-deprecation-workflow`
47 | * [#209](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/209) flushDeprecations merges detected deprecations with existing config ([@simonihmig](https://github.com/simonihmig))
48 |
49 | #### Committers: 1
50 | - Simon Ihmig ([@simonihmig](https://github.com/simonihmig))
51 |
52 | ## Release (2025-03-21)
53 |
54 | ember-cli-deprecation-workflow 3.2.1 (patch)
55 |
56 | #### :bug: Bug Fix
57 | * `ember-cli-deprecation-workflow`
58 | * [#212](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/212) Fix type declarations ([@simonihmig](https://github.com/simonihmig))
59 | * [#210](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/210) Options are optional ([@ef4](https://github.com/ef4))
60 |
61 | #### Committers: 2
62 | - Edward Faulkner ([@ef4](https://github.com/ef4))
63 | - Simon Ihmig ([@simonihmig](https://github.com/simonihmig))
64 |
65 | ## Release (2025-03-06)
66 |
67 | ember-cli-deprecation-workflow 3.2.0 (minor)
68 |
69 | #### :rocket: Enhancement
70 | * `ember-cli-deprecation-workflow`
71 | * [#207](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/207) Allow passing a custom handler to flushDeprecations ([@simonihmig](https://github.com/simonihmig))
72 | * [#206](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/206) Support RegExp for matchId ([@simonihmig](https://github.com/simonihmig))
73 |
74 | #### Committers: 1
75 | - Simon Ihmig ([@simonihmig](https://github.com/simonihmig))
76 |
77 | ## Release (2024-12-27)
78 |
79 | ember-cli-deprecation-workflow 3.1.0 (minor)
80 |
81 | #### :rocket: Enhancement
82 | * `ember-cli-deprecation-workflow`
83 | * [#200](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/200) Add TypeScript declaration file ([@bertdeblock](https://github.com/bertdeblock))
84 |
85 | #### Committers: 1
86 | - Bert De Block ([@bertdeblock](https://github.com/bertdeblock))
87 |
88 | ## Release (2024-08-21)
89 |
90 | ember-cli-deprecation-workflow 3.0.2 (patch)
91 |
92 | #### :bug: Bug Fix
93 | * `ember-cli-deprecation-workflow`
94 | * [#197](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/197) Remove @ember/string (it's unused) ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
95 |
96 | #### Committers: 1
97 | - [@NullVoxPopuli](https://github.com/NullVoxPopuli)
98 |
99 | ## Release (2024-07-11)
100 |
101 | ember-cli-deprecation-workflow 3.0.1 (patch)
102 |
103 | #### :house: Internal
104 | * `ember-cli-deprecation-workflow`
105 | * [#192](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/192) fix repository link in package.json ([@mansona](https://github.com/mansona))
106 | * [#191](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/191) update release plan workflow ([@mansona](https://github.com/mansona))
107 |
108 | #### Committers: 1
109 | - Chris Manson ([@mansona](https://github.com/mansona))
110 |
111 | ## Release (2024-06-25)
112 |
113 | ember-cli-deprecation-workflow 3.0.0 (major)
114 |
115 | #### :boom: Breaking Change
116 | * `ember-cli-deprecation-workflow`
117 | * [#159](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/159) [BREAKING] Convert to a module. Drops support for Ember < 3.28, requires manual initialization ([@lolmaus](https://github.com/lolmaus))
118 | * [#175](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/175) Node 16 is the minimum supported version ([@mixonic](https://github.com/mixonic))
119 |
120 | #### :bug: Bug Fix
121 | * `ember-cli-deprecation-workflow`
122 | * [#181](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/181) Remove unused broccoli magic ([@simonihmig](https://github.com/simonihmig))
123 |
124 | #### :memo: Documentation
125 | * `ember-cli-deprecation-workflow`
126 | * [#184](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/184) Update configuration paths in documentation ([@backspace](https://github.com/backspace))
127 |
128 | #### :house: Internal
129 | * `ember-cli-deprecation-workflow`
130 | * [#189](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/189) start using release-plan ([@mansona](https://github.com/mansona))
131 | * [#188](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/188) start using pnpm ([@mansona](https://github.com/mansona))
132 | * [#178](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/178) Upgrade Ember CLI to 5.4 ([@lolmaus](https://github.com/lolmaus))
133 | * [#170](https://github.com/ember-cli/ember-cli-deprecation-workflow/pull/170) Bump Node, swap to npm, update CI pipeline ([@mixonic](https://github.com/mixonic))
134 |
135 | #### Committers: 5
136 | - Andrey Mikhaylov (lolmaus) ([@lolmaus](https://github.com/lolmaus))
137 | - Buck Doyle ([@backspace](https://github.com/backspace))
138 | - Chris Manson ([@mansona](https://github.com/mansona))
139 | - Matthew Beale ([@mixonic](https://github.com/mixonic))
140 | - Simon Ihmig ([@simonihmig](https://github.com/simonihmig))
141 |
142 | ## v2.2.0 (2023-11-01)
143 |
144 | * Introduce a dependency on ember-string to improve out of the box
145 | compatibiliy with Ember 4.12
146 | * Refactor to adopt newer versions of dev dependencies.
147 |
148 |
149 | ## v2.0.0 (2021-07-04)
150 |
151 |
152 | ## v2.0.0-beta.5 (2021-07-04)
153 |
154 | #### :bug: Bug Fix
155 | * [#118](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/118) Avoid the Ember global deprecation ([@mixonic](https://github.com/mixonic))
156 |
157 | #### Committers: 1
158 | - Matthew Beale ([@mixonic](https://github.com/mixonic))
159 |
160 |
161 | ## v2.0.0-beta.4 (2021-06-04)
162 |
163 | #### :boom: Breaking Change
164 | * [#116](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/116) [BREAKING] Drop Node 10 ([@mixonic](https://github.com/mixonic))
165 |
166 | #### :bug: Bug Fix
167 | * [#123](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/123) [BUGFIX] Check the incremented count for limit ([@mixonic](https://github.com/mixonic))
168 |
169 | #### :house: Internal
170 | * [#125](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/125) Drop ember.component.reopen log ([@mixonic](https://github.com/mixonic))
171 | * [#124](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/124) Clean up test config for clarity ([@mixonic](https://github.com/mixonic))
172 | * [#121](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/121) Remove deprecation-without-for and deprecation-without-since warnings in test ([@SergeAstapov](https://github.com/SergeAstapov))
173 | * [#120](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/120) Update main.js code style ([@mixonic](https://github.com/mixonic))
174 | * [#119](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/119) Bump deps to remove some deprecated use of Ember global ([@mixonic](https://github.com/mixonic))
175 |
176 | #### Committers: 2
177 | - Matthew Beale ([@mixonic](https://github.com/mixonic))
178 | - Sergey Astapov ([@SergeAstapov](https://github.com/SergeAstapov))
179 |
180 |
181 | ## v2.0.0-beta.3 (2021-05-27)
182 |
183 | #### :boom: Breaking Change
184 | * Upgrade verious dependencies across major versions
185 |
186 | #### :bug: Bug Fix
187 | * [#111](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/111) Address a deprecated import path for deprecate in tests
188 | * [#114](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/114) Drop debug handler polyfill, fixes [#113](https://github.com/mixonic/ember-cli-deprecation-workflow/issues/113).
189 |
190 | #### :rocket: Enhancement
191 | * [#93](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/93) Limit logging when a high-repetition deprecation is firing.
192 |
193 | ## v2.0.0-beta.2 (2021-02-27)
194 |
195 | #### :boom: Breaking Change
196 | * [#92](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/92) Modernize ([@wagenet](https://github.com/wagenet))
197 |
198 | #### :house: Internal
199 | * [#98](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/98) Add release automation ([@rwjblue](https://github.com/rwjblue))
200 | * [#97](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/97) Migrate to GH Actions. ([@rwjblue](https://github.com/rwjblue))
201 |
202 | #### Committers: 3
203 | - Igor Terzic ([@igorT](https://github.com/igorT))
204 | - Peter Wagenet ([@wagenet](https://github.com/wagenet))
205 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue))
206 |
207 |
208 | ## v1.0.1 (2018-11-05)
209 |
210 | #### :bug: Bug Fix
211 | * [#62](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/62) Avoid error when running on nested addons (`this.app` is not always present) ([@SparshithNR](https://github.com/SparshithNR))
212 |
213 | #### Committers: 1
214 | - SparshithNRai ([@SparshithNR](https://github.com/SparshithNR))
215 |
216 | ## v1.0.0 (2018-09-26)
217 |
218 | #### :boom: Breaking Change
219 | * [#57](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/57) Update to ember-cli 2.18 ([@Gaurav0](https://github.com/Gaurav0))
220 | * Drop support for Node 4 and lower.
221 |
222 | #### :rocket: Enhancement
223 | * [#55](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/55) Allow custom addon config directory ([@atsao](https://github.com/atsao))
224 | * [#58](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/58) Update to ember-cli@3.4 blueprint. ([@rwjblue](https://github.com/rwjblue))
225 | * [#57](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/57) Update to ember-cli 2.18 ([@Gaurav0](https://github.com/Gaurav0))
226 |
227 | #### :bug: Bug Fix
228 | * [#59](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/59) Update broccoli node to be broccoli-plugin based. ([@rwjblue](https://github.com/rwjblue))
229 |
230 | #### :house: Internal
231 | * [#60](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/60) Add Ember 1.13, 2.4, 2.8, and 2.12 back into config/ember-try.js. ([@rwjblue](https://github.com/rwjblue))
232 |
233 | #### Committers: 3
234 | - Andrew Tsao ([@atsao](https://github.com/atsao))
235 | - Gaurav Munjal ([@Gaurav0](https://github.com/Gaurav0))
236 | - Robert Jackson ([@rwjblue](https://github.com/rwjblue))
237 |
238 |
239 | ## v0.2.5 (2018-08-10)
240 |
241 | #### :bug: Bug Fix
242 | * [#54](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/54) Switch from Ember.Logger to console ([@wagenet](https://github.com/wagenet))
243 |
244 | #### :memo: Documentation
245 | * [#42](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/42) Update README.md ([@tabeth](https://github.com/tabeth))
246 | * [#48](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/48) document production builds and catch-all ([@IRun26Point2](https://github.com/IRun26Point2))
247 |
248 | #### Committers: 3
249 | - Peter Wagenet ([@wagenet](https://github.com/wagenet))
250 | - Tabeth Nkangoh ([@tabeth](https://github.com/tabeth))
251 | - [@IRun26Point2](https://github.com/IRun26Point2)
252 |
253 |
254 | ## v0.2.4 (2017-10-18)
255 |
256 | #### :rocket: Enhancement
257 | * [#46](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/46) Convert "ember-cli-babel" to dev dependency ([@Turbo87](https://github.com/Turbo87))
258 |
259 | #### :memo: Documentation
260 | * [#41](https://github.com/mixonic/ember-cli-deprecation-workflow/pull/41) Update README.md ([@tabeth](https://github.com/tabeth))
261 |
262 | #### Committers: 2
263 | - Tabeth Nkangoh ([@tabeth](https://github.com/tabeth))
264 | - Tobias Bieniek ([@Turbo87](https://github.com/Turbo87))
265 |
--------------------------------------------------------------------------------