Skip to content

[JENKINS-28335] Provide a gitPublisher step.#452

Closed
iwarapter wants to merge 6 commits into
jenkinsci:masterfrom
iwarapter:master
Closed

[JENKINS-28335] Provide a gitPublisher step.#452
iwarapter wants to merge 6 commits into
jenkinsci:masterfrom
iwarapter:master

Conversation

@iwarapter

Copy link
Copy Markdown

I'm after some feedback with this as i'm aware there is lots of duplication but i wasn't sure of the best approach so figured i'd share the code and see what the maintainers think :)

@daniel-beck

Copy link
Copy Markdown
Member

@jenkinsci/code-reviewers PTAL

@daniel-beck daniel-beck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One compatibility breaking change.

private boolean noteReplace;

public String getnoteMsg() {
public String getNoteMsg() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Breaks backward compatibility for a class that is public API. Did you confirm none of the ~60 plugins with dependency on the Git Plugin use these methods?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I originally changed this as i was getting:

WARNING: failed to uncoerce hudson.plugins.git.GitPublisher$NoteToPush@12647296
java.lang.UnsupportedOperationException: no public field ‘noteMsg’ (or getter method) found in class hudson.plugins.git.GitPublisher$NoteToPush

When using the snippet generator, which resulted in this snippet being generated.

gitPublisher notesToPush: [<object of type hudson.plugins.git.GitPublisher.NoteToPush>], url: 'git@github.com:iwarapter/git-plugin.git'

Interestingly the a normal freestyle job doesn't suffer from this and the jelly config is pretty much the same. Any thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Right, I understood the motivation, but it still may have broken plugins depending on the old name. Adding fixed getters makes sense in addition to keeping the old ones. They should probably be marked @deprecated as their names don't follow convention, and their Javadoc should reference the new alternatives.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Javadocs updated, non-conforming methods marked as deprecated.

/*
* The MIT License
*
* Copyright 2014 Jesse Glick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just… no.

<!--
The MIT License

Copyright 2014 Jesse Glick.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@@ -0,0 +1,5 @@
<div>
<p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unusual to have a paragraph here I think.

#
GitSCMSource.DisplayName=Git
GitStep.git=Git
GitPublisherStep=Git Publisher

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Key seems inconsistent with the others.

@iwarapter

Copy link
Copy Markdown
Author

@daniel-beck I have fixed the requested changes, the solution i have for the api change is a dirty hack, am i missing something with the Jelly config?

@iwarapter

Copy link
Copy Markdown
Author

@daniel-beck do you require any further changes?

*/
@Deprecated
public String getnoteMsg() {
return noteMsg;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The old method should ideally invoke the new method

package jenkins.plugins.git;

import com.google.inject.Inject;
import hudson.*;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would rather recommend to expand these imports at least for the production code


@DataBoundConstructor
public GitPublisherStep(String url) {
this.url = url;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not setter as well?

}

@DataBoundSetter
public void setBranch(String branch) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would recommend to make these setters @Restricted(NoExternalUse.class). Otherwise it worth to mention in Javadoc that invocation of these setters does not persist data to the disk.

tagsToPush = new ArrayList<GitPublisher.TagToPush>();
}

return tagsToPush;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Almost 🐛 . IMHO all the lists should be returned as unmodifyable lists to prevent the exposure of the internal implementation

if (isPushTags()) {
for (final GitPublisher.TagToPush t : tagsToPush) {
if (t.getTagName() == null)
throw new AbortException("No tag to push defined");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

NIT: Missing brackets in single-line ifs

if (t.getTargetRepoName() == null)
throw new AbortException("No target repo to push to defined");

final String tagName = environment.expand(t.getTagName());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Formally the checks above do not prevent the return value from being null here. E.g. in the case of the parallel config change. I would recommend assigning the method's return value to a local variable before the check and tthen using this variable in the code

throw new AbortException("Tag " + tagName + " already exists and Create Tag is specified, so failing.");
}

if (tagMessage.length() == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

StringUtils.isBlank() to cover more cases like empty strings


@DataBoundSetter
public void setCredentialsId(String credentialsId) {
this.credentialsId = Util.fixEmpty(credentialsId);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

fixEmptyAndTrim to prevent whitespace-only strings?

listener.getLogger().println("Pushing tag " + tagName + " to repo "
+ targetRepo);

remoteURI = remote.getURIs().get(0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🐛 Missing check of the array size

if (b.getTargetRepoName() == null)
throw new AbortException("No branch repo to push to defined");

final String branchName = environment.expand(b.getBranchName());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same as above


</table>
<div align="right">
<input type="button" value="Delete Note" class="repeatable-delete" style="margin-left: 1em;" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No localization in value

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hi @oleg-nenashev i'm not very familiar with the jelly config stuff, whats the best way to achieve this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@oleg-nenashev oleg-nenashev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry for not using the review mode :( . I think some logic processing needs to be fixed in order to make the implementation more robust against non-success paths

@iwarapter

Copy link
Copy Markdown
Author

Hi @daniel-beck @oleg-nenashev i have just come back from holiday, what are the remaining blockers for this PR?

@MarkEWaite

MarkEWaite commented Jan 26, 2017

Copy link
Copy Markdown
Contributor

They need to review your changes and mark them as "accepted", then the plugin maintainer (me) needs to review the request, create integration tests to confirm it is working as expected, then merge it to the master branch and release it.

I'm currently evaluating a proposal to add large file support to the plugin. That will need at least 1-2 more weeks before I'll evaluate what's next on my review list.

You could speed the review process by creating the integration tests as well, you can model them after the tests in my lts-with-plugins docker instance, or you can submit a pull request as a new branch to my jenkins-bugs git repository.

You could also speed the review process by encouraging others to use a pre-release version of the plugin, and have them post their experiences in this pull request.

@iwarapter

Copy link
Copy Markdown
Author

Hi @MarkEWaite thanks for your feedback, with regards to the integration tests, do you want a PR on the its-with-plugins or add to this PR?

@iwarapter

Copy link
Copy Markdown
Author

Hi guys, any update on this?

@daniel-beck daniel-beck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Haven't really been able to look at this in detail as I'm not very familiar with this plugin, so my comments may be irrelevant.

}
String buildDuration = run.getDurationString().replaceAll("and counting", "");

input = input.replaceAll("\\$BUILDRESULT", buildResult);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should use the utility methods in core to do variable replacement (unless I'm missing something).

Also seems like a limited use case, what is this for exactly? This is a Pipeline step, why need environment variables at all?


<f:entry field="notesToPush" title="${%Notes}" description="${%Notes to push to remote repositories}">

<f:repeatable field="notesToPush" add="${%Add Note}">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a reason this isn't covered by tests?

iwarapter added 2 commits May 31, 2017 00:44
…p push notes functionality (i don't use or know how to properly test this)
# Conflicts:
#	src/main/resources/hudson/plugins/git/Messages.properties
@jglick

jglick commented May 31, 2017

Copy link
Copy Markdown
Member

As I noted in JIRA, I think this is the wrong approach. You can already use withCredentials etc. to run git commands of your choice; if anything is needed, it is just a more convenient wrapper. Similar to the concept of the pipeline-maven plugin, which sets some useful environment variables and then steps out of your way.

@iwarapter

Copy link
Copy Markdown
Author

Hi @jglick thanks for your feedback, i have been working with a some of the workarounds on the JIRA ticket, mainly the sshagent approach for Linux (bug on windows prevents this). However i find myself constantly always wrapping the same commands in isUnix blocks then sh/bat accordingly, which is really bloating my global libraries and i was after a more cleaner solution.

gitPublisher( url: 'ssh:etc', tagsToPush: [tagName: '1.0-FINAL'])

if(isUnix()){
  sshagent([credentialsId]) {
        sh("git tag -a -f -m 'msg' tag")
        sh("git -c core.askpass=true push origin tag")
    }
}
else {
  //this doesnt work https://issues.jenkins-ci.org/browse/JENKINS-28279
  sshagent([credentialsId]) {
        bat("git tag -a -f -m 'msg' tag")
        bat("git -c core.askpass=true push origin tag")
    }
}

I work with many different teams utilizing a large mix of agents so try to keep my scripts as node agnostic as possible to avoid bottlenecks.

A pipeline-maven style solution for git would equally fall into the trap of isUnix if else etc.

Appreciate any feedback/suggestions!

@jglick

jglick commented Jun 1, 2017

Copy link
Copy Markdown
Member

i find myself constantly always wrapping the same commands in isUnix blocks then sh/bat accordingly

Well, this is solvable with a simple helper function, or an integration with the xshell plugin, or some other generic solution that would apply to any more or less cross-platform command, not just git.

@TheDukeDK

Copy link
Copy Markdown

What is the status of this? Will there be a git publisher step for pipeline or has this been dropped?

@MarkEWaite

Copy link
Copy Markdown
Contributor

I don't plan to merge this proposed change. I agree with @jglick that this is better done from a shell wrapper in Pipeline, rather than adding more complexity to the git plugin.

@MarkEWaite MarkEWaite closed this Apr 18, 2018
@iwarapter

Copy link
Copy Markdown
Author

do you know if any such plugin exists? i assume it would be something like this (but for git ofc) https://github.com/openshift/jenkins-client-plugin

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.

6 participants