We are unable to update CreatedBy(System.CreatedBy) workitem field in VSTS 2017 using rest API. The user has been added to "Project Collection Service Accounts" VSTS group in order to bypass the rules while updating the workitem.
Link: https://github.com/Microsoft/vsts-dotnet-samples/blob/master/ClientLibrary/Snippets/Microsoft.TeamServices.Samples.Client/WorkItemTracking/WorkItemsSample.cs#L271
public WorkItem UpdateWorkItemUsingByPassRules(int id)
{
JsonPatchDocument patchDocument = new JsonPatchDocument();
patchDocument.Add(
new JsonPatchOperation() {
Operation = Operation.Add,
Path = "/fields/System.CreatedBy",
Value = "Foo <Foo#hotmail.com>"
}
);
VssConnection connection = Context.Connection;
WorkItemTrackingHttpClient workItemTrackingClient = connection.GetClient<WorkItemTrackingHttpClient>();
WorkItem result = workItemTrackingClient.UpdateWorkItemAsync(patchDocument, id, null, true).Result;
return result;
}
When validateOnly parameter is set to true instead on null, then the result output holds the updated created by value.
System.CreatedBy field can only be modified on work item creation. If the work item has multiple revisions, System.CreatedBy can not be changed by bypassing rule.
You can also find it in make an update bypassing rules:
NOTE: System.CreatedBy and System.CreatedDate can only be modified
using bypass rules on work item creation, i.e. the first revision of a
work item.
Since System.CreatedBy and System.CreatedDate record who and when did a work item created, it can only be updated when you create the work item.
Related
I am trying to change the CreatedBy field in a work item to a test user I have. The CreatedBy field is being updated on the creation of the work item and I have bypassRules set to true. For a bit I thought the code I wrote was not updating the CreatedBy field because in the History section it still said: "USER created the User Story". Note that "USER" is the member who has the access token.
However, if I pull the work item I just created and pull the CreatedBy information it points out to the test user member, which is correct behavior. So my only problem is that history is not updating, is there a way to change CreatedBy in the history section? Below is a snippet of the code I am using to create the work item.
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/fields/System.CreatedBy",
Value = workItem.CreatedBy //Represents string "Test User"
}
);
WorkItem result = workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "User Story", bypassRules: true).Result;
Console.WriteLine("User Story Successfully Created: User Story #{0}", result.Id);
workItem.ItemId = (int)result.Id;
WorkItem testResult = workItemTrackingHttpClient.GetWorkItemAsync(project, workItem.ItemId).Result;
IdentityRef createdBy = (IdentityRef)testResult.Fields["System.CreatedBy"];
Console.WriteLine(createdBy.DisplayName); //This correctly displays "Test User"
return result;
I would like to retrieve the all recent versions of all entities( i.e. everything in Database) that has changed recently.
Following query fetch revisions of specific entity "MyEntity"
queryObject = auditReader.createQuery().forRevisionsOfEntity(MyEntity.class, false, true).addOrder(AuditEntity.revisionNumber().desc())
But I need a mechanism to fetch records for all entities irrespective of particular entity type.
Look into org.hibernate.envers.track_entities_changed_in_revision.
This setting causes a join-table to be created against the revision-entity where a string-based set of entity names will be tracked for each revision number. With this information, you should be able to build necessary queries using the AuditReader#createQuery() API to iterate all the changes.
In pseudo code, it would be something like:
List<Number> revisions = // create AuditQuery to get all revision numbers
for ( Number revision : revisions ) {
DefaultTrackingModifiedEntitiesRevisionEntity revisionEntity = // create query to get revision entity
for ( String entityName : revisionEntity.getModifiedEntityNames() ) {
// create query based on entityName + revisionNumber
}
}
trigger LMDofNotes on Note (after insert, after update) {
Id accountId;
Date LMDofNote;
for(Note att: Trigger.new){
accountId = att.ParentId;
LMDofNote= (Date)att.LastModifiedDate;
}
Account acc = [Select Id,LMD_of_Notes__c from Account where Id=:accountId LIMIT 1];
acc.LMD_of_Notes__c = LMDofNote;
update acc;
system.debug('updated date'+LMDofNote);
}
Orgs with Enhanced Notes active do not create Note records, which represents classic Notes.
Instead, they create ContentNote records, which are part of a much more complex ERD. ContentNote doesn't have a ParentId field (its relationship to records is many-to-many), so your trigger would have to be on the ContentDocumentLink object.
ContentNote is basically a facade on the underlying ContentDocument and ContentVersion objects, but you can identify the note records by the FileType field:
All notes have a file type of SNOTE.
Be aware that ContentDocumentLink is used for linking all Content records (not just notes) to sObjects, and that there are unique restrictions on querying it that are described in the documentation linked above.
I am trying to use the VSTS API to remove all parent links on items, and set those parents as related items.
https://www.visualstudio.com/en-us/docs/integrate/api/wit/work-items#update-work-items
I do not fully understand how the "Path" needed to remove relations work – I am getting inconsistent results where sometimes it works, sometimes not (so, im clearly doing it wrong)
I am making an assumption that its simply the order returned by the API. So, for example:
Index[0] item
Index[1] item
Index[2] item <- this is the one I want to remove, so I use index 2
public void RemoveParentLink(int pathIndex, int itemToUpdate, string link)
{
JsonPatchDocument patchDocument = new JsonPatchDocument();
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Remove,
Path = $"/relations/{pathIndex}"
}
);
WorkItem result = witClient.UpdateWorkItemAsync(patchDocument, itemToUpdate).Result;
}
The documentation states that Path is:
Path to the value you want to add, replace, remove, or test.
For a specific relation, use "relations/Id".
For all relations, use "/relations/-".
Index is NOT the Id of course, but how do I get the relation/Id exactly?
Using GetWorkItemAsync or GetWorkItemsAsync with WorkItemExpand.Relations parameter to get linked work items.
Var workItem=witClient.GetWorkItemAsync(id: [work item id], expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations).Result.
Then the index is the index of relations.
The 'id' in the '/relation/id' path is a index in fact. You retrieve the work item definition, then the 'id' is the index of the link in the 'relations' array. Hence your assumption is right.
Evidence: given a work item with 2 links, if you try to delete/modify id >= 2 it will answer with:
{ "$id": "1", "innerException": null, "message": "Index out of range
for path /relations/2.", "typeName":
"Microsoft.VisualStudio.Services.WebApi.Patch.PatchOperationFailedException,
Microsoft.VisualStudio.Services.WebApi, Version=14.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "typeKey":
"PatchOperationFailedException", "errorCode": 0, "eventId": 3000 }
0 and 1 as id work just fine instead.
I may be wrong, but I could guess that you could get an error when using the 'replace' operation before the 'add' operation. For example you need to add a 'comment' inside the 'attributes' of a link before modifying (i.e. 'replace' operation) its value.
When we insert multiple rows at the same time with Entity framework it's good to add these objects one by one and then commit in the end, instead of adding and comitting each time.
So in that case, how do I get IDs for those insertions?
Example:
foreach (var item in list)
{
Subscription subscription = new Subscription();
subscription.Amount = item.ItemTotal;
this.ClientRepositories.LiveData.AddToSubscriptions(subscription);
// LiveData is db context via webservice proxy
// how to get IDS of these insertions if you do not commit each time?
int id = subscription.Id;
someOtherOperation(id); //i need to insert ID for each row that was inserted
}
this.ClientRepositories.LiveData.SaveChanges();
If I use commit inside for each time it adds new object I can easily get the latest inserted ID, but its not good to commit each time for multiple rows I heard.
I'm assuming that you are using auto incremented id's. I think your going to have to keep a list of your subscription objects outside of your loop. During each loop iteration, add the current subscription to the list. After your execute 'SaveChanges();' The subscription id's will be automatically added.
Would look like this:
List<Subscription> subList = new List<Subscription>();
foreach (var item in list)
{
Subscription subscription = new Subscription();
subscription.Amount = item.ItemTotal;
this.ClientRepositories.LiveData.AddToSubscriptions(subscription);
subList.add(subscription);
}
this.ClientRepositories.LiveData.SaveChanges();
/* At this point, each Subscription in your 'subList' should have an id */