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

(#1) BASH-20 Add base and override config #586

Merged
merged 2 commits into from
Oct 11, 2017

Conversation

csduarte
Copy link
Contributor

@csduarte csduarte commented Sep 8, 2017

Description
This PR moves configuration values to a base.json file (src/common/config/base.json) and allow to override those config values on file override.json (src/common/config/override.json). That way the override values can be stored on a separate repository when building the clientes.

Test Cases
Add override values like this:

// Example override.js
{
  "1": {
    "showTrayIcon": true,
    "trayIconTheme": "light"
  }
}

@yuya-oc
Copy link
Contributor

yuya-oc commented Sep 9, 2017

Thanks for a lot of PRs!

This mechanism doesn't require Electron, so would you write tests in test/specs/settings_test.js? At least, upgrading from v0 to v1 is breaking. You can use describe.only() or it.only() to execute only your tests.

I thinks this PR forces only default settings. So users can change all settings. Is this correct?

@yuya-oc
Copy link
Contributor

yuya-oc commented Sep 9, 2017

Just curious, why does override.json require version number? I feel it's enough there is one config in the file.

Copy link
Contributor

@yuya-oc yuya-oc left a comment

Choose a reason for hiding this comment

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

Please write tests for overriding.

function deepMergeArray(dest) {
return dest;
}

function loadDefault(version, spellCheckerLocale) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please test how loadDefault() works. Possibly require('override.json') doesn't match for writing tests because its static 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.

@yuya-oc do you want an automated test?

We followed the exact same style as the mobile app in terms of config and override. Possibly would like to match that to start with and then diverge?

Copy link
Contributor

@yuya-oc yuya-oc Sep 18, 2017

Choose a reason for hiding this comment

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

@csduarte If possible. At least, I want that existing tests (test/specs/settings_test.js) is passed.
Unfortunately I'm not sure about mobile app source code. Would you tell me the part?

@yuya-oc
Copy link
Contributor

yuya-oc commented Sep 9, 2017

@jasonblais This would be one of solution for #483, but admins have to build apps from source on their own. Of course code-signing would be gone when they don't. Is this beneficial?

@yuya-oc yuya-oc added the All Platforms null label Sep 9, 2017
@yuya-oc
Copy link
Contributor

yuya-oc commented Sep 14, 2017

Please let me confirm. What is the purpose of this feature? At first, I thought that this PR let users use pre-configured preferences.
However users can change their preferences. And in other PRs, this feature is also used to change "non user-preferences" behavior like ./configure.sh of C/C++ projects. I feel this will be confusing later, so this should be separated to two modules.

To change default preferences, it's enough that the maintainer edits base.json.

@csduarte
Copy link
Contributor Author

@yuya-oc We were trying to make the smallest possible changes, because we know that getting bigger changes back is quite hard. So we used the only config there was to allow what we think of 'Feature Flags'.

Being able to flip something on or off, sometimes dynamically. -- If you could imagine, in the future, we could be developing a brand new feature in the master branch, but have it disabled because of a flag in this config, and that could be flipped. So it certainly crosses the bounds between system config and user config, but eventually we decided a division doesn't make a lot of sense. Just some configs are visible to the user and some are not, and maybe an admin could have access to all of them to flip on and off.

@jasonblais jasonblais added this to the v3.8.0 milestone Sep 15, 2017
src/package.json Outdated
@@ -12,6 +12,7 @@
"auto-launch": "^5.0.1",
"bootstrap": "^3.3.7",
"create-react-class": "^15.5.3",
"deepmerge": "^1.5.1",
Copy link
Contributor

@jasonblais jasonblais Sep 15, 2017

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

correct, also seen here https://www.npmjs.com/package/deepmerge

@jasonblais
Copy link
Contributor

@csduarte In terms of the use case, when developing a new feature in the master branch, we'd have it turned on by default, but have that setting disabled via config/override.json until the feature is finished? Is that correct?

@csduarte
Copy link
Contributor Author

@jasonblais The exact use case is quote flexible. In products that I know better, there is actually another service that will give the config option to the user on boot and show/hide certain features. Basically, An easy way to to A/B testing and test features, all while maintaining continuous integration and deployment.

@jasonblais
Copy link
Contributor

jasonblais commented Sep 18, 2017

Thanks! The context is very helpful.

EDIT: Chatted further with @yuya-oc and we're open to taking the PR, but there might be a few small adjustments that we'd propose. I'll make another post here by end of the day.

@jasonblais jasonblais mentioned this pull request Sep 18, 2017
2 tasks
@jasonblais
Copy link
Contributor

Hey @dmeza, @csduarte

Not urgent, but wondering for your thoughts on the following:

1 - Having both default and 1 lists in the /config/base.json file might be confusing to admins/developers building the apps from the source. It's not immediately obvious why there are two sets of default settings present and what their purpose is.

Would it make sense to split this file into base.json (containing "default") and pastDefault.json (containing "1", and other versions in the future)?

2 - Wondering your thoughts about keeping the core PR the same, but splitting the base.json file into defaultPreferences.json (user config) and buildConfig.json (system config)?

^Open for feedback, as we want to keep further changes from you minimal.

@dmeza
Copy link
Contributor

dmeza commented Sep 27, 2017

Hey @jason, @yuya-oc,
Sorry for the delay to reply. We've been focused on mobile and platform.
Our proposed changes/solution is based on the code that's already there, we're open to getting to the same result with different changes. I have a question as if default and 1 are really needed or there could be a different solution?
Our goal is having configuration values that can enable/disable features and for white-labeling, so both of the proposed changes work. @csduarte explains it here: #586 (comment)

@dmeza
Copy link
Contributor

dmeza commented Sep 29, 2017

@yuya-oc: settings tests are passing now. Fixed the upgrade test and added a test for loadDefault.

@@ -1,4 +1,5 @@
'use strict';
process.env.TEST = 'test';
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this necessary for you?

Copy link
Contributor

Choose a reason for hiding this comment

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

@yuya-oc this the packages context for build and test seems to be different and needed a different deepmerge require:
let deepmerge = require('deepmerge').default; if (process.env.TEST) { deepmerge = require('deepmerge'); // eslint-disable-line }
https://github.com/mattermost/desktop/pull/586/files#diff-7cdc7778ed182028c72b7c53ac2af20bR4

Copy link
Contributor

Choose a reason for hiding this comment

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

@dmeza Got it. Assuming that, this sentence is not needed. When src/common/settings.js requires deepmerge, it correctly uses src/node_modules/deepmerge. Probably you met the error of that test/specs/settings_test.js requires deepmerge at outside of src/.

const baseConfig = require('../../src/common/config/base.json');
const overrideConfig = require('../../src/common/config/override.json');
const expectedDefaults = deepmerge(
baseConfig[1], overrideConfig[1] || {}, {clone: true, arrayMerge: settings.deepMergeArray}
Copy link
Contributor

Choose a reason for hiding this comment

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

This part is actually same to loadDefault() implementation. So this test always passes. Is this intended?

Copy link
Contributor

Choose a reason for hiding this comment

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

@yuya-oc I think that it will provide the context to be able to test specific base config and override changes. What other test do you think we should add here?

Copy link
Contributor

Choose a reason for hiding this comment

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

@dmeza I had imagined the test simply comparing to "expected" default config. So in this case, something like expectedDefaults = { teams: [], showTrayIcon: false, ... } instead of calling deepmerge() because a plain object is obvious as an expected value.
However, surely this might be enough for now. I can accept.

package.json Outdated
@@ -60,5 +61,6 @@
"webpack": "^2.5.1",
"webpack-dev-server": "^2.4.5",
"webpack-merge": "^4.1.0"
}
},
"dependencies": {}
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems accidentally changed.

@dmeza
Copy link
Contributor

dmeza commented Sep 29, 2017

Hey @jason, @yuya-oc, one way to simplify is to have a single version on the override.json file.
Not this:
// Example override.js { "1": { "showTrayIcon": true, "trayIconTheme": "light" } }
But this:
// Example override.js { "showTrayIcon": true, "trayIconTheme": "light" }

Copy link
Contributor

@yuya-oc yuya-oc left a comment

Choose a reason for hiding this comment

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

Sorry for late reply and many requests. Would you confirm again?

@@ -1,4 +1,5 @@
'use strict';
process.env.TEST = 'test';
Copy link
Contributor

Choose a reason for hiding this comment

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

@dmeza Got it. Assuming that, this sentence is not needed. When src/common/settings.js requires deepmerge, it correctly uses src/node_modules/deepmerge. Probably you met the error of that test/specs/settings_test.js requires deepmerge at outside of src/.

const baseConfig = require('../../src/common/config/base.json');
const overrideConfig = require('../../src/common/config/override.json');
const expectedDefaults = deepmerge(
baseConfig[1], overrideConfig[1] || {}, {clone: true, arrayMerge: settings.deepMergeArray}
Copy link
Contributor

Choose a reason for hiding this comment

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

@dmeza I had imagined the test simply comparing to "expected" default config. So in this case, something like expectedDefaults = { teams: [], showTrayIcon: false, ... } instead of calling deepmerge() because a plain object is obvious as an expected value.
However, surely this might be enough for now. I can accept.

@@ -1,35 +1,37 @@
'use strict';

const fs = require('fs');
let deepmerge = require('deepmerge').default;
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned at #586 (comment), const deepmerge = require('deepmerge') is enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

@yuya-oc this form const deepmerge = require('deepmerge') failed when building. Did you try it and worked for you for both cases building and running tests?

Copy link
Contributor

Choose a reason for hiding this comment

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

@dmeza Thanks for feedback. Somehow deepmerge becomes object from function in webpack. So error occurs at run time.
I'm not sure whether it's bug or spec of webpack though, let's keep this for now.

@dmeza
Copy link
Contributor

dmeza commented Oct 9, 2017

@yuya-oc from your comments I gather that this PR is ready, right?

@yuya-oc
Copy link
Contributor

yuya-oc commented Oct 9, 2017

@dmeza Ah, yeah. I had not been sure whether you are preparing more updates about simplified override.json or splitting to two config files.
If there are no more updates here, I think it’s ready to merge.

cc: @jasonblais

@jasonblais
Copy link
Contributor

Thanks all! Let's go ahead and merge the PR.

@yuya-oc
Copy link
Contributor

yuya-oc commented Oct 11, 2017

@csduarte @dmeza Huge thanks for many iteration!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants