[英]Make TeamCity pull down all git branches
在構建服務器上,我設置了 TeamCity (8.1.1),以便它在使用分支說明符的主分支、功能分支之一或拉取請求分支之一發生更改時執行構建過程:
+:refs/heads/*
+:refs/pull/(*/merge)
我打開了構建代理選項:
teamcity.git.use.local.mirrors=true
它將存儲庫克隆到構建目錄之外的目錄中,然后從該本地存儲庫中提取。
構建過程需要訪問 git 存儲庫和 master 分支,即使是構建功能分支或拉取請求分支之一。 然而,TeamCity 只有包含本地存儲庫中更改的分支,從而使我的構建失敗,例如,當更改在 issue/mycoolissue 分支上時,這是 TeamCity 工作空間中 git 存儲庫中存在的唯一分支。
我曾嘗試執行本地git fetch
來獲取 master 分支,但由於本地存儲庫沒有 master 分支,因此失敗。 雖然我可以添加一個指向源的遠程(一個 github 私有存儲庫),但這意味着我還必須處理憑據,我寧願讓 TeamCity 為我處理所有這些。
我的問題是是否有辦法告訴 TeamCity 將所有分支都拉到本地存儲庫和工作存儲庫中?
從 TeamCity 10.0.4 開始,您可以通過添加配置參數teamcity.git.fetchAllHeads=true
來做到這一點, 請參見此處
事實證明(到目前為止)在 TeamCity 中沒有辦法很好地做到這一點,因此與此同時,通過在構建過程開始時運行一個額外的 MsBuild 腳本來驗證主分支是否存在於當前(本地)存儲庫,如果不是,則獲取它。
該腳本如下所示:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
DefaultTargets="Run"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DirWorkspace>$(MSBuildProjectDirectory)</DirWorkspace>
<DirRepository Condition=" '$(DirRepository)' == '' ">$(DirWorkspace)</DirRepository>
<DirGit Condition=" '$(DirGit)' == '' ">c:\Program Files (x86)\Git\bin</DirGit>
</PropertyGroup>
<Import Project="$(DirWorkspace)\GitHasMasterBranch.msbuild"
Condition="Exists('$(DirWorkspace)\GitHasMasterBranch.msbuild')"/>
<Import Project="$(DirWorkspace)\GitGetMasterBranch.msbuild"
Condition="Exists('$(DirWorkspace)\GitGetMasterBranch.msbuild')"/>
<Target Name="Run" DependsOnTargets="_DisplayInfo;_FetchOriginMasterIfNotExists">
<!-- Do nothing here -->
</Target>
<!-- Display info -->
<Target Name="_DisplayInfo">
<Message Text="Preparing workspace ..." />
</Target>
<PropertyGroup>
<ExeGit>$(DirGit)\git.exe</ExeGit>
</PropertyGroup>
<Target Name="_FetchOriginMasterIfNotExists" DependsOnTargets="_DisplayInfo">
<GitHasMasterBranch LocalPath="$(DirRepository)">
<Output TaskParameter="HasMaster" PropertyName="HasMaster" />
</GitHasMasterBranch>
<Message Text="Not fetching master branch because it already exists" Condition="($(HasMaster))" />
<Message Text="Fetching master branch because it does not exist" Condition="(!$(HasMaster))" />
<GitGetMasterBranch LocalPath="$(DirRepository)" Condition="(!$(HasMaster))"/>
</Target>
</Project>
在此腳本中, GitHasMasterBranch
MsBuild 內聯腳本如下所示:
<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'
ToolsVersion="4.0">
<UsingTask TaskName="GitHasMasterBranch"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<LocalPath ParameterType="System.String" Required="true" />
<HasMaster ParameterType="System.Boolean" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Method" Language="cs">
<![CDATA[
public override bool Execute()
{
var info = new System.Diagnostics.ProcessStartInfo
{
FileName = "git",
Arguments = "branch",
WorkingDirectory = LocalPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
var text = new System.Text.StringBuilder();
var process = new System.Diagnostics.Process();
process.StartInfo = info;
process.OutputDataReceived +=
(s, e) =>
{
text.Append(e.Data);
};
process.ErrorDataReceived +=
(s, e) =>
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
Log.LogError(e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
HasMaster = text.ToString().Contains("* master");
// Log.HasLoggedErrors is true if the task logged any errors -- even if they were logged
// from a task's constructor or property setter. As long as this task is written to always log an error
// when it fails, we can reliably return HasLoggedErrors.
return !Log.HasLoggedErrors;
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
GitGetMasterBranch
MsBuild 內聯腳本如下所示:
<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'
ToolsVersion="4.0">
<UsingTask TaskName="GitGetMasterBranch"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<LocalPath ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Method" Language="cs">
<![CDATA[
public override bool Execute()
{
// Get the name of the current branch
var info = new System.Diagnostics.ProcessStartInfo
{
FileName = "git",
Arguments = "symbolic-ref --short -q HEAD",
WorkingDirectory = LocalPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
var text = new System.Text.StringBuilder();
var process = new System.Diagnostics.Process();
process.StartInfo = info;
process.OutputDataReceived +=
(s, e) =>
{
text.Append(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
var currentBranch = text.ToString().Trim();
// git fetch
info = new System.Diagnostics.ProcessStartInfo
{
FileName = "git",
Arguments = "fetch origin",
WorkingDirectory = LocalPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
process = new System.Diagnostics.Process();
process.StartInfo = info;
process.OutputDataReceived +=
(s, e) =>
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
Log.LogMessage(MessageImportance.High, e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
// git checkout master
info = new System.Diagnostics.ProcessStartInfo
{
FileName = "git",
Arguments = "checkout master",
WorkingDirectory = LocalPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
process = new System.Diagnostics.Process();
process.StartInfo = info;
process.OutputDataReceived +=
(s, e) =>
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
Log.LogMessage(MessageImportance.High, e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
// git pull
info = new System.Diagnostics.ProcessStartInfo
{
FileName = "git",
Arguments = "pull",
WorkingDirectory = LocalPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
process = new System.Diagnostics.Process();
process.StartInfo = info;
process.OutputDataReceived +=
(s, e) =>
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
Log.LogMessage(MessageImportance.High, e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
// git checkout <CURRENT_BRANCH>
info = new System.Diagnostics.ProcessStartInfo
{
FileName = "git",
Arguments = string.Format("checkout {0}", currentBranch),
WorkingDirectory = LocalPath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
process = new System.Diagnostics.Process();
process.StartInfo = info;
process.OutputDataReceived +=
(s, e) =>
{
if (!string.IsNullOrWhiteSpace(e.Data))
{
Log.LogMessage(MessageImportance.High, e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
// Log.HasLoggedErrors is true if the task logged any errors -- even if they were logged
// from a task's constructor or property setter. As long as this task is written to always log an error
// when it fails, we can reliably return HasLoggedErrors.
return !Log.HasLoggedErrors;
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
基本上所有的這最后一個腳本確實是存儲當前分支的名稱,執行GIT fetch
來獲得所有分支,執行GIT checkout
的主分支,然后執行GIT checkout
原分公司。
這不是最快的方法,但目前有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.