-
Notifications
You must be signed in to change notification settings - Fork 367
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
Support common prefix listing of diffs (uncommitted, commit view, compare view) #2051
Conversation
This pull request introduces 1 alert when merging 15869ed into 50391bb - view on LGTM.com new alerts:
|
This pull request introduces 1 alert when merging a9752a4 into 50391bb - view on LGTM.com new alerts:
|
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.
Great! minor style comments
pkg/api/controller.go
Outdated
if params.Delimiter == nil { | ||
delimiter = "" | ||
} else { | ||
delimiter = *params.Delimiter | ||
} |
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.
keep it simple
if params.Delimiter == nil { | |
delimiter = "" | |
} else { | |
delimiter = *params.Delimiter | |
} | |
if params.Delimiter != nil { | |
delimiter = *params.Delimiter | |
} |
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.
removed
pkg/api/controller.go
Outdated
if params.Delimiter == nil { | ||
delimiter = "" | ||
} else { | ||
delimiter = *params.Delimiter | ||
} |
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.
if params.Delimiter == nil { | |
delimiter = "" | |
} else { | |
delimiter = *params.Delimiter | |
} | |
if params.Delimiter != nil { | |
delimiter = *params.Delimiter | |
} |
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.
removed
pkg/catalog/catalog.go
Outdated
} | ||
|
||
func GetStartPos(prefix, after, delimiter string) string { | ||
// find the correct place to start iterating from based on delimiter, prefix, after |
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.
convert to godoc for this func
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.
Done
@@ -50,7 +52,10 @@ export const ChangeEntryRow = ({ entry, showActions, onRevert }) => { | |||
break; | |||
} | |||
|
|||
const pathText = entry.path; | |||
let pathText = entry.path; | |||
if (pathText.indexOf(relativeTo) === 0) { |
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.
if (pathText.indexOf(relativeTo) === 0) { | |
if (pathText.startsWith(relativeTo)) { |
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.
Done
if delimiter != "" { | ||
// common prefix logic goes here. | ||
// for every path, after trimming "prefix", take the string upto-and-including the delimiter | ||
// if the received path == the entire remainder, add that object as is | ||
// if it's just a part of the name, add it as a "common prefix" entry - | ||
// and skip to next record following all those starting with this prefix |
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.
Consider reduce the code block size inside this loop by splitting it to extractCommonPrefix, checking if there is a common prefix, and fall to the part where we append and check the limit)
after: (!!after) ? after : "", | ||
prefix: (!!prefix) ? prefix : "", | ||
delimiter: (!!delimiter) ? delimiter : "", |
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.
no need to convert to boolean when we evaluate an expression already
after: (!!after) ? after : "", | |
prefix: (!!prefix) ? prefix : "", | |
delimiter: (!!delimiter) ? delimiter : "", | |
after: after ? after : "", | |
prefix: prefix ? prefix : "", | |
delimiter: delimiter ? delimiter : "", |
after={(!!after) ? after : ""} | ||
prefix={(!!prefix) ? prefix : ""} | ||
delimiter={(!!delimiter) ? delimiter : ""} |
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.
after={(!!after) ? after : ""} | |
prefix={(!!prefix) ? prefix : ""} | |
delimiter={(!!delimiter) ? delimiter : ""} | |
after={after ? after : ""} | |
prefix={prefix ? prefix : ""} | |
delimiter={delimiter ? delimiter : ""} |
return {pathname: '/repositories/:repoId/objects', params, query}; | ||
}; | ||
|
||
export const URINavigator = ({ repo, reference, path, relativeTo = "", pathURLBuilder = buildPathURL }) => { |
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.
export const URINavigator = ({ repo, reference, path, relativeTo = "", pathURLBuilder = buildPathURL }) => { | |
export const URINavigator = ({ repo, reference, path, relativeTo="", pathURLBuilder=buildPathURL }) => { |
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.
Please note LGTM.com comments -- they are sometimes worthwhile, and in any case I'd rather keep the number of open comments down.
Thanks, it looks great and my comments are minor.
}) | ||
} | ||
} | ||
|
||
func TestCatalog_ListRepositories(t *testing.T) { |
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.
Can/should we also add tests for listings with empty prefixes, i.e. paths such as a/b///c
, a/b//c
, a/b/c
?
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.
Yep, added
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.
That was fast
pkg/api/controller.go
Outdated
|
||
// discern between an empty delimiter and no delimiter being passed at all | ||
// by default, go-swagger will use the default value ("/") even if we pass | ||
// a delimiter param that is explicitly empty. This overrides this (wrong) behavior. |
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.
This behavior is not wrong, adding allowEmptyValue: true
to the parameter definition should solve this.
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.
Well, this uncovered a weird behavior in our system. Once upon a time, there was no delimiter in the object listing API.
It worked as if there's always a delimiter that is "/"
. When we added a configuratble one, we tried being backwards compatible. IMO, this was probably a mistake. It worked like this:
- if no delimiter is passed, assume delimiter =
/
- if delimiter is passed but is empty (i.e.
?delimiter=
), assume no delimiter - if delimiter is passed and is any other value, use that.
while it retained the previous behavior it's a weird choice. it means that if I add a delimiter parameter to diff endpoints I can choose between:
- doing the same thing and now assume that no delimiter actually means
/
- this would now break existing diff clients. - make the API inconsistent by having different defaults: for objects, no delimiter means
/
, for diff it means no delimiter. - make the API consistent by fixing object listing (and breaking it): no delimiter means no delimiter.
I went with the painful option 3.
pkg/api/transform.go
Outdated
@@ -10,7 +10,7 @@ func transformDifferenceTypeToString(d catalog.DifferenceType) string { | |||
return "added" | |||
case catalog.DifferenceTypeRemoved: | |||
return "removed" | |||
case catalog.DifferenceTypeChanged: | |||
case catalog.DifferenceTypeChanged, catalog.DifferenceTypeCommonPrefix: |
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.
So common prefixes are always shown as changed, regardless of what happened underneath? Worth adding a comment here.
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.
Removed this diff type as it isn't a diff type.
@@ -188,7 +188,7 @@ | |||
} | |||
|
|||
.diff-changed { | |||
background-color: #d1ecf1; | |||
background-color: #ffeaa7; |
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.
😍
pkg/catalog/catalog.go
Outdated
return "" | ||
case delimiter != "" && after != "": | ||
// if we have a delimiter and after is not empty, start at the next common prefix after "after" | ||
return string(graveler.UpperBoundForPrefix([]byte(after))) |
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.
It is not clear to me why the presence of a delimiter changes the return value of this function.
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.
with a normal after
, you'd want to start the page with the next lexicographically sorted entry after after
.
Once a delimiter is present, you'd want the next entry (or prefix) that doesn't start with after
.
Example:
after = a/b/
without a delimiter, a/b/c
would be a valid first entry
with a delimiter /
, a/b/c
is wrong, as it is already folded into a/b/
- the first valid entry would be the next entry not starting with a/b/
func listDiffHelper(it EntryDiffIterator, limit int, after string) (Differences, bool, error) { | ||
const commonPrefixSplitParts = 2 | ||
|
||
func listDiffHelper(it EntryDiffIterator, prefix, delimiter string, limit int, after string) (Differences, bool, error) { |
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.
I think it's time to add unit tests for catalog diff/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.
Suppose the diff contains two entries b
and c
.
Suppose after=a
, and prefix=c
.
The returned diff should be c
. I think this function will return an empty diff.
(This may be an abuse of this function, but still as a unit it should return valid results)
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 point - but this is logic that should be in GetStartPos
- as in this case the start pos should be "c" and not "a". I also added a test case for it.
<Card.Header> | ||
<span className="float-left"> | ||
{(delimiter !== "") && ( | ||
<URINavigator path={prefix} reference={reference} repo={repo} relativeTo={`${reference.id} workspace`} pathURLBuilder={(params, query) => { |
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.
"workspace" is a term we didn't publicly mention yet - I think best to avoid it for now. Also here it appears in the same font as the path - which is confusing.
Also the breadcrumb links do not work for me
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.
We do use it publicly..
<URINavigator | ||
path={prefix} | ||
reference={reference} | ||
relativeTo={`${reference.id}...${compareReference.id}`} |
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.
optional: trim if reference is a commit hash, to conform with a single commit view
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.
Will do
return { | ||
pathname: '/repositories/:repoId/commits/:commitId', | ||
params: {repoId: repo.id, commitId: commit.id}, | ||
query: {delimiter: "/", prefix: query.path} |
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.
is this the right place to hardcode a /
?
</span> | ||
<span className="float-right"> | ||
<Form> | ||
<Form.Switch |
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.
Optional: extract the toggle switch to a component
@nopcoder @johnnyaug @arielshaqed - please notice that I broke backwards compatibility for the object listing API. If you have a better idea I'd love to not do it. |
This pull request introduces 1 alert when merging 04fb060 into d9ae3b9 - view on LGTM.com new alerts:
|
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.
- About b/c: as long as existing deployed clients are OK (I think we have just the
lakectl
command) I see no issues with breaking b/c on some weird-ish edge cases. - Note new LGTM.com complaint.
- Two minor comments.
- ???
- THANKS (& PROFIT)!!!
api/swagger.yml
Outdated
size_bytes: | ||
type: integer | ||
format: int64 |
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.
Unclear what is the "size" of a diff. Can you add a description please?
pkg/api/controller_test.go
Outdated
@@ -935,8 +935,9 @@ func TestController_ObjectsListObjectsHandler(t *testing.T) { | |||
} | |||
|
|||
t.Run("get object list", func(t *testing.T) { | |||
pfx := api.PaginationPrefix("foo/") |
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.
pfx := api.PaginationPrefix("foo/") | |
prefix := api.PaginationPrefix("foo/") |
Why abbreviate?
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.
Nice.
In the UI, I still suggest dropping the word "workspace" from the path.
Addressing some of #2029 - When working with large diffs, paging across multiple data objects is not optimal.
This PR adds the ability (a toggle in the UI) to view diffs with a directory structure. Should make answering "which tables/partitions were modifed" much easier.