Tracking build progress with TeamCity REST API - rest

I use the TeamCity (7.0) REST API to allow developers to trigger custom builds. I add the build to the queue like this:
http://teamcity/httpAuth/action.html?add2Queue=[buildTypeId]&name=[propName]&value=[propValue]
My question is how I best can track the progress of the build just triggered. The REST call does not return any info about build ID assigned to the build, so even if I poll the list of builds (running/finished) I will not know if one of them is the one I triggered. There could potentially be several builds for the same buildTypeId in the queue, so I need a way to separate out the one I am after.
I read somewhere a suggestion that you could add a build property with a unique value to each build you put in the queue, and then later poll the build list and look for one with that exact property value. I have however not found a way of listing the properties for the builds, so I am still stuck. This REST call does not provide information about properties:
http://teamcity/httpAuth/app/rest/builds/?locator=buildType:[buildTypeId]
Any suggestions on how to solve this? I would ideally like to know if the build is in the queue, if it is running, and when it's done I would like to get the status. The most important is however to know if it is done and what the status has.

After some further investigation I came up with a solution for this which seems to work fine:
I found out that even though you did not get any information about the custom build properties using the "/builds/?locator=buildType:x" call, you could extract the build ID for each one of the builds in that list and then do another REST call to get more details about one specific build. The rest call looks like this:
http://teamcity/httpAuth/app/rest/builds/id:{0}
The response from this call will give you a "build object" which contains a list of build properties, among other things.
My solution for tracking the build progress was then like this:
When a build is added to the TeamCity queue, I first add a property to the URL called "BuildIdentifier". The value is just a GUID. I pass this identifier back to the client application, and then the client starts polling the server, asking for the status of the build with this specific identifier. The server then goes through some steps to identify the current stage of the build:
1: Check if the build is running. I get the list of running builds with the call "/builds?locator=running:true", iterate through the builds and use the build ID to query the REST API for details. I then go through the details for each running build looking for a build with a matching "BuildIdentifier" property to the one I received from the client. If there is a match in one of the running builds I send a response with a message that the build is running at x percent (PercentageComplete property of the build object) to the client who is tracking the progress. If a match is not found I move on to step 2.
2: Check if it is finished: First get the latest build list using the "/builds/?locator=buildType:x" call. Then do the same thing as in step 1, and extract the X latest builds from the list (I chose 5). In order to limit the number of REST calls I set an assumption that the build would be in the latest 5 builds if it was finished. I then look for a match on the BuildIdentifier, and if I get one I return the status of the build (FAILED, SUCCESS, etc.).
3: If there was no match for the BuildIdentifier in step 1 or 2 I can assume that the build is in the queue, so I return that as the current status.
On the client side I poll the server for the status every x seconds as long as the status is saying that the build is either in the queue, or running.
Hope this solution could be helpful if there are someone else with the same problem out there! I would think that tracking the progress of a triggered build is a pretty common task if you use the TeamCity REST API.

The Queued Builds rest api is the best way to accomplish this but has only been available since version 8.1.
To start the build send a POST request to ~/httpAuth/app/rest/buildQueue like this
{
buildType: { id: "bt667" },
branchName: "master",
properties: {
property: [
{ "name": "Property", "value": "test" }
]
}
}
The response contains a href which can be used to check the status of the build.
{
...
"href": "/httpAuth/app/rest/buildQueue/taskId:49337",
...
}
To check the status of the build queued send a GET request to the href specified in the response from step 1.
This is a huge improvement over the previous API.

Since TeamCity 8.1, REST API got a dedicated way to trigger a build and tracking the queued build results is much easier as the build queue request returns the link to the queued build which can later be used to track the build's current status.
See details in the TeamCity documentation.

Related

Asynchronous callback not working in VSTS gates Invoke REST API task

I am using the Invoke REST API task in as a pre-deployment gate in my environment. The task has been configured to wait for a callback from my service (external to VSTS).
The problem is that when I try to call into VSTS to mark the task as completed I always get an error saying orchestration session xxxxxx_xxxxxx_xxxxxx not found for hub Gates. The same code when used with release or build definitions work fine but fails with this error when used with gates.
Here is a snippet of my code that makes the API call
var taskCompletedEvent = new TaskCompletedEvent(jobId, taskInstanceGuid, TaskResult.Succeeded);
taskClient.RaisePlanEventAsync(projectGuid, HUBNAME, planGuid, taskCompletedEvent).SyncResult();
This problem occurs because of a slight deviation on how gates are executed when compared to builds or releases. In general, the safest way to update such server side tasks using the callback mode would be by using the TaskClient maintained by the VSTS team itself, which takes care of all such quirks.
The slight change that can be made in the original code to make it work would be -
var taskCompletedEvent = new TaskCompletedEvent(taskInstanceId, Guid.Empty, TaskResult.Succeeded);
taskClient.RaisePlanEventAsync(projectGuid, HUBNAME, planGuid, taskCompletedEvent).SyncResult();
The difference lies in how the event is initialised. The TaskId parameter is not defined and JobId is not used anywhere. The recommendation is still to use the TaskClient on GitHub to ensure everything continues to work fine even when the VSTS Release Management team decides to fix this rather annoying difference.

How to listen the runscope test result?

we are triggering the runscope test using triggerid of the specific test. How can we learn the status of the test so we can progress our builds ?
We have a blog post that describes how to do this with Codeship, but the same methods (especially the polling done in the Python sample script) should be applicable to any CI environment.
Apologies for bumping an old post, but I was looking for something similar, that is, checking the Runscope results to automatically approve the next step in a release (as opposed to a build that OP asked about).
It seems that VSTS has the concept of Gates that can do some action and only progress the release when the action succeeds, with configurable timeout and retry. One of the actions is Invoke REST API, which would probably do the job.
https://learn.microsoft.com/en-us/vsts/pipelines/release/approvals/gates?view=vsts
Note, I haven't actually tried this yet, so YMMV

Activity has a method called getTaskId(). How do I know if this task id matches the task id of the Application task stack?

I can get the app ID from my running activity via activity.getTaskId(). It will report back 185. If I go to another app, and start my activity from a share button, it will be placed IN THAT apps stack. If I do activity.getTaskId() it will report back 192 for example. I am assuming that an application process can only have one main task stack associated with it. How do I get that tasks ID? I want to be able to know "Hey I'm running outside of your apps task stack".
I contemplated doing this by polling the taskId the first time my activity is created and set that as a member variable to my Application Class, but if my app is killed, and then started first from another application, it will have the incorrect task id as the "AppTaskStackId". I haven't found any API for this.
A different approach might be to have both an exported and non-exported activity. The exported activity would simply be forwarded on to the non-exported activity, but with an extra denoting that it was started externally. And then when starting the activity internally, you always call the non-exported activity without that "isExternal" extra.
And then, in the non-exported activity, you can check for the existence of that extra to determine if the activity was started internally or externally.
The only way I could find to get even close to what you are trying to accomplish would be with the following code in, say, your Activity's onCreate:
ActivityManager m = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> runningTaskInfoList = m.getRunningTasks(1);
if(!runningTaskInfoList.isEmpty()) {
String callingPackageName = runningTaskInfoList.get(0).baseActivity.getPackageName();
}
Here callingPackageName would be set to the package name of your app if the activity has been invoked from another activity in your own app, or is the main activity of your app.
However, if the activity was started by another app, say using the share function, then callingPackageName would be the package name of the calling app, so all you have to do is check if this is equal to your app's package name by calling getPackageName().
Also note that:
Your app will now need the android.permission.GET_TASKS permission
The documentation for this method states:
Note: this method is only intended for debugging and presenting task management user
interfaces. This should never be used for core logic in an application, such as deciding between
different behaviors based on the information found here. Such uses are not supported, and will
likely break in the future.
So I'm not sure how reliable this is or if it is even useful to you.
A recently (API 29) added TaskInfo:
https://developer.android.com/reference/android/app/TaskInfo
should help here.

Buildbot - Two Schedulers with one builder = Double checkin emails?

I have a buildbot running with two Schedulers - One triggered by code checkins and another triggered by content checkins; the former needs a much shorter treeStableTimer. Both of these Schedulers trigger the same builder, but what happens now is that everyone gets build notification mails twice for each checkin; once for the code scheduler and once for the content scheduler.
For example, if the following checkins go in...
CL# 1000 12:00pm user_a (code)
CL# 1001 1:00pm user_b (content)
...we'd see a build fire off on CL#1000 and send build notification mail to user_a. Then, a build would fire off from CL#1001 and send build notification to user_a and user_b - user_a gets two notifications that his checkin succeeded, when he should only get one.
I'd like to set things up so that we have two Schedulers, but when a builder triggers and sends email, it sends notification to the number of people who checked in since that builder's last build, not that Scheduler's last build. This seems straightforward conceptually, but I haven't seen anything on this in the docs or forums.
What's the right way to do this? We do need different treeStableTimers on the same builder, and people need build mail notification when their build completes, regardless of which of the two Schedulers triggered the builder.
Are you using fileIsImportant to pick out which which changes to trigger on which scheduler? By default, this doesn't affect the list of changes passed to the source stamp (and build) as triggering the build. All it does is accumulate changes until a change to an important file is made. The onlyImportant paramaeter of schedulers can be used to discard unimportant changes, so they don't get included in source stamps (and thus don't trigger emails).

How to use a WF DelayActivity in an ASP.Net web based workflow

I have a web application that I am adding workflow functionality to using Windows Workflow Foundation. I have based my solution around K. Scott Allen's Orders Workflow example on OdeToCode. At the start I didn't realise the significance of the caveat "if you use Delay activities with and configure active timers for the manual scheduling service, these events will happen on a background thread that is not associated with an HTTP request". I now need to use Delay activities and it doesn't work as is with his solution architecture. Has anyone come across this and found a good solution to this? The example is linked to from a lot of places but I haven't seen anyone else come across this issue and it seems like a bit of a show stopper to me.
Edit: The problem is that the results from the workflow are returned to the the web application via HttpContext. I am using the ManualWorkflowSchedulerService with the useActiveTimers and this works fine for most situations because workflow events are fired from the web app and HttpContext still exists when the workflow results are returned and the web app can continue processing. When a delay activity is used processing happens on a background thread and when it tries to return results to the web app, there is no valid HttpContext (because there has been no Http Request), so further processing fails. That is, the webapp is trying to process the workflow results but there has been no http request.
I think I need to do all post Delay activity processing within the workflow rather than handing off to the web app.
Cheers.
You didn't describe the problem you are having. But maybe this is of some help.
You can use the ManualWorkflowSchedulerService with the useActiveTimers and the workflow will continue on another thread. Normally this is fine because your HTTP request has already finished and it doesn't really matter.
If however you need full control the workflow runtime will let you get a handle on all loaded workflows using the GetLoadedWorkflows() function. This will return acollection of WorkflowInstance objects. usign these you can can call the GetWorkflowNextTimerExpiration() to check which is expired. If one is you can manually resume it. In this case you want to use the ManualWorkflowSchedulerService with the useActiveTimers=false so you can control the last thread as well. However in most cases using useActiveTimers=true works perfectly well.