想要将 Rally 故事从一个项目复制到另一个项目 [英] Want to copy Rally stories from one project to another

查看:28
本文介绍了想要将 Rally 故事从一个项目复制到另一个项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将故事和任务(及其层次结构)从一个 Rally 项目复制到另一个.

I'm trying to copy stories and tasks (and their hierarchies) from one Rally project to another.

我只需要从一个模板"项目中复制,所以我不需要使用 ProjectPicker 小部件.只需利用复制故事和任务的现有应用程序即可它需要能够从一个项目读取并写入另一个项目(您登录的当前项目将是最简单.)

I only need to copy from one 'template' project so I don't need to make use of the ProjectPicker widget. Simply leveraging the existing app that copies stories and tasks is all that is need but it needs to be able to read from one project and write to another project (the current project you're logged into would be the easiest.)

我修改了应用程序,以便它可以从我未登录的项目中读取 - 很好.该副本导致我正在阅读的项目中复制了一个故事 - 而不是我在 Rally 中登录的那个 - 有人知道如何实现这一点吗?

I modified the app so that it can read from a project I'm not logged into - good. The copy results in a copied story in the project I'm reading from - not the one I'm logged into in Rally - does anyone know how to make this happen?

推荐答案

我假设您正在使用 Story Deep Copy 应用程序.从您的问题来看,您似乎已经为从中复制的项目修改了 hangman 变量.假设该项目的 OID 为 22222,而您要复制的目标项目的 OID 为 33333.这两个项目位于同一个工作区中,OID 为 11111.

I assume you are using Story Deep Copy app. From your question it looks like you already modified the hangman variable for a project from which you copy. Let's say the OID of that project is 22222, and the OID of the destination project where you want to copy is 33333. Both projects are in the same workspace, OID 11111.

var dataSource = new rally.sdk.data.RallyDataSource('11111', '22222',
                    '__PROJECT_SCOPING_UP__', '__PROJECT_SCOPING_DOWN__');

我在 this._copyStory 中添加了一行:

I added one line in this._copyStory :

foundObject.Project._ref = "https://rally1.rallydev.com/slm/webservice/1.29/project/33333.js";

这是完整的代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html dir="ltr">
<head>
    <title>Deep Copy Story</title>
    <meta name="Name" content="App: Story Deep Copy"/>
    <meta name="Version" content="2012.01.14"/>
    <meta name="Vendor" content="Rally Software"/>
    <script type="text/javascript" src="/apps/1.29/sdk.js?apiVersion=1.29"></script>

    <script type="text/javascript">
    rally.StoryDeepCopy = function (rallyDataSource, config) {
            var storyBuffer = [];
            var firstStory = null;
            var finishedCallback;
            var that = this;

            function getTypeFromRef(ref) {
                if (rally.sdk.util.Ref.isRef(ref)) {
                    var list = ref.split("/");
                    list.pop();
                    return list.pop();
                }
                else {
                    throw "Function getTypeFromRef expected a Rally Reference.";
                }
            }

            //dojo.connect(obj, event, context, method, dontFix);
            this._fireEvent = function(eventName, eventArgs) {

                if (config && config.eventListeners[eventName] && dojo.isFunction(config.eventListeners[eventName])) {
                    config.eventListeners[eventName](that, eventArgs);
                }
            };

            // removes private and read only fields to keep from pushing them up.
            this.filterObject = function (object) {
                delete object.Discussion;
                delete object.Rank;
                delete object.LastUpdateDate;
                delete object.Attachments;
                delete object.AcceptedDate;
                delete object.Blocker;
                delete object.Defects;
                delete object.TaskActualTotal;
                delete object.TaskEstimateTotal;
                delete object.TaskRemainingTotal;
                delete object.TaskEstimateTotal;
                delete object.RevisionHistory;
                delete object.Subscription;
                delete object.FormattedID;
                delete object.CreationDate;
                delete object.Changesets;
                delete object.ObjectID;
                for (var j in object) {
                    if (j.substring(0, 1) == '_') {
                        delete object[j];
                    }
                }
                return object;
            };

            this._addObject = function(object, typeName, callback) {
                var item = dojo.clone(object);
                item = this.filterObject(item);
                function errorFunctionWrapper(error) {
                    if (dojo.isArray(error.Errors)) {
                        var errorMessage = error.Errors.pop();
                        if (errorMessage.indexOf("Not authorized to create:") >= 0) {
                            errorMessage = "Unable to create an object. This can happen due to a child or task being in a project you do not have write permissions to.";
                        }
                        rally.sdk.ui.AppHeader.showMessage("error", errorMessage, 10000);
                    }
                    else if(dojo.isObject(error)&&error.message){
                        rally.sdk.ui.AppHeader.showMessage("error", error.message, 10000);
                        error = [error.message];
                    }
                    if (dojo.isFunction(config.onError)) {
                        config.onError(error);
                    }
                }

                rallyDataSource.create(typeName, item, callback, errorFunctionWrapper);
            };

            this._copyAllFromBuffer = function() {
                if (storyBuffer.length > 0) {
                    var story = storyBuffer.pop();
                    that._copyStory(story.ref, story.parent, that._copyAllFromBuffer);
                }
                else {
                    if (finishedCallback) {
                        finishedCallback(firstStory);
                    }
                }
            };

            this._addStoriesToBuffer = function(storyArray, parentRef) {
                dojo.forEach(storyArray, function (story) {
                    storyBuffer.push({
                        ref: story._ref,
                        parent: parentRef
                    });
                });
            };

            this._copyStory = function(ref, parentRef, callback) {
                rallyDataSource.getRallyObject(ref, function (foundObject) {
                    var type = getTypeFromRef(ref);
                    that._fireEvent("storyPreAdd", {story:foundObject});
            console.log(foundObject.Name);
            console.log(foundObject.Project._ref);
            foundObject.Project._ref = "https://rally1.rallydev.com/slm/webservice/1.29/project/33333.js";
                    if (parentRef) {
                        foundObject.Parent = parentRef;
                    }
                    else {
                        foundObject.Name = "(Copy of) " + foundObject.Name;
                    }
                    that._addObject(foundObject, type, function (storyRef) {
                        if (!firstStory) {
                            firstStory = storyRef;
                        }
                        that._fireEvent("storyPostAdd", {});
                        that._addStoriesToBuffer(foundObject.Children, storyRef);
                        that._copyTasksToStory(foundObject.Tasks, storyRef, callback);
                    }, null);
                });
            };

            this._copyTasksToStory = function(tasks, storyRef, callback) {
                //Copy the array
                var localTasks = tasks.slice(0);
                if (localTasks.length > 0) {
                    var task = localTasks.pop();
                    that._copyTask(task._ref, storyRef, function () {
                        that._copyTasksToStory(localTasks, storyRef, callback);
                    });
                }
                else {
                    callback();
                }
            };

            this._copyTask = function(ref, storyRef, callback) {
                rallyDataSource.getRallyObject(ref, function (foundObject) {
                    var type = getTypeFromRef(ref);
                    foundObject.WorkProduct = storyRef;
                    that._fireEvent("taskPreAdd", {task:foundObject});
                    that._addObject(foundObject, type, function (ref, warnings) {
                        if (callback) {
                            that._fireEvent("taskPostAdd", [ref]);
                            callback();
                        }
                    }, null);
                });
            };

            this.copyStory = function (ref, callback) {
                that._copyStory(ref, undefined, that._copyAllFromBuffer);
                finishedCallback = callback;
            };
        };

    </script>

    <script type="text/javascript">
        rally.addOnLoad(function() {
            var selectedValue = null;
            var tasksAdded = 0;
            var storiesAdded = 0;
            var searchStories;
            var goButton, chooseButton;
            var chooser;
            var waiter;
            var dataSource = new rally.sdk.data.RallyDataSource('111111', '2222222',
                    '__PROJECT_SCOPING_UP__', '__PROJECT_SCOPING_DOWN__');

            function taskPostAdd(object, args) {
                tasksAdded = tasksAdded + 1;
                displayTasksAdded(tasksAdded);
            }

            function taskPreAdd(object, args) {
                dojo.byId("currentInfo").innerHTML = "Adding Task " + args.task.FormattedID + " - " + args.task.Name;
            }

            function storyPreAdd(object, args) {
                dojo.byId("currentInfo").innerHTML = "Adding User Story " + args.story.FormattedID + " - " + args.story.Name;
            }

            function storyPostAdd(object, args) {
                storiesAdded = storiesAdded + 1;
                displayStoriesAdded(storiesAdded);
            }

            function displayStoriesAdded(count) {
                dojo.byId("storyResult").innerHTML = "Stories added: " + count;
            }

            function displayTasksAdded(count) {
                dojo.byId("taskResult").innerHTML = "Tasks added: " + tasksAdded;
            }


            function storyCopied(story) {
                dojo.byId("currentInfo").innerHTML = "Copy complete: ";
                var link = new rally.sdk.ui.basic.Link({
                    item: story,
                    text: story._refObjectName
                });

                link.display('currentInfo');
                goButton.setEnabled(true);
                chooseButton.setEnabled(true);
                if(waiter) {
                    waiter.hide();
                    waiter = null;
                }
            }

            function buttonPressed() {

                if (selectedValue) {
                    var config = {
                        eventListeners:{
                            storyPreAdd:storyPreAdd,
                            storyPostAdd:storyPostAdd ,
                            taskPreAdd:taskPreAdd,
                            taskPostAdd: taskPostAdd
                        }
                    };
                    tasksAdded = 0;
                    displayTasksAdded(tasksAdded);
                    storiesAdded = 0;
                    displayStoriesAdded(storiesAdded);
                    dojo.byId("currentInfo").innerHTML = "";
                    var copy = new rally.StoryDeepCopy(dataSource, config);
                    goButton.setEnabled(false);
                    chooseButton.setEnabled(false);
                    waiter = new rally.sdk.ui.basic.Wait({});
                    waiter.display('wait');
                    copy.copyStory(rally.sdk.util.Ref.getRelativeRef(selectedValue), storyCopied);
                }

            }

            function onChooserClose(chooser, args) {
                if (args.selectedItem) {
                    selectedValue = args.selectedItem;
                    goButton.setEnabled(true);
                    dojo.byId('storyBox').innerHTML = args.selectedItem.FormattedID + ' - ' +
                            args.selectedItem.Name;
                }
            }

            function showChooser() {
                var chooserConfig = {
                    fetch:"FormattedID,Name,Description,Project",
                    title: 'Story Chooser'
                };
                chooser = new rally.sdk.ui.Chooser(chooserConfig, dataSource);
                chooser.addEventListener('onClose', onChooserClose);
                chooser.display();
            }

            rally.addOnLoad(function () {
                goButton = new rally.sdk.ui.basic.Button({
                    text: "Copy",
                    enabled: false
                });
                goButton.addEventListener('onClick', buttonPressed);
                goButton.display('goButton');

                chooseButton = new rally.sdk.ui.basic.Button({
                    text: "Choose"
                });
                chooseButton.addEventListener('onClick', showChooser);
                chooseButton.display('chooseButton');

                showChooser();

                rally.sdk.ui.AppHeader.setHelpTopic("252");
            });
        });

    </script>
</head>
<body>
<div id="container">
    <div style="float:left">
        <span id="chooseButton"></span>
        <span id="storyBox" style="line-height:18px;vertical-align:middle">[No story selected]</span>
        <span id="goButton"></span>
    </div>
    <div id="wait" style="float:left; height: 16px; width: 24px;"></div>
    <div style="margin-left:5px;padding-top:10px;clear:both">
        <div id="currentInfo" style="height:16px"></div>
        <div id="storyResult" style="margin-top:10px"></div>
        <div id="taskResult"></div>
    </div>
</div>
</body>
</html>

上面的代码被修改为使用一个对象下拉列表,从中选择一个目标项目.因此,无需对目标项目的引用进行硬编码.

The code above was modified to use an object dropdown from which a destination project is selected. Hence there is no need to hardcode the destination project's reference.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html dir="ltr">
<head>
    <title>Deep Copy Story</title>
    <meta name="Name" content="App: Story Deep Copy"/>
    <meta name="Version" content="2012.01.14"/>
    <meta name="Vendor" content="Rally Software"/>
    <script type="text/javascript" src="/apps/1.29/sdk.js?apiVersion=1.29"></script>

    <script type="text/javascript">
    rally.StoryDeepCopy = function (rallyDataSource, config) {
            var storyBuffer = [];
            var firstStory = null;
            var finishedCallback;
            var that = this;

            function getTypeFromRef(ref) {
                if (rally.sdk.util.Ref.isRef(ref)) {
                    var list = ref.split("/");
                    list.pop();
                    return list.pop();
                }
                else {
                    throw "Function getTypeFromRef expected a Rally Reference.";
                }
            }

            //dojo.connect(obj, event, context, method, dontFix);
            this._fireEvent = function(eventName, eventArgs) {

                if (config && config.eventListeners[eventName] && dojo.isFunction(config.eventListeners[eventName])) {
                    config.eventListeners[eventName](that, eventArgs);
                }
            };

            // removes private and read only fields to keep from pushing them up.
            this.filterObject = function (object) {
                delete object.Discussion;
                delete object.Rank;
                delete object.LastUpdateDate;
                delete object.Attachments;
                delete object.AcceptedDate;
                delete object.Blocker;
                delete object.Defects;
                delete object.TaskActualTotal;
                delete object.TaskEstimateTotal;
                delete object.TaskRemainingTotal;
                delete object.TaskEstimateTotal;
                delete object.RevisionHistory;
                delete object.Subscription;
                delete object.FormattedID;
                delete object.CreationDate;
                delete object.Changesets;
                delete object.ObjectID;
                for (var j in object) {
                    if (j.substring(0, 1) == '_') {
                        delete object[j];
                    }
                }
                return object;
            };

            this._addObject = function(object, typeName, callback) {
                var item = dojo.clone(object);
        console.log(item);
                item = this.filterObject(item);
                function errorFunctionWrapper(error) {
                    if (dojo.isArray(error.Errors)) {
                        var errorMessage = error.Errors.pop();
                        if (errorMessage.indexOf("Not authorized to create:") >= 0) {
                            errorMessage = "Unable to create an object. This can happen due to a child or task being in a project you do not have write permissions to.";
                        }
                        rally.sdk.ui.AppHeader.showMessage("error", errorMessage, 10000);
                    }
                    else if(dojo.isObject(error)&&error.message){
                        rally.sdk.ui.AppHeader.showMessage("error", error.message, 10000);
                        error = [error.message];
                    }
                    if (dojo.isFunction(config.onError)) {
                        config.onError(error);
                    }
                }

                rallyDataSource.create(typeName, item, callback, errorFunctionWrapper);
            };

            this._copyAllFromBuffer = function() {
                if (storyBuffer.length > 0) {
                    var story = storyBuffer.pop();
                    that._copyStory(story.ref, story.parent, that._copyAllFromBuffer);
                }
                else {
                    if (finishedCallback) {
                        finishedCallback(firstStory);
                    }
                }
            };

            this._addStoriesToBuffer = function(storyArray, parentRef) {
                dojo.forEach(storyArray, function (story) {
                    storyBuffer.push({
                        ref: story._ref,
                        parent: parentRef
                    });
                });
            };

            this._copyStory = function(ref, parentRef, callback) {
                rallyDataSource.getRallyObject(ref, function (foundObject) {
                    var type = getTypeFromRef(ref);
                    that._fireEvent("storyPreAdd", {story:foundObject});
            foundObject.Project._ref = destinationProject;
                    if (parentRef) {
                        foundObject.Parent = parentRef;
                    }
                    else {
                        foundObject.Name = "(Copy of) " + foundObject.Name;
                    }
                    that._addObject(foundObject, type, function (storyRef) {
                        if (!firstStory) {
                            firstStory = storyRef;
                        }
                        that._fireEvent("storyPostAdd", {});
                        that._addStoriesToBuffer(foundObject.Children, storyRef);
                        that._copyTasksToStory(foundObject.Tasks, storyRef, callback);
                    }, null);
                });
            };

            this._copyTasksToStory = function(tasks, storyRef, callback) {
                //Copy the array
                var localTasks = tasks.slice(0);
                if (localTasks.length > 0) {
                    var task = localTasks.pop();
                    that._copyTask(task._ref, storyRef, function () {
                        that._copyTasksToStory(localTasks, storyRef, callback);
                    });
                }
                else {
                    callback();
                }
            };

            this._copyTask = function(ref, storyRef, callback) {
                rallyDataSource.getRallyObject(ref, function (foundObject) {
                    var type = getTypeFromRef(ref);
                    foundObject.WorkProduct = storyRef;
                    that._fireEvent("taskPreAdd", {task:foundObject});
                    that._addObject(foundObject, type, function (ref, warnings) {
                        if (callback) {
                            that._fireEvent("taskPostAdd", [ref]);
                            callback();
                        }
                    }, null);
                });
            };

            this.copyStory = function (ref, callback) {
                that._copyStory(ref, undefined, that._copyAllFromBuffer);
                finishedCallback = callback;
            };
        };

    </script>

    <script type="text/javascript">
         var destinationProject;
         function dropdownChanged(dropdown, eventArgs) {
          destinationProject = eventArgs.value
          console.log(destinationProject);
      }

        rally.addOnLoad(function() {
            var selectedValue = null;
            var tasksAdded = 0;
            var storiesAdded = 0;
            var searchStories;
            var goButton, chooseButton;
            var chooser;
            var waiter;
            var dataSource = new rally.sdk.data.RallyDataSource('1111', '2222',
                    '__PROJECT_SCOPING_UP__', '__PROJECT_SCOPING_DOWN__');

            var config = {
                type : "project",
                attribute: "Name",
                query : '(State = "Open")'
             };

          var objectDropdown = new rally.sdk.ui.ObjectDropdown(config, dataSource);
         objectDropdown.display("aDiv", dropdownChanged);

            function taskPostAdd(object, args) {
                tasksAdded = tasksAdded + 1;
                displayTasksAdded(tasksAdded);
            }

            function taskPreAdd(object, args) {
                dojo.byId("currentInfo").innerHTML = "Adding Task " + args.task.FormattedID + " - " + args.task.Name;
            }

            function storyPreAdd(object, args) {
                dojo.byId("currentInfo").innerHTML = "Adding User Story " + args.story.FormattedID + " - " + args.story.Name;
            }

            function storyPostAdd(object, args) {
                storiesAdded = storiesAdded + 1;
                displayStoriesAdded(storiesAdded);
            }

            function displayStoriesAdded(count) {
                dojo.byId("storyResult").innerHTML = "Stories added: " + count;
            }

            function displayTasksAdded(count) {
                dojo.byId("taskResult").innerHTML = "Tasks added: " + tasksAdded;
            }


            function storyCopied(story) {
                dojo.byId("currentInfo").innerHTML = "Copy complete: ";
                var link = new rally.sdk.ui.basic.Link({
                    item: story,
                    text: story._refObjectName
                });

                link.display('currentInfo');
                goButton.setEnabled(true);
                chooseButton.setEnabled(true);
                if(waiter) {
                    waiter.hide();
                    waiter = null;
                }
            }

            function buttonPressed() {

                if (selectedValue) {
                    var config = {
                        eventListeners:{
                            storyPreAdd:storyPreAdd,
                            storyPostAdd:storyPostAdd ,
                            taskPreAdd:taskPreAdd,
                            taskPostAdd: taskPostAdd
                        }
                    };
                    tasksAdded = 0;
                    displayTasksAdded(tasksAdded);
                    storiesAdded = 0;
                    displayStoriesAdded(storiesAdded);
                    dojo.byId("currentInfo").innerHTML = "";
                    var copy = new rally.StoryDeepCopy(dataSource, config);
                    goButton.setEnabled(false);
                    chooseButton.setEnabled(false);
                    waiter = new rally.sdk.ui.basic.Wait({});
                    waiter.display('wait');
                    copy.copyStory(rally.sdk.util.Ref.getRelativeRef(selectedValue), storyCopied);
                }

            }

            function onChooserClose(chooser, args) {
                if (args.selectedItem) {
                    selectedValue = args.selectedItem;
                    goButton.setEnabled(true);
                    dojo.byId('storyBox').innerHTML = args.selectedItem.FormattedID + ' - ' +
                            args.selectedItem.Name;
                }
            }

            function showChooser() {
                var chooserConfig = {
                    fetch:"FormattedID,Name,Description,Project",
                    title: 'Story Chooser'
                };
                chooser = new rally.sdk.ui.Chooser(chooserConfig, dataSource);
                chooser.addEventListener('onClose', onChooserClose);
                chooser.display();
            }

            rally.addOnLoad(function () {
                goButton = new rally.sdk.ui.basic.Button({
                    text: "Copy",
                    enabled: false
                });
                goButton.addEventListener('onClick', buttonPressed);
                goButton.display('goButton');

                chooseButton = new rally.sdk.ui.basic.Button({
                    text: "Choose"
                });
                chooseButton.addEventListener('onClick', showChooser);
                chooseButton.display('chooseButton');

                showChooser();

                rally.sdk.ui.AppHeader.setHelpTopic("252");
            });
        });

    </script>
</head>
<body>
<div id="container">
<div id="aDiv"></div>
    <div style="float:left">
        <span id="chooseButton"></span>
        <span id="storyBox" style="line-height:18px;vertical-align:middle">[No story selected]</span>
        <span id="goButton"></span>
    </div>
    <div id="wait" style="float:left; height: 16px; width: 24px;"></div>
    <div style="margin-left:5px;padding-top:10px;clear:both">
        <div id="currentInfo" style="height:16px"></div>
        <div id="storyResult" style="margin-top:10px"></div>
        <div id="taskResult"></div>
    </div>
</div>
</body>
</html>

这篇关于想要将 Rally 故事从一个项目复制到另一个项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆