有没有人使用命令行并以编程方式传入凭据从 Visual Studio Team Services(以前称为 Visual Studio Online、Team Foundation Service)版本控制服务器成功获取最新源代码?

- 我发现您无法在命令行中使用用于登录团队资源管理器或 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

如果您缓存了 Windows ID 凭据,则上述命令将忽略/login 凭据,或者它返回错误消息 TF30063:您无权访问 myaccount.visualstudio.com(这不是真的,因为凭据确实适用于 Java客户)

是否有其他不需要安装 Java 的替代方案?

最佳答案

我从 Microsoft 支持那里得到了答复: AA Creds for VSO 目前不适用于 TF.EXE。 TEE CLC 或使用对象模型代码是目前唯一的选择。我们正在考虑在 future 这样做。

对象模型代码引用 dll 中同名的 Microsoft.TeamFoundation.VersionControl.Client 命名空间。我最终编写了一个快速的 C# 控制台应用程序来下载最新的代码,而无需安装 Java。这种方法的另一个好处是它不需要创建一次性工作区。

如果您使用下面的代码创建一个名为 tfsget.exe 的可执行文件,则可以像这样从命令行调用它:

tfsget https://myvso.visualstudio.com/DefaultCollection $/MyProj/Folder c:\Projects login password

我添加了一个静默开关来禁止列出每个可以使用的文件,例如:

tfsget https://myvso.visualstudio.com/DefaultCollection $/MyProj/Folder c:\Projects login password silent

这是代码,希望这有助于直到 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;
        }
    }
}

关于visual-studio - 使用命令行通过 TF.exe 传递/登录凭据从 Visual Studio Team Services 获取最新信息,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21005274/

10-13 09:16