How to suppress initial post-build event error in Visual Studio 2017 (C#)? - c#

I have a C# solution in Visual Studio 2017. I also have a batch script called foobar.bat that contains the following code:
echo foobar : error 1: This is a test error.
My goal is to get only the test error message above to appear in Visual Studio's Error List when I build a particular project and for the build to stop when it appears. So I put [path to script]\foobar.bat in the project's post-build event command line and then build. Now I'm getting two error messages in the Visual Studio Error List:
The command "[path to script]\foobar.bat" exited with code -1.
This is a test error.
In this case, seeing that first error message that just prints out the contents of my post-build event isn't helpful. I want to suppress this initial error so that only my custom error messages show up in the Error List (or at least change it to say something more useful).
Here's what I've tried:
Adding 2>nul to the end of my batch script has no effect.
Adding 1>nul to the end of my batch script suppresses both errors, which isn't what I want.
Adding &set errorlevel=0 to the end of my batch script has no effect.
Adding the line exit 0 to the end of my batch script has no effect.
Adding the following to the end of my .csproj file (per this article) suppresses the first error, but makes it so the build no longer fails:
<Target
Name="PostBuildEvent"
Condition="'$(PostBuildEvent)'!=''"
DependsOnTargets="$(PostBuildEventDependsOn)">
<Exec WorkingDirectory="$(OutDir)" Command="$(PostBuildEvent)" IgnoreExitCode="true" />
</Target>
The last option almost gets me what I want. However, in spite of there being an error message, the Error List doesn't pop up and the build does not fail. It appears as though anything that would cause the initial error message to not appear will also cause the build to no longer fail. Is that the case? Or is there some way I can get the build to fail without showing that initial error message?

What you can do is use an exec and an error task together.
You need to edit the .csproj file and add these tasks after your the Target PostBuildEvent from your last bullet point above.
This solution works by getting the ExitCode and Output of your exec task and using them to trigger the error task which will then stop the build and log the message.
The Exec task needs three parameters:
IgnoreStandardErrorWarningFormat and IgnoreExitCode prevent the error from being logged at this step
ConsoleToMsBuild parameter is required to get the output (spelled ConsoleToMSBuild in VS 2017).
So the tasks look like this:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="$(PostBuildEvent)" IgnoreStandardErrorWarningFormat="true" IgnoreExitCode="true" ConsoleToMsBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="OutputMessage" />
<Output TaskParameter="ExitCode" PropertyName="ExitCode" />
</Exec>
<Error Text="$(OutputMessage)" Condition="$(ExitCode) == 10" />
<!-- <Error Text="(optional text) : $(OutputMessage)" Condition="$(ExitCode) == 11" />
<Error Text="(optional text) : $(OutputMessage)" Condition="$(ExitCode) == 12" /> -->
</Target>
And edit the file foobar.bat:
echo foobar : error 1: This is a test error.
exit /b 10 <-- /b parameter needed if used in a .bat file
The important part is the exit that will set the code we want to use afterwards.
You can have more than one Error task do to more conditional logging or just use the output as is.

Re: Adding &set errorlevel=0 to the end of my batch script has no effect.
To ignore the exitcode from a single command use || not & or &&. e.g.
Robocopy || set errorlevel=0
This says only if RoboCopy exits with errorlevel != 0, set errorlevel=0
What does “&&” do in this batch file?]1 explains this and more
Historical Notes
The single ampersand e.g.
(prog1 arg1 arg2) & (cmd2 arg1 arg2 arg3)
runs both commands. It was not very useful in DOS. In Unix, it runs both commands at the same time (2 processes), waiting until both finished. Since DOS did not support multiple-processes the '&' was just syntactic sugar for running sequentially.
The single pipe prog1 | prog2 suffered the same limitations in DOS. In Unix after prog1 writes a modest amount on stdout, it is available to prog2 on its stdin.
In DOS this was shorthand for
prog1 > tmpFile
prog2 < tmpFile
In many cases this worked well enough. In the simple case of write1Meg | head, (or more)
DOS had to run to completion before, head could exit after reading the 1st 10 lines.
What does & do?
Unix also supports & at the end of the command-line
prog1 &
This starts prog1 and returns control to the console quickly.
&& and || only make sense when you know that an exit code of 0 is treated like 'true' and non-zero as 'false'. Also short-circuit evaluation is done, so the second command after checking the exit code of the first.
prog1 && prog2
After prog1 exits, prog2 runs only if exitcode == 0
prog1 || prog2
After prog1 exits prog2 runs only if exitcode != 0

Related

Get the ErrorLevel in Jenkins

I created/modified a Resource translator Tool in C# that check the Format in all my resource files in a project.
the program returns an integer.
0 means no Format issue has been found.
A number > 0 is the count of all format issues found.
Less than 0 is an error like Folder not found etc..
I need to integrate this process in our Jenkins build pipeline (I need to stop the build if the return is not 0)
I modified the Jenkins Script and it's working pretty good, the only problem is that I can't catch up the ErrorLevel.
I want like to throw an Eco blah-blah if the return is 0 and something else if the return is != 0.
any help how to do that.
This what I did so far, as I said it's working and the build stop if the return value is not 0, but I need to catch that value somehow to know for example the Total count of the Format issues I have etc..
try{
stage('Check Translation'){
buildResult.checkTranslationSuccssfull = false
// Clean project
bat "${MSBuildPath} ${WORKSPACE}\"\\Translator\\ResxTranslator.sln\" /t:Clean,Build /p:Configuration=\"Release\" /p:Platform=\"x86\" /p:BuildProjectReferences=false >>${OutPutBuildLog}"
// Build reference SmartFramework
bat "#Echo Off"
bat "#Echo [Check all Resx format]"
bat "#echo"
bat "${WORKSPACE}\\Translator\\bin\\Release\\ResxTranslator.exe /checkForamt ${WORKSPACE}\\DataBlock\\SmartFramework"
buildResult.checkTranslationSuccssfull = true
}
}
catch(Exception ex){
echo "test ${env.errorlevel}"
echo "Check Translation failed. Check BuildServer solution."
echo ex.toString()
currentBuild.result = 'UNSTABLE' // mark as unstable to continue with pipeline
}
You could use the returnStatus flag
Normally, a script which exits with a nonzero status code will cause the step to fail with an exception. If this option is checked, the return value of the step will instead be the status code. You may then compare it to zero, for example.
And here's how you could use it
def returnCode = bat (
script: "${WORKSPACE}\\Translator\\bin\\Release\\ResxTranslator.exe /checkForamt ${WORKSPACE}\\DataBlock\\SmartFramework",
returnStatus: true
)
It wouldn't fail the build or throw exceptions so you can handle it properly and do whatever you need.

Retrieving shell script exit code (return value)

Trying to validate a Logstash config file. When running the following line from a Windows command line:
C:> C:\Logstash\bin\logstash -t -f C:\Logstash\config\my.config
I can then check the result using
echo %errorlevel%
which returns 1 in case of a syntax error. Now I want to do this programatically in C#, so:
using System.Diagnostics;
var logstashProcess = Process.Start(#"C:\Logstash\bin\logstash", #"-t -f C:\Logstash\config\my.config");
logstashProcess.WaitForExit();
return logstashProcess.ExitCode == 0;
The problem is that it always returns true (exit code is zero) - even when the config file is totally messed up.
My guess: since C:\Logstash\bin\logstash is a shell script, the zero I get is the shell itself running successfully - not the Logstash process (which is executed from within that script using jruby). Any idea on how to get the real return value? Will a batch file work? (I prefer not to add an extra script to the party at this point)

Visual Studio 2012 Post Build Events - Error Code 255

Here is my attempt to copy my application executable to another folder changing it's name:
IF $(ConfigurationName) == Release (
SET DESTINATION=$(ProjectDir)Output\Distribution
IF NOT EXIST "%DESTINATION%" ( MD "%DESTINATION%" )
XCOPY /Q /Y "$(TargetPath)" "%DESTINATION%"
RENAME "%DESTINATION%\$(TargetFileName)" "$(TargetName).Plain$(TargetExt)"
)
I've tried everything to make it work, but it always throw error code 255 or 1, it depends. Running that code with a plain batch file works like a charm!
You need to enable delayed expansion, using the SETLOCAL EnableDelayedExpansion command. Do it at the top of the post-build event. After that, you can access your variable by using not %VARIABLE_NAME%, but !VARIABLE_NAME! (use an exclamation symbol on either side of the variable name, not the percentage symbol which you would use in a regular batch file).
So, for example
SETLOCAL EnableDelayedExpansion
IF $(ConfigurationName) == Release (
SET DESTINATION=$(ProjectDir)Output\Distribution
echo My destination dir is !DESTINATION!
)
This will output something like
My destination dir is D:\Work\Projects\PBExample\Output\Distribution.
Since the Post-build event command line actually runs as a batch file you need to escape characters like % by doubling them to %%:
https://stackoverflow.com/a/13552702/74585

C#/.Net launched process with exit code -2146234327

I have a C# 4 application which launches another one to execute some Python code. The Python code can be executed with no problems (checked on PythonWin).
In my app I see that the exit code is -2146234327. I've been Googling and couldn't figure out what does it mean.
Any ideas?
Thanks
-2146234327 is HRESULT code, typically looked for in hex. See Interpreting HRESULTS returned from .NET/CLR: 0x8013XXXX:
HOST_E_EXITPROCESS_TIMEOUT 0x80131029 Process exited due to
Timeout escalation.
I’ve written a workaround based on the fact that this is a warning rather than an error.
I have included the following in the DOS Batch file that runs Analyse and Index Rebuild processes for ArcGIS
set myRC=%ERRORLEVEL%
echo %myRC%
set Constant=-2146234327
echo %Constant%
if %myRC% EQU %Constant% set ERRORLEVEL=0
echo %ERRORLEVEL%
Line 1 sets a variable to the value returned from the call command e.g. call D:\Python27\ArcGIS10.2\python.exe D:\Analyze\Analyze.py >> D:\Analyze\Log\output.txt
Line 2 echoes the value returned
Line 3 sets a constant variable
Line 4 echoes this out
Line 5 compares the value returned from the CALL command against the constant and sets the ERRORLEVEL variable to zero if they match
Line 6 echoes out the return Code.
Found this information elsewhere that may shed a little more light on the issue:
https://github.com/ucd-cws/arcpy_metadata/issues/13

Run a c# Console App with .application file type from a .BAT

I've created a console app (using Visual Studio 2010) which can read command arguments.
When I debug, I parse some test parameters which are set in Project-> [project name] Properties... -> Debug -> Command line arguments:
It reads:
"parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
I used the following code to read the parameters:
for (Int16 argumentsCount = 0; argumentsCount < args.Length; argumentsCount++)
{
String[] parameterItem = args[argumentsCount].Split('|');
String parameterName = parameterItem[0].ToString();
String parameterValue = parameterItem[1].ToString();
/*code continues*/
}
When I run in debug mode the app it works just fine and all parameters are read.
I then published the app to a server and ensured it was installed with the correct permissions (for the purposes of demonstration lets say it's on C:\MyApp and the Complied code resides in MyApp.application
I then created a batch script that executes the app. The *.BAT contains the following command:
"C:\MyApp\MyApp.application" "parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
This kind of works as the application executes when I run the batch... However... none of my parameters are being received by my app. I know this because I recompiled and published with some code to read how many parameters are being received with:
Console.Write("Arguments " + args.Length.ToString());
and that shows Arguments: 0
Can someone please tell me how to write my batch script to run the app and parse my parameters/command line arguments.
ETA: Nevermind. Your problem is .application instead of a .exe. Look in your file associations what happens with .application compared to .exe:
> assoc .application
.application=Application.Manifest
> ftype Application.Manifest
Application.Manifest=rundll32.exe dfshim.dll,ShOpenVerbApplication %1
> assoc .exe
.exe=exefile
> ftype exefile
exefile="%1" %*
You see the difference in what is passed there? Namely that normal executables get command-line arguments (the %*). So I guess you should use an executable instead of an executable manifest or whatever .application actually is (I've never seen it in the wild, honestly).
With a fairly minimal test program
class Args {
static void Main(string[] args) {
for (int i = 0; i < args.Length; i++) {
System.Console.WriteLine("[{0}]=<{1}>", i, args[i]);
}
}
}
it works fine for me. The following batch file:
#"args.exe" "parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
yields the following output:
[0]=<parametername1|parametervalue1>
[1]=<parametername2|parametervalue2>
[2]=<parametername3|parametervalue3>
So I guess there is something wrong in the code you didn't show us. Maybe you're not actually using the command-line arguments in your C# application but instead reference a different string[] there?
The pipe character | has a special meaning in batch files. I would suggest using a different character to make things easier. Otherwise you have to use a Escape Character to use the pipe character. It would probably look like this:
"C:\MyApp\MyApp.application" "parametername1^|parametervalue1" "parametername2^|parametervalue2" "parametername3^|parametervalue3"
note the caret ^ before the pipe |.

Categories