构造jenkins groovy管道脚本的正确方法

构造jenkins groovy管道脚本的正确方法,jenkins,groovy,Jenkins,Groovy,我写了一个与jeknins一起使用的管道,但是作为jenkins脚本的新手,我有很多不清楚的东西,这是整个脚本,我将在下面表达这些问题 脚本: node() { def libName = "PROJECT" def slnPath = pwd(); def slnName = "${slnPath}\\${libName}.sln" def webProject = "${slnPath}\\PROJECT.Web\\PROJECT.Web.csproj

我写了一个与jeknins一起使用的管道,但是作为jenkins脚本的新手,我有很多不清楚的东西,这是整个脚本,我将在下面表达这些问题

脚本:

    node()
{
    def libName = "PROJECT"
    def slnPath = pwd();
    def slnName = "${slnPath}\\${libName}.sln"
    def webProject = "${slnPath}\\PROJECT.Web\\PROJECT.Web.csproj"
    def profile = getProperty("profiles");
    def version = getProperty("Version");
    def deployFolder = "${slnPath}Deploy";
    def buildRevision = "";
    def msbHome = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\MSBuild\\15.0\\Bin\\msbuild.exe"
    def msdHome = "C:\\Program Files (x86)\\IIS\\Microsoft Web Deploy V3\\msdeploy.exe"

    def nuget = "F:\\NugetBin\\nuget.exe";

    def assemblyScript = "F:\\Build\\Tools\\AssemblyInfoUpdatePowershellScript\\SetAssemblyVersion.ps1";

    def webserverName ="192.168.0.116";

    def buildName = "PROJECT";
    def filenameBase ="PROJECT";

    stage('SCM update')
    {
        checkout([$class: 'SubversionSCM', additionalCredentials: [], excludedCommitMessages: '', excludedRegions: '', excludedRevprop: '', excludedUsers: '', filterChangelog: false, ignoreDirPropChanges: false, includedRegions: '', locations: [[credentialsId: '08ae9e8c-8db8-43e1-b081-eb352eb14d11', depthOption: 'infinity', ignoreExternalsOption: true, local: '.', remote: 'http://someurl:18080/svn/Prod/Projects/PROJECT/PROJECT/trunk']], workspaceUpdater: [$class: 'UpdateWithRevertUpdater']])
    }

stage('SCM Revision')
    {
    bat("svn upgrade");
    bat("svn info \"${slnPath}\" >revision.txt");

        for (String i : readFile('revision.txt').split("\r?\n"))
        {
            if(i.contains("Last Changed Rev: "))
            {
                def splitted = i.split(": ")

                echo "Revisione : "+ splitted[1];

                buildName += "." + splitted[1];
                currentBuild.displayName = buildName;
                buildRevision += version + "." + splitted[1];
            }
        }
    }
    stage("AssemblyInfo update")
    {
            powerShell("${assemblyScript} ${buildRevision} -path .") 
     }
    stage('Nuget restore')
    {
        bat("${nuget} restore \"${slnName}\"")
    }

    stage('Main build')
    {
        bat("\"${msbHome}\" \"${slnName}\" /p:Configuration=Release /p:PublishProfile=Release /p:DeployOnBuild=true /p:Profile=Release ");

        stash includes: 'Deploy/Web/**', name : 'web_artifact'
        stash includes: 'PROJECT.Web/Web.*', name : 'web_config_files'

        stash includes: 'output/client/release/**', name : 'client_artifact'
        stash includes: 'PROJECT.WPF/App.*', name : 'client_config_files'

        stash includes: 'PROJECT.WPF/Setup//**', name : 'client_setup'
    }

    stage('Profile\'s customizations')
    {
        if (profile != "")
        {
            def buildProfile = profile.split(',');

        def stepsForParallel = buildProfile.collectEntries {
            ["echoing ${it}" : performTransformation(it,filenameBase,buildRevision)]

        }

        parallel stepsForParallel;
        } 
    }

post
{
    always
    {
        echo "mimmo";
    }
}

}


def powerShell(psCmd) {
bat "powershell.exe -NonInteractive -ExecutionPolicy Bypass -Command \"\$ErrorActionPreference='Stop';[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;$psCmd;EXIT \$global:LastExitCode\""
}

def performTransformation(profile,filename,buildRevision) {
 return {
    node {
        def ctt ="F:\\Build\\Tools\\ConfigTransformationTool\\ctt.exe";
        def nsiTool = "F:\\Build\\Tools\\NSIS\\makensis.exe";
        def slnPath = pwd();

        unstash 'web_artifact'
        unstash 'web_config_files'

        def source = 'Deploy/Web/Web.config';
        def transform = 'PROJECT.Web\\web.' + profile + '.config';

        bat("\"${ctt}\" i s:\"${source}\" t:\"${transform}\" d:\"${source}\"" )

        def  fname= filename + "_" + profile + "_" + buildRevision + "_web.zip";

        if (fileExists(fname))
            bat("del "+ fname);

        zip(zipFile:fname, dir:"Deploy\\Web")

        archiveArtifacts artifacts: fname

        //Now I generate the client part
        unstash 'client_artifact'
        unstash 'client_config_files'
        unstash 'client_setup'

        def sourceClient = 'output/client/release/PROJECT.WPF.exe.config';
        def transformClient = 'PROJECT.WPF/App.' + profile + '.config';

        bat("\"${ctt}\" i s:\"${sourceClient}\" t:\"${transformClient}\" d:\"${sourceClient}\"" )


        def directory = new File(pwd() + "\\output\\installer\\")

        if(!directory.exists())
        {
            bat("mkdir output\\installer");
        }

        directory = new File( pwd() + "\\output\\installer\\${profile}")

        if(!directory.exists())
        {
            echo " directory does not exist";
            bat("mkdir output\\installer\\${profile}");
        }
        else
        {
            echo " directory exists";
        }

           def  filename2= filename + "_" + profile + "_" + buildRevision + "_client.zip";

            bat("${nsiTool} /DAPP_VERSION=${buildRevision} /DDEST_FOLDER=\"${slnPath}\\output\\installer\\${profile}\" /DTARGET=\"${profile}\" /DSOURCE_FILES=\"${slnPath}\\output\\client\\release\" \"${slnPath}\\PROJECT.WPF\\Setup\\setup.nsi\"  ");

           if (fileExists(filename2))
              bat("del "+ filename2);
           zip(zipFile:filename2, dir:"output\\installer\\" + profile);

           archiveArtifacts artifacts: filename2
    }
 }
 };
系列问题包括:

  • 我见过一些脚本,其中所有内容都封装在管道{}中,这是必要的还是Jenkins管道插件粘贴它
  • 我真的不喜欢将所有这些定义都放在节点中,然后在下面复制
  • 我看不到Jenkins工作流内部的并行性,即使我有4个执行器处于空闲状态
  • 我无法调用post pipeline事件来清除工作区(现在它只是一个echo)
  • 有两种类型的管道。像您所写的一样,纯groovy被称为脚本化管道它周围的块是一个声明式管道。声明式管道对于新的管道用户来说更容易,并且是开始使用管道的好选择。许多管道不需要脚本允许的复杂性
  • 这就是groovy。如果你想声明一堆变量,你必须在某个地方做。否则你就要在脚本的某个地方硬编码这些值。在groovy中,你不必声明每个变量,但你必须在某个地方定义它,除非你知道声明将如何影响作用域,你应该只声明它们编程语言需要某种类型的变量声明,特别是当你不得不担心范围时,所以我不认为这是一个问题。我认为在顶部的一个位置定义所有变量值是非常干净的。更易于维护
  • 乍一看,您的并行执行看起来应该可以工作,但除非我设置并运行了它,否则很难说。可能是并行部分运行得足够快,以致UI无法更新。您应该能够在控制台输出中看到它们是否并行运行
  • post
    管道块在脚本化管道中不可用。这是声明性管道语法的一部分。在脚本化管道中,要执行类似操作,必须使用try/catch捕捉错误并运行post类型的操作