Running TFS queries from C# replacing the #Today Variable - tfs

I´m writing an extension to TFS that can run queries. As I have seen, before running the query with the TFS API, all defined variables must be replaced.
I have looked at the default TFS variables here and I can understand all except for #Today variable.
The main problem with the #Today variable is that you can add operators to it like:
[Source].[Microsoft.VSTS.Common.ActivatedDate] = #today - 7
Do I need to replace the variable with the current date (and time?) and let the query engine do the math, or should I do the math before passing it to the query engine?

You do not need to replace #Today with anything, you can just run the query "as is".
For example running the following in Linqpad:
using (var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(CollectionAddress)))
{
tfs.EnsureAuthenticated();
var server = tfs.GetService<WorkItemStore>();
server
.Query("select * from WorkItems where System.CreatedDate > #today - 1")
.Cast<WorkItem>()
.Select(wi => new { wi.Id, wi.CreatedDate, })
.Dump(); //This is a http://LinqPad.net extension method.
}
Returns all the work items logged in my TFS Collection in since this morning.
The Work Item Query Language (WIQL) parser must take care of these things for you.

Related

Snowflake Tasks causing error in timezone in queries

I am running a simple insert query inside a stored procedure with to_timeatamp_ntz("column value") along with other columns.
This works fine when I am running it with the snowflake UI and logged in with my account.
This works fine when I am calling it using python scripts from my visual studio instance.
The same stored procedure fails when it is being called by a scheduled task.
I am thinking if it has something to do with the user's timezone of 'System' vs my time zone.
Execution error in store procedure LOAD_Data(): Failed to cast variant
value "2019-11-27T13:42:03.221Z" to TIMESTAMP_NTZ At
Statement.execute, line 24 position 57
I tried to provide timezone as session parameters in task and in the stored proc but does not seem to be addressing the issue. Any ideas?
I'm guessing (since you didn't include the SQL statement that causes the error) that you are trying to bind a Date object when creating a Statement object. That won't work.
The only parameters you can bind are numbers, strings, null, and the special SfDate object that you can only get from a result set (to my knowledge). Most other parameters must be converted to string using mydate.toJSON(), JSON.stringify(myobj), etc., before binding, eg:
var stmt = snowflake.createStatement(
{ sqlText: `SELECT :1::TIMESTAMP_LTZ NOW`, binds: [(new Date).toJSON()] }
);
Date object errors can be misleading, because Date objects causing an error can be converted and displayed as strings in the error message.
I found the issue:
my Task was using a copy paste effect similar to this:
CREATE TASK TASK_LOAD_an_sp
WAREHOUSE = COMPUTE_WH
TIMEZONE = 'US/Eastern'
SCHEDULE = 'USING CRON 0/30 * * * * America/New_York'
TIMESTAMP_INPUT_FORMAT = 'YYYY-MM-DD HH24'
AS
Call LOAD_an_sp();
The Timestamp input format was causing this.

Tfs Can not Get Project Name from Query programmatically using #Project parameter

i'm looking for your help, guys! I want to get Current Project Name from query, using my custom plugin.
Here is my code
WorkItemCollection queryResults = workItemStore.Query("SELECT [System.TeamProject] FROM WorkItems WHERE [System.TeamProject] = '#Project'");
foreach (WorkItem item in queryResults)
{
// SomeCode;
}
So result of Query is empty.. I have no idea why.. If i'm writing
real Project Name instead of the '#Project' it's works.. Also i tried to write #Project wihout quotes - also no result.
You can't use "#Project" in code like this. #Project is only available within a VisualStudio work item query where it can infer the team project based on your currently selected project in the Team Explorer.
You can try this code if your plugin is an WorkItemChangedEventHandler:
WorkItemChangedEvent workItemChange = (WorkItemChangedEvent)notificationEventArgs;
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi = workItemStore.GetWorkItem(workItemChange.CoreFields.IntegerFields[0].NewValue);
string p = wi.Project.Name

Access the Kanban Column (a Team-Specific Field) for a Work Item

Is there a way to programmatically access the "Kanban Column" for a WorkItem using the TFS 2012 API?
Using the Scrum 2.2 template, the history of a Bug or Product Backlog Item shows "[MyProject\MyTeam] Kanban Column" as a changed field whenever a work item is dragged between Kanban columns on the Board, but the field is not accessible when specifically retrieving a work item through the TFS API.
It also shows up as a changed field in the WorkItemChangedEvent object when implementing the ProcessEvent method on the Microsoft.TeamFoundation.Framework.Server.ISubscriber interface.
Workaround:
A coworker found a blogpost about creating a read-only custom field to persist the value of the Kanban Column, taking advantage of the WorkItemChangedEvent to capture the latest value. It is then possible to query on this column. One problem with this approach is that only a single team's Kanban Column can be tracked.
Update:
According to this blogpost, the Kanban Column is not a field, rather a "WIT Extension". This may help lead to an answer.
I've found a way to read the value using the TFS 2013 API, inside the ISubscriber.ProcessEvent method:
var workItemId = 12345;
var extService = new WorkItemTypeExtensionService();
var workItemService = new WorkItemService();
var wit = workItemService.GetWorkItem(requestContext, workItemId);
foreach (var wef in extService.GetExtensions(requestContext, wit.WorkItemTypeExtensionIds))
{
foreach (var field in wef.Fields)
{
if (field.LocalName == "Kanban Column" || field.LocalName == "Backlog items Column")
{
// Access the new column name
var columnName = wit.LatestData[field.Field.FieldId];
}
}
}
If you are prepared to dig into the database you can mine this information out. I don't fully understand the modelling of the teams in TFS yet but first you need to work out which field id the team of interest is storing the Kanban state in as follows (TFS 2012):
USE Tfs_DefaultCollection
SELECT TOP(10)
MarkerField + 1 as FieldId,*
FROM tbl_WorkItemTypeExtensions with(nolock)
JOIN tbl_projects on tbl_WorkItemTypeExtensions.ProjectId = tbl_projects.project_id
WHERE tbl_projects.project_name LIKE '%ProjectName%
Then replace XXXXXXXX below with the FieldId discovered above
SELECT TOP 1000
wid.Id,
wia.State,
wid.StringValue as Kanban,
wia.[Work Item Type],
wia.Title,
tn.Name as Iteration
FROM tbl_WorkItemData wid with(nolock)
JOIN WorkItemsAre wia on wia.ID = wid.Id
JOIN TreeNodes tn on wia.IterationID = tn.ID
WHERE FieldId = XXXXXXXX and RevisedDate = '9999-01-01 00:00:00.000'
ORDER BY Id
I am not familiar with the Scrum 2.2 template, but the works are the same for CMMI or Scrum templates when it comes to TFS Work Item tracking.
Try something like this:
public string GetKanbanColumn(WorkItem wi)
{
if (wi != null)
{
return wi["Kanban"].ToString();
}
return string.Empty;
}
Depending on the actual name of the column, specified in the Work Item Template XML file. Hope this helps.

How to use Slickgrid Formatters with MVC

I am working on a first Slickgrid MVC application where the column definition and format is to be stored in a database. I can retrieve the list of columns quite happily and populate them until I ran into the issue with formatting of dates. No problem - for each date (or time) column I can store a formatter name in the database so this can be retrieved as well. I'm using the following code which works ok:
CLOP_ViewColumnsDataContext columnDB = new CLOP_ViewColumnsDataContext();
var results = from u in columnDB.CLOP_VIEW_COLUMNs
select u;
List<dynColumns> newColumns = new List<dynColumns>();
foreach(CLOP_VIEW_COLUMN column in results)
{
newColumns.Add(new dynColumns
{
id = column.COLUMN_NUMBER.ToString(),
name = column.HEADING.Trim(),
field = column.VIEW_FIELD.Trim(),
width = column.WIDTH,
formatter = column.FORMATTER.Trim()
});
}
var gridColumns = new JavaScriptSerializer().Serialize(newColumns);
This is all fine apart from the fomatter. An example of the variable gridColumns is:
[{"id":"1","name":"Date","field":"SCHEDULED_DATE","width":100,"formatter":"Slick.Formatters.Date"},{"id":"2","name":"Carrier","field":"CARRIER","width":50,"formatter":null}]
Which doesn't look too bad however the application the fails with the error Microsoft JScript runtime error: Function expected in the slick.grid.js script
Any help much appreciated - even if there is a better way of doing this!
You are assigning a string to the formatter property, wich is expected to be function.
Try:
window["Slick"]["Formatters"]["Date"];
But i really think you should reconsider doing it this way and instead store your values in the db and define your columns through code.
It will be easier to maintain and is less error prone.
What if you decide to use custom editors and formatters, which you later rename?
Then your code will break or you'll have to rename all entries in the db as well as in code.

How to use was clause with Jql

i am developing report plugin for jira where i need to get assignee for given duration.it could be diffrent than current assignee in given duration.
now i am building my query in report like below.
JqlQueryBuilder queryBuilder = JqlQueryBuilder.newBuilder();
query = queryBuilder.where().updatedBetween(stdate,endDate).and().assignee() in(status_val).buildQuery();
return searchProvider.searchCount(query, remoteUser);
i want to get the count for prior assigned issues for given duration.
please let me know how i can use Was clause with assignee and updatedbetween dates.
regards,
tousif shaikh.
Try reading this answer. In short, you'll need to define a new clause and use it in your query, like this:
JqlQueryBuilder builder = JqlQueryBuilder.newBuilder();
WasClauseImpl wasClause = new WasClauseImpl("status", Operator.WAS, new SingleValueOperand("Resolved"), new TerminalHistoryPredicate(Operator.AFTER, new SingleValueOperand(3500000L)));
JqlClauseBuilder clauseBuilder = JqlQueryBuilder.newClauseBuilder(wasClause);
Query query = clauseBuilder.buildQuery();

Resources