3

我正在尝试进入修订历史,但我不确定如何获得它。无论我做什么,它都会返回 null。相关代码如下:

        string objectType = "HierarchicalRequirement";
        string orderString = "";
        bool fetchFullObjects = true;
        long start = 1;
        long pageSize = 200;
        QueryResult queryResult = Global.service.query(Global.workspace, objectType, queryString, orderString, fetchFullObjects, start, pageSize);
        int cnt = 0;
        for (int i = 0; i < queryResult.Results.Length; i++)
        {
            // Results array is of type "DomainObject"
            DomainObject rallyobject = queryResult.Results[i];
            HierarchicalRequirement story = (HierarchicalRequirement)rallyobject;
            var rev = story.RevisionHistory;

            if (rev.Revisions != null)
            {
                  // traverse revisions for info, never gets here
            }

            dataGridView3.Rows.Add(new object[] { story.FormattedID, story.Description, story.InProgressDate, story.AcceptedDate, story.PlanEstimate});

        }

        // Return the avereage days from inprogress to accepted
        return;
    }

在调试中,rev 总是返回 null ..

也许我错误地投射查询结果?

4

4 回答 4

3

为了结束循环,这里有一个示例,展示了如何执行 Kyle 提到的 service.read()。Mark 建议使用 LBAPI 肯定是跟踪工件快照的一种更可靠的方法,但是您必须自己构建 LBAPI 的 REST 查询 URL,Rally 还没有用于 LBAPI 的 C# SDK .

提醒一下,特别是如果您刚刚开始构建集成,我强烈建议您使用 Rally 的.NET REST SDK之一,而不是 SOAP。

REST 更健壮、性能更高,而且,Webservices API 1.4x(x 尚未确定)将是支持 SOAP 的最终 API 版本。Webservices 2.x 将仅支持 REST,因此对于任何希望推进新的 Web 服务功能的人来说,使用 REST 将是必不可少的。

namespace SOAP_QueryStoryRevisions
{
    class Program
    {
        static void Main(string[] args)
        {

            // create a service object
            RallyServiceService service = new RallyServiceService();

            // Credentials
            string rallyUser = "user@company.com";
            string rallyPassword = "topsecret";

            // set the service URL
            service.Url = "https://rally1.rallydev.com/slm/webservice/1.37/RallyService";

            // login to service using HTTP Basic auth
            System.Net.NetworkCredential credential =
               new System.Net.NetworkCredential(rallyUser, rallyPassword);

            Uri uri = new Uri(service.Url);
            System.Net.ICredentials credentials = credential.GetCredential(uri, "Basic");
            service.Credentials = credentials;
            service.PreAuthenticate = true;

            // Configure the service to maintain an HTTP session cookie
            service.CookieContainer = new System.Net.CookieContainer();

            // Get current user
            User user = (User)service.getCurrentUser();

            // Get reference to UserProfile for current user
            UserProfile profile = new UserProfile();
            profile.@ref = user.UserProfile.@ref;

            // Read will return a WSObject that you can then cast to a UserProfile 
            WSObject resultobj = service.read(profile);
            UserProfile newprofile = (UserProfile)resultobj;

            // Default workspace for current user
            Console.WriteLine(newprofile.DefaultWorkspace.@ref);

            // set workspace for query
            Workspace workspace = new Workspace();
            workspace.@ref = newprofile.DefaultWorkspace.@ref;

            // Make the web service call
            //---------------------------

            // Look for Stories
            string objectType = "hierarchicalrequirement";

            // Find Stories
            string queryString = "(FormattedID < US100)";

            // Order by FormattedID Ascending
            string orderString = "FormattedID asc";

            // Fetch full objects, or return just object shells
            // with the "@ref" attribute set.  You can fetch the full version
            // of a ref object later by calling service.read().
            bool fetchFullObjects = true;

            // Paging information
            long start = 0;
            long pageSize = 200;

            // Query for project
            QueryResult projectQueryResult = service.query(workspace, "Project", "(Name = \"My Project\")", orderString, fetchFullObjects, start, pageSize);

            // look at the object returned from query()
            Console.WriteLine("Query returned " + projectQueryResult.TotalResultCount + " Projects");

            // Grab project
            DomainObject myProjectObject = projectQueryResult.Results[0];
            Project myProject = (Project)myProjectObject;

            // issue query
            QueryResult queryResult = service.query(workspace, myProject, true, true, objectType, queryString, orderString, fetchFullObjects, start, pageSize);

            // look at the object returned from query()
            Console.WriteLine("Query returned " + queryResult.TotalResultCount + " objects");

            // loop through results returned

            Console.WriteLine("There are " + queryResult.Results.Length + " objects on this page");
            for (int i = 0; i < queryResult.Results.Length; i++)
            {
                // Results array is of type "DomainObject"
                DomainObject rallyobject = queryResult.Results[i];
                Console.WriteLine("  result[" + i + "] = " + rallyobject);
                Console.WriteLine("           ref = " + rallyobject.@ref);

                HierarchicalRequirement myStory = (HierarchicalRequirement)rallyobject;

                Console.WriteLine("===>           FormattedID = " + myStory.FormattedID);
                Console.WriteLine("===>           Story Name = " + myStory.Name);

                RevisionHistory myStoryRevisionHistory = myStory.RevisionHistory;

                // Perform service.read on RevisionHistory
                RevisionHistory myRevisionHistoryHydrated =  (RevisionHistory)service.read(myStoryRevisionHistory);

                // Grab revisions
                Revision[] myRevisions = myRevisionHistoryHydrated.Revisions;

                // Loop through each Revision and read it, output summary
                for (int j = 0; j < myRevisions.Length; j++)
                {
                    Revision revisionHydrated = (Revision)service.read(myRevisions[j]);
                    Console.WriteLine("===>                Revision[" + j + "] = " + revisionHydrated.RevisionNumber);
                    Console.WriteLine("===>                Description: " + revisionHydrated.Description);
                }
            }

            Console.ReadKey();
        }

        // determine if the result had errors
        static bool hasErrors(OperationResult result)
        {
            return (result.Errors.Length > 0);
        }

        // print warnings and errors to the console
        static void printWarningsErrors(OperationResult result)
        {
            if (result.Warnings.Length > 0)
            {
                Console.WriteLine("Result has warnings:");
                for (int i = 0; i < result.Warnings.Length; i++)
                {
                    Console.WriteLine("  warnings[" + i + "] = " + result.Warnings[i]);
                }
            }
            if (result.Errors.Length > 0)
            {
                Console.WriteLine("Result has errors:");
                for (int i = 0; i < result.Errors.Length; i++)
                {
                    Console.WriteLine("  errors[" + i + "] = " + result.Errors[i]);
                }
            }
        }
    }
于 2013-03-28T18:12:48.073 回答
0

我不确定您要如何处理修订历史记录,但您可能想要查看的另一个选项是新的 Lookback API:

https://rally1.rallydev.com/analytics/doc/

这为 REST API 提供了更丰富且可解析的工件历史视图。例如,要查找对象 ID 为 1234 的项目(或任何子项目)下故事的完整历史记录,您可以执行以下操作:

find={ _ProjectHierarchy: 1234, _TypeHierarchy: "HierarchicalRequirement" }

对于分析团队,完整的 URL 将是:

https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/41529001/artifact/snapshot/query.js?find={_ProjectHierarchy:279050021,_TypeHierarchy:"HierarchicalRequirement"}

其中 41529001 是工作区的 ObjectID,279050021 是项目 OID。

添加 fields 参数以指定要返回的字段,或在处于开发模式时添加 fields=true 以确定可用的字段:

https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/41529001/artifact/snapshot/query.js?find={_ProjectHierarchy:279050021,_TypeHierarchy:%22HierarchicalRequirement%22}&fields=true

请注意,fields=true 限制为每页 200 个结果,因此您应该指定生产中所需的实际字段列表。例如,要返回创建快照的对象 ID、故事名称和日期,它将变为:

https://rally1.rallydev.com/analytics/v2.0/service/rally/workspace/41529001/artifact/snapshot/query.js?find={_ProjectHierarchy:279050021,_TypeHierarchy:%22HierarchicalRequirement%22}&fields=[%22ObjectID%22,%20%22Name%22,%20%22_ValidFrom%22,%20%22_ValidTo%22]

此快照模型可能感兴趣的另一个功能是 _PreviousValues 字段,它保存在当前快照中更改的字段的旧值,因此您可以检测(和查询)工件状态的更改。更多信息在这里: https ://rally1.rallydev.com/analytics/doc/Analytics2.0LookbackAPIUserManual.html?_debugResources=y&n=1364482493883#h.uv4o9mhshx4

希望这可以帮助。

于 2013-03-28T15:02:43.050 回答
0

我不确定您是否可以使用 SOAP 做到这一点。fetchFullObjects 参数不会填充诸如修订历史和修订等子对象字段。这些字段可通过 WSAPI 在一个请求中使用,但是通过在 fetch 参数中指定它们。

在这种情况下,您可能必须执行 service.read(rev) 来填充修订。

于 2013-03-28T13:13:23.217 回答
0

这是一种使用 REST 获取和显示修订历史记录的方法。

import com.google.gson.JsonObject;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.request.QueryRequest;
import com.rallydev.rest.response.QueryResponse;
import com.rallydev.rest.util.Fetch;
import com.rallydev.rest.util.QueryFilter;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeSet;

public class revisions {

    public static void main(String[] args) throws URISyntaxException, IOException {

        // Configure RallyRestApi
        final String rallyURL = "https://rally1.rallydev.com";
        final String wsapiVersion = "v2.0";
        final RallyRestApi restApi = new RallyRestApi(new URI(rallyURL), "RallyID", "password");    // TODO: update id / password
        restApi.setWsapiVersion(wsapiVersion);

        // Select and query project information
        final String myProject = "A Project Name";                      // TODO: update project name
        QueryRequest projectRequest = new QueryRequest("Project");
        projectRequest.setFetch(new Fetch("Name", "Iterations"));
        projectRequest.setQueryFilter(new QueryFilter("Name", "=", myProject));
        QueryResponse projectQueryResponse = restApi.query(projectRequest);
        String iterationListRef = projectQueryResponse.getResults().get(0).getAsJsonObject().get("Iterations").getAsJsonObject().get("_ref").toString().replaceAll("\"", "");
        iterationListRef = iterationListRef.substring(iterationListRef.indexOf("Project"));

        // Query and store iteration information
        QueryRequest iterationRequest = new QueryRequest(iterationListRef);
        QueryResponse iterationQueryResponse = restApi.query(iterationRequest);

        HashMap<String, String> iterations = new HashMap<String, String>();
        String iterationName = "", iterationStartDate="";
        int irc = iterationQueryResponse.getTotalResultCount();
        for (int iter = 0; iter < irc; iter++) {
            JsonObject iterationObj = iterationQueryResponse.getResults().get(iter).getAsJsonObject();

            iterationName = iterationObj.get("_refObjectName").toString();
            iterationName = iterationName.substring(1, iterationName.length()-1);
            iterationStartDate = iterationObj.get("StartDate").toString().replaceAll("\"", "").substring(0, 10);
            iterations.put(iterationName, iterationStartDate);
        }

        // Query and store story information
        QueryRequest storyRequest = new QueryRequest("HierarchicalRequirement");
        String ir = iterationRequest.toUrl();
        storyRequest.setProject(ir.substring(0, ir.indexOf("/iterations")));
        QueryResponse storyQueryResponse = restApi.query(storyRequest);

        TreeSet<StoryInfo> stories = new TreeSet<StoryInfo>(new StoryComp());
        String refIteration = "", storyID = "", storyName = "", revHistory = "";
        int src = storyQueryResponse.getTotalResultCount();
        for (int story = 0; story < src; story++) {         
            JsonObject storyOjb = storyQueryResponse.getResults().get(story).getAsJsonObject();

            refIteration = storyOjb.get("Iteration").toString();
            if (refIteration.contains("_refObjectName")) 
                refIteration = storyOjb.get("Iteration").getAsJsonObject().get("_refObjectName").toString().replaceAll("\"", "");

            storyID = storyOjb.get("FormattedID").toString();
            storyID = storyID.substring(1, storyID.length()-1);

            storyName = storyOjb.get("_refObjectName").toString().replaceAll("\"", "");

        revHistory = storyOjb.get("RevisionHistory").getAsJsonObject().get("_ref").toString().replaceAll("\"", "");
        revHistory = revHistory.substring(revHistory.indexOf("revisionhistory"))+"/Revisions";

        stories.add(new StoryInfo(refIteration, ""+iterations.get(refIteration), storyID, storyName, revHistory));
        }

        System.out.println("Project: "+myProject);
        for (StoryInfo s:stories) {
            // Print the story iteration, id, name and revisions!
        System.out.println('\n'+s.iteration+" - "+s.id+" "+s.name);
        QueryRequest historyRequest = new QueryRequest(s.revHist);
        QueryResponse historyResponse = restApi.query(historyRequest);
        final int hrc = historyResponse.getTotalResultCount();
        for (int rev = 1; rev < hrc; rev++) {
            JsonObject historyObj = historyResponse.getResults().get(rev).getAsJsonObject();
//          System.out.println(historyObj);     // BINGO !!!
            System.out.println(historyObj.get("RevisionNumber")+" "+historyObj.get("CreationDate")+" "+historyObj.get("Description"));
        }                
        }
        restApi.close();
    }

    static class StoryComp implements Comparator<StoryInfo> {
        public int compare(StoryInfo i1, StoryInfo i2) {
            return (i1.startDate+i1.id).compareTo(i2.startDate+i2.id);
        }
    }   

    static class StoryInfo {
        String iteration, startDate, id, name, revHist;
        StoryInfo(String it, String sd, String i, String n, String rh) {
            iteration = it; startDate = sd; id = i; name = n; revHist = rh;
        }
    }

}
于 2013-09-03T17:30:14.900 回答