0

この質問は、別のユーザーによって以前に尋ねられました。

Rally PythonまたはRuby APIを使用してテストケースとテストフォルダーをコピーする[終了]

しかし、過度に広範な質問であるとしてモデレーターによって閉じられました. ただし、 Rally UI内でテスト フォルダーとそのメンバー テスト ケースをコピーできないことを考えると、これは Rally ユーザーの一般的なニーズです。

したがって、うまくいけば、有効な質問として立つのに十分な詳細で、質問を再提示します。また、元の質問に対して作成した回答を再投稿します。

質問: Rally Python および Ruby REST API のRallyユーザーおよび開発者として、 Rally API ツールキットを活用してこのタスクを達成するにはどうすればよいですか?

4

3 に答える 3

2

パイソン:

このタスクを実行するスクリプトを次に示します。このスクリプトは、FormattedID で識別されるソース テスト フォルダーから、やはり FormattedID で識別されるターゲット テスト フォルダーにすべてのテスト ケースをコピーします。すべてのテスト ステップと添付ファイルもコピーされます。ターゲット テスト フォルダが存在する必要があります。つまり、ターゲットが見つからない場合、スクリプトはテスト フォルダを作成しません。

スクリプトは、新しいテスト ケースを元のテスト ケースの作業成果物 (つまり、欠陥、ユーザー ストーリー) に関連付けたり、ディスカッション アイテム、テスト ケースの結果、最後のビルド、評決などをコピーしたりしません。新しいテスト ケースが必要であると想定されているためです。 「空白」の状態になります。

Rally Python REST ライブラリをインストールして構成する必要がある場合:

Rally 開発者ポータル: Pyral のダウンロードとインストール

ピラルドキュメンテーション

#!/usr/bin/env python

#################################################################################################
#
#  copy_test_folder.py -- Copy all Test Cases in Source Test Folder to Target. Includes Test Steps
#                         and attachments. Target Test Folder must exist (i.e. the script will not
#                         create a new targeet Test Folder for you)
#
USAGE = """
Usage: copy_test_folder.py
"""
#################################################################################################
# import needed python libs
import sys, os
import re
import string
import base64

from pprint import pprint

# import needed pyral libs
from pyral import Rally, rallySettings, RallyRESTAPIError

errout = sys.stderr.write

my_server      = "rally1.rallydev.com"
my_user        = "user@company.com"
my_password    = "topsecret"
my_workspace   = "My Workspace"
my_project     = "My Project"

source_test_folder_formatted_id = "TF1"
target_test_folder_formatted_id = "TF4"

rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project)
# rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project, debug=True)
rally.enableLogging('copy_test_folder.log')

# Query for source and target test folders
source_test_folder_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % source_test_folder_formatted_id)
target_test_folder_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % target_test_folder_formatted_id)

# Check to make sure folders exist
if source_test_folder_response.resultCount == 0:
                 errout('No Source Test Folder Found matching Formatted ID: %s\n' % (source_test_folder_formatted_id))
                 sys.exit(4)

if target_test_folder_response.resultCount == 0:
                 errout('No Target Test Folder Found matching Formatted ID: %s\n. Target Test Folder must be created before copying.' % (target_test_folder_formatted_id))
                 sys.exit(4)

# Get references to source Test Folder and Test Cases, etc.                 
source_test_folder = source_test_folder_response.next()
source_test_cases = source_test_folder.TestCases

# Get reference to target Test Folder
target_test_folder = target_test_folder_response.next()

for source_test_case in source_test_cases:
                 # Create update fields for target Test Case
                 # Does NOT associate new Test Case to original Test Case's work product (i.e. Defect, User Story)
                 # Does NOT copy Discussion items - as the old Discussions are likely not desired on new Test Case
                 # Does NOT copy Last Build, Last Run, Last Update Date, Last Verdict as new Test Case will effectively
                 # be "blank" and not have any results associated to it
                 if source_test_case.Owner != None:
                                  target_owner = source_test_case.Owner.ref
                 else:
                                  target_owner = None
                 target_test_case_fields = {
                                  "Package": source_test_case.Package,
                                  "Description": source_test_case.Description,
                                  "Method": source_test_case.Method,
                                  "Name": source_test_case.Name,
                                  "Objective": source_test_case.Objective,
                                  "Owner": target_owner,
                                  "PostConditions": source_test_case.PostConditions,
                                  "PreConditions": source_test_case.PreConditions,
                                  "Priority": source_test_case.Priority,
                                  "Project": source_test_case.Project.ref,
                                  "Risk": source_test_case.Risk,
                                  "ValidationInput": source_test_case.ValidationInput,
                                  "ValidationExpectedResult": source_test_case.ValidationExpectedResult,
                                  "TestFolder": target_test_folder.ref,
                 }

                 # Create the target test case
                 try:
                                  target_test_case = rally.create("TestCase", target_test_case_fields)
                                  message = "Copied Source Test Case: " + source_test_case.FormattedID + \
                                            " To: " + target_test_folder.FormattedID + ": " + target_test_folder.Name + \
                                            ": " + target_test_case.FormattedID
                                  print message

                 except RallyRESTAPIError, details:
                                  sys.stderr.write('ERROR: %s \n' % details)
                                  sys.exit(2)


                 # Copy Test Steps
                 # Add Test Case Steps
                 source_test_case_steps = source_test_case.Steps
                 for source_step in source_test_case_steps:
                                  target_step_fields = {
                                                  "TestCase"          : target_test_case.ref,
                                                  "StepIndex"         : source_step.StepIndex,
                                                  "Input"             : source_step.Input,
                                                  "ExpectedResult"    : source_step.ExpectedResult                                                   
                                  }
                                  target_test_case_step = rally.put('TestCaseStep', target_step_fields)
                                  print "===> Copied  TestCaseStep: %s   OID: %s" % (target_test_case_step.StepIndex, target_test_case_step.oid)                 

                 # Copy Attachments
                 source_attachments = rally.getAttachments(source_test_case)

                 for source_attachment in source_attachments:

                                  # First copy the content
                                  source_attachment_content = source_attachment.Content
                                  target_attachment_content_fields = {
                                                   "Content": base64.encodestring(source_attachment_content)
                                  }

                                  try:
                                                   target_attachment_content = rally.put('AttachmentContent', target_attachment_content_fields)
                                                   print "===> Copied AttachmentContent: %s" % target_attachment_content.ref
                                  except RallyRESTAPIError, details:
                                                   sys.stderr.write('ERROR: %s \n' % details)
                                                   sys.exit(2)

                                  # Next copy the attachment object
                                  target_attachment_fields = {
                                                   "Name": source_attachment.Name,
                                                   "Description": source_attachment.Description,
                                                   "Content": target_attachment_content.ref,
                                                   "ContentType": source_attachment.ContentType,
                                                   "Size": source_attachment.Size,
                                                   "Artifact": target_test_case.ref,
                                                   "User": source_attachment.User.ref
                                  }
                                  try:
                                                   target_attachment = rally.put('Attachment', target_attachment_fields)
                                                   print "===> Copied Attachment: %s" % target_attachment.ref
                                  except RallyRESTAPIError, details:
                                                   sys.stderr.write('ERROR: %s \n' % details)
                                                   sys.exit(2)


                 # Copy Tags
                 source_tags = source_test_case.Tags;
                 target_tags = list()
                 for source_tag in source_tags:
                                  target_tags.append({"_ref":source_tag.ref})


                 target_test_case_fields = {
                                  "FormattedID": target_test_case.FormattedID,
                                  "Tags": target_tags
                 }

                 try:
                                  update_response = rally.update('TestCase', target_test_case_fields)
                 except RallyRESTAPIError, details:
                                  sys.stderr.write('ERROR: %s \n' % details)
                                  sys.exit(2)
于 2012-11-04T22:29:32.120 に答える
0

ルビー:

この Ruby スクリプトは、FormattedID で識別されるソース テスト フォルダーから、同じく FormattedID で識別されるターゲット テスト フォルダーに、すべてのテスト ケースをコピーします。すべてのテスト ステップと添付ファイルもコピーされます。ターゲット テスト フォルダが存在する必要があります。つまり、ターゲットが見つからない場合、スクリプトはテスト フォルダを作成しません。

スクリプトは、新しいテスト ケースを元のテスト ケースの作業成果物 (つまり、欠陥、ユーザー ストーリー) に関連付けたり、ディスカッション アイテム、テスト ケースの結果、最後のビルド、評決などをコピーしたりしません。新しいテスト ケースが必要であると想定されているからです。 「空白」の状態になります。

Ruby REST Toolkit をインストールして構成する必要がある場合は、次のリンクを参照してください。

開発者ポータル: Ruby 用 Rally REST API

ギットハブ

    # Copyright 2002-2012 Rally Software Development Corp. All Rights Reserved.

    require 'rally_api'

    $my_base_url       = "https://rally1.rallydev.com/slm"
    $my_username       = "user@company.com"
    $my_password       = "password"
    $my_workspace      = "My Workspace"
    $my_project        = "My Project"
    $wsapi_version     = "1.37"

    # Test Folders
    $source_test_folder_formatted_id = "TF4"
    $target_test_folder_formatted_id = "TF8"

    # Load (and maybe override with) my personal/private variables from a file...
    my_vars= File.dirname(__FILE__) + "/my_vars.rb"
    if FileTest.exist?( my_vars ) then require my_vars end

    #==================== Make a connection to Rally ====================
    config                  = {:base_url => $my_base_url}
    config[:username]       = $my_username
    config[:password]       = $my_password
    config[:workspace]      = $my_workspace
    config[:project]        = $my_project
    config[:version]        = $wsapi_version

    @rally = RallyAPI::RallyRestJson.new(config)

    begin

      # Lookup source Test Folder
      source_test_folder_query = RallyAPI::RallyQuery.new()
      source_test_folder_query.type = :testfolder
      source_test_folder_query.fetch = true
      source_test_folder_query.query_string = "(FormattedID = \"" + $source_test_folder_formatted_id + "\")"

      source_test_folder_result = @rally.find(source_test_folder_query)

      # Lookup Target Test Folder
      target_test_folder_query = RallyAPI::RallyQuery.new()
      target_test_folder_query.type = :testfolder
      target_test_folder_query.fetch = true
      target_test_folder_query.query_string = "(FormattedID = \"" + $target_test_folder_formatted_id + "\")"

      target_test_folder_result = @rally.find(target_test_folder_query)

      if source_test_folder_result.total_result_count == 0
        puts "Source Test Folder: " + $source_test_folder_formatted_id + "not found. Exiting."
        exit
      end

      if target_test_folder_result.total_result_count == 0
        puts "Target Test Folder: " + $target_test_folder_formatted_id + "not found. Target must exist before copying."
        exit
      end

      source_test_folder = source_test_folder_result.first()
      target_test_folder = target_test_folder_result.first()

      # Populate full object for Target Test Folder
      full_target_test_folder = target_test_folder.read

      # Get Target Project
      target_project = full_target_test_folder["Project"]

      # Grab collection of Source Test Cases
      source_test_cases = source_test_folder["TestCases"]

      # Loop through Source Test Cases and Copy to Target
      source_test_cases.each do |source_test_case|
        # Get full object for Source Test Case
        full_source_test_case = source_test_case.read

        # Check if there's an Owner
        if !full_source_test_case["Owner"].nil?
          source_owner = full_source_test_case["Owner"]
        else
          source_owner = nil
        end

        # Populate field data from Source to Target
        target_test_case_fields = {}
        target_test_case_fields["Package"] = full_source_test_case["Package"]
        target_test_case_fields["Description"] = full_source_test_case["Description"]
        target_test_case_fields["Method"] = full_source_test_case["Method"]
        target_test_case_fields["Name"] = full_source_test_case["Name"]
        target_test_case_fields["Objective"] = full_source_test_case["Objective"]
        target_test_case_fields["Owner"] = source_owner
        target_test_case_fields["PostConditions"] = full_source_test_case["PostConditions"]
        target_test_case_fields["PreConditions"] = full_source_test_case["PreConditions"]
        target_test_case_fields["Priority"] = full_source_test_case["Priority"]
        target_test_case_fields["Project"] = target_project
        target_test_case_fields["Risk"] = full_source_test_case["Risk"]
        target_test_case_fields["ValidationInput"] = full_source_test_case["ValidationInput"]
        target_test_case_fields["ValidationExpectedResult"] = full_source_test_case["ValidationExpectedResult"]
        target_test_case_fields["Tags"] = full_source_test_case["Tags"]
        target_test_case_fields["TestFolder"] = target_test_folder

        # Create the Target Test Case
        begin
          target_test_case = @rally.create(:testcase, target_test_case_fields)
          puts "Test Case: #{full_source_test_case["FormattedID"]} successfully copied to #{full_target_test_folder["FormattedID"]}"
        rescue => ex
          puts "Test Case: #{full_source_test_case["FormattedID"]} not copied due to error"
          puts ex
        end

        # Now Copy Test Steps
        # Add Test Case Steps
        source_test_case_steps = full_source_test_case["Steps"]

        source_test_case_steps.each do |source_test_case_step|
          full_source_step = source_test_case_step.read
          target_step_fields = {}
          target_step_fields["TestCase"] = target_test_case
          target_step_fields["StepIndex"] = full_source_step["StepIndex"]
          target_step_fields["Input"] = full_source_step["Input"]
          target_step_fields["ExpectedResult"] = full_source_step["ExpectedResult"]
          begin
            target_test_case_step = @rally.create(:testcasestep, target_step_fields)
            puts "===> Copied TestCaseStep: #{target_test_case_step["_ref"]}"
          rescue => ex
            puts "Test Case Step not copied due to error:"
            puts ex
          end
        end

          # Now Copy Attachments
          source_attachments = full_source_test_case["Attachments"]

        source_attachments.each do |source_attachment|
          full_source_attachment = source_attachment.read
          source_attachment_content = full_source_attachment["Content"]
          full_source_attachment_content = source_attachment_content.read

          # Create AttachmentContent Object for Target
          target_attachment_content_fields = {}
          target_attachment_content_fields["Content"] = full_source_attachment_content["Content"]
          begin
            target_attachment_content = @rally.create(:attachmentcontent, target_attachment_content_fields)
            puts "===> Copied AttachmentContent: #{target_attachment_content["_ref"]}"
          rescue => ex
            puts "AttachmentContent not copied due to error:"
            puts ex
          end

          # Now Create Attachment Container
          target_attachment_fields = {}
          target_attachment_fields["Name"] = full_source_attachment["Name"]
          target_attachment_fields["Description"] = full_source_attachment["Description"]
          target_attachment_fields["Content"] = target_attachment_content
          target_attachment_fields["ContentType"] = full_source_attachment["ContentType"]
          target_attachment_fields["Size"] = full_source_attachment["Size"]
          target_attachment_fields["Artifact"] = target_test_case
          target_attachment_fields["User"] = full_source_attachment["User"]
          begin
            target_attachment = @rally.create(:attachment, target_attachment_fields)
            puts "===> Copied Attachment: #{target_attachment["_ref"]}"
          rescue => ex
            puts "Attachment not copied due to error:"
            puts ex
          end
        end
      end
    end
于 2012-11-04T22:26:55.693 に答える
0

次の機能を追加する同じ Python スクリプトの改良

  • テスト フォルダー (ソースと宛先) は、ハードコードされているのではなく、引数で渡されます
  • 作成は再帰的に行われます (つまり、テスト フォルダーとテスト ケースをその中にコピーします)。
  • テスト ケースが既に存在する場合は (名前に基づいて) 置き換えられます。
  • パスワードではなく API キーを使用して接続する
  • あきらめる前に Rally への接続を 5 回試行してください

それを使用して(すでに存在する)にコピーTF10するには:TF99python copy_test_folder TF10 TF99

#!/usr/bin/env python

#################################################################################################
#
#  copy_test_folder.py -- Copy all Test Cases in Source Test Folder to Target. Includes Test Steps
#                         and attachments. Target Test Folder must exist (i.e. the script will not
#                         create a new targeet Test Folder for you)
#
USAGE = """
Usage: copy_test_folder.py TF_src TF_dest
"""
#################################################################################################
# import needed python libs
import sys, os
import re
import string
import base64

from pprint import pprint

# import needed pyral libs
from pyral import Rally, rallySettings, RallyRESTAPIError

errout = sys.stderr.write

my_server      = "rally1.rallydev.com"
my_user        = "name@domain.com"
my_password    = "<PASSWORD>"
my_workspace   = "<WORKSPACE>"
my_project     = "<PROJECT>"
my_key         = "<API KEY>"


def connect(nb_attempts=5):
    '''Connect to Rally'''
    global is_connected
    global rally
    #Connect
    if not is_connected and nb_attempts>0:
        print "...Attempting to connect to Rally for project %s..." % my_project
        try:
            # rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project)
            rally = Rally(my_server, apikey=my_key, workspace=my_workspace, project=my_project)
            print "Connected to Rally for project %s (%s)" % (my_project, my_workspace)
            is_connected=True
            rally.enableLogging('copy_test_folder.log')
        #Errors during connection (attempting to connect again)
        # except Exception, details: 
        except AttributeError: 
            if nb_attempts>1:
                connect(nb_attempts-1)
            else:
                errout('Error during connection to Rally (%s)\n' % details)
                exit(4)
    else: pass


def copyTF(src_TF, dest_TF):
    '''Copy Test Cases from one folder into another (including children Test Folders)'''
    # List names and FormattedID of existing Test Cases in destination
    dest_TCs = dest_TF.TestCases
    existing_dest_TC = {tc.Name:tc.FormattedID for tc in dest_TCs} 

    # Copy Test Cases to destination folder (replace if Test Case with same name exists)
    src_TCs = src_TF.TestCases
    for src_TC in src_TCs:
        # Create update fields for target Test Case
        # Does NOT associate new Test Case to original Test Case's WorkProduct (i.e. Defect, User Story)
        # Does NOT copy Discussion items - as the old Discussions are likely not desired on new Test Case
        # Does NOT copy Last Build, Last Run, Last Update Date, Last Verdict as new Test Case will effectively
        # be "blank" and not have any results associated to it
        tcName = src_TC.Name
        dest_TC_fields = {
            "Package": src_TC.Package,
            "Description": src_TC.Description,
            "Method": src_TC.Method,
            "Name": tcName,
            "Objective": src_TC.Objective,
            "Owner": getattr(src_TC.Owner, 'ref', None),
            "PostConditions": src_TC.PostConditions,
            "PreConditions": src_TC.PreConditions,
            "Priority": src_TC.Priority,
            "Project": src_TC.Project.ref,
            "Risk": src_TC.Risk,
            "ValidationInput": src_TC.ValidationInput,
            "ValidationExpectedResult": src_TC.ValidationExpectedResult,
            "TestFolder": dest_TF.ref,
         }

        # Create/Update the target test case
        try:
            if existing_dest_TC.has_key(tcName):
                operation = "Update"
                dest_TC_fields['FormattedID'] = existing_dest_TC[tcName]
                dest_TC = rally.update("TestCase", dest_TC_fields)
            else:
                #Create
                operation = "Create"
                dest_TC = rally.create("TestCase", dest_TC_fields)

            message = operation + "d Source Test Case: " + src_TC.FormattedID + \
                " To: " + dest_TF.FormattedID + ": " + dest_TF.Name + \
                ": " + dest_TC.FormattedID
            print message

        except RallyRESTAPIError, details:
            sys.stderr.write('ERROR: %s \n' % details)
            sys.exit(2)


        # Copy Test Steps
        #Cleared-up all Test Steps in destination if Test Case is updated
        if operation == "Update":
            dest_TC_steps = dest_TC.Steps
            for dest_step in dest_TC_steps:
                rally.delete('TestCaseStep', dest_step.oid)
            print "===> Cleared all Test Steps"

        # Add Test Case Steps
        src_TC_steps = src_TC.Steps
        for src_step in src_TC_steps:
            target_step_fields = {
                "TestCase"          : dest_TC.ref,
                "StepIndex"         : src_step.StepIndex,
                "Input"             : src_step.Input,
                "ExpectedResult"    : src_step.ExpectedResult                                                   
            }
            dest_TC_step = rally.put('TestCaseStep', target_step_fields)
            print "===> Copied  TestCaseStep: %s   OID: %s" % (dest_TC_step.StepIndex, dest_TC_step.oid)                 

        # Copy Attachments
        source_attachments = rally.getAttachments(src_TC)

        for source_attachment in source_attachments:
            # First copy the content
            source_attachment_content = source_attachment.Content
            target_attachment_content_fields = {
                "Content": base64.encodestring(source_attachment_content)
            }

            try:
                target_attachment_content = rally.put('AttachmentContent', target_attachment_content_fields)
                print "===> Copied AttachmentContent: %s" % target_attachment_content.ref
            except RallyRESTAPIError, details:
                sys.stderr.write('ERROR: %s \n' % details)
                sys.exit(2)

            # Next copy the attachment object
            target_attachment_fields = {
                "Name": source_attachment.Name,
                "Description": source_attachment.Description,
                "Content": target_attachment_content.ref,
                "ContentType": source_attachment.ContentType,
                "Size": source_attachment.Size,
                "Artifact": dest_TC.ref,
                "User": source_attachment.User.ref
            }
            try:
                target_attachment = rally.put('Attachment', target_attachment_fields)
                print "===> Copied Attachment: %s" % target_attachment.ref
            except RallyRESTAPIError, details:
                sys.stderr.write('ERROR: %s \n' % details)
                sys.exit(2)


        # Copy Tags
        source_tags = src_TC.Tags;
        target_tags = list()
        for source_tag in source_tags:
            target_tags.append({"_ref":source_tag.ref})

        dest_TC_fields = {
            "FormattedID": dest_TC.FormattedID,
            "Tags": target_tags
         }

        try:
            update_response = rally.update('TestCase', dest_TC_fields)
        except RallyRESTAPIError, details:
            sys.stderr.write('ERROR: %s \n' % details)
            sys.exit(2)

    # Recursive call for each child Test Folder (after creating it)
    src_children_TFs = src_TF.Children
    dest_children_TFs = dest_TF.Children
    existing_dest_TF = {tf.Name:tf for tf in dest_children_TFs} 
    for src_child_TF in src_children_TFs:
        tfName = src_child_TF.Name
        # Create Test Folder if needed
        if existing_dest_TF.has_key(tfName):
            dest_child_TF = existing_dest_TF[tfName]
        else:
            target_TF_fields = {
                'Name': tfName,
                'Parent': dest_TF.ref
            }
            dest_child_TF = rally.put('TestFolder', target_TF_fields)
            print "Created Test folder %s (%s)" % (tfName, dest_child_TF.FormattedID)
        # Copy Test Cases of this folder
        copyTF(src_child_TF, dest_child_TF)

if '__main__' in __name__:

    # Get source and destination test folders
    src_TF_formatted_id = sys.argv[1]
    dest_TF_formatted_id = sys.argv[2]

    # Connect to Rally
    global is_connected
    is_connected = False
    connect(5)

    # Query for source and target test folders
    global rally
    src_TF_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % src_TF_formatted_id)
    dest_TF_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % dest_TF_formatted_id)

    # Check to make sure folders exist
    if src_TF_response.resultCount == 0:
        errout('No Source Test Folder Found matching Formatted ID: %s\n' % (src_TF_formatted_id))
        sys.exit(4)

    if dest_TF_response.resultCount == 0:
        errout('No Target Test Folder Found matching Formatted ID: %s\n. Target Test Folder must be created before copying.' % (dest_TF_formatted_id))
        sys.exit(4)

    # Get Objects of source and target Test Folders                
    src_TF = src_TF_response.next()
    dest_TF = dest_TF_response.next()

    # Copy file
    copyTF(src_TF, dest_TF)
于 2017-02-22T10:44:46.127 に答える