2

ソース管理に追加する 2 つの新しいプロジェクトのループで次の関数が呼び出されています。ループの反復ごとに、ソース コードが取得され、それがフォルダーにコピーされ、tfs チーム プロジェクトが作成され、そのプロジェクトのワークスペースが作成され、コードがソース管理に追加されます。

static void Main(string[] args) {
    var tfsWorkItems = _<IWorkItems>();
    var workItems = tfsWorkItems.GetProjectsToMigrate();
    var tfs = _<ITfs>();
    var logFilePath = new DirectoryInfo("C:\\log");
    var workingDirectory = new DirectoryInfo("C:\\m");
    Cleanup(workItems, tfs, logFilePath, workingDirectory);
    var svn = _<ISvn>();
    var app = _<IApplication>();
    foreach (var workItem in workItems)
    {
        var root = Path.Combine(workingDirectory.FullName, workItem.Id.ToString());
        var svnBase = Path.Combine(root, "s");
        var localWorkspacePath = Path.Combine(root, "t");
        var tfsBase = Path.Combine(localWorkspacePath, workItem.TfsProjectName, "Main");
        var tfsProject = workItem.ProjectType.ToLower() == "php" ? Path.Combine(tfsBase, "src")
                                                                    : tfsBase;
        svn.CheckoutFromSvn(workItem.SvnLocation, svnBase);
        app.CopyToTfsFolderStructure(svnBase, tfsProject);
        tfs.CreateTeamProject(workItem.TfsProjectName, logFilePath);
        tfs.CreateWorkspace(workItem.WorkspaceName, localWorkspacePath);
        tfs.AddToSourceControl(workItem.WorkspaceName, localWorkspacePath, workItem.TfsProjectName);
    }
}

2 つのプロジェクトがあります。最初のプロジェクトは正しく動作しますが、2 番目のプロジェクトは動作しません。2 番目のプロジェクトは、プロジェクトとワークスペースを作成しますが、AddToSourceControl

public void AddToSourceControl(string workspaceName, string localPath, string projectName) {
    var tfs = new TfsTeamProjectCollection(_collection);
    var vcs = tfs.GetService<VersionControlServer>();
    var user = vcs.AuthorizedUser;
    var workspace = vcs.GetWorkspace(workspaceName, user);
    var serverPath = workspace.GetServerItemForLocalItem(Path.Combine(localPath, projectName, "Main"));
    var itemSpec = new ItemSpec[] {
        new ItemSpec(serverPath, RecursionType.Full)
    };
    workspace.PendAdd(serverPath, true);

    // doesn't return anything
    var pendingSets = vcs.QueryPendingSets(
        itemSpec, workspace.Name, user, true);
    var pendingChanges = pendingSets.Aggregate(new List<PendingChange>(), (acc, item) => {
        acc.AddRange(item.PendingChanges);
        return acc;
    });
    var parameters = new WorkspaceCheckInParameters(pendingChanges, "svn to tfs migration") {
        OverrideGatedCheckIn = ((CheckInOptions2)vcs.SupportedFeatures & CheckInOptions2.OverrideGatedCheckIn) == CheckInOptions2.OverrideGatedCheckIn,
        PolicyOverride = new PolicyOverrideInfo("migration triggered check-in", null),
        SuppressEvent = true,
    };
    workspace.CheckIn(parameters);
}

workspace.PendAdd(serverPath, true)どのプロジェクトが 2 番目であるかに関係なく、2 番目のプロジェクトには常に 0 を返します。最初のプロジェクトは常に適切に完了します。どのプロジェクトが 2 番目であるかは問題ではありません。2 番目のプロジェクトは、常に 0 アイテムを返します。もちろん、すべてのプロジェクトをソース管理に正しく追加する必要があります。ここで何が起こっているのですか?

4

5 に答える 5

10

アプリケーションが機能しない理由はわかりませんが、TFS API は複数のワークスペースを作成し、何も破棄したり、GC を呼び出したり、そのような奇妙なことをしたりすることなく、それらからチェックインすることができます。

これは、接続サイトに投稿したものから変更された、正しい動作を示すプログラムの例です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.IO;
using Microsoft.TeamFoundation.VersionControl.Common;

namespace AddToSourceControl
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Uri serverUri = new Uri(args[0]);
                string serverPath = args[1];
                string localPath = args[2];

                for (int i = 0; i < 5; i++)
                {
                    string uniqueId = Guid.NewGuid().ToString();

                    if (i > 0)
                    {
                        Console.WriteLine();
                    }

                    Console.WriteLine("Creating a workspace and checking in with id " + uniqueId);

                    TfsTeamProjectCollection connection = new TfsTeamProjectCollection(serverUri);
                    VersionControlServer vcs = connection.GetService<VersionControlServer>();

                    string uniqueServerPath = VersionControlPath.Combine(serverPath, uniqueId);
                    string uniqueFolder = Path.Combine(localPath, uniqueId);

                    Workspace workspace = vcs.CreateWorkspace(uniqueId, vcs.AuthorizedUser, "", new WorkingFolder[] {
                        new WorkingFolder(uniqueServerPath, uniqueFolder)
                    });

                    Console.WriteLine("Created TFS workspace " + uniqueId);

                    CheckinLocalFolder(serverUri, localPath, uniqueId);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Failed: " + e);
            }
        }

        private static void CheckinLocalFolder(Uri serverUri, string localPath, string uniqueId)
        {
            TfsTeamProjectCollection connection = new TfsTeamProjectCollection(serverUri);
            VersionControlServer vcs = connection.GetService<VersionControlServer>();

            string uniqueFolder = Path.Combine(localPath, uniqueId);
            string uniqueFile = Path.Combine(uniqueFolder, uniqueId + ".txt");

            Workspace workspace = vcs.GetWorkspace(uniqueFolder);

            Console.Out.WriteLine("Found workspace " + workspace.Name);

            // Create a local folder with a file in it
            Directory.CreateDirectory(uniqueFolder);
            using (TextWriter output = new StreamWriter(uniqueFile))
            {
                output.WriteLine("This is " + uniqueId);
                output.Close();
            }

            Console.WriteLine("Created file " + uniqueFile);

            workspace.PendAdd(uniqueFolder, true);

            PendingChange[] pendingChanges = workspace.GetPendingChanges();

            Console.WriteLine("Pended changes:");
            foreach (PendingChange pendingChange in pendingChanges)
            {
                Console.WriteLine(" " + pendingChange.LocalItem + " (" + pendingChange.ChangeType + ")");
            }

            int changeset = workspace.CheckIn(pendingChanges, "Test from id " + uniqueId);

            Console.WriteLine("Checked in " + pendingChanges.Length + " as changeset " + changeset);
        }
    }
}

したがって、問題はコードの他の場所にあることをお勧めします。ただし、何層もの抽象化を行わずに問題を示す短い自己完結型の例を作成できれば、それは役に立ちます。

役立つヒント:

ワークスペースのマッピングが正しく設定されていることを確認してください: そうしないと、再帰的に呼び出しPendAddても実際には何も追加されません。

同じ理由で、ファイルがローカルに存在することを確認してください。

エラーのリッスン: TFS API には、コンシューマーに通知できるイベントがいくつかあります。特に役立つのは、「致命的ではない」エラー通知です。多くの操作では、操作の一部が失敗する可能性があり、終了または例外をスローする代わりに、「非致命的」が発生し、操作が続行されます。

この例は、複数のパスを に追加していてPendAdd、そのうちの 1 つが失敗した場合です (たとえば、パスがロックされているため)。致命的ではないエラーを聞かないと、このパスが保留中の変更から除外されていることがわかりません。(ただし、リターン コードを見ると、パスが除外されていることがわかります。)

あなたが持っている場合VersionControlServer vcs

public class Example
{
    static void Main(string[] args)
    {
        VersionControlServer vcs = ConnectToServer(); // ... etc ...
        vcs.NonFatalError += Example.OnNonFatalError;
    }

    internal static void OnNonFatalError(Object sender, ExceptionEventArgs e)
    {
        if (e.Exception != null)
        {
            Console.Error.WriteLine("  Non-fatal exception: " + e.Exception.Message);
        }
        else
        {
            Console.Error.WriteLine("  Non-fatal failure: " + e.Failure.Message);
        }
    }
}

(この例は、Buck Hodges の役立つクライアント API サンプルブログ投稿から引用したものであることに注意してください。)

于 2012-09-11T14:29:11.457 に答える
3

私も同じ問題を抱えていました (MSDN サンプルでさえ私のマシンでは動作しませんでした) が、致命的ではないエラーを聞くと、 PendAddを呼び出す前にWorkstation.EnsureUpdateWorkspaceInfoCache を呼び出すヒントが得られました。これで解決しました。

于 2017-03-24T22:09:37.497 に答える
-1

この問題を回避する方法を見つけました。メソッド内のコードを含む別のコンソール アプリケーションを作成し、クラスAddToSourceControlを介してコンソール アプリケーションを呼び出す必要があります。System.Diagnostics.Processプログラム全体が終了するまで、TFS API 内の何かが適切に解放されてはなりません。

于 2012-09-11T12:20:32.977 に答える