Skip to content

Commit

Permalink
Add pipeline step
Browse files Browse the repository at this point in the history
  • Loading branch information
reda-alaoui committed Feb 10, 2022
1 parent e63eec8 commit 0130343
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 49 deletions.
64 changes: 18 additions & 46 deletions src/main/java/io/jenkins/plugins/git_push/GitPush.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package io.jenkins.plugins.git_push;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.plugins.git.GitException;
import hudson.plugins.git.GitSCM;
import hudson.scm.SCM;
import hudson.tasks.BuildStepDescriptor;
Expand All @@ -18,31 +16,35 @@
import java.io.IOException;
import java.io.Serializable;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.gitclient.GitClient;
import org.jenkinsci.plugins.gitclient.UnsupportedCommand;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;

/** @author Réda Housni Alaoui */
public class GitPush extends Recorder implements Serializable {

private final String targetBranch;
private final String targetRepo;
private String targetBranch;
private String targetRepo;

@DataBoundConstructor
public GitPush(String targetBranch, String targetRepo) {
public GitPush() {
// Only needed to mark the constructor with @DataBoundConstructor
}

@DataBoundSetter
public void setTargetBranch(String targetBranch) {
this.targetBranch = targetBranch;
this.targetRepo = targetRepo;
}

public String getTargetBranch() {
return targetBranch;
}

@DataBoundSetter
public void setTargetRepo(String targetRepo) {
this.targetRepo = targetRepo;
}

public String getTargetRepo() {
return targetRepo;
}
Expand Down Expand Up @@ -72,38 +74,17 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen

GitSCM gitSCM = (GitSCM) scm;
EnvVars environment = build.getEnvironment(listener);

GitClient git =
gitSCM.createClient(
listener, environment, build, build.getWorkspace(), new GitPushUnsupportedCommand());

String remoteRepo = environment.expand(targetRepo);
String remoteBranch = environment.expand(targetBranch);

RemoteConfig remote = gitSCM.getRepositoryByName(remoteRepo);
if (remote == null) {
throw new AbortException("No repository found for target repo name '" + remoteRepo + "'");
}

remote = gitSCM.getParamExpandedRepo(environment, remote);
URIish remoteURI = remote.getURIs().get(0);

try {
git.fetch_().from(remoteURI, remote.getFetchRefSpecs()).execute();
ObjectId remoteRev = git.revParse(remoteRepo + "/" + remoteBranch);
git.merge().setRevisionToMerge(remoteRev).execute();
git.push().to(remoteURI).ref("HEAD:" + remoteBranch).tags(true).execute();
git.fetch_().from(remoteURI, remote.getFetchRefSpecs()).execute();
} catch (GitException e) {
e.printStackTrace(listener.error("Failed to push to " + remoteRepo));
new GitPushCommand(gitSCM, build, listener, build.getWorkspace())
.call(environment.expand(targetBranch), environment.expand(targetRepo));
} catch (GitPushCommand.Failure e) {
e.printStackTrace(listener.error(e.getMessage()));
return false;
}

return true;
}

@Extension
@Symbol("gitPush")
public static class Descriptor extends BuildStepDescriptor<Publisher> {

@Override
Expand Down Expand Up @@ -133,13 +114,4 @@ private FormValidation checkFieldNotEmpty(String value) {
return FormValidation.ok();
}
}

private static class GitPushUnsupportedCommand extends UnsupportedCommand {
@Override
public boolean determineSupportForJGit() {
// Do not know why we exactly need that. Inspired by
// https://github.com/jenkinsci/git-plugin/blob/b95bffa7579c91cb79616b5a1e45feea52e4f70b/src/main/java/hudson/plugins/git/GitPublisher.java#L189
return false;
}
}
}
62 changes: 62 additions & 0 deletions src/main/java/io/jenkins/plugins/git_push/GitPushCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.jenkins.plugins.git_push;

import hudson.AbortException;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.git.GitException;
import hudson.plugins.git.GitSCM;
import java.io.IOException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.jenkinsci.plugins.gitclient.GitClient;

/** @author Réda Housni Alaoui */
public class GitPushCommand {

private final GitSCM scm;
private final Run<?, ?> run;
private final TaskListener listener;
private final FilePath workspace;

public GitPushCommand(GitSCM scm, Run<?, ?> run, TaskListener listener, FilePath workspace) {
this.scm = scm;
this.run = run;
this.listener = listener;
this.workspace = workspace;
}

public void call(String targetBranch, String targetRepo)
throws IOException, InterruptedException, Failure {
EnvVars environment = run.getEnvironment(listener);

GitClient git =
scm.createClient(listener, environment, run, workspace, new GitPushUnsupportedCommand());

RemoteConfig remote = scm.getRepositoryByName(targetRepo);
if (remote == null) {
throw new AbortException("No repository found for target repo name '" + targetRepo + "'");
}

remote = scm.getParamExpandedRepo(environment, remote);
URIish remoteURI = remote.getURIs().get(0);

try {
git.fetch_().from(remoteURI, remote.getFetchRefSpecs()).execute();
ObjectId remoteRev = git.revParse(targetRepo + "/" + targetBranch);
git.merge().setRevisionToMerge(remoteRev).execute();
git.push().to(remoteURI).ref("HEAD:" + targetBranch).tags(true).execute();
git.fetch_().from(remoteURI, remote.getFetchRefSpecs()).execute();
} catch (GitException e) {
throw new Failure("Failed to push to " + targetRepo, e);
}
}

public static class Failure extends Exception {
public Failure(String message, Throwable cause) {
super(message, cause);
}
}
}
133 changes: 133 additions & 0 deletions src/main/java/io/jenkins/plugins/git_push/GitPushStep.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package io.jenkins.plugins.git_push;

import com.google.common.collect.ImmutableSet;
import hudson.AbortException;
import hudson.Extension;
import hudson.FilePath;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.git.GitSCM;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Set;
import javax.annotation.Nonnull;
import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import org.jenkinsci.plugins.workflow.steps.StepExecution;
import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

/** @author Réda Housni Alaoui */
public class GitPushStep extends Step {

private GitSCM gitScm;
private String targetBranch;
private String targetRepo;

@DataBoundConstructor
public GitPushStep() {
// Only needed to mark the constructor with @DataBoundConstructor
}

@DataBoundSetter
public void setGitScm(GitSCM gitScm) {
this.gitScm = gitScm;
}

public GitSCM getGitScm() {
return gitScm;
}

@DataBoundSetter
public void setTargetBranch(String targetBranch) {
this.targetBranch = targetBranch;
}

public String getTargetBranch() {
return targetBranch;
}

@DataBoundSetter
public void setTargetRepo(String targetRepo) {
this.targetRepo = targetRepo;
}

public String getTargetRepo() {
return targetRepo;
}

@Override
public StepExecution start(StepContext context) {
return new Execution(context, gitScm, targetBranch, targetRepo);
}

private static class Execution extends SynchronousNonBlockingStepExecution<Void> {

private static final long serialVersionUID = 1L;

private transient GitSCM gitScm;
private String targetBranch;
private String targetRepo;

protected Execution(
@Nonnull StepContext context,
@Nonnull GitSCM gitScm,
@Nonnull String targetBranch,
@Nonnull String targetRepo) {
super(context);
this.gitScm = gitScm;
this.targetBranch = targetBranch;
this.targetRepo = targetRepo;
}

@Override
protected Void run() throws Exception {
if (gitScm == null) {
throw new AbortException("gitScm is missing");
}

new GitPushCommand(
gitScm,
getContext().get(Run.class),
getContext().get(TaskListener.class),
getContext().get(FilePath.class))
.call(targetBranch, targetRepo);

return null;
}

private void writeObject(ObjectOutputStream outputStream) throws IOException {
outputStream.writeObject(targetBranch);
outputStream.writeObject(targetRepo);
}

private void readObject(ObjectInputStream inputStream)
throws IOException, ClassNotFoundException {
gitScm = null;
targetBranch = (String) inputStream.readObject();
targetRepo = (String) inputStream.readObject();
}
}

@Extension
public static final class DescriptorImpl extends StepDescriptor {

@Override
public String getDisplayName() {
return "Git Push";
}

@Override
public Set<? extends Class<?>> getRequiredContext() {
return ImmutableSet.of(Run.class, TaskListener.class, FilePath.class);
}

@Override
public String getFunctionName() {
return "gitPush";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.jenkins.plugins.git_push;

import org.jenkinsci.plugins.gitclient.UnsupportedCommand;

/** @author Réda Housni Alaoui */
class GitPushUnsupportedCommand extends UnsupportedCommand {
@Override
public boolean determineSupportForJGit() {
// Do not know why we exactly need that. Inspired by
// https://github.com/jenkinsci/git-plugin/blob/b95bffa7579c91cb79616b5a1e45feea52e4f70b/src/main/java/hudson/plugins/git/GitPublisher.java#L189
return false;
}
}
13 changes: 10 additions & 3 deletions src/test/java/io/jenkins/plugins/git_push/GitPushTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void without_it_no_commit_is_pushed() throws Exception {
@Test
public void it_pushes_commits() throws Exception {
project.getBuildersList().add(new CommitBuilder());
project.getPublishersList().add(new GitPush("master", "origin"));
project.getPublishersList().add(createGitPush("master", "origin"));
project.save();

FreeStyleBuild build = project.scheduleBuild2(0).get();
Expand All @@ -136,7 +136,7 @@ public void it_pushes_commits() throws Exception {
public void it_pushes_tags() throws Exception {
project.getBuildersList().add(new CommitBuilder());
project.getBuildersList().add(new TagBuilder());
project.getPublishersList().add(new GitPush("master", "origin"));
project.getPublishersList().add(createGitPush("master", "origin"));
project.save();

FreeStyleBuild build = project.scheduleBuild2(0).get();
Expand Down Expand Up @@ -174,7 +174,7 @@ public void it_create_merge_commit_if_needed() throws Exception {
.push(true)
.publishCommitAction(false));
project.getBuildersList().add(new CommitBuilder());
project.getPublishersList().add(new GitPush("master", "origin"));
project.getPublishersList().add(createGitPush("master", "origin"));
project.save();

FreeStyleBuild build = project.scheduleBuild2(0).get();
Expand All @@ -196,6 +196,13 @@ public void it_create_merge_commit_if_needed() throws Exception {
}
}

private GitPush createGitPush(String targetBranch, String targetRepo) {
GitPush gitPush = new GitPush();
gitPush.setTargetBranch(targetBranch);
gitPush.setTargetRepo(targetRepo);
return gitPush;
}

private static class CommitBuilder extends Builder {

private String gitDir;
Expand Down

0 comments on commit 0130343

Please sign in to comment.