Tio*_*ion 4 command-line credentials visual-studio azure-devops
有没有人使用命令行从Visual Studio Team Services(以前的Visual Studio Online,Team Foundation Service)版本控制服务器获取最新源代码并以编程方式传入凭据?
- 我发现您无法使用用于在命令行中登录Team Explorer或VSO网站的Windows ID凭据.您需要在Team Services中为用户配置文件创建备用凭据.
- 我发现如果省略tf.exe中的/ login,将出现Team Services登录对话框,并要求您键入Windows ID凭据(除非它们已经缓存在您的团队资源管理器或Visual Studio中(甚至可能)浏览器和Windows凭据缓存)
- 我发现备用凭证有效使用Java版本的tf.exe - Team Explorer Everywhere命令行客户端(TEE CLC).TEE CLC实际上使用您传入的/ login凭据并允许您连接.C:\ Program Files(x86)\ Microsoft Visual Studio 12.0\Common7\IDE \中的TF.EXE似乎不可能做同样的事情.但是在这个建立环境中安装JAVA是违反政策的.所以TEE CLC不是一个可行的选择.
tf get $/MyProj /collection:https://myaccount.visualstudio.com/DefaultCollection /login:user:pass
Run Code Online (Sandbox Code Playgroud)
如果您缓存了Windows ID凭据,或者它返回错误消息TF30063,则上述命令会忽略/ login凭据:您无权访问myaccount.visualstudio.com(这不是真的,因为凭据可以与Java一起使用客户)
还有其他不需要安装Java的替代方案吗?
我得到了Microsoft支持的答复:VSO的AA Creds目前不能与TF.EXE一起使用.TEE CLC或使用对象模型代码是目前唯一的替代方案.我们正在考虑将来这样做.
对象模型代码是指同名的dll中的Microsoft.TeamFoundation.VersionControl.Client命名空间.我最终编写了一个快速的C#控制台应用程序,无需安装Java即可下载最新代码.这种方法的另一个好处是它不需要创建一次性工作区.
如果你使用下面的代码创建一个名为tfsget.exe的可执行文件,可以从命令行调用它,如下所示:
tfsget https://myvso.visualstudio.com/DefaultCollection $/MyProj/Folder c:\Projects login password
Run Code Online (Sandbox Code Playgroud)
我添加了一个静默开关来禁止列出可以使用的每个文件,如:
tfsget https://myvso.visualstudio.com/DefaultCollection $/MyProj/Folder c:\Projects login password silent
Run Code Online (Sandbox Code Playgroud)
这是代码,希望这有助于MS更新TF.exe
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace TfsGet
{
class Program
{
static void Main(string[] args)
{
var tfsParams = TfsDownloadParams.Create(args);
var tpc = new TfsTeamProjectCollection(new Uri(tfsParams.ServerUrl), tfsParams.Credentials);
CheckAccess(tpc, tfsParams);
Download(tpc, tfsParams);
}
private static void CheckAccess(TfsTeamProjectCollection tpc, TfsDownloadParams tfsParams)
{
try
{
tpc.Authenticate();
}
catch
{
Console.WriteLine("TFS Authentication Failed");
Console.WriteLine("Server Url:{0}", tfsParams.ServerUrl);
Console.WriteLine("Project Path:{0}", tfsParams.ServerProjectPath);
Console.WriteLine("Target Path:{0}", tfsParams.TargetPath);
Environment.Exit(1);
}
}
static void Download(TfsTeamProjectCollection tpc, TfsDownloadParams tfsParams)
{
var versionControl = tpc.GetService<VersionControlServer>();
// Listen for the Source Control events.
versionControl.NonFatalError += Program.OnNonFatalError;
var files = versionControl.GetItems(tfsParams.ServerProjectPath, VersionSpec.Latest, RecursionType.Full);
foreach (Item item in files.Items)
{
var localFilePath = GetLocalFilePath(tfsParams, item);
switch (item.ItemType)
{
case ItemType.Any:
throw new ArgumentOutOfRangeException("ItemType.Any - not sure what to do with this");
case ItemType.File:
if (!tfsParams.Silent) Console.WriteLine("Getting: '{0}'", localFilePath);
item.DownloadFile(localFilePath);
break;
case ItemType.Folder:
if (!tfsParams.Silent) Console.WriteLine("Creating Directory: {0}", localFilePath);
Directory.CreateDirectory(localFilePath);
break;
}
}
}
private static string GetLocalFilePath(TfsDownloadParams tfsParams, Item item)
{
var projectPath = tfsParams.ServerProjectPath;
var pathExcludingLastFolder = projectPath.Substring(0, projectPath.LastIndexOf('/')+1);
string relativePath = item.ServerItem.Replace(pathExcludingLastFolder, "");
var localFilePath = Path.Combine(tfsParams.TargetPath, relativePath);
return localFilePath;
}
internal static void OnNonFatalError(Object sender, ExceptionEventArgs e)
{
var message = e.Exception != null ? e.Exception.Message : e.Failure.Message;
Console.Error.WriteLine("Exception: " + message);
}
}
public class TfsDownloadParams
{
public string ServerUrl { get; set; }
public string ServerProjectPath { get; set; }
public string TargetPath { get; set; }
public TfsClientCredentials Credentials { get; set; }
public bool Silent { get; set; }
public static TfsDownloadParams Create(IList<string> args)
{
if (args.Count < 5)
{
Console.WriteLine("Please supply 5 or 6 parameters: tfsServerUrl serverProjectPath targetPath userName password [silent]");
Console.WriteLine("The optional 6th 'silent' parameter will suppress listing each file downloaded");
Console.WriteLine(@"Ex: tfsget ""https://myvso.visualstudio.com/DefaultCollection"" ""$/MyProject/ProjectSubfolder"" ""c:\Projects Folder"", user, password ");
Environment.Exit(1);
}
var tfsServerUrl = args[0]; //"https://myvso.visualstudio.com/DefaultCollection";
var serverProjectPath = args[1]; // "$/MyProject/Folder Path";
var targetPath = args[2]; // @"c:\Projects\";
var userName = args[3]; //"login";
var password = args[4]; //"passsword";
var silentFlag = args.Count >= 6 && (args[5].ToLower() == "silent"); //"silent";
var tfsCredentials = GetTfsCredentials(userName, password);
var tfsParams = new TfsDownloadParams
{
ServerUrl = tfsServerUrl,
ServerProjectPath = serverProjectPath,
TargetPath = targetPath,
Credentials = tfsCredentials,
Silent = silentFlag,
};
return tfsParams;
}
private static TfsClientCredentials GetTfsCredentials(string userName, string password)
{
var networkCreds= new NetworkCredential(userName, password);
var basicCreds = new BasicAuthCredential(networkCreds);
var tfsCreds = new TfsClientCredentials(basicCreds)
{
AllowInteractive = false
};
return tfsCreds;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4889 次 |
| 最近记录: |