Mark Ku's Blog

時空背景

目前公司內大部的系統都能夠容器化,但總有些舊網站,最舊也最大也最賺錢,暫時無法做技術昇級,但人數一多手動佈版,都會遇到有人漏提交 Binary,因此想把自動建置的部份自動化,優化佈版流程,同時也減少錯誤帶來的影響。

因為是舊系統及Net Mvc framework 的舊框架,無法容器化,全自動佈版,會有點風險,因此這邊佈署的部份,仍然還是採用手動。

目標

  • 當有人 Push 任何code 到 Master 分支時,Jenkins 就會自動建置,並將建置完的 Binary,自動提交及推送到 Github。
  • 生產環境寫一個腳本,透過 Git 將最新的準備佈署的Binary 拉下來,接著透過 Beyond compare 比較 binary 差異,最後交由人工手動佈版。

環境說明

因為是舊系統,Jenkins 安裝在 Windows server 上。

首先,找回 MS Build

我們都知道NET MVC 的建置是透過Msbuild 這個工具,依據對照的 Visual Studio 2019 版本找到對照的版本是MSBuild 16 ,但在微軟的網頁,目前舊版 Msbuild tool 下載連結都找不太到下載連結,最後我從MSDN 訂閱帳號,裡找回舊版的 Visual stdio 2019 下載連結。
MSDN

安裝記得勾選 Desktop development with c++ Installation

設定 Jenkins 的MS Build 路徑

MS Build 安裝路徑是 Visual studio 2019 一起安裝的MSBuild.exe 路徑是

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin

下載nuget.exe

下載 Nuget.exe 至

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin 

下載並安裝 .NET Framework 4.8 Developer Pack

首先,至 Github repo 設定webhook 當程式commit 時通知 Jenkins 自動建置

Github webhook setting
Github webhook setting
http://jks.xxx.com/github-webhook/

接著,Jenkins 設定自動建置 pipeline

建立Job >選擇New Item > Pipeline,並設定 Github Project。

github project setting
github project setting
properties([pipelineTriggers([githubPush()])])

pipeline {
	agent any

	environment {		
	}
	
	options {
		buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '3', daysToKeepStr: '', numToKeepStr: '3')
	}

	stages {
	    stage('Cleanup Directories') {
            steps {
                script {
                    // Delete the 'Api' and 'Artifact' directories
                    dir('Api') {
                        deleteDir()
                    }
                    dir('Artifact') {
                        deleteDir()
                    }
                    
                    dir('Publish') {
                        deleteDir()
                    }
                    echo "Deleted Api and Artifact directories."
                }
            }
        }
	
	    stage("GitHub Pull - Net mvc api") {
            steps {
                dir('Api') {
                    git(
                        branch: 'master',
                        credentialsId: 'xxxx-xxxx-xxxx',
                        url: '[email protected]:iRobot/MVC.Api.git'
                    )
                }
            }
        }
		
		 stage("GitHub Pull - Artifact") {
            steps {
                dir('Artifact') {
                    git(
                        branch: 'main',
                        credentialsId: 'xxxx-xxxx-xxxx',
                        url: '[email protected]:iRobot/Artifact.git'
                    )
                }
            }
        }
        
    stage('Restore nuget') {
        steps {
        script {
            bat 'echo Current Directory: %CD%'
            bat 'echo Workspace Directory: %WORKSPACE%'
            bat '"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin\\nuget.exe" restore ".\\Api\\IRobot.WebCore\\IBuyPower.WebCore.sln"'
        }
        }
    }
    
    stage('Build') {
            steps {
                script {
                    // Define the MSBuild path and solution file
                    def msBuildPath = '"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"'
                    def solutionPath = '".\\api\\IRobot.WebCore\\IRobot.WebCore.sln"'

                    // Build command with all necessary parameters
                    def buildCommand = "${msBuildPath} ${solutionPath} /t:Clean,Build /p:Configuration=enUSLive /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:DeleteExistingFiles=True /p:OutDir=\"%WORKSPACE%\\Publish\" /p:ExcludeGeneratedDebugSymbol=True -verbosity:minimal"

                    // Execute the build command
                    bat script: buildCommand, returnStatus: true
                }
            }
    }
    
     stage("Copy to Artifact") {
            steps {
                script {
                    
                    def buildCommand =  "robocopy \"%WORKSPACE%\\Publish\\_PublishedWebsites\\Core.Web\" \"%WORKSPACE%\\Artifact\" /E /COPY:DAT /MT:100"

                    // Execute the build command
                    bat script: buildCommand, returnStatus: true
                }
            }
        
    }
    
    stage('Check for Changes and Commit') {
    steps {
        dir('Artifact') {
            script {
                // Set local git configuration for user identity
                bat "git config user.email \"[email protected]\""
                bat "git config user.name \"Jenkins CI\""

                // Stage all changes
                bat "git add ."

                // Commit with a timestamp
                bat "git commit -m \"Automated commit at ${new Date().format('HH:mm:ss')} by Jenkins\""

                // Attempt to push changes to remote repository
                def pushResult = bat(script: "git push --set-upstream origin main", returnStdout: true, returnStatus: true)
                if (pushResult != 0) {
                    echo "Failed to push changes. Error Code: ${pushResult}"
                }
            }
        }
    }
}	
}
}

手動佈版

因為是舊系統及Net Mvc的舊框架,無法容器化,全自動佈版,會有點風險,因此這邊佈署的部份,仍然還是採用手動。

再安裝 Beyond Compare

撰寫powerhsell deploy.ps1

git pull 

$LOCAL = "C:\Workspace\USApiArtifact\bin"
$REMOTE = "C:\inetpub\Core.Web\bin"

$env:Path = "C:\Program Files\Beyond Compare 4\" 
$filters = "/filters=-web.config"
BCompare.exe /excludefilter="web.config"  "$LOCAL" "$REMOTE" $filters

最後,執行後就能透過,Beyond compare 去比較此次佈版的dll 是不是和所想的一樣,最後透過右鍵 Copy to Right 來佈署新版應用程式。

Final
Final

作者

Mark Ku

擁有 10+ 年經驗的資深軟體工程師,現為 AI 應用 Builder,專注於大型平台架構與簡化複雜系統設計,從電商系統到訂閱與收費平台,結合 AI Agent、AI 整合與自動化開發,打造高效率且可持續演進的產品技術基礎。閱讀更多

覺得這篇有幫助?

作者做的免費工具、每日 Podcast 與電子報,都在這裡。

Mark Ku · 本文採用 CC BY 4.0 授權,轉載請註明作者並附上原文連結。

留言

訂閱電子報

訂閱後即時收到新文章通知,不錯過任何技術分享。

提交即表示同意接收電子報,隨時可

熱門文章

View all
Mark Ku
··611

Oracle Cloud 永久免費方案 Linux 主機及固定 IP :0 元打造雲端解決方案

Oracle Cloud 永久免費方案 Linux 主機及固定 IP :0 元打造雲端解決方案
Mark Ku
··474

告別 Postman 收費陷阱!開源 Git 原生 API 測試神器 Bruno 實戰指南

告別 Postman 收費陷阱!開源 Git 原生 API 測試神器 Bruno 實戰指南
Mark Ku
··331

一款免費開源類似於 Notion 類知識庫系統 — Outline Wiki 佈署與備份全攻略

一款免費開源類似於 Notion 類知識庫系統 — Outline Wiki 佈署與備份全攻略
Mark Ku
··237

打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1

打造高效 API 管理平台:從 0 開始部署 Kong Gateway - Part 1
Mark Ku
··236

訓練自己的 AI 語音:硬體門檻、開源模型比較與 LoRA 微調

訓練自己的 AI 語音:硬體門檻、開源模型比較與 LoRA 微調
Mark Ku
··212

在 Ubuntu 上設置 Samba 來共享資料夾,讓 Windows 11 用戶可以存取

在 Ubuntu 上設置 Samba 來共享資料夾,讓 Windows 11 用戶可以存取