Batch file loses logs in loops - batch-file

I have various test cases in a folder that require me to make continuous loops. To try this I tried making a batch script that would loop the test cases. However the earlier completed iterations would be lost and only the most recent iteration would be kept. How can I keep the XML logs of all the iterations?
My batch file looks like this:
FOR /L %%A IN (1,1,300) DO (
call pybot --name *.robot
)

You will need to have your script tell robot to give a unique name to the output file generated by each iteration of the loop. You will then need an extra step to combine all of those outputs into one.
First, generating unique output files:
FOR /L %%A IN (1,1,300) DO (
call pybot --output output-%%A.xml *.robot
)
Note: by default pybot will generate log.html and report.html. If you want to generate a single unified log and report, you might want to suppress them within the loop. If so, add --log none --report none before the filenames to prevent these files from being created in the loop.
Next, you can use rebot to join all of those individual reports into a single report:
call rebot *.xml
I don't know if rebot is a known command on your system -- it's part of robot but I don't know how you installed things on your system. Generally speaking, if pybot is a valid command, rebot should be too. For more information on rebot see Post-processing outputs in the robot framework user guide.
Note: you seem to have a bug in your batch script. When you do call pybot --name *.robot, the very first file will not get run as a test since it will be given to the --name option rather than be treated as a test file that should be run.

Specify explicitly the log file names, with these parameters:
FOR /L %%A IN (1,1,300) DO (
call pybot --output otput_%%A.html --log log_%%A.html --report report_%%A.html *.robot
)
Have in mind any selenium screenshots will still be overwritten though (if you are using selenium in your tests).

FOR /L %%A IN (1,1,300) DO (
call pybot --name *.robot
)>>afilename.txt

Related

Kicking off a script and moving on to start another

I'm trying to remotely deploy some software and I have a few batch scripts to help this process along. The basics of my process is to have a text list that scriptA goes through, scriptA copies the necessary files to the target PCs (retrieved from the list) and launches ScriptB. The theory would then be that it would move on to the next PC in the list as soon as ScriptB launches and doesn't wait for ScriptB to finish before moving on. The basics of what I have are below:
ScriptA:
Set /P List= Please enter the list name
Set /P Name= Please enter your username
FOR /F %%A IN (%LIST%) DO (
MKDIR \\%%A\C$\Temp\Install
XCOPY "\\share\necessary files" "\\%%A\C$\Temp\Install"
PSEXEC \\%%A -u DOMAIN\%NAME% -e "\\%%A\C$\Temp\Install\scriptB.bat"
)
ScriptB just runs the installer and cleans up after itself.
Like I said, the goal would be that once scriptA has finished copying over files and gets things kicked off, it would move on to the next PC on the list. I've confirmed that everything works as is right now (so please ignore any random things that wouldn't work in the pseudocode above) it just takes forever because it waits for the installation to finish before moving on.
EDIT:
I realized I had the wrong files shown as being copied. What was originally listed as 'install.bat' should have been scriptB. I apologize, it has been very hard to try to get my question across as I'm having a very hard time describing the problem.
Per Request, here is how I was using start:
ScriptA:
START PSECEC \\%%A -u DOMAIN\%NAME% -e "\\%%A\C$\Temp\Install\ScriptB.bat"
It worked to start ScriptB in a new window, but what I'm really trying to have as the final product is:
scriptA gets prompts for the list of PC names
scriptA pulls the first name from the list and copies over the install files from a network share, including scriptB and puts them in \temp\install
scriptA kicks off scriptB on the PC it just copied files to.
While scriptB is running, scriptA moves on and copies the files to the next PC on the list and kicks of the next copy of scriptB
repeat until the whole list of PCs is completed.
I hope this helps to clarify things, and again, I apologize for the confusion. I have all of the steps listed above working as I would hope, the only thing that isn't working is that I can't get scriptA to kick off scriptB without pausing scriptA to wait for scriptB to finish and what I would like to have happen is that it moves on without waiting (so that I could start this script at the end of the day and it would continue installing at night until it finished the list of PCs).
Thanks again for any help!
You can use the START command to launch a command without waiting for it to end before moving on. Note that this will execute the specified command in a newly created command prompt, not in the same command prompt process.
Be aware though that if the path to your executable/batch file contains spaces, you must specify an empty string argument as the first argument. Example:
START "" "C:\Path with spaces\My other script.bat"
This is due to the fact that if the first arguments is surrounded by quotes, it is considered as being the title of the new command prompt that is launched to execute your new process. Specifying an empty argument (or the title you'd like to use for that matter) will work around this situation.
The further we are away from the actual problem, the less able we are to help. The more general the question, the more vague the response.
We're pointlessly mapping from "ScriptB" to "Install.bat" and you've claimed to have added the start command but not shown us where you've used it.
Using your original script, changing
PSEXEC \\%%A -u DOMAIN\%NAME% -e "\\%%A\C$\Temp\Install.bat"
to
start "installing on %%A" PSEXEC \\%%A -u DOMAIN\%NAME% -e "\\%%A\C$\Temp\Install.bat"
should solve the problem - but no guarantees.

Using a condition in a batch script with SQL

I'm trying to set up a batch script that basically runs a SQL statement against a database, and if the script returns results it will follow some logic.
Is there a way to have SQLCMD actually return the number of rows it found, or something similar?
I see that I can have the output displayed on the screen or a file, but is there a way to have it put it into a variable so I can have the script evaluate the variable? For example:
SQLCMD -q "select count(*) from active_connections" -r #varactive
IF #varactive > 0 THEN
<do things>
ELSE END
Or would I need to switch to Powershell to handle this sort of logic?
While #Gary is technically correct that the only thing returned is the ERRORLEVEL, sqlcmd does also display its results to STDOUT. Armed with that, you could do something like this in a batch file:
set SERVERNAME=yoursqlserver
for /f "skip=2" %%x in ('sqlcmd -S %SERVERNAME% -Q "select count(*) from active_connections" ^| findstr /v /c:"rows affected"') do set COUNT=%%x
echo There are %COUNT% records in the active_connections table.
See Docs for sqlcmd and you will see quite a few options you probably never paid attention to.
The only thing an executatble "returns" to the batch script environment is the ERRORLEVEL. For SqlCmd you need the -b option to set this (based on the sql server error level)
If you use the -m option, you can control the error messages send to stdout -- I can't test at the moment, but I think this include the rows affected message (a level 0 error perhaps). You would then have to parse this too (ugly in batch scripts)
This sounds like a real kludge at best to be, you are likely better off to use a better scripting environment. PowerShell, Perl, Python, etc. all more powerful and you can find plenty of examples on-line.
Batch is best when you have a "no-deployment" requirement or you needs are simple. Easy to hit the wall as needs change.

SVN Update specific files from repository only

There's this repository which is many many gigabytes, 99% of which I don't need. What I want to do is get/update only the *.js *.css *.html .doc and *.pdf files. The rest, which are the enormous ones, I want to leave up there and not waste time and disk space getting because I don't need to look at them and I'll never be changing them.
I realize that the svn:ignore feature isn't what I need, that's related only to what gets checked in and what gets ignored. I also know that there's no parameters or settings in SVN that I can take advantage of to do what I want.
What I have found though is that if I right-click on my SVN folder and select "Check for Modifications" and then in the next dialog choose "Check repository" then I get a full list of the files I don't have. It's then an easy task to add "Extension" to the column headers and sort by extension. I can then scroll down and find all the .js files grouped together.
Here's where my #fail happens. If I right-click on ONE of the JS files and select UPDATE, then it will bring the file down and create the sub-directory hierarchy necessary to support that file. This is exactly what I'd want to happen. At this point I jump in the air thinking I've found what I need. This isn't such a troublesome process, I can live with this. Then I selected all of the JS files and right-clicked. First thing I noticed is that the context menu that appears has less options, that's troubling. But the UPDATE option is there, so I'm not too worried. I choose UPDATE then click OK, just like I did for the one single JS file I'd earlier tried. What happens next is the weird thing though. Instead of repeating the process that happened with the one single file, but this time to all selected files, it shows "Skipped" against each file and reports it's done. This happens every time. I can do each file manually (which would take hours) but I can't do them all at once.
Help. I'm doing this in a virtual machine which I'd rather not quadruple the size of just to get files I don't need.
Sorry for the delayed answer, there's been a lot going on and I also had to spend some time to get this working. As you already noted, there is no straightforward way to do an "extension-only-checkout". But there is a way using Subversion command-line tools and a batch script I wrote. It works by using the sparse directories feature of Subversion, which lets you specify which "depth" a checkout should have. By specifying a depth of empty, an empty working copy is created and no files or folders are actually checked out. Then, you can update immediate files and folders of your choice from the repository into that working copy. This allows to create that "extension-only-checkout" which you're after.
The script I wrote allows you to specify multiple extensions in the EXTENSIONS variable separated by spaces. The repository specified in the SVN_ROOT variable is then scanned for files with the given extensions. Then it proceeds to build up a working copy which consists only of the directory structure needed to support the files having the extensions you specified (using the method described above). I tested it quite a bit and hope it will suit your needs.
Note: Depending on the size of the repository and the number of files matching the specified extensions, the process of creating the working copy will take some time.
#ECHO OFF
SetLocal EnableDelayedExpansion
SET SVN_ROOT=svn://your-repository.com/svn/your-project
SET EXTENSIONS=.js .css .html .doc .pdf
SET ROOT_DIR=%CD%
ECHO Listing repository...
svn -R ls %SVN_ROOT% > _files-all.txt
REM filter list for specified extensions
FOR %%H IN (%EXTENSIONS%) DO (
TYPE _files-all.txt | FINDSTR /I /R "%%H$" >> _files-selected.txt
)
REM initial checkout in empty mode
svn co %SVN_ROOT% --depth empty .
FOR /F "tokens=*" %%I IN (_files-selected.txt) DO (
REM "escape" path elements by wrapping them into double quotes
SET TMP_PATH=%%I
SET TMP_PATH="!TMP_PATH:/=" "!"
ECHO Fetching %%I
REM iterate over path elements
FOR %%J IN (!TMP_PATH!) DO (
REM "unescape" each path element again
SET PATH_ELEM=%%J
SET PATH_ELEM=!PATH_ELEM:~1,-1!
REM if we don't have this element, fetch it from repository
IF NOT EXIST "!PATH_ELEM!" (
svn up %%J --depth empty 2>&1 > nul
)
REM if the element is a directory, enter it
IF EXIST %%~sJ\NUL CD %%J
)
CD !ROOT_DIR!
)
REM clean up temporary files
DEL _files-all.txt _files-selected.txt
I ended up having to abandon my dreams of having an svn update that only gets me certain file extensions and leaves all others on the server. I had to accept I need to get the whole thing, unless I want each update to involve navigating a large tree structure and selecting only the sub-folders I want.

Batch incrementation from external file

I have a script who creates new tags in a SVN, and add some files. I want to automate this task so I would like to find some way to do automatically the incrementation for the tags name, from 1.0 to X.0.
I thought about a conf file who would contains "1.0" as a first version number and who would be overwrite at each call to the script. But not sure I can get the "1.0" value from the file and then do an incrementation on it in my script.
Any help would be really appreciate.
Thanks in advance
Don't create a seed configuration file. Instead, let the batch script default to 1.0 if file does not exist.
#echo off
setlocal
set "conf=version.conf"
if not exist "%conf%" (set version=1.0) else (
for /f "usebackq delims=." %%N in ("%conf%") do set /a version=%%N+1
)
set "version=%version%.0"
(echo %version%)>"%conf%"
I'm assuming you will never run this process multiple times in parallel - it can fail if you do run in parallel. Modifications can be made to lock the conf file so you can run in parallel if need be. See the accepted answer to how to check in command line if given file or directory is locked, that it is used by a process? for more info.
Take a look at keywords in Subversion using autoprops.
First, setup subversion to honor keyword expansion
enable-auto-props = yes
[auto-props]
version.txt = svn:keywords=Revision
Then, setup a simple file, let's call it version.txt with the $revision$ keyword and some random content.
$revision$
Random content
Then, in your batch file, recreate the version.txt file with new random content
echo $revision$ >version.txt
echo %random% %date% %time% >>version.txt
and check in this new file every time your batch file is run, so it will become
$revision 32 $
4214 Mon 21/01/2013 15:53:27,62
This way, subversion will keep an accurate version number of all the runs of the batch file, even in multiple clients and simultaneosly.
You might then extract and use the revision number from version.txt with code similar to
for /f "tokens=1,2" %%a in (version.txt) do (
if %%a==$revision (
echo Revision number is %%b
echo do something with %%b, create %%b tag or whatever
)
)
Since you don't say what language you want to use only general remarks can be given:
It certainly is possible to maintain a small 'version' file holding the 'dottet version number', something like 0.2.6 maybe. That files content can be read by any process. You should implement a little collection of methods to split that content into its numerical tokens (major and minor version and the like). Those numerical values can be processed by any mathematical function you like to use. For example you can increment them. Another method would be some 'implode' function that takes the numerical tokens and creates again a 'dottet version number' (now maybe 0.2.7...) and finally you can write that information back into the file. It certainly makes sense to allow an argument that controls which part of the version should be incremented.
Such scheme is not really efficient, but often sufficient.
Note, that such approach will only work if you can guarantee that it is always only a single process to access that version file. Otherwise multiple processes might overwrite each others results which certainly is a cause of problems.
As an alternative, maybe a more elegant alternative, you might consider treating the subversion repository itself as seed storage for your version number: instead of reading a special files content (what if that file is deleted or something else happens?) make a request to the tags folder inside subversion. It should contain all previously tagged versions. So that is precisely the information you want. Take all version numbers, sort them, take the highest one and process it as above.

Jenkins always considers a build successful using batch/bat

I just joined a company that uses batch files to build a C++ project. The batch does all sorts of things (updates svn, which is now done by jenkins), creates build folders, deletes unnecessary files after building, copies library files to the build folder, etc.
My problem is Jenkins always considers the build successful, even when it´s not. The .bat file creates a file called errormake.txt when something goes wrong. How do I make jenkins read that and mark the build as a failure?
Also, is there any way I can find out the build folder Jenkins created from inside the .bat file (maybe send a variable when I call the batch file)?
This is the single line I'm currently using to call the .bat file:
call "C:\Source\BuildVersion\AppName\build_version.bat"
Edit: Also, this project is split up into several SVN repositories. %SVN_REVISION% is blank. How can I get the correct %SVN_REVISION% from the first repository (the main one)?
To answer each of your questions -
Jenkins always return "SUCCESS", even when the Job actually failed:
Jenkins sets the status of the Job, based on the return-code of the last command
that ran in each "Execute windows batch command" block.
If your last command is copy some.log D:,
Jenkins thinks everything is OK
(If the 'copy' command went fine...)
Use EXIT xx or EXIT /B xx, depending on your OS,
where 'xx' is some integer greater than zero.
How do I make Jenkins mark the build as a failure, based on a log-file:
Use the Text-finder Plugin, as mentioned by sdmythos_gr .
Is there any way I can find out the build folder Jenkins created:
There are a few parameters that are available as environment-variables
for each script that runs under Jenkins - see here for the list of those parameters:
Jenkins Environment Variables.
To your question:
%WORKSPACE% - The absolute path of the workspace
%BUILD_NUMBER% - The current build number, such as "153"
%BUILD_ID% - The current build id, such as "2005-08-22_23-59-59"
(YYYY-MM-DD_hh-mm-ss)
How can I get the correct %SVN_REVISION% from the first repository:
This answer is from the same link:
%SVN_REVISION% - For Subversion-based projects,
this variable contains the revision number of the module.
If you have more than one module specified, this won't be set.
Hope that helps
Jenkins use the windows error code to know whether a build failed or not.
You should return a value different from 0 when your build failed, with "exit /B 1" for example.
On "newer" versions of Windows (I tested on Server 2012 R2), put the following at the end of each Windows batch command:
#EXIT /b %ERRORLEVEL%
This will pass the error code that the cmd.exe received back to the caller (i.e. Jenkins). The "#" turns off echoing so you don't clutter up your log.
If you have multiple lines in the command and want to stop after the first failure, put the following after each line that you want to check (yes, this is not pretty):
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
For example:
step1.exe
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
step2.exe
#IF NOT %ERRORLEVEL% == 0 EXIT /b %ERRORLEVEL%
call "C:\Source\BuildVersion\AppName\build_version.bat"
#EXIT /b %ERRORLEVEL%
I'm also going to answer just part of your question.
There is a Text Finder plugin for Jenkins that you could use.
https://wiki.jenkins-ci.org/display/JENKINS/Text-finder+Plugin
You can mark the build as unstable or failed at the end of the build depending on the contents of a file or the console output.
Maybe this could help...
I know the question is quite older but may be useful to some people. To execute your bat file, instead of using following line,
call "C:\Source\BuildVersion\AppName\build_version.bat"
You can use below format,
<someRelativeOrAbsolutePath>\<.batFileName> <param1> <param2> <and so on>
Executing the command in this way inside Execute Windows Batch Command of Build section of Jenkins will use your last return code of the command. ${BUILD_STATUS} will depend on that. And you will not have to modify your script to return some condition based error codes.
As other users have stated your batch files should use "exit /B 1". Here is a trick to chain together your calls causing Jenkins to return a failure if one fails:
call a.bat &&^
echo "a success" &&^
call b.bat &&^
echo "b success"
"&&" denotes that the next action should only run on success (exit code 0). "^" lets us split the command into multiple lines. The downside to this approach is the build progress bar doesn't display accurately.

Resources