在构建服务器上,我已经设置了TeamCity(8.1.1),以便在主服务器,其中一个功能分支或其中一个使用分支说明符的拉取请求分支发生更改时执行构建过程:
+:refs/heads/*
+:refs/pull/(*/merge)
我已打开构建代理选项:
teamcity.git.use.local.mirrors=true
将存储库克隆到构建目录之外的目录中,然后从该本地存储库中提取。
构建过程需要访问git存储库和主分支,即使是其中一个功能分支或拉取请求分支的构建也是如此。但是,TeamCity只有包含本地存储库中的更改的分支,从而使我的构建失败,例如当更改发生在issue / mycoolissue分支上时,那是TeamCity工作空间中git存储库中唯一存在的分支。
我已尝试执行本地git fetch
以获取主分支,但由于本地存储库没有主分支,因此失败。虽然我可以添加一个远程指向源(一个github私有存储库),这意味着我也必须处理凭据,而我宁愿让TeamCity为我处理所有这些。
我的问题是,是否有办法告诉TeamCity将所有分支都拉到本地存储库和工作存储库中?
答案 0 :(得分:8)
Starting from TeamCity 10.0.4, you can do that by adding a configuration parameter teamcity.git.fetchAllHeads=true
See here
答案 1 :(得分:0)
事实证明(到目前为止)没有办法在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
原始分支。
这不是最快的方法,但现在可以使用。