Skip to content
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

feat(Config): Introduce new config resolution #70

Merged
merged 1 commit into from
Jan 26, 2021

Conversation

pgrzesik
Copy link
Contributor

Notifications tests had to be adjusted because they became nondeterministic - in some cases, the lastShown date for two notifications was the same and not the one that was expected was returned.

It introduces the following breaking changes:

  • Removed getGlobalConfig from API
  • removed support for all rc-discoverable files
  • update not always modify only global config (if local is present, it's the one that will get updated)

Closes: #69

@pgrzesik pgrzesik added the enhancement New feature or request label Jan 23, 2021
@pgrzesik pgrzesik force-pushed the feature-adjust-config-util branch 2 times, most recently from bc3b25f to c22141a Compare January 23, 2021 18:44
@codecov
Copy link

codecov bot commented Jan 23, 2021

Codecov Report

Merging #70 (668e7d9) into master (3f4cee4) will increase coverage by 8.33%.
The diff coverage is 95.58%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #70      +/-   ##
==========================================
+ Coverage   80.83%   89.17%   +8.33%     
==========================================
  Files           8        8              
  Lines         167      194      +27     
==========================================
+ Hits          135      173      +38     
+ Misses         32       21      -11     
Impacted Files Coverage Δ
config.js 92.63% <95.58%> (+19.10%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3f4cee4...668e7d9. Read the comment docs.

@pgrzesik pgrzesik self-assigned this Jan 24, 2021
@pgrzesik pgrzesik requested a review from medikoo January 25, 2021 07:36
let globalConfigPath;

before(async () => {
await fs.promises.mkdir('local');
Copy link
Contributor Author

@pgrzesik pgrzesik Jan 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for that construct being present in multiple tests is the fact that we're mocking both homedir and cwd to a temporary directory, which means that both local and global config has the same location in these scenarios. I'd love to hear feedback on how to potentially improve that in the scope of these tests

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've taken very good approach, I cannot think of anything better 👍

Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good! It's great to see so extensive testing (after all it's a very sensitive functionality)

I have just few comments. Let me know

config.js Outdated
config.meta.updated_at = Math.round(Date.now() / 1000);
// write to .serverlessrc file
return storeConfig(config);
return storeConfig(config, configPath, { updated: true });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in all cases we should return same value as getConfig would return (in light of that I would strip returning any value from storeConfig)

Copy link
Contributor Author

@pgrzesik pgrzesik Jan 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can skip returning anything from storeConfig 👍 The question here is - should we return anything from storeConfig then? I was thinking about true/false for indicating if save was successful or not or maybe we should just throw any potential errors?

config.js Outdated
try {
writeFileAtomic.sync(serverlessrcPath, JSON.stringify(config, null, 2));
if (options.updated) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need that option, can't we store it unconditionally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to keep previous behavior when on default global config creation updated_at was not populated but I'm fine with updating it unconditionally. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would update it unconditionally. I think there's no valid reason to be conditional here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated 👍

config.js Outdated
if (!config.userId) {
return null;
}
const user = get(['users', config.userId, 'dashboard'], config);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we already resolved config, probably more optimal would be to resort o _.get(config, path) here (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely, I totally missed that when moving functionality from platform-sdk

config.js Show resolved Hide resolved
test/config.js Outdated

it('should have CONFIG_FILE_NAME', () => {
const configFilename = config.CONFIG_FILE_NAME;
expect(configFilename).to.exist; // eslint-disable-line
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need this eslint disable comment (I know it's like that in master, but I guess we can clean this now)

let clock;

before(() => {
clock = sinon.useFakeTimers(Date.now());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why those tests needed to be updated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to clarify that on lines 27-28. Essentially, it turned out that after refactoring, new config resolution is faster than rc and this test started to fail from time to time. After inspection, it was caused by the fact that some of the notifications were emitted almost at the exact same time, which caused them to have the same lastShown value. That in turn resulted in the functionality selecting the next notification to be emitted to be resolved incorrectly (I've observed situations where CODE0A was selected instead of CODE0C because they had the same lastShown date.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, good point, but in such case I'd rather introduce await wait(1) between calls (with a comment that it ensures distinct ms timestamps)

At least (but maybe it's just my bias) interfering with JS clock feels quite invasive to me. I'd rely on it, as a last resort (where e.g. we need simulate longer periods of times, or precisely reproduce some time sequences)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think wait(1) here makes sense and is definitely enough 👍 I might be heavily biased myself due to my background in Python, where mocking time is much more common practice. I've changed to the suggested approach 👍

test/config.js Outdated
Comment on lines 19 to 25
before(() => {
clock = sinon.useFakeTimers(now);
});

after(() => {
clock.restore();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take, it's to test, the updated_at, but isn't it overkill? Can't we simply do setTimeout(.., 10) and confirm that updated_at was updated (?) If it appears as needed, maybe it'll be nicer to mock timers only for tests where we test that functionality and not whole test file (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it might be a bit of an overkill here. I'll adjust it 👍

let globalConfigPath;

before(async () => {
await fs.promises.mkdir('local');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've taken very good approach, I cannot think of anything better 👍

@pgrzesik pgrzesik force-pushed the feature-adjust-config-util branch 3 times, most recently from c8f2be1 to 0f86d99 Compare January 25, 2021 15:04
@pgrzesik pgrzesik requested a review from medikoo January 25, 2021 16:27
Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great @pgrzesik ! I've posted just a few minor suggestions

config.js Outdated
Comment on lines 45 to 46
config.meta = config.meta || {};
config.meta.updated_at = Math.round(Date.now() / 1000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove those two from try. Technically this clause is dedicated to catch write error and nothing else.

To be fully bulletproof also config stringification is best if outside of try/catch clause (if it crashes it feels as programmer error on our side, which I would expose unconditionally)

config.js Outdated
config.meta.updated_at = Math.round(Date.now() / 1000);
// write to .serverlessrc file
return storeConfig(config);
return storeConfig(config, configPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As now storeConfig doesn't return anything, I think we need to return result of getConfig here

config.js Outdated
if (key && typeof key === 'string') {
config = _.omit(config, [key]);
} else if (key && Array.isArray(key)) {
config = _.omit(config, key);
}
// write to .serverlessrc file
return storeConfig(config);
return storeConfig(config, configPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

BREAKING CHANGE: Removed `getGlobalConfig`, removed support
for all `rc`-discoverable files, update not always modify only global config
Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! 👍

@pgrzesik pgrzesik merged commit 3bff1b4 into master Jan 26, 2021
@pgrzesik pgrzesik deleted the feature-adjust-config-util branch January 26, 2021 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unify configuration file handling
2 participants