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

Store server feature level in Redux #4079

Merged
merged 13 commits into from Sep 19, 2020
Merged

Conversation

hashirsarwar
Copy link
Contributor

@hashirsarwar hashirsarwar commented Apr 30, 2020

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.

@hashirsarwar
Copy link
Contributor Author

@gnprice @chrisbobbe this is ready for a review. :)

@chrisbobbe
Copy link
Contributor

Thanks, @hashirsarwar!

Just a note to @gnprice that zulipFeatureLevel: number | null, on Account, instead of zulipFeatureLevel?: number, was on my advice, based on e026c6a (in PR #4047, currently a draft) — so if this is wrong, please let me know too. 🙂

Copy link
Contributor

@chrisbobbe chrisbobbe left a 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."

src/api/settings/getServerSettings.js Outdated Show resolved Hide resolved
src/__tests__/lib/exampleData.js Outdated Show resolved Hide resolved
src/__tests__/lib/exampleData.js Outdated Show resolved Hide resolved
src/__tests__/lib/exampleData.js Show resolved Hide resolved
@hashirsarwar
Copy link
Contributor Author

@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. 🙂

@chrisbobbe
Copy link
Contributor

chrisbobbe commented Apr 30, 2020

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.

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?

@hashirsarwar
Copy link
Contributor Author

@chrisbobbe here are some other examples of recent commit messages from the web repository.

Screenshot from 2020-05-01 00-29-13

Still, I would like to know what others think about it. 🙂
Thanks once again!

@timabbott
Copy link
Sponsor Member

timabbott commented Apr 30, 2020

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.

@chrisbobbe
Copy link
Contributor

chrisbobbe commented Apr 30, 2020

Hmm, the commits in that screenshot also seem to follow both patterns. 🙂

@timabbott said:

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, 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.

src/types.js Outdated Show resolved Hide resolved
@gnprice
Copy link
Member

gnprice commented May 1, 2020

The paragraph body is a more normal paragraph explaining relevant background/motivation/etc. for the change.

@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:

While working on this, I fixed various issues where feature levels
could be mentioned or endpoints didn't properly document changes.

[...]  We fix this inconsistency by making
the database model case-insensitive.

Fix this by ensuring all the files we generate are in this special
subdirectory.

Also improve the headings for it.

and I think that's for good reasons -- sometimes there's just more to say than makes sense to put in the summary line.

imperative mood is only expected in the summary line

It looks like the practice on this is mixed. At a quick survey of recent zulip.git history:

  • As quoted above, your messages sometimes put the "what" in the same syntactic form we use in summary lines, and sometimes in the plain indicative like we do for background in the bodies.
  • Mine generally have the "what" match the summary line.
  • Anders tends to write shorter messages; when they do include some "what", it matches the summary line.
  • Steve includes some "what" in the body more frequently, and consistently has it in the indicative, like the background in the body.

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.

@chrisbobbe
Copy link
Contributor

@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:

@gnprice said:

Then we'll want to use it instead of the version number anywhere we can -- basically, for any new server feature that's after 2.1.0.

@gnprice, do we know the particular minimum server version that will have this flag? The above implies that such a minimum server version exists, but it's not 2.1.0. Maybe 2.1.1?

Just so we can put the right comment on zulip_feature_level in ApiResponseServerSettings.

@gnprice
Copy link
Member

gnprice commented May 1, 2020

do we know the particular minimum server version that will have this flag?

Ah, my wording here was confusing:

basically, for any new server feature that's after 2.1.0.

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:

Just so we can put the right comment on zulip_feature_level in ApiResponseServerSettings.

I think the answer is:

  • In the past (and in the future, for server features introduced in the past), we'd identify a zulip.git commit and the release it appeared in.

  • Thanks to this very feature, and to improvements in the Zulip API documentation, I think we can shift to something that's both easier and usually more helpful!

    Specifically, this can say something like "Added in server version 2.2, feature level 1."

    And there's already a link in that file to https://zulipchat.com/api/server-settings , which documents that fact. (I guess in this instance it's not 100% clear about the "feature level 1" detail -- but in general the API docs will now say things like "New in Zulip 2.2 (feature level 2)" or whatever.)

src/message/fetchActions.js Outdated Show resolved Hide resolved
@hashirsarwar
Copy link
Contributor Author

Okay, based on your feedback, I have made the following changes:

  • Added a commit to include the zulip_feature_level property obtained from /register response in InitialDataRealm.

  • Since we have zulip_feature_level in initData for realmInit(), we don't need to mantain this value seprately. So, I have removed two commits that added a seprate feature level property in RealmInitAction and dispatched realmInit() with the redundant feature level value as @gnprice mentioned.

  • Fixed some typos in the comments and commit messages.

@chrisbobbe @gnprice kindly have a look. 🙂

Copy link
Contributor

@rk-for-zulip rk-for-zulip left a 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.)

src/__tests__/lib/exampleData.js Outdated Show resolved Hide resolved
@hashirsarwar hashirsarwar force-pushed the feature-level branch 6 times, most recently from 7eaea28 to 58f0202 Compare May 6, 2020 20:40
Copy link
Member

@gnprice gnprice left a 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.

src/api/initialDataTypes.js Outdated Show resolved Hide resolved
src/api/settings/getServerSettings.js Outdated Show resolved Hide resolved
src/api/initialDataTypes.js Outdated Show resolved Hide resolved
src/api/initialDataTypes.js Outdated Show resolved Hide resolved
src/api/settings/getServerSettings.js Outdated Show resolved Hide resolved
src/start/RealmScreen.js Outdated Show resolved Hide resolved
src/account/accountsReducer.js Show resolved Hide resolved
src/types.js Show resolved Hide resolved
@hashirsarwar
Copy link
Contributor Author

@gnprice thanks for the feedback. Can you review this once again?

chrisbobbe added a commit to hashirsarwar/zulip-mobile that referenced this pull request Sep 18, 2020
Like we did for `zulipVersion`, except the interesting data is found
on `action.data`, not `action`, as I mention in
  zulip#4079 (comment).
chrisbobbe added a commit to hashirsarwar/zulip-mobile that referenced this pull request Sep 18, 2020
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)
chrisbobbe added a commit to hashirsarwar/zulip-mobile that referenced this pull request Sep 18, 2020
Like we did for `zulipVersion`, except the interesting data is found
on `action.data`, not `action`, as I mention in
  zulip#4079 (comment).
chrisbobbe added a commit to hashirsarwar/zulip-mobile that referenced this pull request Sep 18, 2020
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)
@chrisbobbe
Copy link
Contributor

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.

gnprice pushed a commit to hashirsarwar/zulip-mobile that referenced this pull request Sep 19, 2020
Like we did for `zulipVersion`, except the interesting data is found
on `action.data`, not `action`, as I mention in
  zulip#4079 (comment).
gnprice pushed a commit to hashirsarwar/zulip-mobile that referenced this pull request Sep 19, 2020
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)
hashirsarwar and others added 13 commits September 18, 2020 17:30
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.
@gnprice gnprice merged commit e122cfb into zulip:master Sep 19, 2020
@gnprice
Copy link
Member

gnprice commented Sep 19, 2020

Thanks @chrisbobbe ! These look good. Merged, with a few additional commits on top; take a look.

@chrisbobbe
Copy link
Contributor

chrisbobbe commented Sep 19, 2020

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! 🙂

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

Successfully merging this pull request may close these issues.

Store server feature level in Redux
5 participants