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

[JENKINS-43507] Allow SCMSource and SCMNavigator subtypes to share common traits #494

Merged
merged 38 commits into from
Jul 5, 2017

Conversation

stephenc
Copy link
Member

@stephenc stephenc commented May 4, 2017

Downstream of jenkinsci/scm-api-plugin#36

See JENKINS-43507

@reviewbybees

Todo

  • Ensure that the trait implementations work correctly when GitHub and BitBucky branch sources pick up traits

@stephenc stephenc requested review from MarkEWaite and rsandell May 4, 2017 10:42
@stephenc
Copy link
Member Author

stephenc commented May 4, 2017

@MarkEWaite @rsandell this PR is still somewhat in progress until I complete the TODO tasks... should be mostly stable enough to review

if (revision instanceof SCMRevisionImpl) {
extensions.add(new BuildChooserSetting(new SpecificRevisionBuildChooser((SCMRevisionImpl) revision)));
GitSCMBuilder<?> builder = newBuilder(head, revision);
if (Util.isOverridden(AbstractGitSCMSource.class, getClass(), "getExtensions")) {
Copy link
Member Author

Choose a reason for hiding this comment

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

@rsandell This method is the one that needs great care and attention as we discussed previously.

The assumption is that any new subclasses cannot override these methods as they are @Restricted thus there are either no traits (because old implementations cannot have overridden getTraits()) or there are only traits...

Hence these methods just apply the equivalent decoration to the builder to result in the same behaviour as before...

Now I have convinced myself of the equivalence, but I really need you to probe my self-convictions ;-)

Copy link
Member

Choose a reason for hiding this comment

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

Looks OK except for my worry about the DoNotUse.class restriction.

@ghost
Copy link

ghost commented May 4, 2017

This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation.

Copy link
Member

@rsandell rsandell left a comment

Choose a reason for hiding this comment

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

nothing major. mostly concerned with the suspicious hashCode()s.

*/
@Override
public int hashCode() {
return 0;
Copy link
Member

Choose a reason for hiding this comment

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

timeout.hashCode()?

Copy link
Member Author

Choose a reason for hiding this comment

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

the fields are all mutable, thus the hashcode must be constant... should be CheckoutOption.class.hashCode() if I am being fair to any hashsets/maps

Copy link
Member

Choose a reason for hiding this comment

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

So CheckoutOption.class.hashCode() then to be consistent with all the others.

*/
@Override
public int hashCode() {
return CloneOption.class.hashCode();
Copy link
Member

Choose a reason for hiding this comment

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

Not really following the equals/hashCode contract here either.

Copy link
Member Author

Choose a reason for hiding this comment

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

the fields are all mutable, thus the hashcode must be constant...

Copy link
Member

Choose a reason for hiding this comment

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

If they where all imutable I would understand that argument.

Copy link
Member Author

Choose a reason for hiding this comment

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

The hashcode must be consistent or the object cannot be found again. Thus you must exclude mutable fields from the hashCode calculation.

If all fields are mutable then no fields may be used to calculate the hashCode.

Since we expect these to end up in collections with their sibling class implementations and we only ever have at most one impl of a given type, we just give each impl a different constant hashCode and all is right with the world

Copy link
Contributor

Choose a reason for hiding this comment

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

It would even be acceptable if they had the same hashCode, wouldn't it? They would collide in the hash buckets, but that would (at most) have a performance impact, not a functional impact.

*/
@Override
public int hashCode() {
return LocalBranch.class.hashCode();
Copy link
Member

Choose a reason for hiding this comment

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

dito

*/
@Override
public int hashCode() {
return SubmoduleOption.class.hashCode();
Copy link
Member

Choose a reason for hiding this comment

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

dito

try {
hash = client.revParse(context.remoteName() + "/" + revision).name();
} catch (GitException x2) {
listener.getLogger().println(x.getMessage());
Copy link
Member

Choose a reason for hiding this comment

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

So in case of the first exception x, but not the second x2, there won't be anything printed to the log?

RefSpecsSCMSourceTrait trait = asRefSpecsSCMSourceTrait(rawRefSpecs, remoteName);
if (trait != null) {
traits.add(trait);
}
Copy link
Member

Choose a reason for hiding this comment

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

should probably set most fields to null after the conversion to potentially be able to collect some garbage.

@@ -188,43 +344,55 @@ public String getRemote() {
return remote;
}

@Override
public String getRemoteName() {
Copy link
Member

Choose a reason for hiding this comment

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

hard to see in this diff if all old removed signatures are removed or just moved.

*/
@Override
public String getDisplayName() {
return "Use commit author in changelog";
Copy link
Member

Choose a reason for hiding this comment

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

I18n? Some display names might be reusable from the extensions.

public String getHelpFile() {
String primary = super.getHelpFile();
return primary == null ? getExtensionDescriptor().getHelpFile() : primary;
}
Copy link
Member

Choose a reason for hiding this comment

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

not the tooltip? :-p

~ THE SOFTWARE.
-->

<div>
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't this just be moved to the trait?

Copy link
Member

@rsandell rsandell left a comment

Choose a reason for hiding this comment

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

🐝

*/
@Override
public int hashCode() {
return 0;
Copy link
Member

Choose a reason for hiding this comment

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

So CheckoutOption.class.hashCode() then to be consistent with all the others.

if (refSpecs.isEmpty()) {
return "";
}
if (refSpecs.size() == 1) {
Copy link
Member

Choose a reason for hiding this comment

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

StringUtils.join(refSpecs, ' ');

*/
@Override
public String getDisplayName() {
return "Advanced checkout behaviours";
Copy link
Member

Choose a reason for hiding this comment

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

I18n

*/
@Override
public String getDisplayName() {
return "Ref Spec";
Copy link
Member

Choose a reason for hiding this comment

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

I18n?

assertThat(instance.gitTool(), is("git"));
GitSCM scm = instance.build();
assertThat(scm.getBrowser(), is(nullValue()));
assertThat(scm.getUserRemoteConfigs(), contains(allOf(
Copy link
Member

Choose a reason for hiding this comment

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

Seems very excessive to assert on these all the time, since if there is a problem with it it will get reported on "unrelated" tests.

Copy link
Contributor

@MarkEWaite MarkEWaite left a comment

Choose a reason for hiding this comment

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

Started, but not finished the review. No issues found to date

if (o == null || getClass() != o.getClass()) {
return false;
}
return o instanceof AuthorInChangelog;
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't the check:

getClass() != o.getClass()

guarantee that o is an instanceof AuthorInChangelog? If so, isn't this more readily expressed as "return true"? Or is this worrying about the risk of a class which might inherit from this class and fail to override the equals method?

I think it is correct that every instance of AuthorInChangelog is equal to every other instance of AuthorInChangelog, since the AuthorInChangelog class is being used as a boolean. If AuthorInChangelog is enabled, then the author should be used rather than the committer when displaying changelogs.

@Override
public void decorateFetchCommand(GitSCM scm, GitClient git, TaskListener listener, FetchCommand cmd) throws IOException, InterruptedException, GitException {
cmd.shallow(shallow);
if (shallow && depth > 1) {
cmd.depth(depth);
cmd.depth(depth);
Copy link
Contributor

Choose a reason for hiding this comment

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

Leading tab before a space?

*/
@Override
public int hashCode() {
return CloneOption.class.hashCode();
Copy link
Contributor

Choose a reason for hiding this comment

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

It would even be acceptable if they had the same hashCode, wouldn't it? They would collide in the hash buckets, but that would (at most) have a performance impact, not a functional impact.

@stephenc
Copy link
Member Author

stephenc commented Jul 5, 2017

Ok, merging to master in order to cut beta... any required changes will be in follow-up PRs

@stephenc stephenc merged commit dd2b842 into jenkinsci:master Jul 5, 2017
@stephenc
Copy link
Member Author

stephenc commented Jul 5, 2017

https://github.com/jenkinsci/git-plugin/tree/stable-3.3.x was cut from master pre-merge in case any changes are needed to be released on the 3.3.x line

@stephenc stephenc deleted the jenkins-43507 branch July 5, 2017 21:51
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.

3 participants