Microsoft.TeamFoundation.Build.WebApi Get Build Status Launched by PR policy - azure

In our pipeline we programmatically create a pull request (PR). The branch being merged into has a policy on it that launches a build. This build takes a variable amount of time. I need to query the build status until it is complete (or long timeout) so that I can complete the PR, and clean up the temp branch.
I am trying to figure out how to get the build that was kicked off by the PR so that I can inspect the status by using Microsoft.TeamFoundation.Build.WebApi, but all overloads of BuildHttpClientBase.GetBuildAsync require a build Id which I don't have. I would like to avoid using the Azure Build REST API. Does anyone know how I might get the Build kicked off by the PR without the build ID using BuildHttpClientBase?
Unfortunately the documentation doesn't offer a lot of detail about functionality.

Answering the question you asked:
Finding a call that provides the single deterministic build id for a pull request doesn't seem to be very readily available.
As mentioned, you can use BuldHttpClient.GetBuildsAsync() to filter builds based on branch, repository, requesting user and reason.
Adding the BuildReason.PullRequest value in the request is probably redundant according to the branch you will need to pass.
var pr = new GitPullRequest(); // the PR you've received after creation
var requestedFor = pr.CreatedBy.DisplayName;
var repo = pr.Repository.Id.ToString();
var branch = $"refs/pull/{pr.PullRequestId}/merge";
var reason = BuildReason.PullRequest;
var buildClient = c.GetClient<BuildHttpClient>();
var blds = await buildClient.GetBuildsAsync("myProject",
branchName: branch,
repositoryId: repo,
requestedFor: requestedFor,
reasonFilter: reason,
repositoryType: "TfsGit");
In your question you mentioned wanting the build (singular) for the pull request, which implies that you only have one build definition acting as the policy gate. This method can return multiple Builds based on the policy configurations on your target branch. However, if that were your setup, it would seem logical that your question would then be asking for all those related builds for which you would wait to complete the PR.
I was looking into Policy Evaluations to see if there was a more straight forward way to get the id of the build being run via policy, but I haven't been able to format the request properly as per:
Evaluations are retrieved using an artifact ID which uniquely identifies the pull request. To generate an artifact ID for a pull request, use this template:
vstfs:///CodeReview/CodeReviewId/{projectId}/{pullRequestId}
Even using the value that is returned in the artifactId field on the PR using the GetById method results in a Doesn't exist or Don't have access response, so if someone else knows how to use this method and if it gives exact build ids being evaluated for the policy configurations, I'd be glad to hear it.
An alternative to get what you actually desire
It sounds like the only use you have for the branch policy is to run a "gate build" before completing the merge.
Why not create the PR with autocomplete.
Name - autoCompleteSetBy
Type - IdentityRef
Description - If set, auto-complete is enabled for this pull request and this is the identity that enabled it.
var me = new IdentityRef(); // you obviously need to populate this with real values
var prClient = connection.GetClient<GitHttpClient>();
await prClient.CreatePullRequestAsync(new GitPullRequest()
{
CreatedBy = me,
AutoCompleteSetBy = me,
Commits = new GitCommitRef[0],
SourceRefName = "feature/myFeature",
TargetRefName = "master",
Title = "Some good title for my PR"
},
"myBestRepository",
true);

Related

Retrieving project coverage with python-gitlab

I use the python-gitlab module to retrieve the project statistics for a number of projects in Gitlab via its API. One of the values I want to get is the CI status and the code coverage. While the status is easy:
from gitlab import Gitlab
gl = Gitlab('http://gitlab.example.com')
project = gl.projects.get('olebole/myproject')
branch = project.branches.get(project.default_branch)
commit = project.commits.get((branch.commit['id'])
print(commit.last_pipeline['status'])
I didn't find a way to retrieve the coverage; also adding with_stats=True to the commit retrieval didn't make it.
How can one get this value?
This is in the pipeline object:
pipeline = project.pipelines.get(commit.last_pipeline['id'])
print(pipeline.status, pipeline.coverage)

VdmComplex Changes Not Working with PATCH

Using the SAP B1 .edmx with 3.39.0 and trying to update DeliveryNotes with new DocumentPackages. However, the list of DocumentPackage that eventually gets passed by the execution of the update operation is empty.
Code:
var packagesUpdateDocument = new Document();
packagesUpdateDocument.setDocEntry(1);
var documentPackages = new ArrayList<DocumentPackage>();
var documentPackage = new DocumentPackage();
documentPackage.setNumber(10);
documentPackages.add(documentPackage);
packagesUpdateDocument.setDocumentPackages(documentPackages);
var updateDeliveryPackagesRequest = service.withServicePath("etc")
.updateDeliveryNotes(packagesUpdateDocument);
var updateDeliveryPackagesResponse = updateDeliveryPackagesRequest.tryExecute(serviceLayerDestination);
Looking at the logs of the service layer I can see this is the request which was eventually sent by the client:
PATCH /b1s/v2/DeliveryNotes(1)
{"DocEntry":1,"DocumentPackages":[{}],"#odata.type":"SAPB1.Document"}
From my understanding, PATCH requests will automatically disregard anything the generated client deems as 'unchanged.'
Printing the changed fields:
System.out.println(packagesUpdateDocument.getChangedFields());
Yields:
{
DocEntry=175017,
DocumentPackages=
[DocumentPackage
(
super=VdmObject(customFields={},
changedOriginalFields={}),
odataType=SAPB1.DocumentPackage,
number=10,
)
]
.....
}
I believe the Package is not recording the fields which have changed. Although I am not certain.
Is there a step I am missing or is this a feature gap?
As of SAP Cloud SDK 3.42.0 we support updating complex properties with PATCH out-of-the-box. See the release notes for more details.
Yes this is a feature gap currently. PATCH will only consider properties of the root entity and navigation properties while disregarding changes in complex properties.
Until that is supported updating with PUT instead via the .replacingEntity() option should work.

Cannot change branch through code

I have a process whereby I want to change company AND branch when creating a new Journal Entry record. I have the following code to change branch, which I've obtained from Ruslan:
jegraph.FieldDefaulting.AddHandler<Batch.branchID>((s, e) =>
{
.NewValue = tgtbranch.BranchID; //Set to ID = 6...
.Cancel = true;
});
However, when checking the value of the branch (for troubleshooting purposes), the branch I come up with is incorrect. In order to check the branch I'm currently in, I'm using:
jegraph.Accessinfo.BranchID;
So, either my branch change code is not working, or the AccessInfo method is giving me the wrong information.
Is this the best way to change the branch for a new batch record, or am I not getting the correct info from AccessInfo?
The branch info from AccessInfo was incorrect. The original AddHandler event handler code is working as expected.

Job based security per branch - Jenkins Multibranch pipeline

I have a Jenkins multi-branch pipeline for building artifacts and there are branches for master, *-dev etc.
I want to enable project based security on a per branch basis, ie only allow devs to run the *-dev branch jobs of the build not any other ones because doing so would have undesirable effects.
I know there is project based security, but I didn't see any per branch. Does this exist? We are behind in updating Jenkins and are currently running Jenkins 2.46.1.
Otherwise I am thinking I might have to have a separate upstream job to call the correct branch of the downstream one and make the downstream artifact job unable to be run by devs with the privilege to do so. (This sounds like overkill).
Or is there any way to accomplish this in the branch's Jenkinsfile?
Here's some Jenkinsfile groovy that will get you close to what you want:
// return the user id that caused this build; else empty string
#NonCPS
def user_id_cause() {
def CAUSE = currentBuild.rawBuild.getCause(
hudson.model.Cause.UserIdCause.class
);
return CAUSE ? CAUSE.getUserId() : "";
}
// return all groups to which the given user id belongs
#NonCPS
def groups(USER_ID) {
return Jenkins.instance.securityRealm.loadUserByUsername(USER_ID).authorities.collect{ it.toString() };
}
...
env.USER_ID_CAUSE = user_id_cause();
if (!env.BRANCH_NAME.endsWith('-dev')) {
if (env.USER_ID_CAUSE) {
if ('jenkins_admins' in groups(env.USER_ID_CAUSE)) {
echo("INFO: user id `${env.USER_ID_CAUSE}` is in the group `jenkins_admins`.");
} else {
currentBuild.result = 'ABORTED';
error("user id `${env.USER_ID_CAUSE}` is not in the group `jenkins_admins`.");
}
}
}
Caveats:
These tricks rely heavily on API functions that require "In-process Script Approval" by a Jenkins administrator.
The above example assumes the existence of the jenkins_admins group to which privileged users belong --- your user/groups situation may be very different.
In general, playing with objects returned from Jenkins API functions should be done within #NonCPS-annotated functions --- you risk java.io.NotSerializableException otherwise.
References:
https://github.com/jenkinsci/workflow-cps-plugin/blob/master/README.md
http://javadoc.jenkins-ci.org/hudson/model/Cause.UserCause.html
http://javadoc.jenkins-ci.org/hudson/model/Run.html#getCause-java.lang.Class-
http://javadoc.jenkins.io/hudson/security/SecurityRealm.html#loadUserByUsername-java.lang.String-

How to customize a merge request message on Gitlab?

Before starting a new issue, I always create a new branch for it (directly from Gitlab). When I finish the job on that issue (and tests are Ok), I create a merge request (from Gitlab).
After the merge is done, I have an "auto-generated" message linked to that merge (this message is very generic and identical to all merges I done).
The some thing happens also when I merge develop into master:
Is there a way to customize the merge request message to have a message like this:
Merge {shortIssueName}: {issueDescription} into {develop|master}
Note:
I'm using GitLab Community Edition 8.15.3.
Globally, automatically - I don't think so. As I see, it's hard-coded:
message = [
"Merge branch '#{source_branch}' into '#{target_branch}'",
title
]
if !include_description && closes_issues_references.present?
message << "Closes #{closes_issues_references.to_sentence}"
end
message << "#{description}" if include_description && description.present?
message << "See merge request #{to_reference}"
message.join("\n\n")
You can override message for any merge request manually:
It's also possible if you create merge request with API. It requires your time but you can build some mechanism that fetches all data with API and set it as a description (but you must ensure all is available with API, issueDescription and so on).
Even tho #piotr-dawidiuk makes a good point, I believe is outdated.
According to gitlab docs, you can create your .md files, changing all templates. Check it here. As it states,
Similarly to issue templates, create a new Markdown (.md) file inside the .gitlab/merge_request_templates/ directory in your repository. Commit and push to your default branch.

Resources