javascript - 想要将 Rally 故事从一个项目复制到另一个项目

标签 javascript copy rally

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

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

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

最佳答案

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

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

我在 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>

编辑:修改上面的代码以使用从中选择目标项目的对象下拉列表。因此无需对目标项目的引用进行硬编码。

<!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>

关于javascript - 想要将 Rally 故事从一个项目复制到另一个项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17795224/

相关文章:

javascript - 提取字符串部分的最有效方法

javascript - 如何以低音量自动启动 Youtube 视频 (iframe)

javascript - GWT 中是否有任何通知将要下载哪个片段

excel - 过滤以确定要复制的单元格,现在复制最后找到的条件

Vbscript - 如果比目标文件新,则比较并复制文件夹中的文件

C - 使用动态数组复制结构

javascript - 使用 401 连接 Rally Web 服务 API 身份验证

Javascript 从网站(成员(member)网站)提取数据

javascript - Rally 示例应用程序错误

java - Rally:更新测试用例中引用的测试文件夹