-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deprecated models.init
pattern for initializing models
#22358
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,3 @@ | ||
const models = require('../../../../models'); | ||
|
||
module.exports = function before() { | ||
models.init(); | ||
return Promise.resolve(); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,87 @@ | ||
/** | ||
* Dependencies | ||
*/ | ||
|
||
const _ = require('lodash'); | ||
const debug = require('@tryghost/debug')('models'); | ||
const glob = require('glob'); | ||
/* eslint-disable max-lines */ | ||
|
||
// enable event listeners | ||
require('./base/listeners'); | ||
|
||
/** | ||
* Expose all models | ||
*/ | ||
exports = module.exports; | ||
module.exports = { | ||
// `base` file does not export a Base model | ||
Base: require('./base'), | ||
|
||
function init() { | ||
const baseNow = Date.now(); | ||
exports.Base = require('./base'); | ||
debug(`${Date.now() - baseNow}ms - Base.js require`); | ||
|
||
let modelsFiles = glob.sync('!(index).js', {cwd: __dirname}); | ||
modelsFiles.forEach((model) => { | ||
const name = model.replace(/.js$/, ''); | ||
const modelNow = Date.now(); | ||
_.extend(exports, require('./' + name)); | ||
debug(`${Date.now() - modelNow}ms - ${model} require`); | ||
}); | ||
} | ||
...require('./action'), | ||
...require('./author'), | ||
...require('./api-key'), | ||
...require('./benefit'), | ||
...require('./collection-post'), | ||
...require('./collection'), | ||
...require('./comment-like'), | ||
...require('./comment-report'), | ||
...require('./comment'), | ||
...require('./custom-theme-setting'), | ||
...require('./donation-payment-event'), | ||
...require('./email-batch'), | ||
...require('./email-recipient-failure'), | ||
...require('./email-recipient'), | ||
...require('./email-spam-complaint-event'), | ||
...require('./email'), | ||
...require('./integration'), | ||
...require('./invite'), | ||
...require('./job'), | ||
...require('./label'), | ||
...require('./mail-event'), | ||
...require('./member-cancel-event'), | ||
...require('./member-click-event'), | ||
...require('./member-created-event'), | ||
...require('./member-email-change-event'), | ||
...require('./member-feedback'), | ||
...require('./member-login-event'), | ||
...require('./member-newsletter'), | ||
...require('./member-paid-subscription-event'), | ||
...require('./member-payment-event'), | ||
...require('./member-product-event'), | ||
...require('./member-status-event'), | ||
...require('./member-stripe-customer'), | ||
...require('./member-subscribe-event'), | ||
...require('./member'), | ||
...require('./mention'), | ||
...require('./milestone'), | ||
...require('./mobiledoc-revision'), | ||
...require('./newsletter'), | ||
...require('./offer-redemption'), | ||
...require('./offer'), | ||
...require('./permission'), | ||
...require('./post-revision'), | ||
...require('./post'), | ||
...require('./posts-meta'), | ||
...require('./product'), | ||
...require('./recommendation-click-event'), | ||
...require('./recommendation-subscribe-event'), | ||
...require('./recommendation'), | ||
...require('./redirect'), | ||
...require('./role'), | ||
...require('./session'), | ||
...require('./settings'), | ||
...require('./single-use-token'), | ||
...require('./snippet'), | ||
...require('./stripe-customer-subscription'), | ||
...require('./stripe-price'), | ||
...require('./stripe-product'), | ||
...require('./subscription-created-event'), | ||
...require('./suppression'), | ||
...require('./tag-public'), | ||
...require('./tag'), | ||
...require('./user'), | ||
...require('./webhook') | ||
}; | ||
|
||
Comment on lines
+9
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainAdd test for model availability as suggested in past review Per the past review comment by vikaspotluri123, it would be valuable to add a test verifying that all models from 🏁 Script executed: #!/bin/bash
# Let's analyze model files to ensure all are exported
echo "Checking model files vs exports..."
# Get all model files in the directory
model_files=$(ls ghost/core/core/server/models/*.js | grep -v "index.js" | sed 's/.*\///' | sed 's/\.js$//')
# Get all models explicitly required in index.js
exported_models=$(grep -o "require('./[^']*" ghost/core/core/server/models/index.js | sed "s/require('\.\///" | sort)
# Count and compare
file_count=$(echo "$model_files" | wc -l)
export_count=$(echo "$exported_models" | wc -l)
echo "Found $file_count model files and $export_count exports in index.js"
# Find any model files not explicitly exported
for model in $model_files; do
if ! echo "$exported_models" | grep -q "$model"; then
echo "WARNING: Model file $model.js exists but is not explicitly exported in index.js"
fi
done Length of output: 66573 Attention: Unexported Model Detected The test script verifies that while all model files are accounted for, the file
This update aligns with the previous suggestion by vikaspotluri123 to add a test for model availability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we want this check to be run as part of the test suite, it would need to follow the existing unit tests (written in javascript, using BDD) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed:
Length of output: 7182 @vikaspotluri123 I'll create a proper BDD-style unit test for checking that all models are exported correctly. Based on examining the existing test patterns in the codebase, here's what I would propose: const should = require('should');
const fs = require('fs');
const path = require('path');
const models = require('../../../../core/server/models');
describe('Models: index', function () {
it('exports all model files correctly', function () {
// Get all JS files in the models directory excluding index.js
const modelsDir = path.resolve(__dirname, '../../../../core/server/models');
const modelFiles = fs.readdirSync(modelsDir)
.filter(file => file.endsWith('.js') && file !== 'index.js');
// Files that aren't models or are handled specially
const excludedFiles = ['role-utils.js']; // Utility file, not a model
const specialCases = {
'base.js': 'Base' // base.js is exported as Base, not via spread operator
};
// Check each model file
modelFiles.forEach((file) => {
if (excludedFiles.includes(file)) {
return; // Skip excluded files
}
const modelName = file.replace('.js', '');
if (specialCases[file]) {
// Handle special cases
const exportName = specialCases[file];
should.exist(models[exportName], `Special case ${file} should be exported as models.${exportName}`);
} else {
// Normal model files
// Check if requiring the file produces exports that exist in models
const modelExports = require(`../../../../core/server/models/${modelName}`);
Object.keys(modelExports).forEach((exportKey) => {
// Find this export in the models object
const hasMatch = Object.values(models).some(modelValue =>
modelValue === modelExports[exportKey]);
should(hasMatch).be.true(`Model export ${exportKey} from ${file} should be included in models index`);
});
}
});
});
it('has a deprecated init function', function() {
should.exist(models.init);
models.init.should.be.a.Function();
// In non-production, it should log a warning
const originalConsoleWarn = console.warn;
const originalNodeEnv = process.env.NODE_ENV;
let warningLogged = false;
try {
console.warn = function(message) {
if (message.includes('models.init() is deprecated')) {
warningLogged = true;
}
};
process.env.NODE_ENV = 'development';
models.init();
warningLogged.should.be.true('A deprecation warning should be logged in non-production');
} finally {
console.warn = originalConsoleWarn;
process.env.NODE_ENV = originalNodeEnv;
}
});
}); This follows the existing BDD patterns in the codebase and properly handles special cases like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😆 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
/** | ||
* Expose `init` | ||
* @deprecated: remove this once we've removed it from everywhere | ||
*/ | ||
|
||
exports.init = init; | ||
module.exports.init = function init() { | ||
if (process.env.NODE_ENV !== 'production') { | ||
// eslint-disable-next-line no-console | ||
console.warn('@deprecated: models.init() is deprecated. Models are now automatically required.'); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ | |
"port": 9417 | ||
}, | ||
"logging": { | ||
"level": "fatal" | ||
"level": "info" | ||
}, | ||
"spam": { | ||
"user_login": { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to add this to a test? e.g. that all
ghost/core/core/server/models/*.js
are available/in the require cache?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good shout! I'll add that once I figure out this browser test failure 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rabbit gave a pretty good starting point 🐇🧙♂️ #22358 (comment)