Jenkins to only build Projects that Changed not whole Solution - c#

We have a large repo that contains many C# projects but we would only like to build the projects where a change was committed.
So if a Change was committed to Project A, then it will only build Project A and not all the projects in the solution.
Is this possible using Jenkins?
Thanks in advance.

Yes, it is possible. But, you'll have to configure all the projects as separate jobs in Jenkins.

We did exactly this in a solution with over 165 projects grouped into 30 individual services and web applications. However instead of building a specific project with msbuild we created individual solutions based on the respective service and web application domain. The result were solutions like JenkinsBuild_Project1.sln and JenkinsBuild_Project2.sln.
https://stackoverflow.com/a/19534376/3850405
The code below can be modified to use msbuild instead with minor changes.
Jenkinsfile:
#!groovy
import groovy.json.*
pipeline {
agent {
node {
label 'msbuild'
}
}
environment {
OCTOPUS_PUBLISH_KEY = credentials('OctoPackPublishApiKey')
//Global variable where we save what to build
BUILD_LIST =''
}
stages {
stage('What to build?') {
steps {
script {
GIT_DIFF = bat (
script: 'git diff --name-status HEAD..HEAD~1',
returnStdout: true
).trim()
echo "From batscript: ${GIT_DIFF}"
//Environment variable values must either be single quoted, double quoted, or function calls and therefore a json string is used to save the array
//https://stackoverflow.com/a/53745878/3850405
BUILD_LIST = new JsonBuilder(whatToBuild("${GIT_DIFF}")).toPrettyString()
echo BUILD_LIST
}
}
}
stage('Prepare') {
steps {
script {
def buildList = new JsonSlurper().parseText(BUILD_LIST)
for (i = 0; i < buildList.size(); i++){
bat "C:\\Program\\NuGet\\nuget_4.4.1.exe restore Source\\${buildList[i]}\\${buildList[i]}.sln"
}
}
}
}
stage('Build') {
steps {
script {
def buildList = new JsonSlurper().parseText(BUILD_LIST)
for (i = 0; i < buildList.size(); i++){
bat "\"${tool 'Build Tools 2019'}\" /t:Clean;Build /p:Configuration=JenkinsBuild JenkinsBuild\\JenkinsBuild_${buildList[i]}.sln"
}
}
}
}
stage('Publish') {
when {
anyOf {
branch 'master';
}
}
steps {
script {
def buildList = new JsonSlurper().parseText(BUILD_LIST)
for (i = 0; i < buildList.size(); i++){
bat """\"${tool 'Build Tools 2019'}\" ^
/t:Build ^
/p:Configuration=JenkinsBuild ^
/p:RunOctoPack=true ^
/p:OctoPackEnforceAddingFiles=true ^
/p:AllowedReferenceRelatedFileExtensions=none ^
/p:OctoPackNuGetProperties=env=${env.BRANCH_NAME};change=${env.CHANGE_ID} ^
/p:OctoPackPackageVersion=2.1.${BUILD_NUMBER}-${env.BRANCH_NAME}1 ^
/p:OctoPackPublishPackageToHttp=https://OurOctopusServer:1337/nuget/packages ^
/p:OctoPackPublishApiKey=${env.OCTOPUS_PUBLISH_KEY} ^
JenkinsBuild\\JenkinsBuild_${buildList[i]}.sln"""
}
}
}
}
}
post {
always {
//Clean and notify
}
}
}
Groovy script that takes a file list from git command git diff --name-status HEAD..HEAD~1 and filters out unique project values like Project1 and Project2 from paths like below.
/Source/Project1/Project1.Data/Properties/AssemblyInfo.cs
/Source/Project2/Project2.Clients.WinService/Services/Project2.Designer.cs
whatToBuild.groovy:
#!/usr/bin/env groovy
def call(String fileList) {
println "Printing filelist in whatToBuild()"
println fileList
def lines = fileList.tokenize('\n')
println lines
def list = []
lines.eachWithIndex{ value, key ->
println "Printing value"
println value
if (value.contains("Source")) {
def result = value =~ /Source\/([A-Z]*)\//
println "Printing result"
println result[0][1]
list.add(result[0][1])
}
}
def listUnique = list as Set
println listUnique
return listUnique
}

Related

File.Exists not working in unity

I'm trying to write a script so the text of a save button changes if it has found a save file in that slot. However, my script cannot seem to find the file no matter what I do. Here's what I have right now.
if (File.Exists ("save1.dat")) {
//set button text
} else {
Debug.Log ("Failure");
}
I've tried multiple different variations on this. I've tried it with different files, different file extensions, including the Application.dataPath, using Resources.Load, but nothing works. For some reason, these functions cannot seem to find any files in my unity project, despite the fact I can see them clearly in both the unity editor and my file explorer. What are some reasons this might be happening? Are there ways to circumvent this?
The file path you are asking for is not a valid file path. You need to use the Application.dataPath as a root directory and make sure that it ends in a / before appending a file. You may also have to replace \ with / (looking at my own code).
This is sort of a hodgepodge, but I use this to determine the application directory for file IO:
public static class Configuration {
public static string currentBaseDirectory = "";
public static string currentDirectory = "";
public static void loadCurrentDirectory ()
{
currentDirectory = Application.dataPath;
currentDirectory = currentDirectory.Replace( #"\", "/" );
bool hasFoundMatch = false;
if ( !currentDirectory.EndsWith( "/" ) )
currentDirectory += "/";
switch (Application.platform) {
case RuntimePlatform.OSXEditor: //<path to project folder>/Assets
case RuntimePlatform.WindowsEditor:
if(currentDirectory.EndsWith("Assets/")) {
currentDirectory = currentDirectory.Substring(0, currentDirectory.LastIndexOf( "Assets/" ) );
currentDirectory += "RuntimeData/";
hasFoundMatch = true;
}
break;
case RuntimePlatform.WindowsPlayer: //<path to executablename_Data folder>
break;
case RuntimePlatform.OSXPlayer: //<path to player app bundle>/Contents
if(currentDirectory.EndsWith(".app/Contents/")) {
currentDirectory = currentDirectory.Substring(0, currentDirectory.LastIndexOf( ".app/Contents/" ) );
currentDirectory += "RuntimeData/";
hasFoundMatch = true;
}
break;
case RuntimePlatform.OSXDashboardPlayer: //<path to the dashboard widget bundle>
case RuntimePlatform.WindowsWebPlayer: //not supported
case RuntimePlatform.OSXWebPlayer:
default:
hasFoundMatch = false;
break;
}
if (!hasFoundMatch) {
currentDirectory = Path.GetFullPath("RuntimeData/");
currentDirectory = currentDirectory.Replace(#"\", "/");
}
if (!Directory.Exists( currentDirectory)) {
for (int i = 0; i < 3; i++)
currentDirectory = currentDirectory.Substring( 0, currentDirectory.LastIndexOf( "/" ) );
currentDirectory += "/RuntimeData/";
}
currentBaseDirectory = currentDirectory.Replace("/RuntimeData", "");
}
}
This allows me to have a RuntimeData directory next to Assets that I can put things like save files in. This folder then ships with the executable when published (although you might want a clean copy, free from any dev testing saves ;) ).

Formatting a Linux path in C#

So I am making a file browser using the WinSCP library in C#. The files and folders from the remote server are loaded into a ListView, and I have an event on the ListView_DoubleClick event that will go and get the files for that folder. However my problem is, the "CurrentPath" returned from WinSCP is built like so;
"/eddata/T". Now if a user goes back up a directory, the path returned is "/eddata/T/../". If the user then goes into another folder called "Bob", the path now looks like; "/eddata/T/../Bob".
I want a way so I can display the current path in a user friendly way. So when a user is in the directory; "/eddata/T/" and they go up a level, a label should tell them they are in; "/eddata/";
This is my attempt but isn't working as expected, it doesn't deal the event where a user goes back up two directories at the same time;
private string FormatPathString(string input)
{
String working = input;
bool replacement = true;
while (replacement)
{
string[] splits = working.Split('/');
splits = splits.AsEnumerable().Where(x => x != String.Empty).ToArray();
int? found_index = null;
for (int i = splits.Count() - 1; i > 0; i--)
{
if (splits[i] == "..")
{
found_index = i;
break;
}
}
if (found_index.HasValue)
{
replacement = true;
splits = splits.Where((val, idx) => (idx != found_index) && (idx != found_index - 1)).ToArray();
working = String.Join("/", splits);
}
else
{
replacement = false;
}
}
return working;
}
You can use the Path class.
string pathWithDots= "/eddata/T/../Bob";
string pathWithoutDots = Path.GetFullPath(pathWithDots); // Result: c:\eddata\Bob
however the Path class assumes that you are using a windows path and adds C: and changes slashes to backslashes so you will need to remove the C: at the start and replace all back slashes with forward slashes.
string pathNx = pathWithoutDots.Substring(2).Replace("\\", "/"); // Result: /eddata/Bob

MS Paint shortcut exist on desktop or not?

i want to find out that mspaint shortcut exist in desktop or no? if its exist, user score is 7 else its 0. i use this code:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (Directory.Exist (path + #"\mspaint.exe"))
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
but anyway the result is "0".but this code works for directory and folders and return 7.
also i try "File.Exist" but it has same problem.
How can i check a shortcut of specific program exist in desktop or no?
if (questionNumber == 2)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var list = Directory.EnumerateFiles(path);
foreach (var v in list)
{
var extension = Path.GetExtension(v);
if (extension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(v);
if (Path.GetFileName(link.TargetPath).Equals("mspaint.exe", StringComparison.InvariantCultureIgnoreCase))
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
}
}
}
when i use this, its ok, but it returns 0 for not exist and return both of 0 and 7 for exist
Shortcut is just another type of files, as MSDN says:
When the user creates a shortcut to an object by choosing the Create
Shortcut command from the object's shortcut menu, Windows stores the
information it needs to access the object in a link file—a binary file
that has the .lnk file name extension.
It mean that you should refer exactly to shortcut: with exact name and .lnk extension.
You need to check shortcut for example like this:
File.Exist(Path.Combine(path, "Paint.lnk"))
But in my opinion right solution is to get all shortcuts from desktop and examine target path for each one for mspaint.exe path.
For reading shortcut information read this SO post: Get target of shortcut folder
This needs explicit coding and you cannot look for names of the file in deskTop since it can be changed to anything because its just a short cut,
Include the COM addin reference Windows Script Host Object Model - Interop.IWshRuntimeLibrary
using IWshRuntimeLibrary;
public string test()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var list = Directory.EnumerateFiles(path);
foreach(var v in list)
{
var extension = Path.GetExtension(v);
if (extension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase))
{
WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut) shell.CreateShortcut(v);
if (Path.GetFileName(link.TargetPath).Equals("mspaint.exe", StringComparison.InvariantCultureIgnoreCase))
{
return link.TargetPath;
}
}
}
return null;
}
A Shortcut is a special kind of file
A shortcut is a special kind of file. It contains data which points to a location (for example mspaint.exe), but that doesn't mean it needs to be named the same as the exe it's pointing to. For example, it can have a name of "HappyPaint.lnk" and point to "mspaint.exe".
Reading Shortcut Destination
Therefore you need to look for all "*.lnk" files on the desktop and read their destination paths. Here's how you can go about it:
First, add a reference to Microsoft Shell Controls And Automation:
Second, add some code along the lines of:
string desktopDirectoryPath = Environment.GetFolderPath(
Environment.SpecialFolder.DesktopDirectory);
string msPaintPath = Environment.ExpandEnvironmentVariables(
#"%windir%\system32\mspaint.exe");
// add reference to COM --> Microsoft Shell controls and Automation
Shell shell = new Shell();
Folder folder = shell.NameSpace(desktopDirectoryPath);
var shortcutFilePaths = Directory.GetFiles(desktopDirectoryPath, "*.lnk");
bool msPaintShortcutExists = false;
foreach (string shortcutFilePath in shortcutFilePaths)
{
FolderItem folderItem = folder.ParseName(Path.GetFileName(shortcutFilePath));
Shell32.ShellLinkObject link = (Shell32.ShellLinkObject) folderItem.GetLink;
var shortcutDestination = Environment.ExpandEnvironmentVariables(link.Path);
if (string.Compare(
msPaintPath, shortcutDestination, StringComparison.OrdinalIgnoreCase) == 0)
{
msPaintShortcutExists = true;
break;
}
}
if (msPaintShortcutExists)
{
Controller.ExamController.AddExam(1, n, 7, time, Session.currentUserId);
}
else
{
Controller.ExamController.AddExam(1, n, 0, time, Session.currentUserId);
}
Needs to be run in an STAThread
Note: In case an InvalidCastException with a message
Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{286E6F1B-7113-4355-9562-96B7E9D64C54}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
occurs on new Shell(); you're not running the code in an STAThread but it needs to be run in an STAThread. An easy work around is to add the following method:
private static void ExecuteInStaThread(Action a)
{
var thread = new Thread(() => a());
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
if (!thread.Join(TimeSpan.FromSeconds(30)))
{
thread.Abort();
}
}
and wrap the code in a call to it:
ExecuteInStaThread(() =>
{
string desktopDirectoryPath = ...
...
});

Assigning TestCases to TestFolders via Rally web service

I have a situation where there are lots of test cases that don't belong to a test folder. This is fine, but I'd like to write an application to move these 'orphaned' test cases into a test folder (mostly so it's easy to easily see how the tests are doing)
All of the test cases and the test folder I create are in the same project, but I get the following errors;
Validation error: TestFolder.TestCases is an invalid relationship. One or more of the artifacts is in a different project.
Validation error: TestCase.TestFolder is an invalid relationship. One or more of the artifacts is in a different project.
These seem to be telling me that I am assigning the test cases to a test folder in a different project - but they aren't.
Here's a snip of the code - m_currentRallyProject and m_workspace have already been set by a different method
Any thoughts?
public void CreateTestFolderForOrphanedTestCases(HierarchicalRequirement aUserStory, List<TestCase> testCases)
{
TestFolder myNewTestFolder = createTestFolder(aUserStory.Name);
for (int i = 0; i < testCases.Count; i++)
{
TestCase myTestCase = (TestCase)testCases[i];
myTestCase.TestFolder = myNewTestFolder;
OperationResult myResult = m_rallyService.update(myTestCase);
if (hasErrors(myResult))
{
updateStatus("Could not set Test Folder for " + myTestCase.FormattedID);
printWarningsErrors(myResult);
}
else
{
updateStatus("updated test case " + myTestCase.FormattedID);
}
}
}
private TestFolder createTestFolder(String testFolderName, TestFolder aParentTestFolder = null)
{
TestFolder myNewTestFolder = new TestFolder();
myNewTestFolder.Name = testFolderName;
myNewTestFolder.Project = m_currentRallyProject;
myNewTestFolder.Workspace = m_workspace;
CreateResult createTestFolderResult = m_rallyService.create(myNewTestFolder);
if (hasErrors(createTestFolderResult))
{
// something went wrong
Console.WriteLine("Could not create Test Folder");
printWarningsErrors(createTestFolderResult);
}
else
{
myNewTestFolder = (TestFolder)m_rallyService.read(createTestFolderResult.Object);
return myNewTestFolder;
}
return null;
}
Dropping an answer in from the comments above :)
Make certain they're in the same project - you shouldn't get this message if they are. Being in the same Project Hierarchy doesn't count. I.E. a Test Folder that is in a Child Project of the current Project, even with child scoping down = true, counts as being in a different Project. Try adding some logging that outputs the Project Name or ref for both the Test Case and the Target Test Folder.
If you add some logging that outputs Project metadata for both TestCase and target TestFolder, make sure to output both Name and ref - since Project Name is not guaranteed to be unique (different Rally Projects can have the same Name).

MATLAB .NET assembly (Undefined function or variable 'feedforwardnet')

I'm trying to integrate MATLAB 2010b with Visual Studio 2008 Professional.
I have the following MATLAB method.
function varargout = perform( func, varargin )
%% // Set default values
workspaceDirectory = ['Results/MatlabWorkspace_' datestr(now, 'yyyy-mm-dd_HH-MM-SS')];
clear args
args = struct('workspacePath', [ workspaceDirectory '/workspace.mat'], ...
'testArray', [], ...
'k', 50, ...
'rate', 0.0001, ...
'trainingDataPath', 'P2AT_LaserImageVectorList.csv', ...
'network', 'feedforwardnet', ...
'initialWeights', [], ...
'divideFcn', 'dividerand', ...
'trainRatio', 70/100, ...
'testRatio', 15/100, ...
'valRatio', 15/100, ...
'trainInd', [], ...
'testInd', [], ...
'valInd', [], ...
'trainFcn', 'trainlm', ...
'performFcn', 'mse', ...
'biasConnect', [0; 0; 0], ...
'layerSize', [9; 4; 1], ...
'layerTransferFcn', ['tansig '; 'tansig '; 'purelin'], ...
'max_fail', 10, ...
'mu_dec', 0.04, ...
'useInitialWeights', false, ...
'saveResults', true);
% // Returns a modified properties structure
args = getopt(args,varargin);
args.layerTransferFcn = cellstr(args.layerTransferFcn);
if args.saveResults && ~strcmpi(func,'test')
if (exist(workspaceDirectory, 'dir') ~= 7)
mkdir(workspaceDirectory);
end
end
if (strcmpi(func,'test'))
try
load(args.workspacePath, '-regexp', '.*');
catch err
Warning(err.message);
varargin{1,1} = null;
return;
end
data_inputAngle = args.testArray(2501);
data_inputPCA = args.testArray(1:2500);
if size(data_inputPCA,1) == 1
data_inputPCA = data_inputPCA';
end
switch(featureExtractionMethod)
case {'gha','apex'}
% // [W, errvals] = gha(data_inputPCA, k, varargin{1,3});
data_PCs = W' * data_inputPCA;
data_inputNN = [data_PCs; data_inputAngle];
case 'nnmf'
% // [W,H,D] = nnmf(data_inputPCA',k);
data_PCs = H * data_inputPCA;
data_inputNN = [data_PCs; data_inputAngle];
case 'pcaProcess'
otherwise
warning = 'ERROR: no feature extraction method has been defined.';
Warning('ERROR: no feature extraction method has been defined.');
varargout{1,1} = null;
return;
end
% // Just to test to see if it recognizes 'feedforwardnet'.
testnet = feedforwardnet; % // <------------------------------- LINE 81
% // Saving all the workspace variables to see if they are all correctly processed.
save('all');
varargout{1,1} = net(data_inputNN); %// <------------------------- LINE 86
end
end
And this is how I create my DLL file to import in Visual Studio:
%%// Determine path names
workdir = pwd();
outdir = fullfile(workdir, 'Output');
dnetdir = fullfile(workdir, 'dotnet');
%%// Determine file names
mfile = fullfile(workdir, 'perform.m');
dnetdll = fullfile(dnetdir, 'dotnet.dll');
%%// Build .NET Assembly
eval(['mcc -N -d ''' dnetdir ''' -W ''dotnet:dotnet,' ...
'dotnetclass,0.0,private'' -T link:lib ''' mfile '''']);
So everything works perfectly fine when I use MATLAB Engine's COM interface to run the routine inside MATLAB from C#:
/*
* This function calls the routine inside
* MATLAB using the MATLAB Engine's COM interface
*/
static private float MatlabTestDebug(float[] testData, Double targetAngle)
{
Array X = new double[testData.Length + 1];
testData.CopyTo(X, 0);
X.SetValue((double)targetAngle, testData.Length);
Array zerosX = new double[X.GetLength(0)];
MLApp.MLAppClass matlab = new MLApp.MLAppClass();
matlab.PutFullMatrix("testArray", "base", X, zerosX);
matlab.PutWorkspaceData("workspacePath", "base", "workspace.mat");
// Using Engine Interface, execute the ML command
// contained in quotes.
matlab.Execute("cd 'c:\\Users\\H\\Documents\\Project\\Source Code\\MatlabFiles';");
matlab.Execute("open perform.m");
matlab.Execute("dbstop in perform.m");
matlab.Execute("result = perform('test', 'workspacePath', 'workspace.mat', 'testArray', testArray);");
matlab.Execute("com.mathworks.mlservices.MLEditorServices.closeAll");
return (double)matlab.GetVariable("result", "base");
}
But when I use the .NET assembly, it's not recognizing 'feedforwardnet'. I used to get an error on line 86 (net(data_inputNN)). So I added a line to test to see if it at least recognizes 'feedforwardnet', but it didn't.
Note: I'm loading some variables from a file including "net" which is a neural network (load(args.workspacePath, '-regexp', '.*');)
Also in the MATLAB method if I load a saved "network" from file and then save it to see how it processes the network, it will save it as a "struct" instead of a "network".
I'm assuming it's loading it as a struct to begin with.
I also had this problem inside MATLAB 2009b itself. That's the reason I'm using MATLAB 2010b now, because apparently MATLAB 2009b didn't have this particular neural networks toolbox.
Following is the C# code to use the .NET assembly.
/*
* Calls the method from inside a .NET assembly created with MATLAB
* using Builder for .NET.
*/
private float MatlabTest(float[] testData, Double targetAngle)
{
if (testData != null)
{
dotnetclass AClass = new dotnetclass();
Array X = new double[testData.Length + 1];
testData.CopyTo(X, 0);
X.SetValue((double)targetAngle, testData.Length);
MWNumericArray XNumericArray = new MWNumericArray(X);
MWArray[] RetVal = AClass.perform(1, "test",
"workspacePath", "workspace.mat",
"testArray", XNumericArray);
Array result = ((MWNumericArray)RetVal[0]).ToVector(MWArrayComponent.Real);
return (float)result.GetValue(0);
}
else
{
return 0f;
}
}
I'm getting this error in Visual Studio:
... MWMCR::EvaluateFunction error ...
Undefined function or variable 'feedforwardnet'.
Error in => perform.m at line 81.
NOTE: version of my compiler and softwares:
Compiler: Microsoft Visual C++ 2008 SP1 in C:\Program Files (x86)\Microsoft Visual Studio 9.0
MATLAB: R2010b (64-bit)
Visual Studio: MVS 2008 professional (.NET Framework 3.5 SP1)
Microsoft Windows SDK 6.1
Recent Updates:
I've added the path of the neural network toolbox in mcc.
eval(['mcc -N -p ''C:\Program Files\MATLAB\R2010b\toolbox\nnet'' -d ''' dnetdir ''' -W ''dotnet:dotnet,' ...
'dotnetclass,0.0,private'' -T link:lib -v ''' mfile '''']);
Now I get these messages in mccExcludeFiles.log:
C:\Program Files\MATLAB\R2010b\toolbox\nnet\nnet\#network\network.m
called by C:\Program Files\MATLAB\R2010b\toolbox\nnet\nnet\nnnetwork\cascadeforwardnet.m
(because of toolbox compilability rules)
C:\Program Files\MATLAB\R2010b\toolbox\nnet\nnet\#network\network.m
called by C:\Program Files\MATLAB\R2010b\toolbox\nnet\nnet\nnnetwork\feedforwardnet.m
(because of toolbox compilability rules)
The only answer I could come up with (which not a solution to the problem) was from Creating standalone application that contains neural network toolbox functions, stating that:
You will not be able to compile any
function which trains the network
(like ADAPT). Though the link does not
explicitly list these funcions (like
ADAPT), they fall under the 'All other
command line functionality'.
However, you can deploy a M function
code which uses a pre-trained
network. I believe the SIM function
will deploy fine.
The workflow I see is:
In MATLAB, train you network using test input/output
Save the network (MAT file?)
Create a deployable function which then uses the pretrained network for
new data. The network itself would not
change/adapt/train in this function
Compile and deploy the above function

Categories