As part of my Jenkins pipeline I want to zip my output directory to a shared drive and I have a batch script that works wonderfully when running it through a shell, but when Jenkins runs it the file_names argument to 7zip goes missing and it zips the entire project folder instead.
The batch script looks as follows, where GGProjectName has a string value(no special characters) and CHANGESET is an integer
set path=D:\Data\Builds\%GGProjectName%\development
call "C:\Program Files\7-Zip\7z.exe" a -tzip %path%\%GGProjectName%-%CHANGESET%.zip .\Build\
Calling the batch script through a shell gives the following output with GGProjectName=ProjectName and CHANGESET=2:
E:\Jenkins\ProjectName\ProjectName_Main\workspace>set path=D:\Data\Builds\ProjectName\development
E:\Jenkins\ProjectName\ProjectName_Main\workspace>CALL "C:\Program Files\7-Zip\7z.exe" a -tzip D:\Data\Builds\ProjectName\development\ProjectName-2.zip E:\Jenkins\ProjectName\ProjectName_Main\workspace\Build\
7-Zip [64] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04
Scanning the drive:
23 folders, 439 files, 718413046 bytes (686 MiB)
Creating archive: D:\Data\Builds\ProjectName\development\ProjectName-2.zip
Items to compress: 462
Files read from disk: 439
Archive size: 137063321 bytes (131 MiB)
Everything is Ok
Getting Jenkins to run the same script gives the following output, with GGProjectName=ProjectName and CHANGESET=77:
17:04:21 E:\Jenkins\ProjectName\ProjectName_Main\workspace>set path=D:\Data\Builds\ProjectName\development
17:04:21
17:04:21 E:\Jenkins\ProjectName\ProjectName_Main\workspace>CALL "C:\Program Files\7-Zip\7z.exe" a -tzip D:\Data\Builds\ProjectName\development\ProjectName-77
17:05:57
17:05:57 7-Zip [64] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04
17:05:57
17:05:57 Scanning the drive:
17:05:57 856 folders, 14893 files, 2074486211 bytes (1979 MiB)
17:05:57
17:05:57 Creating archive: D:\Data\Builds\ProjectName\development\ProjectName-77.zip
17:05:57
17:05:57 Items to compress: 15749
17:05:57
17:05:57
17:05:57 Files read from disk: 14893
17:05:57 Archive size: 453305828 bytes (433 MiB)
17:05:57 Everything is Ok
I've identified the issue as Jenkins somehow cutting off the last argument to the call to 7z.exe, though I have no idea what causes it.
The Jenkins stage that runs the script is extremely straightforward so I have a hard time seeing that as the cause.
stage('Deploy') {
steps {
bat 'publish.bat'
}
}
I'm running Jenkins 2.204.2 on a Windows machine.
The main problem is most likely the string value assigned to environment variable CHANGESET
which is not just the string 77
, but the string 77
with a carriage return or a line-feed or carriage return + line-feed appended which results in a truncated command line on execution by Jenkins. So the source of this problem must be searched in code which defines the environment variable CHANGESET
with a string not being only the number, but the number with a newline character.
GG_Victor wrote in a comment:
The carriage return seems to have been the issue and changing the assignment of
CHANGESET
to have a.trim()
on the shell output in the jenkinsfile like so:env.CHANGESET = sh (...).trim()
alleviated the issue.
But it would be even better to find out why the environment variable CHANGESET
is defined with a string value with a carriage return appended to the number as that is the real source of the issue.
Another issue with the batch code is the redefinition of the predefined environment variable PATH
with a string being a single folder path. Please take a look on What is the reason for "X is not recognized as an internal or external command, operable program or batch file"? You should know after reading the long answer from top to bottom why path
should not be used as name of a local environment variable. Better would be FolderPath
or ProjectPath
or ArchivePath
instead of path
.
So the first line should be for example:
set "ArchivePath=D:\Data\Builds\%GGProjectName%\development"
The usage of "
as done here is highly recommended. The reason is described in my answer on:
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The command CALL is needed only to call a batch file from within a batch file. It is not needed to run an executable from within a batch file. The Windows command processor halts the batch file execution until the started executable terminated itself. So the batch file execution is in your case not continued by cmd.exe
until the started 7z.exe
finished creating the archive file and terminated with exit code returned back to Windows command processor which assigns it to ERRORLEVEL
for evaluation by one of the next commands.
This behavior on starting a console or GUI executable from within a batch file can be seen easily by creating a batch file with following five lines and execute it with a double click:
@echo off
echo Run Notepad.
%SystemRoot%\Notepad.exe
echo Notepad terminated.
pause
The Windows command processor outputs Run Notepad.
and starts next Windows Notepad. The console window shows just Run Notepad.
as long as the graphical window of Notepad is open because of cmd.exe
waits for termination of Windows Notepad. Once Windows Notepad is exited by the user, the Windows command processor continues and outputs next the line Notepad terminated.
Last the command execution is paused once more because of command PAUSE to give the user the possibility to see that the batch file execution continued after Notepad termination.
This behavior on starting an executable from within a batch file is different to starting an executable from within a command prompt window. Windows command processor does not wait for termination of the started executable if a user opens a command prompt, enters %SystemRoot%\Notepad.exe
and hits key RETURN or ENTER to run Windows Notepad. The user can in this case immediately enter and execute the next command after switching from still opened Notepad window to the Windows command prompt window.
So for the second line should be used:
"C:\Program Files\7-Zip\7z.exe" a -bd -tzip -y -- "%ArchivePath%\%GGProjectName%-%CHANGESET%.zip" ".\Build\"
The double quotes are highly recommended again, especially on full qualified archive file name containing -
after a space to avoid getting the rest interpreted by mistake as switch by 7z.exe
or on full qualified file name containing a space or one of these characters &()[]{}^=;!'+,`~
. It is best to always enclose file/folder names in double quotes even on not being really necessary.
The three additional switches -bd
, -y
and --
are described in help of 7-Zip.