Python スクリプトの作成
バグ システムの統合のための Python スクリプトは、review_action.pyと呼ばれます。このスクリプトでは次のことを行う必要があります。
- バグ追跡システムの特定
 - 統合のために行う必要があるアクションの定義
 - バグ トラッカーに送信する指摘情報の指定
 
オプションで、次のことを行うこともできます。
- 指摘の詳細ページに表示する [Create a ticket] ボタンのテキストのカスタマイズを行う
 - バグ トラッカーからのコメントの表示に加え、バグ追跡システムのバグ エントリーへの指摘の詳細ページでハイパーリンクの表示を行う
 - スクリプトに診断メッセージを含める
 
例: Bugzilla への接続を確立する
この例では、ユーザーが Static Code Analysis で [Bugzilla に送信] ボタンをクリックすると、Python スクリプト review_action.py がオープンソースのバグ追跡システム Bugzilla への接続を指定します。review_action.py スクリプトでは一般的ですが、指摘 ID、指摘を見つけたチェッカー、チェッカー メッセージ、指摘の URL など、Bugzilla に送信する必要がある指摘データを定義します(スクリプトの定義済み変数のリストについては、[定義済み変数の使用] を参照してください)。
また、スクリプトには、デフォルト値 (Create a ticket) の代わりにボタンのカスタム名 Send to Bugzilla を定義する定義 #ui.nameも含まれます。set_bug_idメソッドは、指摘の対応する Bugzilla のバグへのハイパーリンクになる Bugzilla へのリンクを指定します。また、success_msgメソッドは、診断メッセージを定義します。
import sys
import re
import json
import urllib.request
import urllib.error
class InputData:
    """
    Represents the input JSON structure.
    Fields:
    - issue: dict
    - username: str
    """
    def __init__(self, data):
        self.issue = data.get('issue', {})
        self.username = data.get('username', '')
class OutputData:
    """
    Represents the output JSON structure.
    Fields:
    - bugTrackerId: str
    - comment: str
    - status: str
    """
    def __init__(self, output_path):
        self.output_path = output_path
        self.data = {}
    def update(self, key, value):
        self.data[key] = value
        with open(self.output_path, 'w', encoding='utf-8') as f:
            json.dump(self.data, f)
def main():
    input_path = sys.argv[1]
    output_path = sys.argv[2]
    with open(input_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    input_data = InputData(data)
    output_data = OutputData(output_path)
    issue = input_data.issue
    history = issue.get('statusHistory', [])
    username = input_data.username
    def set_bug_id(id):
        output_data.update("bugTrackerId", id)
    def set_comment(comment):
        output_data.update("comment", comment)
    def success(status_msg):
        output_data.update("status", status_msg)
    def fail(s):
        raise RuntimeError(s)
    def bugzillaAPIRequest():
        host = "https://api-dev.bugzilla.mozilla.org/test/latest/bug?username=prezioso@gmail.com&password=klocwork"
        product = "FoodReplicator"
        component = "Salt"
        version = "1.0"
        target = "---"
        summary = "%s | %s | %s | %s | %s | %s | %s" % (
            issue.get("id", ""), issue.get("code", ""), issue.get("severity", ""),
            issue.get("severityCode", ""), issue.get("status", ""), issue.get("url", ""), issue.get("project", ""))
        op_sys = "Linux"
        platform = "All"
        jdata = json.dumps({
            "product": product,
            "component": component,
            "version": version,
            "target": target,
            "summary": summary,
            "opsys": op_sys,
            "platform": platform
        })
        jdata_bytes = jdata.encode('utf-8')
        req = urllib.request.Request(host, jdata_bytes, {'Content-Type': 'application/json', 'Accept': 'application/json'})
        try:
            resp = urllib.request.urlopen(req)
            content = resp.read().decode('utf-8')
            if not content:
                fail("Empty response from server")
            obj = json.loads(content)
            ref = obj.get('ref', '')
            id = obj.get('id', '')
            set_bug_id(id)
            return "%s" % (ref)
        except urllib.error.HTTPError as e:
            print(f"HTTPError: {e.code}", file=sys.stderr)
            if e.code == 201:
                content = e.read().decode('utf-8')
                if not content:
                    fail("Empty response from server")
                obj = json.loads(content)
                ref = obj.get('ref', '')
                id = obj.get('id', '')
                set_bug_id(id)
                return "%s" % (ref)
            else:
                fail("HTTP error: %s" % e)
        except Exception as e:
            fail("Request failed: %s" % e)
        return "fail"
    success_msg = bugzillaAPIRequest()
    if (success_msg == "fail"):
        fail("ERROR - HTTP POST REQUEST")
    success(success_msg)
if __name__ == "__main__":
    main()
                                                注記:
- 
                                                    
最新の
review_action.pyスクリプトは Python 3 構文に更新されています。古いスクリプトを更新して、レガシー Python 2 コードを削除してください。互換性とサポートを確保するため、今後の変更は更新された Python 3 構造に基づいて行ってください。 - 
                                                    
指摘オブジェクトは JSON オブジェクトになりました。指摘フィールドには
issue.get("id")を指定してアクセスすることができます。 - 
                                                    
履歴オブジェクトは、履歴オブジェクトの JSON 配列です。履歴フィールドには
history[0]['owner']を指定してアクセスすることができます。 - 
                                                    
スクリプト内の input_data は以下の形式になります。
 
{
"issue": {
"id": 95,
"groupId": 0,
"name": "Buffer Overflow - Array Index Out of Bounds",
"message": "Array \u0027i\u0027 of size 10 may use index value(s) 10",
"file": "C:\\Users\\dkumar\\Downloads\\projs\\c\\c_proj\\testFile.c",
"line": 8,
"code": "ABV.GENERAL",
"severity": "Critical",
"severityCode": 1,
"supportLevel": "Klocwork Certified",
"supportLevelCode": 1,
"bugTrackerId": "12345",
"state": "New",
"status": "Analyze",
"lastUpdateDate": 1753821247663,
"owner": "unowned",
"project": "ff",
"buildName": "build_2",
"url": "http://localhost:8080/review/insight-review.html#issuedetails_goto:problemid\u003d95,project\u003dff,view_id\u003d1",
"statusHistory": [
  {
        "date": 1753821247663,
        "userid": "dkumar",
        "comment": "Bug created successfully.",
    "status": "new",
    "owner":"smith"
  },
  {
        "date": 1753783959710,
        "userid": "dkumar",
        "comment": "Fix",
    "status": "new",
    "owner":"john"
  }
]
},
"username": "john"
 }
                                                スクリプトをインストールすると、指摘ウィンドウは次のように表示されます。BUG ID フィールドは指摘の Bugzilla のエントリーへのハイパーリンクを示しています。
                                                
                                            
例: Rational Team Concert との統合
以下の例は、お使いの Klocwork 環境を Rational Team Concert と統合するために必要なステップを詳細に示したものです。
RTC xml ドキュメントのナビゲート方法
RTC で業務詳細を作成するには、まず、RTC サーバーから一連の xml ドキュメントを要求することにより、関連 URL とプロジェクトキーを特定する必要があります。このステップは次のステップと似ています。
- RTC REST API から xml ルートサービスドキュメントをフェッチします: http(s)://yourRTCserver:port/ccm/rootservices
 - "oslc_cm:cmServiceProviders" 内 "rdf:resource" 属性である Services Catalog URL を抽出します。
<oslc_cm:cmServiceProviders xmlns:oslc_cm="http://open-services.net/xmlns/cm/1.0/" rdf:resource="http(s):// yourRTCserver:port /ccm/oslc/workitems/catalog" /> - プロジェクトのタイトル (element dc:title of element oslc_disc:ServiceProvider) を特定することにより、Service Catalog の中から関連するプロジェクトのサービスプロバイダー URL (要素 "oslc_disc:services" の属性 "rdf:resource" of element) を探します。 URL には一意のプロジェクトキー (_Day3sOHaEeO1tdkD6QbZUQ など) が含まれています。
 - サービスプロバイダの URL から、適切なサービスファクトリーの URL ("oslc_cm:url") (要素 “oslc_cm:changeRequests oslc” の要素 “oslc_cm:factory” の<dc:title>Location for creation of change requests</dc:title>) を抽出します 
<oslc_cm:changeRequests oslc_cm:version="1.0"> … <oslc_cm:factory> >dc:title<Location for creation of change requests>/dc:title< >oslc_cm:url< http(s):// yourRTCserver:port /ccm/oslc/contexts/_Day3sOHaEeO1tdkD6QbZUQ/workitems</oslc_cm:url> </oslc_cm:factory> … </oslc_cm:changeRequests> - 業務詳細をファクトリー URL にアップします。たとえば、JSON エンコードの業務詳細は次のようになります。 
{ "dc:title":"Klocwork ID 42: Suspicious dereference of pointer in function call before NULL check: cvs\\src\\checkin.c", "dc:description":"This issue was detected by Klocwork static code analysis. \n \t\t\nId: 42 URL: http(s)://yourKlocworkServer:port/review/kw-review.htm#issuedetails_goto:problemid=42,project=CVS,view_id=1 \nExported to RTC by: jchapman \n \nFile: cvs\\src\\checkin.c \n \nChecker: RNPD.CALL \nType: Suspicious dereference of pointer in function call before NULL check \nMessage: Suspicious dereference of pointer 'options' by passing argument 1 to function 'strcmp' at line 63 before NULL check at line 76 \nSeverity: Critical(1) \nStatus: Analyze \nState: Existing \nOwner: azukich \nLast Update: No Updates \nHistory: \n", "dc:type": "task", "oslc_cm:priority": " http(s):// yourRTCserver:port /ccm/oslc/enumerations/_Day3sOHaEeO1tdkD6QbZUQ/priority/priority.literal.l4" } - 動作が正常に行われた場合、業務詳細がアップされた URL は、レスポンスヘッダー内の “Location” に、業務詳細の ID はレスポンス要素 “dc:identifier” に表示されます。
 
認証の取り扱い方法
初期設定では、RTC サーバーがフォームの記入による認証方法を採用するようにセットアップされています。そのため、RTC サーバーに何かをアップする際には、認証レスポンスリクエストを検索する必要があります。 例:
import urllib.request
import urllib.parse
import urllib.error
targetUrl = "..."  # your target URL
data = b"..."      # your data as bytes
hostbase = "..."   # your host base
rtc_username = "..."  # your username
rtc_password = "..."  # your password
req = urllib.request.Request(targetUrl, data, {'Content-Type': 'application/json', 'Accept': "application/xml"})
try:
    response = urllib.request.urlopen(req)
    if response.info().get('X-com-ibm-team-repository-web-auth-msg') == 'authrequired':
        login_data = urllib.parse.urlencode({'j_username': str(rtc_username), 'j_password': str(rtc_password)}).encode('utf-8')
        reqLogon = urllib.request.Request(
            hostbase + "/j_security_check",
            login_data,
            {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': "application/json"}
        )
        response = urllib.request.urlopen(reqLogon)
        if response.info().get('X-com-ibm-team-repository-web-auth-msg') == 'authfailed':
            raise RuntimeError("RTC logon failed")
        else:
            if data is not None:
                response = urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
    eData = e.read().decode('utf-8')
    if hasattr(e, 'code'):
        if e.code == 201:
            # process response
            pass
        elif e.code == 400:
            # process error message
            pass
                                                
フィールド値の取り扱い方法
フィールド値の列挙子 ("oslc_cm:priority" など) は、プロジェクトごとに定義され、RTC 管理者がカスタマイズすることができます。特定のプロジェクトに対して設定された値を発見するには、お使いのブラウザーとプロジェクトに一意のプロジェクトキーを使ってサーバーにクエリを出します。例:
http(s):// yourRTCserver:port/ccm/oslc/enumerations/_Day3sOHaEeO1tdkD6QbZUQ/priority
ヘルプが必要ですか?静的コード解析プロフェッショナルサービスチームにお問い合わせください。
静的コード解析プロフェッショナルサービスチームは、Bugzilla、JIRA、および IBM Rational Team Concert 向けのベーシックスクリプトを作成してきた長い実績があります。スクリプトはご希望のインストールに合わせてカスタマイズすることができます。ヘルプが必要な場合は、静的コード解析プロフェッショナルサービスチームまでお問い合わせください。
[Create a ticket] ボタンのカスタマイズ
review_action.py スクリプトを projects_root/config ディレクトリに配置すると、Static Code Analysis により、プロジェクトの Static Code Analysis で、指摘の詳細ページに [Create a ticket] ボタンが表示されます。(リンクを表示するにはブラウザーの更新が必要になることがあります)ボタンに別の名前を指定する場合は、スクリプトに次の行を追加します。
#ui.name:<my custom button>
例:
#ui.name:Send to Bugzilla
スクリプトがインストールされると、指摘ウィンドウに新しいボタンが表示されます。
                                                
                                            
ボタン名に日本語を使用するには、review_action.py スクリプトに UTF-8 エンコーディングを含めます。
診断メッセージの組み込み
[Create a ticket] ボタンをクリックしたときにバグレポートが正常に保管されると、Static Code Analysis ウィンドウに、[Ticket created] メッセージが表示されます。失敗すると、[Bug reporting failed] と表示されます。成功時と失敗時のカスタム診断メッセージを指定するには、Python スクリプトで次のメソッドを使用します。
- success(custom_message)
 - fail(custom_message)
 
スクリプトで fail() メソッドを呼び出すと、スクリプトの実行がさらに中断されます。
projects_root へのスクリプトの配置
review_action.pyスクリプトが完了したら、プロジェクトのprojects_root/configディレクトリに配置します。
利用可能な変数
review_action.py スクリプトは、JSON 構造で以下の変数を入力として受け取ります。
| variable.field | 使用方法 | 
|---|---|
| username | [Create a ticket] ボタンでスクリプトをアクティブにしたユーザーの名前 | 
| issue | 次のフィールドのスクリプトに関する情報が含まれているクラス Issue の Python オブジェクト | 
| issue.id | Static Code Analysis での指摘の識別子 | 
| issue.groupId | Static Code Analysis で指摘が属するグループの識別子。値がゼロの場合、グループ計算がオフになっていることを示すので、この変数は使用しないでください。 | 
| issue.name | Static Code Analysis 指摘の詳細ページからの指摘の名前 | 
| issue.message | Static Code Analysis での指摘のチェッカーメッセージ | 
| issue.file | 指摘が出現したファイル | 
| issue.code | 指摘を見つけたチェッカーの名前 | 
| issue.severity | テキスト形式 (数値以外) の指摘の重要度 | 
| issue.severityCode | 数値形式の指摘の重要度 | 
| issue.state | 指摘のステート - 既存 (Existing) または修正済み (Fixed) | 
| issue.status | 要修正 (Fix) または解析 (Analyze) などの指摘のステータス | 
| issue.lastUpdateDate | 最終更新の時間 (ミリ秒単位) | 
| issue.owner | 指摘のオーナー | 
| issue.project | Klocwork プロジェクトの名前 | 
| issue.url | Static Code Analysis での指摘の URL | 
| issue.statusHistory | 更新履歴イベントを持つ配列。各イベントは、次のフィールドがあるクラス StatusHistoryEvent のオブジェクトです。 
  | 
                                                        
| issue.bugTrackerId | Static Code Analysis での指摘のバグトラッカー ID |