How to get Workspace object in new TeamFoundation 2013 Templates - c#

In new version of TeamFoundation 2013 default build templates, the Workspace variable is missing. It is needed as intput parameter for few key activities like ConvertWorkspaceItem. How do I get current workspace for TfvcTemplate.12.xaml templates? I've tried to use this msdn thread but it's not working for me (returns null workspace name). Any suggestions?

There's a new activity in 2013 called GetLocalPath that replaces ConvertWorkspaceItem.
The activity is under the Microsoft.TeamFoundation.Build.Activities.Core namespace in the Microsoft.TeamFoundation.Build.Activities assembly.
It uses the LocalPathProvider class that aggregates all workspaces used in the build and exposes path translation for all of them in one place. This basically removes the dependency of knowing the workspace in order to translate server paths to local paths and allows you to use as many workspaces as you want without worrying about breaking something down the line.
When MS takes something away, it's usually for a good reason. "hacking" is really not necessary.

I went with a hack using internal classes from Microsoft.TeamFoundation.Build.Activities.dll (used by microsoft to create workspace name). You need to create custom activity with following code:
public sealed class GetDefaultWorkspace : BaseActivity<Workspace>
{
public override Activity CreateBody()
{
var type = typeof(TfGetSources).Assembly.GetType("Microsoft.TeamFoundation.Build.Activities.TeamFoundation.TfGetSources+GetDefaultWorkspaceName");
var activity = (CodeActivity<string>)Activator.CreateInstance(type);
var sequence = new Sequence();
var workspaceName = new Variable<string>();
sequence.Variables.Add(workspaceName);
sequence.Activities.Add(activity);
activity.Result = (OutArgument<string>) workspaceName;
sequence.Activities.Add(new GetWorkspace
{
Name = workspaceName,
Result = new LambdaReference<Workspace>(ctx => Result.Get(ctx))
});
return sequence;
}
}

This answer might work better for some people. ghord's answer works well, and passes the Workspace back where it can be used in the XAML. However, for my purposes I only want the workspace in my custom TFS activities, so I ended up with this alternative...
public sealed class CustomActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
// get workspace
var buildDetail = context.GetExtension<IBuildDetail>();
var buildAgent = context.GetExtension<IBuildAgent>();
var buildDirectory = buildAgent.GetExpandedBuildDirectory(buildDetail.BuildDefinition);
var workspacePath = Path.Combine(buildDirectory, "src");
var wsInfo = Workstation.Current.GetLocalWorkspaceInfo(workspacePath);
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsInfo.ServerUri);
tfs.Connect(ConnectOptions.None);
var vcs = tfs.GetService<VersionControlServer>();
// finally can get to the workspace here
var workspace = vcs.GetWorkspace(workspacePath);
}
}
Using this method, I don't have to have an activity that just returns the workspace, and then have to pass the workspace into other TFS activities. I just get the workspace from within my own activity while it runs.

I believe the method employed here will use the already downloaded workspace. Keep in mind, that this approach will only work within the scope of "Run on agent" sequence after "Initialize Environment" and before ResetEnvironment within the finally statement of Try Compile, Test, Publish. Else, the workflow will have no knowledge of a sources directory.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/420ba073-bdf5-4ab4-88da-c84561d1a1ba/creating-dynamic-working-folder-in-tfs2013-defaulttemplate?forum=tfsbuild

Related

Fake Xrm Easy: How to emulate a plugin's behaviour on orgService.Create()?

Microsoft Dynamics CRM 2015.
I test Asp.Net Core controller's action. When I create new Lead record some plugin generates new Guid for lead.new_master_id field (it's type is string). Therefore after creating I retrive the record to get it's generated new_master_id value. How can I emulate this plugin behaviour through Fake Xrm Easy?
var fakedContext = new XrmFakedContext();
fakedContext.ProxyTypesAssembly = typeof(Lead).Assembly;
var entities = new Entity[]
{
// is empty array
};
fakedContext.Initialize(entities);
var orgService = fakedContext.GetOrganizationService();
var lead = new Lead { FirstName = "James", LastName = "Bond" };
var leadId = orgService.Create(lead);
var masterId = orgService.Retrieve(Lead.EntityLogicalName, leadId,
new Microsoft.Xrm.Sdk.Query.ColumnSet(Lead.Fields.new_master_id))
.ToEntity<Lead>().new_master_id;
In v1.x of FakeXrmEasy you'll need to enable PipelineSimulation and register the plugin steps you would like to be fired on Create manually by registering their steps.
fakedContext.UsePipelineSimulation = true;
Once enabled, you'll need to enable the necessary steps via calling RegisterPluginStep. In your example you'll need to at least register something along the lines of:
fakedContext.RegisterPluginStep<LeadPlugin>("Create", ProcessingStepStage.Preoperation);
Where LeadPlugin would be the name of your plugin that generates the new_master_id property.
Keep in mind v1.x is limited in that it supports pipeline simulation for basic CRUD requests only.
Later versions (2.x and/or 3.x) come with a brand new middleware implementation allowing registering plugin steps for any message. Soon we'll be implementing automatic registration of plugin steps based on an actual environment and/or custom attributes.
Here's an example using the new middleware
public class FakeXrmEasyTestsBase
{
protected readonly IXrmFakedContext _context;
protected readonly IOrganizationServiceAsync2 _service;
public FakeXrmEasyTestsBase()
{
_context = MiddlewareBuilder
.New()
.AddCrud()
.AddFakeMessageExecutors()
.AddPipelineSimulation()
.UsePipelineSimulation()
.UseCrud()
.UseMessages()
.Build();
_service = _context.GetAsyncOrganizationService2();
}
}
You can find more info on the QuickStart guide here
Disclaimer: I'm the author of FakeXrmEasy :)

How to move static members between classes in Roslyn? (C#)

As a small step in part of a larger obfuscation process, I'd like to move all static members in the project into one class and update references accordingly.
I'm aware that on its own, this kind of obfuscation isn't very strong but it's only one step of a larger process and also partly a learning exercise.
I'm also aware that this will impact code quality but it will only be a step in a build process and the results won't be committed.
I've gotten part way which I will share below:
public async Task Run(string solutionPath)
{
// Create a workspace to allow loading our solution
m_workspace = MSBuildWorkspace.Create();
// Load our target solution
Solution solution = await m_workspace.OpenSolutionAsync(solutionPath);
// Find all projects in the solution
var projects = solution.Projects;
// Get the first project
var project = projects.FirstOrDefault();
// Enumerate through documents in the project
foreach (var document in project.Documents)
{
// Get our syntax tree representation of the document
var syntaxTree = await document.GetSyntaxTreeAsync();
var semanticModel = await document.GetSemanticModelAsync();
// Find all classes and pass them to be renamed
var classes = syntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var c in classes)
{
foreach (var member in c.Members)
{
if (//How to check if the member is static?)
{
var symbol = semanticModel.GetSymbolInfo(member).Symbol;
var references = await SymbolFinder.FindReferencesAsync(symbol, solution);
//How to move the member to another class and update the references?
}
}
}
}
// When completed, apply changes to our solution
m_workspace.TryApplyChanges(solution);
}
This mostly was derived from here: https://blog.xpnsec.com/building-modifying-packing-devops/
How can I check if a member is static or not in Roslyn?
How can I move the member to another class and update the references?

How to get all installations when using Azure Notification Hubs installation model?

Using NotificationHubClient I can get all registered devices using GetAllRegistrationsAsync(). But if I do not use the registration model but the installation model instead, how can I get all installations? There are methods to retrieve a specific installation but none to get everything.
You're correct, as of July 2016 there's no way to get all installations for a hub. In the future, the product team is planning to add this feature to the installations model, but it will work in a different way. Instead of making it a runtime operation, you'll provide your storage connection string and you'll get a blob with everything associated with the hub.
Sorry for visiting an old thread... but in theory you could use the GetAllRegistrationsAsyc to get all the installations. I guess this will return everything without an installation id as well, but you could just ignore those if you choose.
Could look something like this
var allRegistrations = await _hub.GetAllRegistrationsAsync(0);
var continuationToken = allRegistrations.ContinuationToken;
var registrationDescriptionsList = new List<RegistrationDescription>(allRegistrations);
while (!string.IsNullOrWhiteSpace(continuationToken))
{
var otherRegistrations = await _hub.GetAllRegistrationsAsync(continuationToken, 0);
registrationDescriptionsList.AddRange(otherRegistrations);
continuationToken = otherRegistrations.ContinuationToken;
}
// Put into DeviceInstallation object
var deviceInstallationList = new List<DeviceInstallation>();
foreach (var registration in registrationDescriptionsList)
{
var deviceInstallation = new DeviceInstallation();
var tags = registration.Tags;
foreach(var tag in tags)
{
if (tag.Contains("InstallationId:"))
{
deviceInstallation.InstallationId = new Guid(tag.Substring(tag.IndexOf(":")+1));
}
}
deviceInstallation.PushHandle = registration.PnsHandle;
deviceInstallation.Tags = new List<string>(registration.Tags);
deviceInstallationList.Add(deviceInstallation);
}
I am not suggesting this to be the cleanest chunk of code written, but it does the trick for us. We only use this for debugging type purposes anyways

FluentMigrator Versioning Refresh Views

I am using Fluent Migrator for keeping the database updated. The Up and Down functions works perfectly. Next step is that I want views to be created. These I would like to run from an .SQL file which i have. I want this to be run after all migrations has been run, everytime.
What i have currently is:
var blah = new MigrationConventions();
var maintenanceLoader = new MaintenanceLoader(_migrate, blah);
maintenanceLoader.ApplyMaintenance(MigrationStage.AfterAll);
and a class
[Maintenance(MigrationStage.AfterAll)]
public class ViewMaintenance
{
public ViewMaintenance() {
var blah = 123;
}
}
This is not fired because in maintenanceLoader there are 0 elements that it can find. I am inserting the _migrate, which is defined like this:
var runnerContext = new RunnerContext(new TextWriterAnnouncer(UpdateText));
_migrate = new MigrationRunner(
Assembly.GetExecutingAssembly(),
runnerContext,
new SqlServerProcessor(
new SqlConnection(connectionString),
new SqlServer2012Generator(),
new TextWriterAnnouncer(UpdateText),
new ProcessorOptions(),
new SqlServerDbFactory()));
Why can't the Assembly.GetExecutingAssembly() be scanned, and find the [Maintenance(MigrationStage.AfterAll)] be found?
I would also like for the ViewMaintenance class to be able to run the Execute.Sql( that the Migration classes has.
I downloaded the source code and figured it out.
In the class I want the maintenance to be run, I need to inherit from the : Migration class, just like with migrations (duh..). It will then have access to everything it has access to in migrations, including Execute.Sql(.
When it is inherited from, the Reflection in Fluent Migrator will search for it, find it, and use the attribute that is set to run it after all migrations is run.
This part is not needed:
var blah = new MigrationConventions();
var maintenanceLoader = new MaintenanceLoader(_migrate, blah);
maintenanceLoader.ApplyMaintenance(MigrationStage.AfterAll);
Neat :)

How to make this Unit Testable

Below I have some code that that I cannot Unit test because it tries to read settings from IIS7 and unfortunately our nightly build machine does not have IIS7. The only thing I can think of is to pass the ServerManager into the method, but then again in the caller I will have a ServerManager that will make that method unable to be unit tested. We use MOQ for our Mock library.
public ISection GetCurrentSettings(string location, Action<string> status)
{
#region Sanity Checks
if (string.IsNullOrEmpty(location))
{
throw new ArgumentNullException("location");
}
if (status == null)
{
throw new ArgumentNullException("status");
}
#endregion
ISection section = null;
_logger.Debug(string.Format("Retrieving current IIS settings for app at {0}.", location));
status("Getting current IIS settings.");
using (ServerManager manager = new ServerManager())
{
var data = (from site in manager.Sites
from app in site.Applications
from vdir in app.VirtualDirectories
where vdir.PhysicalPath.Equals(location, StringComparison.CurrentCultureIgnoreCase)
select new {Website = site, App = app}).SingleOrDefault();
if (data == null)
{
_logger.Debug(string.Format("Could not find an application at {0} in IIS. Going to load the defaults instead.", location));
//ToDo possibly load defaults
}
else
{
_logger.Debug(string.Format("Application found in IIS with website: {0} and a path of {1}", data.Website.Name, data.App.Path));
int port =
data.Website.Bindings.Where(b => b.EndPoint != null).Select(b => b.EndPoint.Port).Single();
section = new IISSection
{
ApplicationPoolName = data.App.ApplicationPoolName,
VirtualDirectoryAlias = data.App.Path,
WebsiteName = data.Website.Name,
WebsiteRoot = data.App.VirtualDirectories[0].PhysicalPath,
Port = port.ToString(CultureInfo.InvariantCulture),
WillApply = true,
AnonymousUser = _userService.GetUserByType(UserType.Anonymous)
};
}
return section;
}
Without rewriting your code fully, the general idea would be to pass in an ISettingReader* (implemented as IisSettingReader), which would expose methods that would get the data you need from IIS. Then, you can stub in the ISettingReader to return what you need, by passing ISettingReader into the method/class
*Or, IServerManager as it seems to be the current name, but I am not sure if that is IIS specific
UPDATE
To be more specific, as Darin Dimitrov elaborated, you need to pull all of the dependencies outside of the method and pass them in via parameter/constructor/property injection. This will require a rewrite of the code as it stands in its current state.
If not (and I do suggest a rewrite), then you can use something like TypeMock, which supposedly can fake the dependencies INSIDE a class, but I have not used this myself and only know what I have read on it.
Use Moq.
This will allow you to create a mocked version of ISettings rather than having to create a real one. It has the added advantage of allowing you to specify your own functionality as well.

Categories

Resources