Passing MsBuild Command Line Arguments with BuildEngine - c#

I have the following code to build a project from another C# app:
var buildEngine = new Engine();
buildEngine.RegisterLogger(new ConsoleLogger());
var success = buildEngine.BuildProjectFile(pathToCsProjFile);
if(!success)
{
Log.LogIt("On Noes! We Broke!");
}
else
{
Log.LogIt("It Worked!!!!!!");
}
Currently it builds the default configuration (Debug) but I want it to build the release version. If I were invoking MsBuild from the command line I would do something like:
C:\Windows\WinFX\v3.5>msbuild.exe *.proj /ToolsVersion:3.5 /p:Configuration=Release
How do I pass that configuration switch to the build engine?

You'll want to set the property, something like this should do the trick:
var pathToCsProjFile = "";
var buildEngine = new Engine();
var project = new Project(buildEngine);
project.Load(pathToCsProjFile);
project.SetProperty("Configuration", "Release");
var success = project.Build();

Use one of the other overloaded implementations of BuildProjectFile. I believe this one. Create a BuildPropertyGroup and add the properties you want. In this case 'Configuration' = 'Release'

Related

How to push Tag to Bitbucket Git Repository in Bamboo from Cake build task?

I'm using next code to push Tag to Git repository
#addin "Cake.Git"
using LibGit2Sharp;
var solutionFolder = "./";
var versionTag = "someTag";
Task("Default")
.Does(() =>
{
var remoteRepository = EnvironmentVariable("bamboo_planRepository_repositoryUrl");
var repositoryRevision = EnvironmentVariable("bamboo_planRepository_revision");
var absolutePath = MakeAbsolute(Directory(solutionFolder));
var repoName = "central";
//LibGit2Sharp add remote
using (var repo = new Repository(absolutePath.FullPath))
{
repo.Network.Remotes.Add(repoName, remoteRepository);
}
GitTag(solutionFolder, versionTag, repositoryRevision);
GitPushRef(solutionFolder, gitUser, gitPassword, repoName, versionTag);
}
});
Stuck into the next issue: because our bamboo configured to use SSH protocol, and Cake.Git(LibGit2Sharp) currently doesn't support it receiving next error
Error: unsupported URL protocol
Thanks
I would suspect the issue is to due using shallow clones, which are enabled by default.
Shallow clones allows Bamboo to perform clones with i.e. history truncated to a specified number of revisions.
This should increase the speed of the initial code checkouts, however if your build depends on the full repository history, we recommend that you do not use this option.
GIT operations in general need the full repo to work reliably.
A little bit hacky but it works, will update answer when will find better approach.
Done based on the How to tag a git repo in a bamboo build.
Cake.Git currently doesn't support adding repository but under the hood using LibGit2Sharp so just added LibGit2Sharp namespace to the code.
Core issue is that Cake.Git(LibGit2Sharp) doesn't support SSH yet (Issue on GitHub Is it possible to use Cake.Git with SSH), as workaraound calling git push through cmd How to execute cmd
command
#addin "Cake.Git"
using LibGit2Sharp;
var solutionFolder = "./";
var versionTag = "someTag";
var remoteRepository = EnvironmentVariable("bamboo_planRepository_repositoryUrl");
var repositoryRevision = EnvironmentVariable("bamboo_planRepository_revision");
Task("Default")
.Does(() =>
{
var absolutePath = MakeAbsolute(Directory(solutionFolder));
var repoName = "central";
//LibGit2Sharp add remote
using (var repo = new Repository(absolutePath.FullPath))
{
repo.Network.Remotes.Add(repoName, remoteRepository);
}
GitTag(solutionFolder, versionTag, repositoryRevision);
Cmd($"git push {repoName} {versionTag}");
}
});
private void Cmd(params object[] parameters)
{
if (parameters.Any())
{
var args = new ProcessArgumentBuilder()
.Append(#"/c");
foreach (var param in parameters)
args.Append($"{param}");
StartProcess("cmd", new ProcessSettings { Arguments = args });
}
}

Modify programatically csproj files with Microsoft.Build.Evaluation (instead of Engine)

I would like to read, modify and write back csproj files.
I've found this code, but unfortunately Engine class is depreciated.
Engine engine = new Engine()
Project project = new Project(engine);
project.Load("myproject.csproj");
project.SetProperty("SignAssembly", "true");
project.Save("myproject.csproj");
So I've continued based on the hint I should use Evaluation.ProjectCollection instead of Engine:
var collection = new ProjectCollection();
collection.DefaultToolsVersion = "4.0";
var project = new Project(collection);
// project.Load("myproject.csproj") There is NO Load method :-(
project.FullPath = "myproject.csproj"; // Instead of load? Does nothing...
// ... modify the project
project.Save(); // Interestingly there is a Save() method
There is no Load method anymore. I've tried to set the property FullPath, but the project still seems empty. Missed I something?
(Please note I do know that the .csproj file is a standard XML file with XSD schema and I know that we could read/write it by using XDocument or XmlDocument. That's a backup plan. Just seeing the .Save() method on the Project class I think I missed something if I can not load an existing .csproj. thx)
I've actually found the answer, hopefully will help others:
Instead of creating a new Project(...) and trying to .Load(...) it, we should use a factory method of the ProjectCollection class.
// Instead of:
// var project = new Project(collection);
// project.FullPath = "myproject.csproj"; // Instead of load? Does nothing...
// use this:
var project = collection.LoadProject("myproject.csproj")
Since i can't comment:
This won't work in .net core without first setting the MSBuild.exe path variable. The code to do so can be found here
https://blog.rsuter.com/missing-sdk-when-using-the-microsoft-build-package-in-net-core/
and is written here
private static void SetMsBuildExePath()
{
try
{
var startInfo = new ProcessStartInfo("dotnet", "--list-sdks")
{
RedirectStandardOutput = true
};
var process = Process.Start(startInfo);
process.WaitForExit(1000);
var output = process.StandardOutput.ReadToEnd();
var sdkPaths = Regex.Matches(output, "([0-9]+.[0-9]+.[0-9]+) \\[(.*)\\]")
.OfType<Match>()
.Select(m => System.IO.Path.Combine(m.Groups[2].Value, m.Groups[1].Value, "MSBuild.dll"));
var sdkPath = sdkPaths.Last();
Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", sdkPath);
}
catch (Exception exception)
{
Console.Write("Could not set MSBUILD_EXE_PATH: " + exception);
}
}

Detect current VSIX package's version from code

I am writing a VSIX project and I would like for the code to be able to determine whether an update is available.
I know Visual Studio would be able to check for the update, however, I would like for the extension to be able to prompt user (developer) more verbosely.
I wonder how could make the extension read its own version from the package manifest?
Thank you.
I found that I could read the version information directly from the manifest XML file.
var doc = new XmlDocument();
doc.Load(manifestPath);
var metaData = doc.DocumentElement.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Metadata");
var identity = metaData.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Identity");
var version = identity.GetAttribute("Version");
I also wrote a gist C# class code that encapsulate the code above. Besides, version, this technique could be used to get other information provided by the manifest file.
Nordin's solution seems good, but I just want to mention that there is one more way to get current version of the extension. I have no idea in what situation my solution might be better, maybe if you don't know the path to the manifest on the client that uses this extension.
// get ExtensionManager
IVsExtensionManager manager = GetService(typeof(SVsExtensionManager)) as IVsExtensionManager;
// get your extension by Product Id
IInstalledExtension myExtension = manager.GetInstalledExtension("ProductId-1234-1234-1234-123456789012");
// get current version
Version currentVersion = myExtension.Header.Version;
I call this inside Initialize() method of my package.
This code motivated by Wayne Koorts works for me, even if deploying the package on Visual Studio Gallery:
private string getVsixVersion()
{
var asm = Assembly.GetExecutingAssembly();
var asmDir = Path.GetDirectoryName(asm.Location);
var manifestPath = Path.Combine(asmDir, "extension.vsixmanifest");
var version = "?";
if (File.Exists(manifestPath))
{
var doc = new XmlDocument();
doc.Load(manifestPath);
var metaData = doc.DocumentElement.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Metadata");
var identity = metaData.ChildNodes.Cast<XmlElement>().First(x => x.Name == "Identity");
version = identity.GetAttribute("Version");
}
return version;
}

Upgraded dotLess error: IImporter does not contain definition for 'Paths'

I have the following code in a project I try to upgrade the "dotless" NuGet package from the "1.2.2.0" to the latest (at moment "1.4.0.0"):
private void GetStylesheetContent(HttpContext context, string name)
{
var conf = BundleConfigSectionHandler.GetConfig();
var elt = conf.Stylesheets.GetBundle(name);
if (elt != null) {
Minifier minifier = null;
if (_conf.Stylesheets.Minify) {
minifier = new Minifier();
}
var files = elt.ListFiles();
var existingFiles = new List<string>();
StringBuilder buffer = new StringBuilder();
foreach (var file in files) {
var physicalFile = context.Request.MapPath(file);
if (File.Exists(physicalFile)) {
existingFiles.Add(physicalFile);
string content;
var path = VirtualPathUtility.GetDirectory(file);
if (file.EndsWith(".less", StringComparison.OrdinalIgnoreCase))
{
var reader = new dotless.Core.Input.VirtualFileReader();
var localpath = VirtualPathUtility.ToAbsolute(file);
content = reader.GetFileContents(localpath);
var parse = new Parser();
parse.Importer = new Importer(reader);
/*Error>*/ parse.Importer.Paths.Add(VirtualPathUtility.ToAbsolute(path));
var eng = new LessEngine(parse);
content = eng.TransformToCss(content, localpath);
The error is on the third line from bottom. It says:
Error 417 'dotless.Core.Importers.IImporter' does not contain a
definition for 'Paths' and no extension method 'Paths' accepting a
first argument of type 'dotless.Core.Importers.IImporter' could be
found (are you missing a using directive or an assembly reference?)
Is a pity that the team didn't left the old method with an [Obsolete] attribute and suggestion to upgrade.
Does anyone know how to replace the "Importer.Paths.Add" method ?
I'm not that familiar with the inner workings of dotless. But looking at the source code for the Importer. paths has been protected since version version 1.2.3. Looking around at the class a little more, it seems like you need to use an instance of dotless.Parser.Tree.Import to add your paths manually.
It does look like this is pretty far off the normal dotless path. So it wouldn't surprise me if the API is a little unstable in these areas. You also may want to look at how bundling works in a question like How to use ASP.Net MVC 4 to Bundle LESS files in Release mode? to see how they handle all the dotless classes.

how to pass arguments in EMR job to use in bootstrap script

I have a bootstrap script which runs with my EMR job.
I need to pass a parameter to this script so I can configure a path for different environments
The following line in my script needs to use it
path=OVA/{EnvironmentName}/Scripts/UniqueUsers
I am using C# to invoke a streaming EMR job. how do I pass this argument while I create the job?
HadoopJarStepConfig config = new StreamingStep()
.WithInputs(input)
.WithOutput(output)
.WithMapper(configMapperLocation)
.WithReducer(configReducerLocation)
.ToHadoopJarStepConfig();
string configName = string.Format("Unique_Users_config_{0}", outputFolder);
StepConfig uniqueUsersDaily = new StepConfig()
.WithName(configName)
.WithActionOnFailure("TERMINATE_JOB_FLOW")
.WithHadoopJarStep(config);
ScriptBootstrapActionConfig bootstrapActionScript = new ScriptBootstrapActionConfig()
.WithPath(configBootStrapScriptLocation);
BootstrapActionConfig bootstrapAction = new BootstrapActionConfig()
.WithName("CustomAction")
.WithScriptBootstrapAction(bootstrapActionScript);
string jobName = string.Format("Unique_User_DailyJob_{0}", outputFolder);
RunJobFlowRequest jobRequest = new RunJobFlowRequest()
.WithName(jobName)
.WithBootstrapActions(bootstrapAction)
.WithSteps(uniqueUsersDaily)
.WithLogUri(configHadoopLogLocation)
.WithInstances(new JobFlowInstancesConfig()
.WithHadoopVersion(configHadoopVersion)
.WithInstanceCount(2)
.WithKeepJobFlowAliveWhenNoSteps(false)
.WithMasterInstanceType(configMasterInstanceType)
.WithSlaveInstanceType(configSlaveInstanceType));
You can use withArgs() of ScriptBootstrapActionConfig, in Java you can do as follows, I am sure there is a similar method for C#:
ScriptBootstrapActionConfig bootstrapActionScript = new ScriptBootstrapActionConfig()
.WithPath(configBootStrapScriptLocation)
.WithArgs(List<String> args);

Categories

Resources