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

Update Clone dialog's handling of clipboard text #9116

Merged

Conversation

nyankoframe
Copy link
Contributor

@nyankoframe nyankoframe commented Apr 26, 2021

Fixes #6260

Proposed changes

  • Adds a new method in FormClone to extract a URL from a text string.
  • Updates Clone form to use new method

Test methodology

  • Manual testing
  • Added new integration test in FormCloneTests.cs

Test environment(s)

  • GIT 2.31.0.windows.1
  • Windows 10.0.19042.868

✒️ I contribute this code under The Developer Certificate of Origin.

|| path.StartsWith("git:", StringComparison.CurrentCultureIgnoreCase)
|| path.StartsWith("ssh:", StringComparison.CurrentCultureIgnoreCase)
|| path.StartsWith("file:", StringComparison.CurrentCultureIgnoreCase));
&& UrlRegex.IsMatch(path);
Copy link
Member

Choose a reason for hiding this comment

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

RegEx parsing of this kind of thing makes me a bit uneasy, as the format is generally quite involved. Why not use Url.TryParse instead?

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'm not sure if there is a Url.TryParse method (unless I'm looking in the wrong place?), but is this what you're referring to?
System.UriParser.IsWellFormedOriginalString

Copy link
Member

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.

I've tried using Uri.TryCreate and it returns false if the string has any characters before or after the URL, which was the original problem - someone had a string in clipboard that of the form "git clone https://...." that wasn't getting detected as a valid potential URL because of the "git clone" text before the URL. I feel that using the regex to detect if the string contains a valid URL allows the user to manually remove non-URL text without having GE guess and potentially get it wrong.

Copy link
Member

Choose a reason for hiding this comment

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

Given a URL cannot contain spaces, you could take the input string, split it by spaces and check each value.

My concern is that the full URL format is complex, and this regex will not cover all valid cases. The Uri class is far more likely to be correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the feedback, I've switched to using Uri.IsWellFormedUriString as that allows file paths to not be treated as URIs (Uri.TryCreate would consider them as URIs resulting in LocalRepositoryManager methods throwing an exception)

GitCommands/PathUtil.cs Outdated Show resolved Hide resolved
@nyankoframe nyankoframe force-pushed the ignore-git-clone-prefix-3.5 branch 2 times, most recently from ef30e74 to c687e82 Compare April 27, 2021 05:57
@nyankoframe
Copy link
Contributor Author

It looks like #9018 was already merged into the 3.5 milestone, so this PR might be redundant. @RussKie could you confirm? If so, I'll go ahead and close it.

@RussKie
Copy link
Member

RussKie commented Apr 27, 2021 via email

contributors.txt Outdated Show resolved Hide resolved
@ghost ghost added the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label Apr 27, 2021
@RussKie RussKie added this to the 3.5.1 milestone Apr 27, 2021
@nyankoframe nyankoframe force-pushed the ignore-git-clone-prefix-3.5 branch from c687e82 to fcbb7d1 Compare May 2, 2021 04:01
@ghost ghost removed the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label May 2, 2021
@nyankoframe nyankoframe changed the title Use regex for detecting potential URLs Use System.Uri methods for detecting potential URLs May 2, 2021
RussKie
RussKie previously requested changes May 2, 2021
Copy link
Member

@RussKie RussKie left a comment

Choose a reason for hiding this comment

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

Thank you, but the API needs a little more work.

GitCommands/PathUtil.cs Outdated Show resolved Hide resolved
Comment on lines 351 to 357
[TestCase("git clone https://github.com/gitextensions/gitextensions", true)]
[TestCase("HTTPS://MYPRIVATEGITHUB.COM:8080/LOUDREPO.GIT", true)]
[TestCase("git://myurl/myrepo.git", true)]
[TestCase("git clone https://github.com/gitextensions/gitextensions && cd gitextensions", true)]
[TestCase("github.com/gitextensions", false)]
[TestCase("github.com/gitextensions/gitextensions/pull/9018", false)]
[TestCase("git clone ssh://username@gerrit-server:/PROJECT", true)]
Copy link
Member

Choose a reason for hiding this comment

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

Neither of these are correct inputs for CanBeGitURL method - because the answer to the question "Can either of those be a git URL?" is "no".

        [TestCase("git clone https://github.com/gitextensions/gitextensions", true)]
        [TestCase("git clone https://github.com/gitextensions/gitextensions && cd gitextensions", true)]
        [TestCase("github.com/gitextensions", false)]
        [TestCase("github.com/gitextensions/gitextensions/pull/9018", false)]
        [TestCase("git clone ssh://username@gerrit-server:/PROJECT", true)]

We can consider renaming the method to ContainsGitUrl, because then the answer becomes "yes". But then the signature must be changed as well to return the valid git URL... So we'll have to make it something like:

        public static bool TryExtractGitUrl(string url, out string gitUrl)

Copy link
Member

Choose a reason for hiding this comment

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

I believe the comments are addressed

Comment on lines 93 to 103
string[] pathElements = path.Split(' ');
bool validUrl = false;
foreach (string str in pathElements)
{
validUrl |= Uri.IsWellFormedUriString(str, UriKind.Absolute);
}
Copy link
Member

Choose a reason for hiding this comment

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

Likewise this method's purpose is to validate the input string, and not break it apart and check each part. The proposal makes the behaviour surprising - as now the question "Is 'git clone https://github.com/gitextensions/gitextensions' a URL?" results in "Yes", which is unexpected to anyone looking at the signature.

Copy link
Member

Choose a reason for hiding this comment

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

Agree. If the caller wants to check individual words, they can split the string and call this on each.

@ghost ghost added the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label May 2, 2021
@RussKie
Copy link
Member

RussKie commented May 2, 2021

Please rebase the PR on to the master branch. This won't go into 3.5.1 Scratch that.

@gerhardol
Copy link
Member

@nyankoframe Any update? 3.5.1 is hopefully released quite soon

@nyankoframe
Copy link
Contributor Author

@nyankoframe Any update? 3.5.1 is hopefully released quite soon

Sorry for the delay; I was a bit buried at work, but should have some time in the next few days to make the proposed changes.

@ghost ghost removed the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label May 18, 2021
@nyankoframe nyankoframe requested a review from RussKie May 25, 2021 01:25
@nyankoframe nyankoframe changed the title Use System.Uri methods for detecting potential URLs Add method for extracting URLs in text string May 25, 2021
return Uri.IsWellFormedUriString(path, UriKind.Absolute);
}

public static bool ExtractURLsFromString(string contents, List<string> urls)
Copy link
Member

Choose a reason for hiding this comment

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

A small change to the API here seems more idiomatic, somehow.

Suggested change
public static bool ExtractURLsFromString(string contents, List<string> urls)
public static bool TryExtractURLsFromString(string contents, out List<string> urls)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the feedback; will update in the next iteration.

return false;
}

string[] parts = contents.Split(' ');
Copy link
Member

Choose a reason for hiding this comment

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

Could use LazyStringSplit here (I think the PR where I added that was merged) to avoid allocating a string[].

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 don't see LazyStringSplit in the 3.5 branch, but will use it when I replace the original implementation in the main branch.

/// <param name="path">A path to check.</param>
/// <returns><see langword="true"/> if the given path starts with 'http', 'ssh' or 'git'; otherwise <see langword="false"/>.</returns>
/// <returns><see langword="true"/> if the given path contains a URL; otherwise <see langword="false"/>.</returns>
[Pure]
public static bool IsUrl(string path)
Copy link
Member

Choose a reason for hiding this comment

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

This method doesn't add much value any more. It's basically just Uri.IsWellFormedUriString. Do we still need it?

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 removed this method and replaced references to it by calling Uri.IsWellFormedUriString.

@RussKie RussKie added the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label May 26, 2021
@ghost ghost removed the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label May 26, 2021
@nyankoframe
Copy link
Contributor Author

I don't understand why the submodule tests are failing in AppVeyor, but pass when I run them locally. :(

Copy link
Member

@gerhardol gerhardol left a comment

Choose a reason for hiding this comment

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

I would like to see the test being updated, but otherwise OK for me

[TestCase("file:", false)]
[TestCase("SSH:", true)]
[TestCase("SSH", false)]
[TestCase("https://myhost:12368/", true)]
public void CanBeGitURL(string url, bool expected)
Copy link
Member

Choose a reason for hiding this comment

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

There are no tests for the second tests

                   || url.EndsWith(".git", StringComparison.CurrentCultureIgnoreCase)
                   || GitModule.IsValidGitWorkingDir(url);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are some tests for paths/URLs that end with .git but I guess there are no tests for IsValidGitWorkingDir since it needs a specific directory structure.

@gerhardol
Copy link
Member

I don't understand why the submodule tests are failing in AppVeyor, but pass when I run them locally. :(

Tests require the as much effort as the code...
This is likely not caused by this PR though.
Updated build is OK.

I cannot see what goes wrong, it seems a little like tests run in parallel (which is not possible for these tests).
The test timed out, likely due to a popup in the test sever, that will need to be investigated by logging in to the server before the timeout fires.

/// <param name="contents">A string to attempt to extract URLs from.</param>
/// <param name="urls">A <see cref="List{T}"/> that contains any URLs extracted from <paramref name="contents"/>.</param>
/// <returns><see langword="true"/> if the given string contains one or more URLs; otherwise <see langword="false"/>.</returns>
public static bool TryExtractURLsFromString(string contents, out List<string> urls)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public static bool TryExtractURLsFromString(string contents, out List<string> urls)
public static bool TryExtractUrls(string contents, out IReadOnlyList<string> urls)

/// <param name="contents">A string to attempt to extract URLs from.</param>
/// <param name="urls">A <see cref="List{T}"/> that contains any URLs extracted from <paramref name="contents"/>.</param>
/// <returns><see langword="true"/> if the given string contains one or more URLs; otherwise <see langword="false"/>.</returns>
public static bool TryExtractURLsFromString(string contents, out List<string> urls)
Copy link
Member

Choose a reason for hiding this comment

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

💭 To clarify - we now have a single callsite for this method in FormClone, right? If this is so, I'd turn this method into a private in FormClone, and test it through a test accessor. And since the only use case for this method is to use the first detected URL, there are questions why we need to allocate a list, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the feedback; I've changed this method to a private in FormClone and have added a test for it.

@RussKie RussKie added the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label Jun 1, 2021
@gerhardol
Copy link
Member

Note: 3.5.1 is hopefully shipped soon...

@ghost ghost removed the 📭 needs: author feedback More info/confirmation awaited from OP; issues typically get closed after 30 days of inactivity label Jun 1, 2021
@nyankoframe nyankoframe changed the title Add method for extracting URLs in text string Update Clone dialog's handling of clipboard text Jun 1, 2021
@nyankoframe nyankoframe requested a review from RussKie June 1, 2021 18:55

accessor.TryExtractUrl(text, out var url).Should().Equals(expected);

url.Should().Equals(expectedUrl);
Copy link
Member

Choose a reason for hiding this comment

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

Should expected URL be tested if expected is false?

This change adds a new FormClone.TryExtractUrl method
to split a string by spaces and extract the first string for which
Uri.IsWellFormedUriString returns true.

A new integration test is added for FormClone to validate the
behavior of the new method.

This change updates the Clone dialog to use the new method
for extracting URLs from clipboard contents.

Calls to PathUtil.IsUrl are replaced by direct calls to
Uri.IsWellFormedUriString.
@RussKie RussKie merged commit 4267698 into gitextensions:release/3.5 Jun 5, 2021
@RussKie
Copy link
Member

RussKie commented Jun 5, 2021

Thank you!

@RussKie
Copy link
Member

RussKie commented Jun 5, 2021

@nyankoframe can you please send a matching PR to the master branch?

@nyankoframe nyankoframe deleted the ignore-git-clone-prefix-3.5 branch June 6, 2021 01:07
BlythMeister added a commit to BlythMeister/gitextensions that referenced this pull request Aug 19, 2021
This was changed in gitextensions#9116 to only check for a valid URL
as part of the rework to break down a string of text to find
a valid URL.
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.

None yet

4 participants