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
Store server feature level in Redux #4079
Conversation
@gnprice @chrisbobbe this is ready for a review. :) |
Thanks, @hashirsarwar! Just a note to @gnprice that |
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.
Thanks, @hashirsarwar, I've just had a closer look! Some comments below, and I'm sure @gnprice will have more to add.
Generally, for the part of the commit message that explains what work was done, it's a bit more concise (and, more importantly, consistent with a single style that we've chosen) to use the imperative mood. (I'm still torn on whether it's actually a kind of bare infinitive, but I digress.)
So, instead of
"This adds a new property featureLevel in the type Account."
we tend to write,
"Add a new property featureLevel in the type Account."
@chrisbobbe thanks for the review. As far as commit messages are concerned, I think we use imperative mood in summaries. In case of message bodies, there is no as such restriction. See the commit message example here provided in the documentation. However, I'll make the requested changes soon. 🙂 |
Hmm, interesting. I would have thought the distinction is made on a different axis — not whether the words are in the summary or in the body, but rather, whether they describe some work that gets done in the commit, as opposed to background information, motivations for the work, plans for the future, maybe even close or distant effects of the work, etc. My reading of the commit you've linked to has it following this pattern, too. But the doc does indeed mention "imperative" several times in the section about the summary, and zero times in the section about the body. @gnprice, @ray-kraesig, thoughts? |
@chrisbobbe here are some other examples of recent commit messages from the web repository. Still, I would like to know what others think about it. 🙂 |
That's correct, imperative mood is only expected in the summary line. The paragraph body is a more normal paragraph explaining relevant background/motivation/etc. for the change. |
Hmm, the commits in that screenshot also seem to follow both patterns. 🙂
Hmm, OK. @timabbott, it sounds like there's an additional constraint that the entire work of the change (excluding background, motivation, etc.) be condensed into the summary line. With the summary line's character limit, might it sometimes be impossible to preserve the required amount of detail in that class of explanation, even with minimal, coherent commits? E.g., when follow-on changes on a main change are needed in the same commit, they often deserve their own explanation, right, which I'm not sure would count as background info? Anyway, @hashirsarwar, for the commit I mentioned here: f514d6a Account type: Add a property featureLevel. That bit I highlighted from the body, "This adds a new property featureLevel in the type Account.", seems redundant; you've got it (in the imperative, good 🙂) in the summary line. |
f9ad6af
to
853f90c
Compare
@timabbott I think if you look again you'll agree that this is a stronger statement than you really intend. Among your own recent commit messages, it's not uncommon to have some "how" or high-level "what" in the commit message body, in addition to "why" and background:
and I think that's for good reasons -- sometimes there's just more to say than makes sense to put in the summary line.
It looks like the practice on this is mixed. At a quick survey of recent zulip.git history:
In the mobile repo, we've more or less consistently used the same form for describing "what" in the body (if present there) as we do in the summary line. I don't feel an urgency to make the style uniform one way or another in zulip.git, but unsurprisingly I do like better the style I use. 😉 One reason is that a sentence in the indicative can easily be ambiguous about whether it's describing something already true before this commit (as background) or something newly made true by this commit. In any case we've been pretty consistent in zulip-mobile, and so I'd like to generally maintain that consistency there. |
@hashirsarwar, I like these changes! @gnprice and/or @ray-kraesig will likely have more to add. @gnprice, there's a query here, which perhaps I should have posted on the PR thread, and in any case will quote here:
|
Ah, my wording here was confusing:
In general new features don't appear in a new Zulip patch release, i.e. a version a.b.(c+1) vs. a.b.c. Rather they only appear in a new major release, which is a.(b+1).0 or (a+1).0.0. So a "new server feature that's after 2.1.0" means one whose first release is 2.2.0. (Or 3.0.0 if we were to go straight there, but we won't.) For this purpose, though:
I think the answer is:
|
853f90c
to
251d249
Compare
Okay, based on your feedback, I have made the following changes:
@chrisbobbe @gnprice kindly have a look. 🙂 |
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.
From the commit messages:
The property is optional because some older versions of the server may still not include feature level in the /register response.
Let's not imply that this is in doubt: "... because older versions of the server do not include ...".
Also, although we can (mostly) move to feature level indicators going forward, I think I'd prefer to have the docstrings in this PR act as a bridge, including the server commit ID alongside "feature level 1". (If nothing else, I expect it to help a confused future me find the place in the Zulip server codebase where the feature level is stored.)
7eaea28
to
58f0202
Compare
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.
Thanks @hashirsarwar ! Several comments below.
58f0202
to
f391df7
Compare
@gnprice thanks for the feedback. Can you review this once again? |
f391df7
to
cfcdbf5
Compare
22f50a6
to
563bbbc
Compare
Like we did for `zulipVersion`, except the interesting data is found on `action.data`, not `action`, as I mention in zulip#4079 (comment).
This reorganization does a few things: - Focuses each test case to just a few lines. As Greg points out [1], "[w]hen each one is just a few lines, tests one thing, and it's clear what that one thing is, that helps make it comfortable to have a number of different test cases and really think systematically through having them cover all the interesting different situations. - Tweaks the claim for one test that begins, 'if no account with this realm exists'. Greg points out [2] that a test like this would be redundant: "The case where the account doesn't exist in the state can I think be covered by the "account is not in state" test case in the first pair, because that can just do an equality test on the whole resulting state." This comment from Greg was already addressed with the pair of tests on `zulipVersion`, but not those on `zulipFeatureLevel`. - Brings the tests' logic in line with their claims about the previous state's contents. For example, if a test says that an account in the previous state has a null zulipFeatureLevel, make sure that the account in the previous state actually has a null zulipFeatureLevel. It made sense to stop using the `prevState` for these tests. [1] zulip#4079 (comment) [2] zulip#4079 (comment)
Like we did for `zulipVersion`, except the interesting data is found on `action.data`, not `action`, as I mention in zulip#4079 (comment).
This reorganization does a few things: - Focuses each test case to just a few lines. As Greg points out [1], "[w]hen each one is just a few lines, tests one thing, and it's clear what that one thing is, that helps make it comfortable to have a number of different test cases and really think systematically through having them cover all the interesting different situations. - Tweaks the claim for one test that begins, 'if no account with this realm exists'. Greg points out [2] that a test like this would be redundant: "The case where the account doesn't exist in the state can I think be covered by the "account is not in state" test case in the first pair, because that can just do an equality test on the whole resulting state." This comment from Greg was already addressed with the pair of tests on `zulipVersion`, but not those on `zulipFeatureLevel`. - Brings the tests' logic in line with their claims about the previous state's contents. For example, if a test says that an account in the previous state has a null zulipFeatureLevel, make sure that the account in the previous state actually has a null zulipFeatureLevel. It made sense to stop using the `prevState` for these tests. [1] zulip#4079 (comment) [2] zulip#4079 (comment)
563bbbc
to
6c14907
Compare
Thanks, @hashirsarwar! I've made a few tweaks as commits on top of this branch, and I pinged @gnprice on CZO to double-check them. |
Like we did for `zulipVersion`, except the interesting data is found on `action.data`, not `action`, as I mention in zulip#4079 (comment).
This reorganization does a few things: - Focuses each test case to just a few lines. As Greg points out [1], "[w]hen each one is just a few lines, tests one thing, and it's clear what that one thing is, that helps make it comfortable to have a number of different test cases and really think systematically through having them cover all the interesting different situations. - Tweaks the claim for one test that begins, 'if no account with this realm exists'. Greg points out [2] that a test like this would be redundant: "The case where the account doesn't exist in the state can I think be covered by the "account is not in state" test case in the first pair, because that can just do an equality test on the whole resulting state." This comment from Greg was already addressed with the pair of tests on `zulipVersion`, but not those on `zulipFeatureLevel`. - Brings the tests' logic in line with their claims about the previous state's contents. For example, if a test says that an account in the previous state has a null zulipFeatureLevel, make sure that the account in the previous state actually has a null zulipFeatureLevel. It made sense to stop using the `prevState` for these tests. [1] zulip#4079 (comment) [2] zulip#4079 (comment)
6c14907
to
0c1374e
Compare
As the server-side feature level is implemented, we now add a new property `zulip_feature_level` in `ApiResponseServerSettigs` and `InitialDataRealm` to store the feature level from the responses of /server_settings and /register. The property is optional because older versions of the server do not include feature level in the /server_settings and /register responses. Part of zulip#4049.
This makes REALM_ADD tests clear by handling each case separately and removing some redundant lines.
The feature level accessed from the /server_settings response is passed to the realmAdd action creator. Part of zulip#4049.
Firstly, we add zulipFeatureLevel in Account type. We had to tweak `loginSuccess()` and `realmAdd()` methods in accountsReducer to include `zulipFeatureLevel` in their return values too. Then, we store the feature level in Redux on REALM_ADD and REALM_INIT. Part of zulip#4049.
Continue our pattern of using this where we can, since it's slightly easier to read. A doc about this operator from MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
Like we did for `zulipVersion`, except the interesting data is found on `action.data`, not `action`, as I mention in zulip#4079 (comment).
This reorganization does a few things: - Focuses each test case to just a few lines. As Greg points out [1], "[w]hen each one is just a few lines, tests one thing, and it's clear what that one thing is, that helps make it comfortable to have a number of different test cases and really think systematically through having them cover all the interesting different situations. - Tweaks the claim for one test that begins, 'if no account with this realm exists'. Greg points out [2] that a test like this would be redundant: "The case where the account doesn't exist in the state can I think be covered by the "account is not in state" test case in the first pair, because that can just do an equality test on the whole resulting state." This comment from Greg was already addressed with the pair of tests on `zulipVersion`, but not those on `zulipFeatureLevel`. - Brings the tests' logic in line with their claims about the previous state's contents. For example, if a test says that an account in the previous state has a null zulipFeatureLevel, make sure that the account in the previous state actually has a null zulipFeatureLevel. It made sense to stop using the `prevState` for these tests. [1] zulip#4079 (comment) [2] zulip#4079 (comment)
In particular: * Pull out `baseAction`, reducing repetition of boring bits that don't matter to each test so that things that do (like `newZulipVersion`) better stand out. * Inline some single-use variables like `expectedState` that don't add clarity, making the tests shorter. * Write the properties of an Account object in a consistent order, starting with its unique key of realm + email.
Each of these started by constructing a piece of the expected result state, and then went on to construct the input. That works but gets confusing to read, as the logical flow of information zigzags up and down the test code. Instead, describe first the input and then the expected result. Meanwhile in the "move to front of list" test, as the name suggests, what we're looking for is for the matching account information to move to the front; so say that directly instead of constructing a fresh example account. There are nuances when the zulipVersion or zulipFeatureLevel needs an update, but we cover those in their own test cases just below, and the fresh `eg.makeAccount` call didn't really add any clarity about them.
No need to give names to `newState`, `expectedState`, etc., when they're each used just once and their roles can be communicated directly by where they appear in the `expect` expression. Also no need to check `expect(newState).not.toBe(prevState)`; we're already checking it's equal to `expectedState`, and the latter is indeed not equal to `prevState`.
Like with the existing nested `describe` calls below, this helps organize the tests and in particular allows each group of them to have their own local fixtures like `baseAction`.
In particular, in migration 12 there's no need to check on the existing `a.zulipVersion`; that property must be missing, because in versions of the app before we added that migration it didn't exist.
0c1374e
to
e122cfb
Compare
Thanks @chrisbobbe ! These look good. Merged, with a few additional commits on top; take a look. |
Thanks, and in particular, thanks for those additional commits, I read them all! 🙂 |
Following #14658, we now obtain
feature level
from Zulip server and store it in Redux. This is designed to provide a simple way for mobile apps to decide whether the server supports a given feature or API change.Closes #4049.