How do tf.exe and tfpt.exe establish connections to a TFS instance based on execution directory? - command-line

I'm doing some work at the command line using using the TFS object model, and I want to reproduce the workspace-detection bahavior seen in tf.exe and tfpt.exe without introducing artifacts because of my own particular implementation. Currently, my scripts require more information than what tf.exe needs--a significant amount of my parameters are there simply to instantiate the connection.
Specifically, I have to require users to explicitly pass in the server Uri (tfsUriString) and the collection name (tfsCollectionName), but this seems needless and annoying since tf.exe is able to do it.
Uri tfsUri = new Uri(tfsUriString);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren( new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes.Where(node => node.Resource.DisplayName == tfsCollectionName).SingleOrDefault();
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
What classes and methods can be used to perform this detection in the same way that tf.exe does?

Team Foundation Server clients use a workspace cache that contains all the user's workspaces for each Team Project Collection that they've used from the current machine. tf.exe uses this cache to determine the TfsTeamProjectCollection and Workspace to use for the paths given on the command line.
You can get the cached WorkspaceInfo for a particular local path by using:
Workstation.Current.GetLocalWorkspaceInfo(localPath)
Or you can get the entire workspace cache by calling:
Workstation.Current.GetAllLocalWorkspaceInfo()
The WorkspaceInfo.ServerUri property will contain the server URI you can use to create a TfsTeamProjectCollection with.

Related

Best practice for using variables to configure and create new Github repository instance in Terraform instead of updating-in-place

I am trying to set up a standard Github repository template for my organization that uses Terraform to spin up new repos with the configured settings.
Every time I try to update the configuration file to create a new instance of the repository with a new name, instead it will try to update-in-place any repo that was already created using that file.
My question is what is the best practice for making my configuration file reusable with input variables like repo name? Should I make a module or is there some way of reusing that file otherwise?
Thanks for the help.
Terraform is a desired-state-configuration system, which means that your configuration should represent the full set of objects that should exist rather than an instruction to create a single object.
Therefore the typical way to add a new repository is to add a new resource block declaring that new repository, and leave the existing ones unchanged. Terraform will then see that there's a new resource not currently tracked in the state and will propose to create it.
If your repositories are configured in some systematic way that you can describe using a mechanical rule rather than manual configuration then you can potentially use the for_each meta-argument to declare multiple resource instances from the same resource block, using Terraform language expressions to describe the systematic rule.
For example, you could create a local value with a higher-level data structure that describes what should be different between your repositories and then use that data structure with for_each on a single resource block:
locals {
repositories = tomap({
example_1 = {
description = "First example repository"
}
example_2 = {
description = "Second example repository"
}
})
}
resource "github_repository" "all" {
for_each = local.repositories
name = each.key
description = each.value.description
private = true
}
For simplicity in this example I've only made the name and description variable between the instances, but you can add whatever extra attributes you need for each of the elements of local.repositories and then access them via each.value inside the resource block.
The private argument above illustrates how this approach can avoid the need to re-state argument values that will be the same for each declared repository, and have your local.repositories data structure focus only on the minimum attributes needed to describe the variations you need for your local policies around GitHub repositories.
A resource block with for_each set appears as a map of objects when used in expressions elsewhere, using the same keys as in the map given in for_each. Therefore if you need to access the repository ids, or any other attribute of the systematically-declared objects, you can write Terraform expressions that work with maps. For example, if you want to output all of the repository ids as a map of strings:
output "repository_ids" {
value = tomap({
for k, r in github_repository.all : k => r.repo_id
})
}

Accessing Raw Gamer Profile Picture

I am using the new XBox Live API for C# (https://github.com/Microsoft/xbox-live-api-csharp) for official access through a UWP app.
I am able to authenticate fine and reference the XBox Live user in context.
SignInResult result = await user.SignInAsync();
XboxLiveUser user = new XboxLiveUser();
Success! However, I can't seem to find an appropriate API call to return XboxUserProfile or XboxSocialProfile. Both of these classes contain URLs to the player's raw gamer pics. After reviewing MSDN documentation and the GH library it isn't clear to me how this is achieved. Any help is greatly appreciated.
The below sample should work if you meet the following pre requisits:
Reference the Shared Project that contains the API from your project and don't reference the "Microsoft.Xbox.Services.UWP.CSharp" project
Copy all source code files from the "Microsoft.Xbox.Services.UWP.CSharp" project into your project
Include the Newtonsoft.Json NuGet package into your project
Steps 1 & 2 are important as this allows you to access the "internal" constructors which otherwise would be protected from you.
Code to retrieve the profile data:
XboxLiveUser user = new XboxLiveUser();
await user.SignInSilentlyAsync();
if (user.IsSignedIn)
{
XboxLiveContext context = new XboxLiveContext(user);
PeopleHubService peoplehub = new PeopleHubService(context.Settings, context.AppConfig);
XboxSocialUser socialuser = await peoplehub.GetProfileInfo(user, SocialManagerExtraDetailLevel.None);
// Do whatever you want to do with the data in socialuser
}
You may still run into an issue like I did. When building the project you may face the following error:
Error CS0103 The name 'UserPicker' does not exist in the current
context ...\System\UserImpl.cs 142 Active
If you get that error make sure you target Win 10.0 Build 14393.

CQ5 / AEM5.6 Workflow: Access workflow instance properties from inside OR Split

TL;DR version:
In CQ workflows, is there a difference between what's available to the OR Split compared to the Process Step?
Is it possible to access the /history/ nodes of a workflow instance from within an OR Split?
How?!
The whole story:
I'm working on a workflow in CQ5 / AEM5.6.
In this workflow I have a custom dialog, which stores a couple of properties on the workflow instance.
The path to the property I'm having trouble with is: /workflow/instances/[this instance]/history/[workItem id]/workItem/metaData and I've called the property "reject-or-approve".
The dialog sets the property fine (via a dropdown that lets you set it to "reject" or "approve"), and I can access other properties on this node via a process step (in ecma script) using:
var actionReason;
var history = workflowSession.getHistory(workItem.getWorkflow());
// loop backwards through workItems
// and as soon as we find a Action Reason that is not empty
// store that as 'actionReason' and break.
for (var index = history.size() - 1; index >= 0; index--) {
var previous = history.get(index);
var tempActionReason = previous.getWorkItem().getMetaDataMap().get('action-message');
if ((tempActionReason != '')&&(tempActionReason != null)) {
actionReason = tempActionReason;
break;
}
}
The process step is not the problem though. Where I'm having trouble is when I try to do the same thing from inside an OR Split.
When I try the same workflowSession.getHistory(workItem.getWorkflow()) in an OR Split, it throws an error saying workItem is not defined.
I've tried storing this property on the payload instead (i.e. storing it under the page's jcr:content), and in that case the property does seem to be available to the OR Split, but my problems with that are:
This reject-or-approve property is only relevant to the current workflow instance, so storing it on the page's jcr:content doesn't really make sense. jcr:content properties will persist after the workflow is closed, and will be accessible to future workflow instances. I could work around this (i.e. don't let workflows do anything based on the property unless I'm sure this instance has written to the property already), but this doesn't feel right and is probably error-prone.
For some reason, when running through the custom dialog in my workflow, only the Admin user group seems to be able to write to the jcr:content property. When I use the dialog as any other user group (which I need to do for this workflow design), the dialog looks as though it's working, but never actually writes to the jcr:content property.
So for a couple of different reasons I'd rather keep this property local to the workflow instance instead of storing it on the page's jcr:content -- however, if anyone can think of a reason why my dialog isn't setting the property on the jcr:content when I use any group other than admin, that would give me a workaround even if it's not exactly the solution I'm looking for.
Thanks in advance if anyone can help! I know this is kind of obscure, but I've been stuck on it for ages.
a couple of days ago i ran into the same issue. The issue here is that you don't have the workItem object, because you don't really have an existing workItem. Imagine the following: you are going through the workflow, you got a couple of workItems, with means, either process step, either inbox item. When you are in an or split, you don't have existing workItems, you can ensure by visiting the /workItems node of the workflow instance. Your workaround seems to be the only way to go through this "issue".
I've solved it. It's not all that elegant looking, but it seems to be a pretty solid solution.
Here's some background:
Dialogs seem to reliably let you store properties either on:
the payload's jcr:content node (which wasn't practical for me, because the payload is locked during the workflow, and doesn't let non-admins write to its jcr:content)
the workItem/metaData for the current workflow step
However, Split steps don't have access to workItem. I found a fairly un-helpful confirmation of that here: http://blogs.adobe.com/dmcmahon/2013/03/26/cq5-failure-running-script-etcworkflowscriptscaworkitem-ecma-referenceerror-workitem-is-not-defined/
So basically the issue was, the Dialog step could store the property, but the OR Split couldn't access it.
My workaround was to add a Process step straight after the Dialog in my workflow. Process steps do have access to workItem, so they can read the property set by the Dialog. I never particularly wanted to store this data on the payload's jcr:content, so I looked for another location. It turns out the workflow metaData (at the top level of the workflow instance node, rather than workItem/metaData, which is inside the /history sub-node) is accessible to both the Process step and the OR Split. So, my Process step now reads the workItem's approveReject property (set by the Dialog), and then writes it to the workflow's metaData node. Then, the OR Split reads the property from its new location, and does its magic.
The way you access the workflow metaData from the Process step and the OR Split is not consistent, but you can get there from both.
Here's some code: (complete with comments. You're welcome)
In the dialog where you choose to approve or reject, the name of the field is set to rejectApprove. There's no ./ or anything before it. This tells it to store the property on the workItem/metaData node for the current workflow step under /history/.
Straight after the dialog, a Process step runs this:
var rejectApprove;
var history = workflowSession.getHistory(workItem.getWorkflow());
// loop backwards through workItems
// and as soon as we find a rejectApprove that is not empty
// store that as 'rejectApprove' and break.
for (var index = history.size() - 1; index >= 0; index--) {
var previous = history.get(index);
var tempRejectApprove = previous.getWorkItem().getMetaDataMap().get('rejectApprove');
if ((tempRejectApprove != '')&&(tempRejectApprove != null)) {
rejectApprove = tempRejectApprove;
break;
}
}
// steps up from the workflow step into the workflow metaData,
// and stores the rejectApprove property there
// (where it can be accessed by an OR Split)
workItem.getWorkflowData().getMetaData().put('rejectApprove', rejectApprove);
Then after the Process step, the OR Split has the following in its tabs:
function check() {
var match = 'approve';
if (workflowData.getMetaData().get('rejectApprove') == match) {
return true;
} else {
return false;
}
}
Note: use this for the tab for the "approve" path, then copy it and replace var match = 'approve' with var match = 'reject'
So the key here is that from a Process step:
workItem.getWorkflowData().getMetaData().put('rejectApprove', rejectApprove);
writes to the same property that:
workflowData.getMetaData().get('rejectApprove') reads from when you execute it in an OR Split.
To suit our business requirements, there's more to the workflow I've implemented than just this, but the method above seems to be a pretty reliable way to get values that are entered in a dialog, and access them from within an OR Split.
It seems pretty silly that the OR Split can't access the workItem directly, and I'd be interested to know if there's a less roundabout way of doing this, but for now this has solved my problem.
I really hope someone else has this same problem, and finds this useful, because it took me waaay to long to figure out, to only apply it once!

SSRS ReportingService2010 change embedded DataSource to shared DataSource

I have SQL Server 2008 with SSRS installed on one server and SQL Server 2008 R2 with SSRS installed on a new server. I want to migrate 200+ reports as well as a few shared schedules and a couple data sources from the first server to the second one using the SSRS web service API. For simplicity sake since there are only a couple of shared data sources I went ahead and created those using the Report Manager interface.
Unfortunately, those who came before me embedded the data source information in each report (connection string, login, password, etc). I thought this would be a great time to change these to point to the shared data source so this would not have to be done for each report, one by one. I can create the reports on the new server just fine using CreateCatalogItem but I can't seem to determine how to properly go about changing from an embedded data source to a shared data source.
So far I have tried both SetItemReferences:
itemRef.Reference = "/Data Sources/TMS";
itemRef.Name = "TMS";
itemRef.Reference = "/Data Sources/TMS";
rs2010.SetItemReferences(catItem.Path, new ReportService2010.ItemReference[] { itemRef });
and SetItemDataSources:
ReportService2010.DataSourceReference dataSourceRef = new ReportService2010.DataSourceReference();
dataSourceRef.Reference = "/Data Sources/TMS";
ReportService2010.DataSource dataSource = new ReportService2010.DataSource();
dataSource.Name = "TMS";
dataSource.Item = dataSourceRef;
rs2010.SetItemDataSources(catItem.Path, new ReportService2010.DataSource[] { dataSource });
Both methods result in a "NotFoundException" when attempted on a report with an embedded data source but they both work just fine on reports that are already pointing to a shared data source.
Furthermore, I have searched all over Google as well as StackOverflow for a solution but have found nothing. Can anyone point me in the right direction here?
So I kept working with the SetItemReferences method and had a brilliant idea that ended up working. The final code I used is below:
List<ReportService2010.ItemReference> itemRefs = new List<ReportService2010.ItemReference>();
ReportService2010.DataSource[] itemDataSources = rs2010.GetItemDataSources(catItem.Path);
foreach (ReportService2010.DataSource itemDataSource in itemDataSources)
{
ReportService2010.ItemReference itemRef = new ReportService2010.ItemReference();
itemRef.Name = itemDataSource.Name;
itemRef.Reference = "/Data Sources/TMS";
itemRefs.Add(itemRef);
}
rs2010.SetItemReferences(catItem.Path, itemRefs.ToArray());
The problem was that I was not using the same DataSource name as what was found in the report .rdl file. I was able to determine what the name should be using the GetItemDataSources method. Since this method returns an array and may have more than one item in said array, I looped through it to create multiple ItemReferences if more than one existed though I doubt that happens very often if at all.

How can I Diff a Svn Repository using SharpSvn

My question is quite simple and with the SharpSvn Api, it should be easy as well. Here what I did:
path = "c:\project";
using (SvnLookClient client = new SvnLookClient())
{
SvnLookOrigin o = new SvnLookOrigin(path);
Collection<SvnChangedEventArgs> changeList;
client.GetChanged(o, out changeList); // <-- Exception
}
and when I call the GetChanged, I get an exception:
Can't open file 'c:\project\format': The system cannot find the file specified.
So, Maybe there is something I'm missing? Or maybe it's not the right way to do find out the list of files and folders that were modified in the local repository?
Thanks in advance.
The SvnLookClient class in SharpSvn is the equivalent to the 'svnlook' console application. It is a low level tool that enables repository hooks to look into specific transactions of a repository using direct file access.
You probably want to use the SvnClient class to look at a WorkingCopy and most likely its Status() or in some cases simpler GetStatus() function to see what changed.
The path that the SvnLookOrigin constructor wants is actually:
path = "c:\project\.svn\";
That is, it wants that special ".svn" directory not just the root of where the source is checked out to.
Although you probably do want to listen to Bert and do something like:
path = "c:\project";
using (SvnLookClient client = new SvnLookClient())
{
SvnLookOrigin o = new SvnLookOrigin(path);
Collection<SvnChangedEventArgs> changeList;
client.GetStatus(o, out changeList); // Should now return the differences between this working copy and the remote status.
}