In TeamCity, trigger build with 2 VCS roots with 2 custom revisions using REST API - rest

looking for collective wisdom on this problem I am tackling.
I need to trigger build using REST API on TeamCity. The build configuration has 2 VCS roots and I need to pass specific revision for both of them. In documentation, I found example for single VCS, but I am stuck on setting revisions for both of them.
I am trying to set up something like this:
{
"buildType": {
"id": "ExampleConfiguration"
},
"defaultBranch": "false",
"lastChanges": {
"change": [
{
"locator": "combination of locators that will set VCS 1 - branch + revision"
},
{
"locator": "combination of locators that will set VCS 2 - branch + revision"
}
]
}
}
In principle, I am simulating execution of the build, where both revisions are manually set - this is possible in the UI.
https://www.jetbrains.com/help/teamcity/rest/start-and-cancel-builds.html#Advanced+Build+Run
TC version: 2022.04.3 (build 108706)
Edit:
I was able to detect the changes and resolve their id on both VCS roots. For the changes field in the body I can now use locator of the form {"id": 123456}. But another obstacle on the road, if I specify pair of these changes:
"lastChanges": { "change": [ {"id": 1}, {"id": 2} ] }
I get error
Responding with error, status code: 400 (Bad Request).
Details: jetbrains.buildServer.server.rest.errors.BadRequestException: Several non-personal changes are submitted, only one can be present
Invalid request. Please check the request URL and data are correct.
Same build with the exact revisions is possible to trigger manually from TC UI.

Finally resolved it. The way to go is to use revisions instead of lastChanges. To pass revisions for 2 VCS roots together with branch names, use this:
"revisions": {
"revision": [
{
"vcs-root-instance": {
"id": "111"
},
"vcsBranchName": "branch-name-111",
"version": "rev_on_vcs_111"
},
{
"vcs-root-instance": {
"id": "222"
},
"vcsBranchName": "branch-name-222",
"version": "rev_on_vcs_222"
}
]
}
To resolve VCS root instance id, use API call /app/rest/vcs-root-instances/vcsRoot:(id:(Project_Vcs_Root))"

Related

Unable to update results of a shared test step via Azure Devops REST-api in Postman

I am trying to update the result of a test case via Azure DevOps REST-Api in Postman.
My test case is very simple and consists only of one shared step that has two simple steps inside.
I want to mark these steps of my shared step as "Passed".
Currently I am doing the following steps:
create a new test Run via POST request to {{baseUrlTestApi}}/runs?api-version=7.0
In request's body I pass the test run name, shallow reference to build and owner. Run is successfully created, I can see it on the portal.
create a result of a test case via POST request to {{baseUrlTestApi}}/Runs/{{runId}}/results?api-version=7.0
In request body I pass shallow references to the project, test plan, test suite, test point and test case, outcome ("Passed"), state ("Completed"), testCaseTitle and revision. On the portal I can see that the result is created with the correct outcome and state and is linked to the right test suite and test case.
update the result with actionResults via PATCH request to {{baseUrlTestApi}}/Runs/{{runId}}/results?api-version=7.0
In request body I pass the test result's ID and iteration details, that contains iteration id and an array of action results, where I specify shared step's ID and revision and outcome for each shared step's step. This is the request's body:
[
{
"id": 100000,
"iterationDetails": [
{
"id": 1,
"outcome": "Passed",
"startedDate": "2022-02-16T21:14:14.337Z",
"completedDate": "2022-02-16T21:14:17.057Z",
"durationInMs": 27180000.0,
"actionResults": [
{
"actionPath": "0000000200000001",
"sharedStepModel": {
"id": 18338,
"revision": 2
},
"iterationId": 1,
"stepIdentifier": "1;1",
"outcome": "Passed",
"startedDate": "2022-02-16T21:14:14Z",
"completedDate": "2022-02-16T21:14:14Z",
"url": "{{baseUrlTestApi}}/Runs/{{runId}}/Results/100000/Iterations/1/ActionResults?actionPath=0000000200000001"
},
{
"actionPath": "0000000200000002",
"sharedStepModel": {
"id": 18338,
"revision": 2
},
"iterationId": 1,
"stepIdentifier": "1;2",
"outcome": "Passed",
"startedDate": "2022-02-16T21:14:14Z",
"completedDate": "2022-02-16T21:14:14Z",
"url": "{{baseUrlTestApi}}/Runs/{{runId}}/Results/100000/Iterations/1/ActionResults?actionPath=0000000200000002"
}
],
"parameters": [],
"attachments": [],
"url": "{{baseUrlTestApi}}/Runs/{{runId}}/Results/100000/Iterations/1"
}
]
}
]
Then I go to the portal to see the results. I am expecting to see all three steps of my shared step marked as Passed in the Details section. However, when I go to Runs --> select my run --> test results --> select my result I see this error:
workItemRevision error
I found that what is causing this error is that in the payload of POST request to https://{{organization}}.visualstudio.com/_apis/Contribution/dataProviders/query sent by the portal shared step's work item has an empty string in workItemRevisions.
empty string in workItemRevisions
However, I have explicitly specified the revision ID in step 3 (in sharedStepModel object in each element of actionResults array). If I send a request to this endpoint myself via Postman with the same payload but with "1" instead of empty string, the request is successful.
Before this request, portal sends another one to the same endpoint for the Test Case's workitem and that request is successful, workItemRevisions field is populated correctly, so it is empty string only for the shared step's workitem.
This is the case only if the shared step is involved. If a test case consists of only regular steps, then I am able to mark them as "Passed" with the same flow I described above.
Any ideas what can be causing this? Is this even the right approach to mark the shared step's outcome? Thanks in advance.
After checking the REST API:
You could get a request body (use the Iterations detailsToInclude parameter) and modify the request body. and then to update the result to check if it works.
12.14 Update:
If you manually run the test with shared steps, we can get the actionresults like:
"actionResults": [
{
"actionPath": "00000002",
"iterationId": 1,
"sharedStepModel": {
"id": 142,
"revision": 1
},
"stepIdentifier": "2",
"outcome": "Failed",
"startedDate": "2022-12-14T07:43:03Z",
"completedDate": "2022-12-14T07:43:03Z"
},
{
"actionPath": "0000000200000001",
"iterationId": 1,
"stepIdentifier": "2;1",
"outcome": "Failed",
"startedDate": "2022-12-14T07:43:03Z",
"completedDate": "2022-12-14T07:43:03Z"
}
],
"parameters": [],
"attachments": [],
"url": "https://dev.azure.com/{org}/{project}/_apis/test/Runs/{runId}/Results/100000/Iterations/1"
}
]
And then I change the outcome from "Failed" to "Passed" and then Patch the result to:
https://dev.azure.com/{org}/{project}/_apis/test/Runs/{runId}/results?api-version=7.0
And then I can view the result in the run -> Test results -> The run.
So, I think your problem maybe related to the format of the actionresults, you can try to run a manually test to get the actionresults and then PATCH it to check if it works.

During a PR action on GitHub, what version of the code is actually run?

I've tried to read the GitHub documentation on this and tried to google some information about it, but either the information is missing or I'm just unable to understand it :)
Either way, I'll use an example (python) to illustrate the problem:
foo.py on master:
my_list = [
1,
2,
]
assert len(my_list) == 2
So far, so good.
Create new branch:
foo.py on branch feat_a
my_list = [
0,
1,
2,
]
assert len(my_list) == 3
And a separate feature branch:
foo.py on branch feat_b
my_list = [
1,
2,
3,
]
assert len(my_list) == 3
I then merge feat_a into master. The problem now is that my PR for feat_b is perfectly mergeable which will create the list with 4 items from 0 to 3. But the assert statement will fail after the merge commit takes place. In other words, I have two branches that runs perfectly fine on their own and are mergeable, but are in a bad state AFTER the merge commit.
So my question is this:
When I run a GitHub action, how can I make sure that the action runs the merged code? Is this the default behavior or not?
It will run on the merged code if you, f.e., use the checkout action with default values.
If you look at the event data of a pull request you get something like the following (shortened)
{
"ref": "refs/pull/1/merge",
"sha": "<sha-1>",
"event": {
"number": 1,
"pull_request": {
"head": {
"ref": "<base-branch>",
"sha": "<sha-2>"
}
}
}
}
and the hash the workflow is running on is different to the hash of the commit on the base branch of your pull request.

Linking multiple existing work items to queued build (from Azure Devops SDK)

In Azure Devops REST API, I want to link a task\bug\story (that already exists) when triggering a build. How do I do that?
checkInTicket might be a solution, but it is not documented.
Payload based on Merlin's response worked:
var payload = new object[] {
new {
op = "add",
path = "/relations/-",
value =
new {
rel = "ArtifactLink",
url = $"vstfs:///Build/Build/{buildId}",
attributes = new
{
name = "Build"
}
}
}
};
1. Approach 1
Same with the UI operation, to link the exists work item to build, just need to update one option in build definition:
This is the api:
https://dev.azure.com/{org name}/{project name}/_apis/build/definitions/{definition id}?api-version=5.0-preview.6
In its request body, please focus on below script part:
"options": [
{
"enabled": true,
"inputs": {
"branchFilters": "[\"+refs/heads/*\"]",
"additionalFields": "{}"
},
"definition": {
"id": "5d58cc01-7c75-450c-be18-a388ddb129ec"
}
}
]
The enabled represent whether it will create links to work items which linked to associated changes after the build completed. To achieve what you want, here, please set the enabled value as true. The id value is fixed and represent this option, so here do not worry about this id value.
When you updating the build definition by this method, do not forget increment the revision in request body. revision increment means update the definition as a new revision. or the update action would not actually succeed.
But, what you should concerned is this update should finished before the build triggered. Thus it will create link to the exists WIT automatically after the build finished.
Also, this would only add this build link to work item which associate with the changes.
2. Approach 2
If the above is not what you want, and you just want to link work item to build while the build is triggered. Afraid to say, there's no such direct API could finish that.
You may need to use 2 APIs: one of it is queue build, and another API is add this build link to work item.
The request body sample of add build link to work item:
[
{
"op": "test",
"path": "/rev",
"value": "2"
},
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": "ArtifactLink",
"url": "vstfs:///Build/Build/{the build id that you just queued}"
}
}
]
This method need you get the generated BuildId after you queue the build, and then pass it to the workitem API. Different with the approach 1, in this method, you can customize the work item id which you want to add the build link to.

Implemented a Resource Type: How does Concourse use the output of the check, in, and out scripts?

Reading the Concourse documentation about Implementing a Resource Type, in regards to what the check, in, and out scripts must emit, it is not clear why this output is needed or how Concourse uses it. My questions are:
1) How does Concourse use the output of the check script, the in script, and the out script?
2) And, why is it required that the in and out script emit the version? What happens if you don't?
For context, here is the relevant parts of the documentation:
1) For the check script:
...[it] must print the array of new versions, in chronological order,
to stdout, including the requested version if it's still valid.
For example:
[
{ "ref": "61cbef" },
{ "ref": "d74e01" },
{ "ref": "7154fe" }
]
2) For the in script:
The script must emit the fetched version, and may emit metadata as a list of key-value pairs. This data is intended for public consumption and will make it upstream, intended to be shown on the build's page.
For example:
{
"version": { "ref": "61cebf" },
"metadata": [
{ "name": "commit", "value": "61cebf" },
{ "name": "author", "value": "Hulk Hogan" }
]
}
3) Similar to the in script, the out script:
The script must emit the resulting version of the resource. For
example, the git resource emits the sha of the commit that it just
pushed.
For example:
{
"version": { "ref": "61cebf" },
"metadata": [
{ "name": "commit", "value": "61cebf" },
{ "name": "author", "value": "Mick Foley" }
]
}
Concourse uses the check result to verify if there is any new resource available. According to your pipeline definition, the presence of a new resource would trigger a job. The in is therefore used to read the specific resource using parameters provided by the pipeline whilst the out would take care of writing them.
As your in is going to use the information provided by the check you may want to use a similar structure, but you're not obliged to. It is useful to echo the same version information in your check/in/out in order to be able to log it and understand each resource in your pipeline is belonging to which version.

How do we know a pull request is approved or rejected using API in github?

I would like to know if there is an function in the Github API which would return the status of a pull request whether its accepted or rejected. Does such a function exist?
I was stymied by this problem, too. I had a hard time finding relevant info in the docs.
Option A
The tactic I've landed on is to use the issues search endpoint with the review qualifier in the q param.
So, in my case, when I want to see all PRs assigned to me that have not yet been reviewed, I'd hit this endpoint: https://github.com/api/v3/search/issues?q=is:open+is:pr+review-requested:jordan-bonitatis+review:none
Other review qualifiers include approved and changes_requested as explained here: https://docs.github.com/en/github/searching-for-information-on-github/searching-issues-and-pull-requests#search-by-pull-request-review-status-and-reviewer
Option B
If you want to see the review status for a given PR, instead of getting a list filtered by status like in my example above, you can hit the pull requests reviews endpoint: /repos/:owner/:repo/pulls/:number/reviews
This will return a list of reviews for the PR, each of which have a state key.
Note that a given PR may have multiple reviews with conflicting states. Like, if teamMemberA approved it but teamMemberB requested changes. You'll have to traverse the entire list and decide how you want to treat it based on all the states.
Depending on the repo configuration you can get the answer one way or another. The examples below use the GraphQL API.
Case 1: PR reviews are required before merging
You can query reviewDecision on the pullRequest field for a given repository.
reviewDecision is of type PullRequestReviewDecision, an enum with values of APPROVED, CHANGES_REQUESTED, and REVIEW_REQUIRED.
Example query:
{
repository(name: "gatsby", owner: "gatsbyjs") {
pullRequest(number: 30371) {
title
reviewDecision
url
}
}
}
Response:
{
"data": {
"repository": {
"pullRequest": {
"title": "chore(gatsby): don't terminate dev server if graphql wasn't imported from gatsby",
"reviewDecision": "APPROVED",
"url": "https://github.com/gatsbyjs/gatsby/pull/30371"
}
}
}
}
Case 2: PR reviews are not required before merging
If the repository settings don't specify that reviews are required, reviewDecision will be null regardless of approvals.
In this case you could iterate over the reviews and check the states. state is of type PullRequestReviewState, an enum with values of APPROVED, CHANGES_REQUESTED, COMMENTED, DISMISSED, and PENDING.
Example query:
{
repository(name: "create-react-app", owner: "facebook") {
pullRequest(number: 10003) {
title
reviewDecision
url
reviews(first: 100) {
nodes {
state
author {
login
}
}
}
}
}
}
Response:
{
"data": {
"repository": {
"pullRequest": {
"title": "Update postcss packages",
"reviewDecision": null,
"url": "https://github.com/facebook/create-react-app/pull/10003",
"reviews": {
"nodes": [
{
"state": "APPROVED",
"author": {
"login": "jasonwilliams"
}
}
]
}
}
}
}
}
It's possible to filter reviews for approvals: reviews(first: 100, states: APPROVED).
Note that two reviews will be returned if a reviewer gives his approval and subsequently requests changes.
Checking the PR state (of type PullRequestState) could be misleading: an admin user may have bypassed the required review process to merge changes.
You can get a single PR and check its state and merged properties. If it's merged, then it's accepted. If it's closed and not merged it may be rejected.
In fact it may be not rejected but closed by a creator. I'm not sure if it's possible to check if it was closed by another user (rejected) or by it's creator (denied).
I had a similar requirement - to know if a PR has been approved or not before merging it to master. I added a rule on the repo to ensure that every PR must be approved prior to merging. Then on using the API to get details about the branch there was one field which stated if the branch was clean to merge or blocked . I used this as a way to mange things in my app.
mergeable_state
This is now possible using GraphQL.
Specifically if the mergeStateStatus enum is BLOCKED then the pull request hasn't been approved and for any other status it would have been approved.
This enum is present in the PullRequest object. Do note that at the time of posting this is a preview feature and so must have the appropriate header to work. It will also not work using the GraphQL Explorer while it's in preview.
In the official Github API Documentation it shows that there is a GET request you can make that has the field merged_at if it has already been merged. Edit: theres also a merged field as well.
Snippet:
...
"merge_commit_sha": "e5bd3914e2e596debea16f433f57875b5b90bcd6",
"merged": false,
"mergeable": true,
"merged_by": {
"login": "octocat",
"id": 1,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},