CodeActivity integration with TFS2015 - tfs

I've included custom code activities in TFS2012 and below.
In the "new world" changes in TFS2015, (non-work-flow driven)......I cannot figure out how to add a custom activity.
Now do I integrate the below into a TFS 2015 build?
using System.Activities;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow.Activities;
namespace MyCompany.TFS.CodeCoverageLibrary
{
[BuildExtension(HostEnvironmentOption.All)]
[BuildActivity(HostEnvironmentOption.All)]
public sealed class SimpleCodeActivity : CodeActivity<bool>
{
protected override bool Execute(CodeActivityContext context)
{
context.TrackBuildMessage(string.Format("ActivityInstanceId='{0}', WorkflowInstanceId='{1}'", context.ActivityInstanceId, context.WorkflowInstanceId));
return true;
}
}
}

You don't. The new build system is a complete, ground-up rewrite. XAML build activities won't work in the new build system, although they will continue to work in the XAML build system.
The new task system is based on JSON descriptor files with activities written as PowerShell (for Windows) or Node JS (for cross-platform). You can see examples of the task library on GitHub: https://github.com/Microsoft/vsts-tasks

Related

.net core console application using TopShelf

I have created a .net core console application using TopShelf. But I got an error when running the application using docker (alpine-linux).
Configuration Result:
[Success] Name MyApp
[Success] DisplayName MyApp
[Success] Description My Application
[Success] ServiceName MyApp
Topshelf v4.1.0.177, .NET Framework v4.0.30319.42000
Topshelf.Runtime.Windows.WindowsHostEnvironment Error: 0 : Unable to get parent process (ignored), System.DllNotFoundException: Unable to load shared library 'kernel32.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: Error loading shared library libkernel32.dll: No such file or directory
at Topshelf.Runtime.Windows.Kernel32.CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID)
at Topshelf.Runtime.Windows.WindowsHostEnvironment.GetParent(Process child)
Topshelf.HostFactory Error: 0 : The service terminated abnormally, System.PlatformNotSupportedException: ServiceController enables manipulating and accessing Windows services and it is not applicable for other operating systems.
at System.ServiceProcess.ServiceController.GetServices()
at Topshelf.Runtime.Windows.WindowsHostEnvironment.IsServiceListed(String serviceName)
at Topshelf.Hosts.ConsoleRunHost.Run()
at Topshelf.HostFactory.Run(Action`1 configureCallback)
How to solve this issue? I need to run my console application as a windows service
The Topshelf documentation is pretty specific:
To work with Topshelf you will need to be running on a Windows operating system. The developers of Topshelf regulary test on Windows 7 and Windows Server 2008RC2. Though it should still work on Windows Server 2003, as long as .Net 3.5 sp1 is installed.
The good news is that writing Linux daemons is easier than Windows Services - all they have to be is basically a console application where you control the main loop.
If I got your problem statement correctly, you want to be able to run one service both in Windows and in Docker. In this case it seems the easiest way will be to examine your OS environment on start up with something like System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform()
and either defer your main work to Topshelf or run it Linux-style. For the example below I installed Microsoft.Extensions.Hosting package and opted for implementing an IHostedService (which Topshelf can conveniently reuse)
public class YourHostedService : IHostedService, IDisposable
{
private int executionCount = 0;
private Timer _timer;
public YourHostedService()
{
}
public Task StartAsync(CancellationToken stoppingToken)
{
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
executionCount++;// this gets called every 5 seconds
}
public Task StopAsync(CancellationToken stoppingToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose() => _timer?.Dispose();
}
public class Program
{
public static async Task Main(string[] args)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var rc = HostFactory.Run(x =>
{
var token = CancellationToken.None;
x.Service<YourHostedService>(s =>
{
s.ConstructUsing(name => new YourHostedService());
s.WhenStarted(tc => tc.StartAsync(token));
s.WhenStopped(tc => tc.StopAsync(token));
});
x.RunAsLocalSystem();
x.SetDescription("TopShelf Host");
x.SetDisplayName("YourHostedService");
x.SetServiceName("YourHostedService");
});
}
else
{
await Host.CreateDefaultBuilder(args)
.ConfigureServices(builder =>
{
builder.AddHostedService<YourHostedService>();
})
.RunConsoleAsync();
}
}
}
More inspiration can be drawn from here.
UPD So it seems your particular case can also be solved by running arbitrary (well, in this case your) program as Windows service.
In this case you've got some options that don't involve programming but rather config writing:
The Microsoft's own tool SrvAny that's been part of NT Resource Kit: you basically install it as a dummy service and edit the registry setting to point to your .exe
A 3rd party tool SrvStart: this one's relatively easy to pick up as well, and config is similar to the above
So your requirement is to run a dotnet core (which version?) application as a windows service.
TopShelf might not be the right tool for this, as it supports .NET Framework 4.0 or Mono, not dotnet core.
Since you want to run a windows service, it does not make any sense to publish your app as a Linux Docker image! Use sc create and sc start to register and start your published executable instead.
Topshelf is not a good choice for .NET Core because .Net Core has powerful facilities for build Windows Service. Furthermore, TopShelf is only supporting Windows.
See Examples:
https://medium.com/#tocalai/create-windows-service-using-net-core-console-application-dc2f278bbe42
https://codeburst.io/create-a-windows-service-app-in-net-core-3-0-5ecb29fb5ad0

Choice for build tool: MSBuild, NANT or something else?

I am doing automation in my company. We are a C# workshop.
Currently I am working on automated build. NANT is flow control tool. While NANT is not actively developed (last binary released on June 2012 and github repo is not active), MSBuild is better. Therefore, I prefer MSBuild but retiring NANT is still questionable - what is the cost?
I have come up with some pros and cons, but I know collective intelligence is better. Thanks for your help!
Update:
I have read the question, but the second answer rises a concern for me. On build machine there are multiple .NET frameworks, will it be troublesome?
MSBuild
Pros:
Commercial support
Community is growing
Intergrated with VS and TFS
Keep pace with .Net
Cons:
Rewrite current script
Not familiar by people
NANT
Pros:
Already in use
Familiar by people
Cons:
Not updated for a long time (since 2012)
Community is not active
Lack of new .Net support
We wrote FlubuCore (rewrite of Flubu). It's an open source C# library for building projects and executing deployment scripts using C# code.
Main advantages of flubu that I see are:
.Net Core support.
Easy to learn and to use because you write build script entirely in C#.
Fluent interface and intelisense.
Quite a lot of built in tasks (compile, running tests, managing iis, creating deploy package, publishing nuget packages, executing powershell scripts...)
Write your own custom c# code in script and execute it..
Run any external program or command in script with RunProgramTask.
Reference any .net library or c# source code file in buildscript. Now also available option to reference nuget package in build script.
Write tests, debug your build script..
Use flubu tasks in any other .net application.
Web api is available for flubu. Useful for automated deployments remotely.
Write your own flubu tasks and extend flubu fluent interface with them.
You can find flubu on nuget:
Search for FlubuCore.Runner if u need it for .net project
Search for dotnet-flubu if u need it for.net core project
Example of how flubu is used in .net:
protected override void ConfigureBuildProperties(IBuildPropertiesContext context) {
context.Properties.Set(BuildProps.NUnitConsolePath,
# "packages\NUnit.ConsoleRunner.3.6.0\tools\nunit3-console.exe");
context.Properties.Set(BuildProps.ProductId, "FlubuExample");
context.Properties.Set(BuildProps.ProductName, "FlubuExample");
context.Properties.Set(BuildProps.SolutionFileName, "FlubuExample.sln");
context.Properties.Set(BuildProps.BuildConfiguration, "Release");
}
protected override void ConfigureTargets(ITaskContext session) {
var loadSolution = session.CreateTarget("load.solution")
.SetAsHidden()
.AddTask(x => x.LoadSolutionTask());
var updateVersion = session.CreateTarget("update.version")
.DependsOn(loadSolution)
.SetAsHidden()
.Do(TargetFetchBuildVersion);
session.CreateTarget("generate.commonassinfo")
.SetDescription("Generates common assembly info")
.DependsOn(updateVersion)
.TaskExtensions().GenerateCommonAssemblyInfo()
var compile = session.CreateTarget("compile")
.SetDescription("Compiles the solution.")
.AddTask(x => x.CompileSolutionTask())
.DependsOn("generate.commonassinfo");
var unitTest = session.CreateTarget("unit.tests")
.SetDescription("Runs unit tests")
.DependsOn(loadSolution)
.AddTask(x => x.NUnitTaskForNunitV3("FlubuExample.Tests"));
session.CreateTarget("abc").AddTask(x => x.RunProgramTask(# "packages\LibZ.Tool\1.2.0\tools\libz.exe"));
session.CreateTarget("Rebuild")
.SetDescription("Rebuilds the solution.")
.SetAsDefault()
.DependsOn(compile, unitTest);
}
//// Some custom code
public static void TargetFetchBuildVersion(ITaskContext context) {
var version = context.Tasks().FetchBuildVersionFromFileTask().Execute(context);
int svnRevisionNumber = 0; //in real scenario you would fetch revision number from subversion.
int buildNumber = 0; // in real scenario you would fetch build version from build server.
version = new Version(version.Major, version.Minor, buildNumber, svnRevisionNumber);
context.Properties.Set(BuildProps.BuildVersion, version);
}
Example of how flubu is used in .net core
public class MyBuildScript : DefaultBuildScript
{
protected override void ConfigureBuildProperties(IBuildPropertiesContext context)
{
context.Properties.Set(BuildProps.CompanyName, "Flubu");
context.Properties.Set(BuildProps.CompanyCopyright, "Copyright (C) 2010-2016 Flubu");
context.Properties.Set(BuildProps.ProductId, "FlubuExample");
context.Properties.Set(BuildProps.ProductName, "FlubuExample");
context.Properties.Set(BuildProps.SolutionFileName, "FlubuExample.sln");
context.Properties.Set(BuildProps.BuildConfiguration, "Release");
}
protected override void ConfigureTargets(ITaskContext context)
{
var buildVersion = context.CreateTarget("buildVersion")
.SetAsHidden()
.SetDescription("Fetches flubu version from FlubuExample.ProjectVersion.txt file.")
.AddTask(x => x.FetchBuildVersionFromFileTask());
var compile = context
.CreateTarget("compile")
.SetDescription("Compiles the VS solution and sets version to FlubuExample.csproj")
.AddCoreTask(x => x.UpdateNetCoreVersionTask("FlubuExample/FlubuExample.csproj"))
.AddCoreTask(x => x.Restore())
.AddCoreTask(x => x.Build())
.DependsOn(buildVersion);
var package = context
.CreateTarget("Package")
.CoreTaskExtensions()
.DotnetPublish("FlubuExample")
.CreateZipPackageFromProjects("FlubuExample", "netstandard2.0", "FlubuExample")
.BackToTarget();
//// Can be used instead of CreateZipPackageFromProject. See MVC_NET4.61 project for full example of PackageTask
//// context.CreateTarget("Package2").AddTask(x =>
x.PackageTask("FlubuExample"));
var test = context.CreateTarget("test")
.AddCoreTaskAsync(x => x.Test().Project("FlubuExample.Tests"))
.AddCoreTaskAsync(x => x.Test().Project("FlubuExample.Tests2"));
context.CreateTarget("Rebuild")
.SetAsDefault()
.DependsOn(compile, test, package);
}
}
Detailed presentation and documentation can be found here:
https://github.com/flubu-core/flubu.core
You can find full examples here:
https://github.com/flubu-core/examples
Thanks for all answers. We have decided to use Cake since we are a C# workshop.
There is a property nant.settings.currentframework which is used to set target framework in case you have multiple .net framework
<property name="nant.settings.currentframework" value="net-2.0" />
As per .92 build:
nant.settings.currentframework The current target framework, eg. 'net-1.0'.
nant.settings.currentframework.description Deprecated. Description of the current target framework.
nant.settings.currentframework.frameworkdirectory Deprecated. The framework directory of the current target framework.
nant.settings.currentframework.sdkdirectory Deprecated. The framework SDK directory of the current target framework.
nant.settings.currentframework.frameworkassemblydirectory Deprecated. The framework assembly directory of the current target framework.
nant.settings.currentframework.runtimeengine Deprecated. The runtime engine of the current target framework if used eg. mono.exe.

How to execute a function at the end of all specification files have been executed using spock framework

Problem statement:
How to execute a function at the end of all specification files have been executed using spock framework.
Explantion: I am using geb-spock framework for automation.
I have few specification files. I want to run a function after all specification files have been executed.
I want something like AfterSuite in TestNG. How can i get the feature of AfterSuite in spock. cleanupSpec will be called after every specification file is executed.
Thanks,
Debasish
The simple answer is: no. There's nothing like before or after suite methods in spock since spock is JUnit based and JUnit does not handle such methods. If you siÄ™ tool like maven or gradle maybe you can use task's lifecycle methods.
You can use the JUnit 4 SuiteRunner Look at this answer
#RunWith(Suite.class)
#SuiteClasses({ TestSpec.class, TestSpec.class })
public class CompleteTestSuite {
#BeforeClass
public static void setUpClass() {
System.out.println("Master setup");
}
#AfterClass public static void tearDownClass() {
System.out.println("Master tearDown");
}
}
If you are using build tool as for example Gradle you may wire it on a build configuration level after tests are finished.

How to get build definition from TFS and pass it to the external program

How to get build definition from TFS and pass it to the external program
This is what we are doing manually:
1) Queue new build
2) Once build is completed go to the drop folder and get the exe name
3) pass this exe name to the test automation program and run it.`
I want to automate these 3 steps.
Is it possible to get the build definition programatically?
Create a custom Build Template. Use a copy of the default (or what ever you're using now) as your starting point. Look in the work flow where BuildDetail.CompilationStatus = BuildPhaseStatus.Succeeded. You will then have the opportunity to invoke another application, it would be a stub program/powershell script/any other executable process. you can pass the path of the build that you just completed by using BuildDetail.DropLocation.
Assuming that your step #1 has executed, this latest (successful!) build is reachable as the lastKnownGoodBuild of the specific build definition.With this in mind you can employ a console app that bases on the following:
using System;
using System.IO;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
namespace BuildDropLocation
{
class Program
{
static void Main()
{
TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://yourTFSServerUri"));
var buildService = (IBuildServer)teamProjectCollection.GetService(typeof(IBuildServer));
IBuildDefinition myBuildDefinition = buildService.GetBuildDefinition("TeamProjectName", "BuildDefinitionName");
Uri lastKnownGoodBuild = myBuildDefinition.LastGoodBuildUri;
IBuildDetail myBuildDetail = buildService.GetBuild(lastKnownGoodBuild);
string[] myExeFiles = Directory.GetFiles(myBuildDetail.DropLocation, "*.exe",SearchOption.AllDirectories);
foreach (var exeFile in myExeFiles)
{
Console.WriteLine(myExeFile);
}
}
}
}
With the above you can retrieve the path to any *.exe under the drop location of the last build of build definition BuildDefinitionName that lives in Team Project TeamProjectName.This approach allows you to fully separate your TFS-Build with the execution of your tests. You can, for example, schedule this console-app to execute every night and invoke your runner to operate on the latest successful build.In case you would like the build and the testrun to be coupled in any way, you should proceed as #TimWagaman suggests by invoking your test runner during build. This 'coupling' might include:
The test results are contained in the build log
A failure generates a Bug
Test coverage is reportable
In this case, your tests will execute with each and every build that doesn't break in the compilation phase.
<MakeDir Directories="$(TemporaryFolder)" />
<Exec Condition=" '$(IsInTeamBuild)'=='True'" Command=""$(TfsTask)" history ../ /r /noprompt /stopafter:1 /version:W > "$(TemporaryFolder)\grab-changeset.txt"" />
<Exec Condition=" '$(IsInTeamBuild)'=='True'" Command=""$(TfsTask)" properties "$(MyMSBuildStartupDirectory)\all-companies-run-after-update.js" > "$(TemporaryFolder)\grab-properties.txt"" />
We use the above to extract: build#, branch, revision#
from the generated .txt files.

Unit Test Adapter threw exception: Unable to load one or more... in ASP.NET MVC

Using ASP.NET MVC 1.0 (current) I create a new default ASP.NET MVC project using Visual Studio 2008 on an x64 machine (Server 2008) and accept all the defaults and build and run it. Apart from having to set the System.Web.* assemblies as "Copy Local" it runs and brings up the default web app. When I try and run the unit tests on this project I get:
Unit Test Adapter threw exception: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information..
Now if I repeat the same exercise using VS2008 on an x86 machine (Server 2003) then all 27 default unit tests run fine. (Also I don't need to mark the System.Web.* assemblies as "Copy Local")
Ideas for resolving the exception?
More Info:
After trying some of the solutions suggested I started commenting out parts of the boilerplate test code that is generated with a new project. As such, I believe that the error is being generated by the inclusion of one of the following classes:
public class MockIdentity : IIdentity
{
public string AuthenticationType
{
get
{
return "MockAuthentication";
}
}
public bool IsAuthenticated
{
get
{
return true;
}
}
public string Name
{
get
{
return "someUser";
}
}
}
public class MockPrincipal : IPrincipal
{
IIdentity _identity;
public IIdentity Identity
{
get
{
if (_identity == null)
{
_identity = new MockIdentity();
}
return _identity;
}
}
public bool IsInRole(string role)
{
return false;
}
}
public class MockMembershipUser : MembershipUser
{
public override bool ChangePassword(string oldPassword, string newPassword)
{
return newPassword.Equals("newPass");
}
}
public class MockHttpContext : HttpContextBase
{
private IPrincipal _user;
public override IPrincipal User
{
get
{
if (_user == null)
{
_user = new MockPrincipal();
}
return _user;
}
set
{
_user = value;
}
}
}
First, have you tried it in Release configuration? Have you done a clean on your solution?
Have you tried constructing your test project? Take out the source files for your tests, delete the project from your solution and add a new test project that references the MVC app. Then re-add the test source files.
Edit
Are the classes and interfaces that you are using and implementing in scope from your tests?
Edit
Is it referencing the x64 not the x86 dlls?
Do you have VS 2008 SP1 and .NET 3.5 SP1 installed in your Win2k8 box? By default VS 2008 installed 3.5 framework, but NOT SP1. Make sure you have both the framework SP1 and VS 2008 SP1 installed.
Did you try building your project as x86 project (Project properties ->Build ->Platform target) on x64 machine?
Also, not sure about your unit testing toolkit, but NUnit, for example, can run as tests as either x86 or x64 (on x64 machine). If one of your assemblies accesses some 32-bit code (e.g. COM object), trying to run them under x64 will result in "Unable to load one or more of the requested types" error.
I'm not sure about the subtleties of what's going on with the x64 verus x86, but using custom identity/principals can cause some interesting little glitches to happen, especially if using cassini (the built-in vshost webserver - which I think is what you end up using by running local unit tests within VS). I ran into this issue before, and rather than detailing it here, I'll post a link to some good info. Again, I'm not sure if this is related to your problem (my not being an MVC guru), but take a read through this. Food for thought:
http://www.lhotka.net/weblog/UpdateOnMyStrugglesWithTheASPNETDevelopmentServer.aspx
EDIT: so ultimately, this may be an issue of serialization failure, even if this particular edge case is not relevant. Have you tried marking your mocked iidentity/iprincpal objects as [serializable]? Remember that visual studio is a 32bit application; perhaps testing it on IIS (if not cassini) with a 64bit application pool is causing a context switch somewhere which causes the mock identities (if they get assigned as a thread's identity) to get marshalled across a boundary like that - the lack of a [serializable] attribute will probably cause a TypeLoadException.
Does it still throw if you set IIS to use a 32bit application pool (on your 64bit server)?
-Oisin
I'm wondering if the more significant difference is 2k8 vs 2k3 than 64 vs 32bit. Did you spawn Visual Studio as Administrator? An assembly might be missing due to the Virtual Store of windows 2k8. If this is a development desktop running 2k8 you might want to consider disabling the Virtual Store, it's in you policy labeled as "User Account Control: Virtualize file and registry write failures to per-user locations"
I notice some of the types (specifically IIdentity and IPrincipal) you are implementing are not located within a System.Web.* assembly.
Have you tried marking the System.Security.Principal assembly as "Copy Local"?
This reminded me of an old blog post I once read. Perhaps you can use the same technique to debug the cause of the error:
http://www.agileprogrammer.com/oneagilecoder/archive/2007/11/17.aspx

Resources