Jenkins自动化构建流程记录

 

1

由于本人没有接触过使用Jenkins进行版本构建相关的内容,最近的项目里正好负责了,所以在此记录,做个备忘。和学习。

版本机安装Jenkins,启动Jenkins服务,创建管理员账户,然后登陆。

2

在这里首先在Unity中为版本构建创建一个构建脚本,并且声明一个方法,作为入口,作为Jenkins静默启动Unity进程并且要调用的函数。

/// <summary>
/// 出包函数入口
/// </summary>
[MenuItem("构建版本")]
private static void Build()
{
    //...
}

然后在Jenkins配置中,我将构建流程划分为了Pipeline的几个阶段,分别是:

  • Clean:移除版本机项目内的新文件(unversioned files),这类一般是生成的meta文件,或引擎自己生成的一些别的文件,并且revert所有的变更,让版本机项目保持干净状态。
  • Pull:拉取最新版本到版本机本地。
  • Revert:如果有需要,则回退到指定版本,在指定版本进行打包。
  • GetVersion:获取当前的版本号以参与构建。
  • SetBuildMode:通过一些参数自定义构建。
  • Build:构建。
  • Notification:通知构建完成。

Jenkins使用Groovy脚本声明Pipeline,语法如下

//要处理的SVN目录
def SVN_PATH = 'X:\\your_unity_project'

pipeline
{
    stages 
    {
        //使用stage声明一个pipeline阶段
        stage('Clean') 
        {
            //...
        }
        stage('Update') 
        {
            //...
        }
        stage('Revert') 
        {
            //也可使用when+expression来表示条件,以条件地执行某些阶段
            when{
                expression{
                    //...
                }
            }
            //...
        }
        stage('GetVersion') 
        {
            //..
        }
        stage('SetBuildMode')
        {
            //..
        }
        stage('Build') 
        {
            //...
        }
        stage('Notification') 
        {
            //...
        }
    }
}

接下来摘取一些stage来做说明。

3

Jenkins支持在部署的机器上执行批处理,可以利用这点对版本机项目进行更新,以SVN为例。

  • Clean:

    stage('Clean') 
    {
        steps {
            //调用来利用SVN命令行的方式清理项目
            bat "svn cleanup ${SVN_PATH} --remove-unversioned --remove-ignored"   
            bat "svn revert -R ${SVN_PATH}"  
        }
    }
    

其他stage如revert,update同理,只要调相应的svn命令即可。

  • Revert:

    假如我想要回退到特定版本进行构建,在这种情况下,需要一个参数来表示回退到哪个版本。

    在构建触发器中添加一个字符参数,SVNVersion,并且将他的默认值设置为0.

    在对应的条件stage中,可以这样使用

    stage('SvnRevert') 
    {
        when {
            //当SVNVersion不为0,执行该stage
            expression {  SVNVersion != '0'}
        } 
        steps{
            //回退到指定版本
            bat "svn update -r ${SVNVersion} ${SVN_PATH}"                
        }
    }
    
  • SetBuildMode:如果想要通过一些参数来自定义构建流程,或者让其影响pipeline逻辑的话,则需要一些额外参数。

    可以通过在构建触发器中添加一些参数,或者在流水线脚本中声明一些参数的方式来实现,以我的为例以做参考。

    BuildMode,PackageDebugMode,IsOnlyBuildApp,IsForceRebuildAB,BuildTarget,IsBuildRelease

    他们的含义分别如下

    //触发器添加参数:
    //BuildMode:构建模式,构建分包还是整包
    //PackageDebugMode:构建调试模式
    //SVNVersion:要回滚的版本
    //IsOnlyBuildApp:是否仅构建APP
    //IsForceRebuildAB:是否强制重新构建AssetBundle,因为引擎默认增量打包
    //BuildTarget:构建的目标平台,Windows/Android/iOS
    //IsBuildRelease:是否构建发行版
      
    //在流水线中,如果想要使用他们,先在groovy脚本开头声明
    def BUILD_PARAM = "${BuildMode}"
    def IS_ONLY_BUILD_APP = "${IsOnlyBuildApp}"
    def IS_FORCE_REBUILD_AB = "$IsForceRebuildAB"
    def BUILD_ARGS = ""
    def BUILD_TARGET = "${BuildTarget}"
    def IS_BUILD_RELEASE = "${IsBuildRelease}"
    

    以SetBuildMode stage为例,我这样处理:

    stage('PackageModeParse')
    {
        steps{
            script
            { 
                //可以像java/C#那样在groovy中声明一个stringBuilder用以组合构建参数
                //在构建脚本中添加对应的参数
                def builder = new StringBuilder("PackageDebugMode")
                if (PackageDebugMode == 'VSDebug') 
                {
                    builder.append("-VSDebug")
                } 
                else if(PackageDebugMode == 'MonoPDB') 
                {
                    builder.append("-MonoPDB")
                }
                else if(PackageDebugMode == 'DeepDebug') 
                {
                    builder.append("-DeepDebug")
                }
                else
                {
                    builder.append("-Normal")
                }
                  
                //添加上面声明的参数
                builder.append(" IsOnlyBuildApp-").append(IS_ONLY_BUILD_APP)
                builder.append(" IsForceRebuildAB-").append(IS_FORCE_REBUILD_AB)
                builder.append(" BuildTarget-").append(BUILD_TARGET)
                builder.append(" IsBuildRelease-").append(IS_BUILD_RELEASE)
                  
                //将参数输出到BUILD_ARGS
                BUILD_ARGS=builder.toString() 
                echo BUILD_ARGS
            }                
        }
    }
    

    然后可以通过命令行传入到构建脚本中,参与构建逻辑

    stage('BuildFull') 
    {
        steps 
        {
            bat """
            ${UNITY_PATH} -projectPath ${PROJECT_PATH} -executeMethod your_project.Editor.ProjectBuild.Build ProjMode-FULL ${BUILD_ARGS} -quit -batchmode  -logFile "${PROJECT_PATH}/Reports/Build/JenkinsBuildLog.txt"
            """
        }
    }
    

    以静默方式启动unity,传入项目路径。

    executeMethod可以调用指定方法,之后传入自定义参数

    -logFile输出编辑器的日志文件,方便查看

    unity的命令行参数,可以查看文档:https://docs.unity.cn/cn/2019.4/Manual/CommandLineArguments.html

    在构建脚本中,可以这样获取命令行参数

    /// <summary>
    /// 获取jenkins构建参数,是否构建发行版
    /// </summary>
    public static bool IsBuildRelease()
    {
        //使用System.Enviroment.GetCommandLineArgs()获取命令行参数
        foreach (string arg in System.Environment.GetCommandLineArgs())
        {
            if (arg.StartsWith("IsBuildRelease"))
                return true;
        }
        return false;
    }
    

    大致流程就是如此,之后就是构建项目的逻辑了,比如收集资源,构建资源,构建播放器等等,就不多说了。

补充,经群里大佬指点,给了几个建议:

1、可以考虑全用python做,因为要考虑跨平台,ios用sh,win上bat的,要维护的就多,即使是shell也有很多命令不好写。

2、参数最好是用调用函数的方式,去获取命令行参数的,后续单机写起来麻烦,或者从能单机出包之后,再往Jenkins上挪。

后续:添加了SideLinked Bar,自定义侧边栏,可以配置下载构建日志 / 包体