1

Rally に既存の欠陥を照会し、すべての添付ファイルを維持しながら、いくつかのフィールドのみを変更してその欠陥をコピーできるようにしたいと考えています。これを行う簡単な方法はありますか?rally.create を呼び出して既存の欠陥オブジェクトを渡そうとしましたが、すべてのメンバーを JSON にシリアル化できませんでした。最終的には、この種の機能を含むように pyral が拡張されるとよいでしょう。

代わりに、既存の欠陥の各 python-native 属性をコピーし、その他すべてに .ref を使用するコードをいくつか書きました。それはかなりうまくいっているようです。添付ファイルをコピーするために Mark W のコードを利用しましたが、これもうまく機能しています。残っているフラストレーションの 1 つは、反復のコピーが機能しないことです。Iteration 属性で .ref を呼び出すと、次のようになります。

>>> s
<pyral.entity.Defect object at 0x029A74F0>
>>> s.Iteration
<pyral.entity.Iteration object at 0x029A7710>
>>> s.Iteration.ref
No classFor item for |UserIterationCapacity|
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\python27\lib\site-packages\pyral\entity.py", line 119, in __getattr__
    hydrateAnInstance(self._context, item, existingInstance=self)
  File "c:\python27\lib\site-packages\pyral\restapi.py", line 77, in hydrateAnInstance
    return hydrator.hydrateInstance(item, existingInstance=existingInstance)
  File "c:\python27\lib\site-packages\pyral\hydrate.py", line 62, in hydrateInstance
    self._setAppropriateAttrValueForType(instance, attrName, attrValue, 1)
  File "c:\python27\lib\site-packages\pyral\hydrate.py", line 128, in _setAppropriateAttrValueForType
    elements = [self._unravel(element) for element in attrValue]
  File "c:\python27\lib\site-packages\pyral\hydrate.py", line 162, in _unravel
    return self._basicInstance(thing)
  File "c:\python27\lib\site-packages\pyral\hydrate.py", line 110, in _basicInstance
    raise KeyError(itemType)
KeyError: u'UserIterationCapacity'
>>>

これは Rally の問題でしょうか、それともプロジェクト管理者が引き起こしたカスタム フィールドの問題でしょうか? oid から ref を作成することで回避できました。

newArtifact["Iteration"] = { "_ref": "iteration/" + currentArtifact.Iteration.oid }

しかし、これは私には不器用に感じます。

4

2 に答える 2

0

この質問に対するPythonの回答を確認してください(2つの回答があり、もう1つはRuby用です):

Rally API: テスト フォルダーとメンバー テスト ケースをコピーする方法

回答には、添付ファイル付きのテスト ケースをコピーする python スクリプトが含まれています。スクリプトはテスト ケース用ですが、操作は基本的に同じであり、フィールド属性のみが異なるため、ロジックは欠陥に容易に適応できるはずです。スクリプトは、添付ファイル、タグなど、ほぼすべてのアーティファクトをコピーします。

于 2013-01-08T18:04:46.293 に答える
0

添付ファイルをコピーするための Mark W のコードを含む最終的な解決策

def getDataCopy( data ):

    """ Given a piece of data, figure out how to copy it.  If it's a native python type
        like a string or numeric, just return the value.  If it's a rally object, return
        the ref to it.  If it's a list, iterate and call ourself recursively for the
        list members. """

    if isinstance( data, types.ListType ):
        copyData = []
        for entry in data:
            copyData.append( getDataCopy(entry) )

    elif hasattr( data, "ref" ):
        copyData = { "_ref": data.ref }

    else:
        copyData = data

    return copyData

def getArtifactCopy( artifact ):

    """ Build a dictionary based on the values in the specified artifact.  This dictionary
        can then be passed to a rallyConn.put() call to actually create the new entry in
        Rally.  Attachments and Tasks must be copied seperately, since they require creation
        of additional artifacts """

    newArtifact = {}

    for attrName in artifact.attributes():

        # Skip the attributes that we can't or shouldn't handle directly
        if attrName.startswith("_") or attrName == "oid" or attrName == "Iteration" or attrName == "Attachments":
            continue

        attrValue = getattr( artifact, attrName )
        newArtifact[attrName] = getDataCopy( attrValue )

    if getattr( artifact, "Iteration", None ) != None:
        newArtifact["Iteration"] = { "_ref": "iteration/" + artifact.Iteration.oid }

    return newArtifact

def copyAttachments( rallyConn, oldArtifact, newArtifact ):

    """ For each attachment in the old artifact, create new attachments and attach them to the new artifact"""

    # Copy Attachments
    source_attachments = rallyConn.getAttachments(oldArtifact)

    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 = rallyConn.put( 'AttachmentContent', target_attachment_content_fields )
            print "\t===> Copied AttachmentContent: %s" % target_attachment_content.ref
        except pyral.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,
            "User": source_attachment.User.ref
        }

        # Attach it to the new artifact
        target_attachment_fields["Artifact"] = newArtifact.ref

        try:
            target_attachment = rallyConn.put( source_attachment._type, target_attachment_fields)
            print "\t===> Copied Attachment: '%s'" % target_attachment.Name
        except pyral.RallyRESTAPIError, details:
            sys.stderr.write('ERROR: %s \n' % details)
            sys.exit(2)

def copyTasks( rallyConn, oldArtifact, newArtifact ):

    """ Iterate over the old artifacts tasks and create new ones, attaching them to the new artifact """

    for currentTask in oldArtifact.Tasks:

        newTask = getArtifactCopy( currentTask )

        # Assign the new task to the new artifact
        newTask["WorkProduct"] = newArtifact.ref

        # Push the new task into rally
        newTaskObj = rallyConn.put( currentTask._type, newTask )

        # Copy any attachments the task had
        copyAttachments( rallyConn, currentTask, newTaskObj )

def copyDefect( rallyConn, currentDefect, addlUpdates = {} ):

    """ Copy a defect including its attachments and tasks.  Add the new defect as a
        duplicate to the original """

    newArtifact = getArtifactCopy( currentDefect )

    # Add the current defect as a duplicate for the new one
    newArtifact["Duplicates"].append( { "_ref": currentDefect.ref } )

    # Copy in any updates that might be needed
    for (attrName, attrValue) in addlUpdates.items():
        newArtifact[attrName] = attrValue

    print "Copying %s: %s..." % (currentDefect.Project.Name, currentDefect.FormattedID),
    newDefect = rallyConn.create( currentDefect._type, newArtifact )

    print "done, new item", newDefect.FormattedID

    print "\tCopying attachments"
    copyAttachments( rallyConn, currentDefect, newDefect )

    print "\tCopying tasks"
    copyTasks( rallyConn, currentDefect, newDefect )
于 2013-01-15T18:20:11.970 に答える