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

Add git.default_branch tag to Jenkins Build/Pipeline traces #150

Merged
merged 1 commit into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public class BuildData implements Serializable {
private String gitCommitterName;
private String gitCommitterEmail;
private String gitCommitterDate;
private String gitDefaultBranch;

// Environment variable from the promoted build plugin
// - See https://plugins.jenkins.io/promoted-builds
Expand Down Expand Up @@ -213,15 +214,20 @@ private void populateEnvVariables(EnvVars envVars){
* @param envVars
*/
private void populateGitVariables(Run<?,?> run, TaskListener listener, EnvVars envVars) {
final GitCommitAction action = GitUtils.buildGitCommitAction(run, listener, envVars, this.gitCommit, this.nodeName, this.workspace);
if(action != null) {
this.gitMessage = action.getMessage();
this.gitAuthorName = action.getAuthorName();
this.gitAuthorEmail = action.getAuthorEmail();
this.gitAuthorDate = action.getAuthorDate();
this.gitCommitterName = action.getCommitterName();
this.gitCommitterEmail = action.getCommitterEmail();
this.gitCommitterDate = action.getCommitterDate();
final GitCommitAction gitCommitAction = GitUtils.buildGitCommitAction(run, listener, envVars, this.gitCommit, this.nodeName, this.workspace);
if(gitCommitAction != null) {
this.gitMessage = gitCommitAction.getMessage();
this.gitAuthorName = gitCommitAction.getAuthorName();
this.gitAuthorEmail = gitCommitAction.getAuthorEmail();
this.gitAuthorDate = gitCommitAction.getAuthorDate();
this.gitCommitterName = gitCommitAction.getCommitterName();
this.gitCommitterEmail = gitCommitAction.getCommitterEmail();
this.gitCommitterDate = gitCommitAction.getCommitterDate();
}

final GitRepositoryAction gitRepositoryAction = GitUtils.buildGitRepositoryAction(run, listener, envVars, this.nodeName, this.workspace);
if(gitRepositoryAction != null) {
this.gitDefaultBranch = gitRepositoryAction.getDefaultBranch();
}
}

Expand Down Expand Up @@ -496,6 +502,14 @@ public void setGitCommitterDate(String gitCommitterDate) {
this.gitCommitterDate = gitCommitterDate;
}

public String getGitDefaultBranch(String value) {
return defaultIfNull(gitDefaultBranch, value);
}

public void setGitDefaultBranch(String gitDefaultBranch) {
this.gitDefaultBranch = gitDefaultBranch;
}

public String getPromotedUrl(String value) {
return defaultIfNull(promotedUrl, value);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.datadog.jenkins.plugins.datadog.model;

import hudson.model.InvisibleAction;

import java.io.Serializable;

/**
* Keeps the Git repository related information.
*/
public class GitRepositoryAction extends InvisibleAction implements Serializable {

private static final long serialVersionUID = 1L;

private final String defaultBranch;

private GitRepositoryAction(final Builder builder) {
this.defaultBranch = builder.defaultBranch;
}

public String getDefaultBranch() {
return defaultBranch;
}

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {
private String defaultBranch;

private Builder(){}

public Builder withDefaultBranch(final String defaultBranch) {
this.defaultBranch = defaultBranch;
return this;
}

public GitRepositoryAction build(){
return new GitRepositoryAction(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class CITags {
public static final String GIT_COMMIT_COMMITTER_NAME = "git.commit.committer.name";
public static final String GIT_COMMIT_COMMITTER_EMAIL = "git.commit.committer.email";
public static final String GIT_COMMIT_COMMITTER_DATE = "git.commit.committer.date";
public static final String GIT_DEFAULT_BRANCH = "git.default_branch";
public static final String GIT_BRANCH = "git.branch";
public static final String GIT_TAG = "git.tag";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ public void finishBuildTrace(final BuildData buildData, final Run<?,?> run) {
final String gitCommitterDate = buildData.getGitCommitterDate("").isEmpty() ? pipelineData.getGitCommitterDate("") : buildData.getGitCommitterDate("");
buildSpan.setTag(CITags.GIT_COMMIT_COMMITTER_DATE, gitCommitterDate);

final String gitDefaultBranch = buildData.getGitDefaultBranch("").isEmpty() ? pipelineData.getGitDefaultBranch("") : buildData.getGitDefaultBranch("");
buildSpan.setTag(CITags.GIT_DEFAULT_BRANCH, gitDefaultBranch);

final String rawGitBranch = buildData.getBranch("").isEmpty() ? pipelineData.getBranch("") : buildData.getBranch("");
final String gitBranch = normalizeBranch(rawGitBranch);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.datadog.jenkins.plugins.datadog.model.BuildPipeline;
import org.datadog.jenkins.plugins.datadog.model.BuildPipelineNode;
import org.datadog.jenkins.plugins.datadog.model.GitCommitAction;
import org.datadog.jenkins.plugins.datadog.model.GitRepositoryAction;
import org.datadog.jenkins.plugins.datadog.util.git.GitUtils;
import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode;
import org.jenkinsci.plugins.workflow.graph.BlockEndNode;
Expand Down Expand Up @@ -181,6 +182,13 @@ private void updateBuildData(BuildData buildData, Run<?, ?> run, FlowNode node)
}
}

final GitRepositoryAction repositoryAction = buildGitRepositoryAction(run, pipelineNode, node);
if(repositoryAction != null) {
if(buildData.getGitDefaultBranch("").isEmpty()) {
buildData.setGitDefaultBranch(repositoryAction.getDefaultBranch());
}
}

final String workspace = pipelineNode.getWorkspace();
if(workspace != null && buildData.getWorkspace("").isEmpty()){
buildData.setWorkspace(workspace);
Expand All @@ -197,6 +205,7 @@ private void updateBuildData(BuildData buildData, Run<?, ?> run, FlowNode node)
}
}


private void sendTrace(final Tracer tracer, final BuildData buildData, final BuildPipelineNode current, final SpanContext parentSpanContext) {
if(!isTraceable(current)){
logger.severe("Node " + current.getName() + " is not traceable.");
Expand Down Expand Up @@ -431,4 +440,18 @@ private GitCommitAction buildGitCommitAction(Run<?, ?> run, BuildPipelineNode pi
return null;
}
}


private GitRepositoryAction buildGitRepositoryAction(Run<?, ?> run, BuildPipelineNode pipelineNode, FlowNode node) {
try {
final TaskListener listener = node.getExecution().getOwner().getListener();
final EnvVars envVars = new EnvVars(pipelineNode.getEnvVars());
final String nodeName = pipelineNode.getNodeName();
final String workspace = pipelineNode.getWorkspace();
return GitUtils.buildGitRepositoryAction(run, listener, envVars, nodeName, workspace);
} catch (Exception e) {
logger.fine("Unable to build GitRepositoryAction. Error: " + e);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import org.apache.commons.lang.StringUtils;
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;
import org.datadog.jenkins.plugins.datadog.model.GitCommitAction;
import org.datadog.jenkins.plugins.datadog.model.GitRepositoryAction;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import org.jenkinsci.plugins.gitclient.Git;
import org.jenkinsci.plugins.gitclient.GitClient;
import org.jenkinsci.plugins.workflow.FilePathUtils;

import java.util.logging.Logger;
Expand Down Expand Up @@ -69,33 +71,41 @@ public static FilePath buildFilePath(final Run<?, ?> run){
/**
* Return the RevCommit for a certain commit based on the information
* stored in a certain workspace of a certain node.
* @param run
* @param listener
* @param envVars
* @param gitCommit
* @param nodeName
* @param workspace
* @return revCommit
*/
public static RevCommit searchRevCommit(final Run<?,?> run, final TaskListener listener, final EnvVars envVars, final String gitCommit, final String nodeName, final String workspace) {
public static RevCommit searchRevCommit(final GitClient gitClient, final String gitCommit) {
try {
FilePath ws = GitUtils.buildFilePath(run);
if(ws == null){
ws = GitUtils.buildFilePath(nodeName, workspace);
if(gitClient == null) {
return null;
}

if(ws == null) {
return gitClient.withRepository(new RevCommitRepositoryCallback(gitCommit));
} catch (Exception e) {
LOGGER.fine("Unable to search RevCommit. Error: " + e);
return null;
}
}

/**
* Return the {@code RepositoryInfo} for a certain Git repository.
* @param gitClient
* @return repositoryInfo
*/
public static RepositoryInfo searchRepositoryInfo(final GitClient gitClient) {
try {
if(gitClient == null){
return null;
}

final Git git = Git.with(listener, envVars).in(ws);
return git.getClient().withRepository(new RevCommitRepositoryCallback(gitCommit));
return gitClient.withRepository(new RepositoryInfoCallback());
} catch (Exception e) {
LOGGER.fine("Unable to search RevCommit. Error: " + e);
LOGGER.fine("Unable to search Repository Info. Error: " + e);
return null;
}
}


/**
* Returns the GitCommitAction of the Run instance.
* If the Run instance does not have GitCommitAction or
Expand All @@ -118,7 +128,12 @@ public static GitCommitAction buildGitCommitAction(Run<?, ?> run, TaskListener l
GitCommitAction commitAction = run.getAction(GitCommitAction.class);
if(commitAction == null || !gitCommit.equals(commitAction.getCommit())) {
try {
final RevCommit revCommit = GitUtils.searchRevCommit(run, listener, envVars, gitCommit, nodeName, workspace);
final GitClient gitClient = GitUtils.newGitClient(run, listener, envVars, nodeName, workspace);
if(gitClient == null){
return null;
}

final RevCommit revCommit = GitUtils.searchRevCommit(gitClient, gitCommit);
if(revCommit == null) {
return null;
}
Expand Down Expand Up @@ -157,4 +172,73 @@ public static GitCommitAction buildGitCommitAction(Run<?, ?> run, TaskListener l
return commitAction;
}

/**
* Returns the GitRepositoryAction of the Run instance.
* If the Run instance does not have GitRepositoryAction or
* some infor is not populated in the GitRepositoryAction,
* then a new GitCommitAction is built and stored in the Run instance.
*
* The GitRepository information is stored in an action because
* it's fairly expensive to calculate. To avoid calculating
* every time, it's store in the Run instance as an action.
* @param run
* @param listener
* @param envVars
* @param nodeName
* @param workspace
* @return
*/
public static GitRepositoryAction buildGitRepositoryAction(Run<?, ?> run, TaskListener listener, EnvVars envVars, final String nodeName, final String workspace) {
GitRepositoryAction repoAction = run.getAction(GitRepositoryAction.class);
if(repoAction == null || repoAction.getDefaultBranch() == null) {
try {
final GitClient gitClient = GitUtils.newGitClient(run, listener, envVars, nodeName, workspace);
if(gitClient == null){
return null;
}

final RepositoryInfo repositoryInfo = GitUtils.searchRepositoryInfo(gitClient);
if(repositoryInfo == null) {
return null;
}

final GitRepositoryAction.Builder builder = GitRepositoryAction.newBuilder();
builder.withDefaultBranch(repositoryInfo.getDefaultBranch());

repoAction = builder.build();
run.addOrReplaceAction(repoAction);
} catch (Exception e) {
LOGGER.fine("Unable to build GitRepositoryAction. Error: " + e);
}
}
return repoAction;
}

/**
* Creates a new instance of a {@code GitClient}.
* @param run
* @param listener
* @param envVars
* @param nodeName
* @param workspace
* @return gitClient
*/
public static GitClient newGitClient(final Run<?,?> run, final TaskListener listener, final EnvVars envVars, final String nodeName, final String workspace) {
try {
FilePath ws = GitUtils.buildFilePath(run);
if(ws == null){
ws = GitUtils.buildFilePath(nodeName, workspace);
}

if(ws == null) {
return null;
}

final Git git = Git.with(listener, envVars).in(ws);
return git.getClient();
} catch (Exception e) {
LOGGER.fine("Unable to search RevCommit. Error: " + e);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.datadog.jenkins.plugins.datadog.util.git;

import java.io.Serializable;

public class RepositoryInfo implements Serializable {

private static final long serialVersionUID = 1L;

private final String defaultBranch;

public RepositoryInfo(String defaultBranch) {
this.defaultBranch = defaultBranch;
}

public String getDefaultBranch() {
return defaultBranch;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.datadog.jenkins.plugins.datadog.util.git;

import hudson.remoting.VirtualChannel;
import org.datadog.jenkins.plugins.datadog.traces.GitInfoUtils;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.jenkinsci.plugins.gitclient.RepositoryCallback;

import java.io.IOException;
import java.util.logging.Logger;

/**
* Returns the RepositoryInfo instance for a certain repository
* using the JGit.
*
* This must be called using gitClient.withRepository(...) method.
* See GitUtils.
*/
public final class RepositoryInfoCallback implements RepositoryCallback<RepositoryInfo> {

private static transient final Logger LOGGER = Logger.getLogger(RepositoryInfoCallback.class.getName());
private static final long serialVersionUID = 1L;

@Override
public RepositoryInfo invoke(Repository repository, VirtualChannel channel) throws IOException, InterruptedException {
try {
Ref head = repository.getRefDatabase().findRef("HEAD");
if(head == null) {
LOGGER.fine("Unable to build RepositoryInfo. HEAD is null.");
return null;
}

// Discarded if it's not a symbolic to refs.
if(!head.isSymbolic()) {
LOGGER.fine("Unable to build RepositoryInfo. HEAD is not symbolic.");
return null;
}

final String defaultBranch = GitInfoUtils.normalizeBranch(head.getTarget().getName());
return new RepositoryInfo(defaultBranch);

} catch (Exception e) {
LOGGER.fine("Unable to build RepositoryInfo. Error: " + e);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,6 @@ private void assertGitVariables(DDSpan span) {
assertEquals("401d997a6eede777602669ccaec059755c98161f", span.getTag(CITags.GIT_COMMIT_SHA));
assertEquals("master", span.getTag(CITags.GIT_BRANCH));
assertEquals("https://github.com/johndoe/foobar.git", span.getTag(CITags.GIT_REPOSITORY_URL));
assertEquals("master", span.getTag(CITags.GIT_DEFAULT_BRANCH));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ private void assertGitVariables(DDSpan span) {
assertEquals("401d997a6eede777602669ccaec059755c98161f", span.getTag(CITags.GIT_COMMIT_SHA));
assertEquals("master", span.getTag(CITags.GIT_BRANCH));
assertEquals("https://github.com/johndoe/foobar.git", span.getTag(CITags.GIT_REPOSITORY_URL));
assertEquals("master", span.getTag(CITags.GIT_DEFAULT_BRANCH));
}

}