Build cannot be found when publishing results to TFS - c#

I'm attempting to publish test results to Microsoft Test Manager through TFS but I'm getting the following error when attempting to publish results through the TFS API:
Microsoft.TeamFoundation.TestManagement.Client.TestObjectNotFoundException:
Build vstfs:///Build/Build/### cannot be found.
I'm getting my test plan and creating a test run the way Microsoft suggests:
plan = teamProject.TestPlans.Query(
"SELECT * FROM TestPlan WHERE PlanName = '" + planName + "')[0];
ITestRun run = plan.CreateTestRun(true);
run.AddTestPoints(testPoints, null);
run.Save();
So why is it saying the build can't be found?

Builds are periodically cleared out of the system so you may want to be sure you're using the latest build. You can then get the latest builds URI and associate it with your run.
Uri GetLatestBuildURI(string projectName) {
Uri buildUri = null;
IBuildServer buildServer = _tfs.GetService<IBuildServer>();
IBuildDetailSpec detailSpec = buildServer.CreateBuildDetailSpec(projectName);
detailSpec.MaxBuildsPerDefinition = 1;
detailSpec.QueryOrder = BuildQueryOrder.FinishTimeDescending;
IBuildQueryResult results = buildServer.QueryBuilds(detailSpec);
if (results.Builds.Length == 1) {
IBuildDetail detail = results.Builds[0];
buildUri = detail.Uri;
}
return buildUri;
}
...
ITestRun run = plan.CreateTestRun(true);
run.BuildUri = GetLatestBuildURI(projectName);
run.AddTestPoints(testPoints, null);
run.Save();

Related

Replace not working in 'AppDomain.CurrentDomain.BaseDirectory.Replace("\\bin\\Debug", "");' only when I run using VSTest agent from Azure Devops. why?

Here is the code:
Thread.Sleep(4000);
ITakesScreenshot ts = (ITakesScreenshot)driver;
Screenshot screenshot = ts.GetScreenshot();
string pth = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
//var dir = System.IO.Path.GetDirectoryName(pth).Replace("\\bin\\Debug", "");
//dir = dir.Replace("file:\\", "");
var dir = AppDomain.CurrentDomain.BaseDirectory.Replace("\\bin\\Debug", "");
DirectoryInfo di = Directory.CreateDirectory(dir + "\\Execution_Screenshots\\");
string finalpth = pth.Substring(0, pth.LastIndexOf("bin")) + "Execution_Screenshots/" + screenShotName+DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss-fff") + ".jpg";
localpath = new Uri(finalpth).LocalPath;
screenshot.SaveAsFile(localpath, ScreenshotImageFormat.Jpeg);
This code works when I run my tests locally. Works when I login to remote machine and run VSTest there using CLI. But when i ran this from devops using VSTest agent task, the 'Execution_Screenshots' folder gets created inside Debug folder. Replace doesn't work. Why would it not work?

Running .NUnit files programmatically

.nunit files are not running when using NUNIT in C#
I have tried running below code, but the error returned is that the file is not supported. All the examples on the internet use .dll as the path for a testpackage, not .unit.
According to below sites, it is possible to run .unit files:
https://github.com/nunit/docs/wiki/Writing-Engine-Extensions and
https://github.com/nunit/nunit-project-loader/tree/master/src/extension
var path = #"path to nunit file";
var package = new TestPackage(path);
var engine = TestEngineActivator.CreateInstance();
using (var runner = engine.GetRunner(package))
{
var result = runner.Run(this, TestFilter.Empty);
}
}
I have tried the following by referencing nunitprojectloader dll:
var path = #"C:\Users\Administrator\Desktop\nunit-project-loader-master\nunit-project-loader-master\ConsoleApplication1\bin\Debug\DEV.nunit";
NUnitProjectLoader pl = new NUnitProjectLoader();
pl.LoadFrom(path);
var package = pl.GetTestPackage(path);
var engine = TestEngineActivator.CreateInstance();
using (var runner = engine.GetRunner(package))
{
// execute the tests
var result = runner.Run(this, TestFilter.Empty);
}
There is a new error by doing this:
It tries running NBi.NUnit.Runtime.dll which is referenced in the nunit file.
Everythings works fine using the console.

Can Cake (of http://cakebuild.net) be used for deploying Azure WebApps

Have been checking out Cake (at http://cakebuild.net) and am wondering if it can be used for deploying webapps and/or accessing virtual servers fro deploying of release packages.
I like the idea of cake being a deployment framework in C# so being in the same language as core development.
Are there any examples of azure deployments that I could get access?
There's a few ways you can deploy Azure using Cake, either through prebuilding site using some CI service like VSTS/AppVeyor and then publishing the artifacts using web deploy, git or ftp (there's a few Cake addins that can help with that Cake.WebDeploy, Cake.Git or Cake.FTP or using Azure built-in deployment engine Kudu and a custom deployment script using Cake.
To assist with the Kudu deploy/build environment you can use the Cake.Kudu addin.
The first step is to tell Kudu that you've got an custom deployment script, you do this by adding a ".deployment" file to the root of your repository with the content of
[config]
command = deploy.cmd
The deploy.cmd could look something like this to install & launch Cake
#echo off
IF NOT EXIST "Tools" (md "Tools")
IF NOT EXIST "Tools\Addins" (MD "Tools\Addins")
nuget install Cake -ExcludeVersion -OutputDirectory "Tools" -Source https://www.nuget.org/api/v2/
Tools\Cake\Cake.exe deploy.cake -verbosity=Verbose
And deploy.cake could look something like this:
#tool "nuget:https://www.nuget.org/api/v2/?package=xunit.runner.console"
#tool "nuget:https://www.nuget.org/api/v2/?package=KuduSync.NET"
#addin "nuget:https://www.nuget.org/api/v2/?package=Cake.Kudu"
///////////////////////////////////////////////////////////////////////////////
// ARGUMENTS
///////////////////////////////////////////////////////////////////////////////
var target = Argument<string>("target", "Default");
var configuration = Argument<string>("configuration", "Release");
///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
///////////////////////////////////////////////////////////////////////////////
var webRole = (EnvironmentVariable("web_role") ?? string.Empty).ToLower();
var solutionPath = MakeAbsolute(File("./src/MultipleWebSites.sln"));
string outputPath = MakeAbsolute(Directory("./output")).ToString();
string testsOutputPath = MakeAbsolute(Directory("./testsOutputPath")).ToString();
DirectoryPath websitePath,
                websitePublishPath,
                testsPath;
FilePath projectPath,
            testsProjectPath;
switch(webRole)
{
    case "api":
        {
            websitePath = MakeAbsolute(Directory("./src/Api"));
            projectPath = MakeAbsolute(File("./src/Api/Api.csproj"));
            testsPath = MakeAbsolute(Directory("./src/Api.Tests"));
            testsProjectPath = MakeAbsolute(File("./src/Api.Tests/Api.Tests.csproj"));
            websitePublishPath = MakeAbsolute(Directory("./output/_PublishedWebsites/Api"));
            break;
        }
    case "frontend":
        {
            websitePath = MakeAbsolute(Directory("./src/Frontend"));
            projectPath = MakeAbsolute(File("./src/Frontend/Frontend.csproj"));
            testsPath = MakeAbsolute(Directory("./src/Frontend.Tests"));
            testsProjectPath = MakeAbsolute(File("./src/Frontend.Tests/Frontend.Tests.csproj"));
            websitePublishPath = MakeAbsolute(Directory("./output/_PublishedWebsites/Frontend"));
            break;
        }
    case "backoffice":
        {
            websitePath = MakeAbsolute(Directory("./src/Backoffice"));
            projectPath = MakeAbsolute(File("./src/Backoffice/Backoffice.csproj"));
            testsPath = MakeAbsolute(Directory("./src/Backoffice.Tests"));
            testsProjectPath = MakeAbsolute(File("./src/Backoffice.Tests/Backoffice.Tests.csproj"));
            websitePublishPath = MakeAbsolute(Directory("./output/_PublishedWebsites/Backoffice"));
            break;
        }
    default:
        {
            throw new Exception(
            string.Format(
                    "Unknown web role {0}!",
                    webRole
                )
            );
        }
}
if (!Kudu.IsRunningOnKudu)
{
    throw new Exception("Not running on Kudu");
}
var deploymentPath = Kudu.Deployment.Target;
if (!DirectoryExists(deploymentPath))
{
    throw new DirectoryNotFoundException(
        string.Format(
            "Deployment target directory not found {0}",
            deploymentPath
            )
        );
}
///////////////////////////////////////////////////////////////////////////////
// SETUP / TEARDOWN
///////////////////////////////////////////////////////////////////////////////
Setup(() =>
{
    // Executed BEFORE the first task.
    Information("Running tasks...");
});
Teardown(() =>
{
    // Executed AFTER the last task.
    Information("Finished running tasks.");
});
///////////////////////////////////////////////////////////////////////////////
// TASK DEFINITIONS
///////////////////////////////////////////////////////////////////////////////
Task("Clean")
    .Does(() =>
{
    //Clean up any binaries
    Information("Cleaning {0}", outputPath);
    CleanDirectories(outputPath);
    Information("Cleaning {0}", testsOutputPath);
    CleanDirectories(testsOutputPath);
    var cleanWebGlobber = websitePath + "/**/" + configuration + "/bin";
    Information("Cleaning {0}", cleanWebGlobber);
    CleanDirectories(cleanWebGlobber);
    var cleanTestsGlobber = testsPath + "/**/" + configuration + "/bin";
    Information("Cleaning {0}", cleanTestsGlobber);
    CleanDirectories(cleanTestsGlobber);
});
Task("Restore")
    .Does(() =>
{
    // Restore all NuGet packages.
    Information("Restoring {0}...", solutionPath);
    NuGetRestore(solutionPath);
});
Task("Build")
    .IsDependentOn("Clean")
    .IsDependentOn("Restore")
    .Does(() =>
{
    // Build target web & tests.
    Information("Building web {0}", projectPath);
    MSBuild(projectPath, settings =>
        settings.SetPlatformTarget(PlatformTarget.MSIL)
            .WithProperty("TreatWarningsAsErrors","true")
            .WithProperty("OutputPath", outputPath)
            .WithTarget("Build")
            .SetConfiguration(configuration));
    Information("Building tests {0}", testsProjectPath);
    MSBuild(testsProjectPath, settings =>
        settings.SetPlatformTarget(PlatformTarget.MSIL)
            .WithProperty("TreatWarningsAsErrors","true")
            .WithProperty("ReferencePath", outputPath)
            .WithProperty("OutputPath", testsOutputPath)
            .WithTarget("Build")
            .SetConfiguration(configuration));
});
Task("Run-Unit-Tests")
    .IsDependentOn("Build")
    .Does(() =>
{
    XUnit2(testsOutputPath + "/**/*.Tests.dll", new XUnit2Settings {
        NoAppDomain = true
        });
});
Task("Publish")
    .IsDependentOn("Run-Unit-Tests")
    .Does(() =>
{
    Information("Deploying web from {0} to {1}", websitePublishPath, deploymentPath);
    Kudu.Sync(websitePublishPath);
});
Task("Default")
    .IsDependentOn("Publish");
///////////////////////////////////////////////////////////////////////////////
// EXECUTION
///////////////////////////////////////////////////////////////////////////////
RunTarget(target);
In the above scenario it supports a solution with 3 different websites and the one that is published is based on an appsetting.
For .NET Core web apps the flow is similar, basically something like below:
DotNetCoreRestore
DotNetCoreBuild
DotNetCorePublish
Kudu.Sync
There's a couple of good blog posts on deploying to Azure with Cake:
http://cakebuild.net/blog/2015/10/cake-addin-kudu
https://hackernoon.com/delivering-functions-with-cake-4b269c50f817
https://daveaglick.com/posts/publishing-to-azure-using-cake-and-web-deploy

Quartz.net as service can't configure the quartz_job.xml

When using
var properties = new NameValueCollection();
properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";
properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";
properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
properties["quartz.plugin.jobInitializer.scanInterval"] = "120";
// First we must get a reference to a scheduler
_schedulerFactory = new StdSchedulerFactory(properties);
_scheduler = _schedulerFactory.GetScheduler();
The windows service / quartz cannot resolve the path of quartz_jobs.xml.
If i run this as console it works fine.
public static void StartJobs()
{
try
{
_logger = LogManager.GetCurrentClassLogger();
var properties = new NameValueCollection();
properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";
properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";
properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
properties["quartz.plugin.jobInitializer.scanInterval"] = "120";
// First we must get a reference to a scheduler
_schedulerFactory = new StdSchedulerFactory(properties);
_scheduler = _schedulerFactory.GetScheduler();
// start the schedule
_scheduler.Start();
}
catch (Exception ex)
{
_logger.Error(ex);
throw new Exception(ex.Message);
}
}
If it's still not working, include the file as an embedded resource in the project, set the action to Copy always, to be sure. Then provide the full file path to the quartz property:
Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "quartz_jobs.xml")
I know this thread is from 2015, but i can't find any information regarding using quartz.net in a windows service. In my case, I am using .Net Core 2.1 Generic Host as a windows service with the quartz_jobs.xml which is referenced in my appsettings.json file. When the windows service starts up an looks for the quartz_job.xml it tries to find it in c:\windows\system32. But my quartz_job.xml is located where my executable is located. I tracked down Method ResolveFile in Quaztz\Util\FileUtil.cs of their repo where is says to put a "~" to for relative file. So I changed my appsettings.json to
"plugin": {
"jobInitializer": {
"type": "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins",
"fileNames": "~\\quartz_jobs.xml"
}
and now the windows service is able to read the quartz_jobs.xml. I would expect the if you change
properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
to
properties["quartz.plugin.jobInitializer.fileNames"] = "~\\quartz_jobs.xml";
it should also work.

TFS success build alert email if only the last buiild was a failure though TFS plugin

I currently have the TFS setup email alerts for failure and success builds. I think success build emails are just a noise and I want to get them only if the last build was a failure.
My idea was to cancel the TFS alert email for any success build, but enable it for success after failure builds.
I have successfully hooked up the code to find out if the last build failed and the current build succeeded using a TFS plugin.
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType,
object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = string.Empty;
var objWriter = new System.IO.StreamWriter(#"C:\tfsTests\builds.txt", true);
objWriter.WriteLine(DateTime.Now + "-----------------------------------------------");
objWriter.WriteLine(DateTime.Now + notificationType.ToString());
objWriter.WriteLine(DateTime.Now + notificationEventArgs.ToString());
if ((notificationType == NotificationType.Notification) && (notificationEventArgs is BuildCompletionNotificationEvent))
{
var buildNotificationEventArgs = notificationEventArgs as BuildCompletionNotificationEvent;
objWriter.WriteLine(DateTime.Now + buildNotificationEventArgs.Build.ToString());
objWriter.WriteLine(DateTime.Now + buildNotificationEventArgs.Build.Definition.BuildControllerUri.ToString());
objWriter.WriteLine(DateTime.Now + buildNotificationEventArgs.Build.Definition.LastGoodBuildUri);
objWriter.WriteLine(DateTime.Now + buildNotificationEventArgs.Build.Definition.LastBuildUri);
var locationService = requestContext.GetService<TeamFoundationLocationService>();
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
new Uri(locationService.GetServerAccessMapping(requestContext).AccessPoint + "/" + requestContext.ServiceHost.Name));
var buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));
var spec = buildServer.CreateBuildDetailSpec(buildNotificationEventArgs.Build.TeamProject, buildNotificationEventArgs.Build.Definition.Name);
spec.MaxBuildsPerDefinition = 2;
spec.QueryOrder = Microsoft.TeamFoundation.Build.Client.BuildQueryOrder.FinishTimeDescending;
var builds = buildServer.QueryBuilds(spec);
if (builds.Builds.Count() == 2)
{
if (builds.Builds[0].Status == BuildStatus.Succeeded && builds.Builds[1].Status != BuildStatus.Succeeded && builds.Builds[0].FinishTime > builds.Builds[1].FinishTime)
objWriter.WriteLine(string.Format("{0}", "Send Email"));
}
}
objWriter.Close();
return EventNotificationStatus.ActionPermitted;
}
Above code is working fine and I get the Send Email written in by text file.
I just don't know how to cancel/activate the TFS build email. Do you know how to do this ?
You have subscribed to the Build Event. If you are using TFS 2013 or VSO you can open your team project in web access, then click the cog in the top right to go to the admin side. There should be an Alerts tab.
If you are still on a pre-2012 server in Visual Studio you can right-click on the Team Project in the Team Explorer and edit the Alerts.

Categories