当前位置: 首页 > news >正文

Jenkins 自动构建Job

1.创建Job

  • 登录Jenkins,点击新建Item,创建项目
    在这里插入图片描述
  • 选择Pipeline,然后点击确定
    在这里插入图片描述
  • 接下来主要在Pipeline script中编写脚本

2.签出Git仓库

2.1配置Git账号

  • Manage Jenkins->Security->Credentials 在凭据界面,选择全局
    在这里插入图片描述
  • 添加凭据,添加Git用户名和密码,ID是等下需要使用的。
    在这里插入图片描述

2.2 编写Git签出脚本

在这里插入图片描述

  • 点击 Build Now,就会执行刚刚的脚本。并在Jenkin主目录->workspace->项目名称 下签出对应的Git仓库

3.配置何时执行

3.1 手动执行

直接点击 Build Now 按钮,会立马执行。

3.2 间隔执行

  • 定时获取Git代码,代码更新则构建 (每5分钟执行一次)
    在这里插入图片描述
  • 定时构建,不管代码有没有更新(每5分钟执行一次)
    在这里插入图片描述

3.3 Git有更新主动推送构建

  • 生成触发地址
    在这里插入图片描述
  • 在Git中配置Web 钩子
    使用上面的地址(JENKINS_URL:替换成地址,TOKEN_NAME:替换为身份证令牌Vue1),配置到Git的Web钩子中。可以点击测试,看返回结果。
    在这里插入图片描述
  • 禁用跨站请求伪造(解决错误:No valid crumb was included in the request)
    Git仓库的Web 钩子界面,点击测试推送,返回的响应信息中,提示:No valid crumb was included in the request。
    在Manage Jenkins -> Script Console中执行
hudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION = true
  • 安装Build Authorization Token Root 插件(解决错误:Authentication required)
    Git仓库的Web 钩子界面,点击测试推送,返回的响应信息中,提示:Authentication required。
    Manage Jenkins->Plugins 搜索Build Authorization Token Root,并点击安装
  • Git仓库添加允许列表
    找到gitea的安装目录gitea\custom\conf,编辑app.ini文件
    在这里插入图片描述

4.编写构建脚本

node {
    try {
      stage('SCM') {
        git branch: 'dev', credentialsId: 'Test', url: 'http://127.0.0.1:3000/Test.git'
        // 更新子模块
        bat 'git submodule update --init --recursive'
        bat 'git submodule update --remote'
      }
      stage('BUILD') {
        bat 'dotnet build'
      }
      stage('DEPLOY') {
        bat 'dotnet publish  Test.csproj -c Release -o D:/publish/Test'
      }
    }  catch(Exception e){
        
    }
}

5.发送邮件

当构建失败时,发送邮件通知。

5.1 配置邮件信息

  • 创建邮箱凭据,步骤参考【配置Git账号】
  • 配置邮箱服务器信息 Manage Jenkins->System->Extended E-mail Notification
    在这里插入图片描述
  • 编写邮件发送脚本
node {
      stage('SCM') {
          emailext (
            subject: "编译失败: ${env.JOB_NAME} [${env.BUILD_NUMBER}]",
            body: """
                <p><b>${env.JOB_NAME} [${env.BUILD_NUMBER}]</b> <span style="color:red;">编译失败</span>.</p>
                <p>详情: <a href="${env.BUILD_URL}console">${env.BUILD_URL}console</a></p>
                <br>
            """,
            to: "Test@163.com",
            mimeType: 'text/html',
            from: "codebuild@163.com"
        )
      }
}

6.发布.NET Core 程序

一般Jenkins与应用站点不在同一台服务器,我们可以通过共享文件夹的方式,再使用命令,复制文件到应用站点服务器。

  • 编写powershell脚本文件 copy.ps1
if (!(Test-Path "Y:\")) { 
net use Y: \\192.168.1.100\website /user:administrator 123456
}
Start-Sleep 5
$source = "D:\publish\Test"  
$destination = "Y:\Test"  
$timeThreshold = (Get-Date).AddHours(-1) # 设置时间阈值为一个小时前  
  
# 定义要排除的文件扩展名或名称  
$excludeExtensions = @(".pdb")  
$excludeNames = @("tempfile.txt", "backup.log")  
  
# 使用Get-ChildItem获取文件,并通过管道传递给Where-Object进行筛选  
Get-ChildItem -Path $source -Recurse |   
    Where-Object {   
        # 检查文件的最后写入时间是否早于阈值  
        #$_.LastWriteTime -lt $timeThreshold -and  
        # 检查文件扩展名是否不在排除列表中  
        (-not $excludeExtensions.Contains($_.Extension.ToLower())) -and  
        # 检查文件名是否不在排除列表中  
        (-not $excludeNames.Contains($_.Name.ToLower()))  
    } |   
    ForEach-Object {  
    # 构造目标路径  
    $destinationPath = $_.FullName.Replace($source, $destination)  
    # 如果当前项是文件夹,则创建目标文件夹  
    if ($_.PSIsContainer) {  
        New-Item -ItemType Directory -Path $destinationPath -Force | Out-Null  
    } else {  
        # 否则,复制文件  
        Copy-Item -Path $_.FullName -Destination $destinationPath -Force  
    }  
}
  • 编写jenkins脚本
powershell  "D:/publish/Test.ps1"

7.启动/停止应用站点

替换.NET Core程序时,需要先停止IIS之后才能替换。我们可以在IIS中部署另外一个程序,该程序可以用来停止/启动应用程序池和应用站点。当我们需要发布.NET Core程序时,我们可以先停止应用程序和应用站点,发布成功后,在启动应用程序池和应用站点。
以下代码需要安装Microsoft.Web.Administration、System.ServiceProcess.ServiceController类库

    [Route("api/[controller]/[Action]")]
    [ApiController]
    public class IISController : ControllerBase
    {
        public string GetName()
        {
            return "IIS";
        }

        /// <summary>
        /// 启动站点
        /// </summary>
        /// <param name="siteName"></param>
        /// <returns></returns>
        [HttpGet("{siteName}")]
        public bool StartSite(string siteName)
        {
            var webManager = new ServerManager();
            var startSite = webManager.Sites[siteName];
            if (startSite == null)
            {
                return false;
            }
            if (startSite.State.Equals(ObjectState.Stopped))
            {
                startSite.Start();
            }

            return true;
        }

        /// <summary>
        /// 停止站点
        /// </summary>
        /// <param name="siteName"></param>
        /// <returns></returns>
        [HttpGet("{siteName}")]
        public string StopSite(string siteName)
        {
            var webManager = new ServerManager();
            var startSite = webManager.Sites[siteName];
            if (startSite == null)
            {
                return "不存在";
            }
            if (startSite.State.Equals(ObjectState.Started))
            {
                startSite.Stop();
            }

            return "成功了";
        }

        /// <summary>
        /// 启动应用池
        /// </summary>
        /// <param name="poolName"></param>
        /// <returns></returns>
        [HttpGet("{poolName}")]
        public bool StartPool(string poolName)
        {
            var webManager = new ServerManager();
            var applicationPool = webManager.ApplicationPools[poolName];
            if (applicationPool == null)
            {
                return false;
            }
            if (applicationPool.State.Equals(ObjectState.Stopped))
            {
                applicationPool.Start();
            }

            return true;
        }

        /// <summary>
        /// 停止应用池
        /// </summary>
        /// <param name="poolName"></param>
        /// <returns></returns>
        [HttpGet("{poolName}")]
        public bool StopPool(string poolName)
        {
            var webManager = new ServerManager();
            var applicationPool = webManager.ApplicationPools[poolName];
            if (applicationPool == null)
            {
                return false;
            }
            if (applicationPool.State.Equals(ObjectState.Started))
            {
                applicationPool.Stop();
            }

            return true;
        }

        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        [HttpGet("{serviceName}")]
        public IActionResult StartService(string serviceName)
        {
            try
            {
                using (var serviceController = new ServiceController(serviceName))
                {
                    if (serviceController.Status == ServiceControllerStatus.Stopped || serviceController.Status == ServiceControllerStatus.Paused)
                    {
                        serviceController.Start();
                        serviceController.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
                    }

                    return Ok($"Service {serviceName} started successfully.");
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred while trying to start the service: {ex.Message}");
            }
        }

        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        [HttpGet("{serviceName}")]
        public IActionResult StopService(string serviceName)
        {
            try
            {
                using (var serviceController = new ServiceController(serviceName))
                {
                    if (serviceController.Status == ServiceControllerStatus.Running)
                    {
                        serviceController.Stop();
                        serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
                    }

                    return Ok($"Service {serviceName} stopped successfully.");
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred while trying to stop the service: {ex.Message}");
            }
        }

    }

8.完整Jenkins脚本

node {
    try {
      stage('SCM') {
        git branch: 'dev', credentialsId: 'Test1', url: 'http://127.0.0.1:3000/Test.git'
        // 更新子模块
        bat 'git submodule update --init --recursive'
        bat 'git submodule update --remote'
      }
      stage('BUILD') {
        bat 'dotnet build'
      }
      stage('DEPLOY') {
        bat 'dotnet publish  Test/Test.csproj -c Release -o D:/publish/Test'
      }
      stage('STOPSITE') {
        bat "curl -X GET \"http://192.168.1.100:2000/api/iis/StopSite/Test\""
      }
      stage('STOPPOOL') {
        bat "curl -X GET \"http://192.168.1.100:2000/api/iis/StopPool/Test\""
      }
      stage('COPY') {
        powershell  "D:/publish/test.ps1"
      }
      stage('STARTPOOL') {
        bat "curl -X GET \"http://192.168.1.100:2000/api/iis/StartPool/Test\""
      }
      stage('STARTSITE') {
        bat "curl -X GET \"http://192.168.1.100:2000/api/iis/StartSite/Test\""
      }
    }  catch(Exception e){
         // 构建失败时捕获异常并发送邮件
        emailext (
            subject: "编译失败: ${env.JOB_NAME} [${env.BUILD_NUMBER}]",
            body: """
                <p><b>${env.JOB_NAME} [${env.BUILD_NUMBER}]</b> <span style="color:red;">编译失败</span>.</p>
                <p>详情: <a href="${env.BUILD_URL}console">${env.BUILD_URL}console</a></p>
                <br>
            """,
            to: "test@163.com",
            mimeType: 'text/html',
            from: "test2@163.com"
        )
    }
}

相关文章:

  • idea debug功能演示线程安全问题
  • MATLAB学习之旅:数据建模与仿真应用
  • Autosar Com配置-Timeout配置及实现-基于ETAS工具
  • 解决“error: Tried to call obs_frontend_start_virtualcam with no callbacks!”
  • Tio-Boot 集成 Spring Boot 实现即时通讯功能全解析
  • 运维脚本——9.配置漂移检测
  • 【Linux内核】进程管理(下)
  • directx12 3d开发过程中出现的报错 十三
  • 全链路优化:如何让单点登录认证接口并发性能翻倍?
  • 鸿蒙开发环境搭建-入门篇
  • 网络运维学习笔记 017 HCIA-Datacom综合实验01
  • 区块链相关方法-SWOT分析
  • 侯捷 C++ 课程学习笔记:内存管理与工具应用
  • socket()函数的概念和使用案例
  • Java 使用websocket
  • 【Linux】34.封装 UdpSocket(1)
  • 【读书笔记·VLSI电路设计方法解密】问题53:什么是逻辑综合
  • bind()函数的概念和使用案例
  • WPF实现打印机控制及打印
  • JavaScript 数组连接方法
  • 长沙潮宗街内“金丝楠木老屋文旅博物馆”起火:明火已扑灭,无伤亡
  • 宇树科技王兴兴:第一桶金来自上海,欢迎上海的年轻人加入
  • 印巴战火LIVE丨“快速接近战争状态”:印度袭击巴军事基地,巴启动反制军事行动
  • 《中国人民银行业务领域数据安全管理办法》发布,6月30日起施行
  • 远离军事前线的另一面暗斗:除了“断水”,印度还试图牵制对巴国际援助
  • 晋级中部非省会第一城,宜昌凭什么