指摘とメトリック API の例

これらの例は Python で記述されていますが、この言語の深い知識がなくても理解できるほど簡単なはずです。

以下の例はすべて、<server_install>/samples/demosthenes で Validate パッケージでインストールされる C/C++ サンプルプロジェクト、demosthenes を使用しています。demosthenes サンプルプロジェクトは、Validate パッケージ全体がインストールされている場合にのみ使用でき、Validate サーバーパッケージには同梱されていません。サンプルプロジェクトの設定方法については、そのディレクトリの README ファイルを参照してください。

サンプルプロジェクトまたは自分のプロジェクトで、サンプルスクリプトを試すことができます。自分のプロジェクトで使用する場合は、projectの値を変更する必要があります。また、場合によっては、host の値を localhost からご使用の Validate サーバーホストに変更する必要があります。

要求パラメーターに関するその他の情報については、http(s)://<validate_server_host>:<validate_server_port>/review/api を参照してください。

以下のほとんどの例では、プロジェクトリストの印刷を除いて、プロジェクトフィールドにフルパスを含めることでストリームを指定できます。例: project = "myProj/myStream1/subVariant"

この例でのエラー処理について

curl で Web API を使用して呼び出しが行われると、発生するすべてのエラーが自動的にコンソールに表示されます。このトピックの Python の例では単純なエラー処理について説明していることに注意してください。

コピー
builds = report(url, project, user, action)
print("Existing builds:")
for build in builds:
    print(build)

独自の Python スクリプトでより適切にエラーを処理するには、try ブロックを使用します。

コピー
try:
    builds = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing builds:")
    for build in builds:
        print(build)

以下の例について

以下の例で使用するこのモジュール (authutil) では、システムからの ltokens の読み取りを処理します。読みやすいように別々のモジュールになっています。必ず、以下のコードをコピーして貼り付けて authutil モジュールを作成してください。

コピー
import os.path


def get_token(host, port, user):
    ltoken = os.path.normpath(os.path.expanduser("~/.klocwork/ltoken"))
    ltoken_file = open(ltoken, 'r')
    for r in ltoken_file:
        rd = r.strip().split(';')
        if rd[0] == host and rd[1] == str(port) and rd[2] == user:
            ltoken_file.close()
            return rd[3]
    ltoken_file.close()

例: 重大指摘すべての検索

このサンプル スクリプトは、Demosthenes サンプル プロジェクトの最新ビルドに含まれている重大な指摘 (重要度が 1、2、3) すべてを検索します。

コピー
import getpass
import json
import time
import urllib.parse
import urllib.request

import authutil


class Issue(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.message = attrs["message"]
        self.file = attrs["file"]
        self.method = attrs["method"]
        self.code = attrs["code"]
        self.severity = attrs["severity"]
        self.severityCode = attrs["severityCode"]
        self.supportLevel = attrs["supportLevel"]
        self.supportLevelCode = attrs["supportLevelCode"]
        self.state = attrs["state"]
        self.status = attrs["status"]
        self.taxonomyName = attrs["taxonomyName"]
        self.url = attrs["url"]
        self.created = time.ctime(attrs["dateOriginated"] / 1000)


    def __str__(self):
        return "[%d] %s\n\t%s | %s\n\tCode %s | Severity: %s(%d) | Support Level: %s(%d) | State: %s | Status: %s | Taxonomy: %s | Created: %s\n\t%s" % (
            self.id, self.message, self.file, self.method, self.code, self.severity, self.severityCode, self.supportLevel,
            self.supportLevelCode, self.state,
            self.status, self.taxonomyName, self.created, self.url
        )


def from_json(json_object):
    if 'id' in json_object:
        return Issue(json_object)
    return json_object


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)
values = {"project": project, "user": user, "action": "search"}

login_token = authutil.get_token(host, port, user)
if login_token is not None:
    values["ltoken"] = login_token

values["query"] = "severity:1-3"
data = urllib.parse.urlencode(values)
data = data.encode('utf-8')
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
for record in response:
    print(json.loads(record, object_hook=from_json))

例: 検出された指摘のレポート

この例は、検出された指摘をコンポーネント別、ステート別にグループ化した分散を示しています。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Key(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.name = attrs["name"]

    def __str__(self):
        return "%s (%d)" % (self.name, self.id)


class Report(object):
    def __init__(self, attrs):
        self.rows = attrs["rows"]
        self.columns = attrs["columns"]
        self.data = attrs["data"]

    def __str__(self):
        result = ""
        maxRowName = 0
        for r in self.rows:
            maxRowName = max(len(str(r)), maxRowName)
        maxRowName += 1
        header = ' ' * maxRowName
        colPosition = []
        for c in self.columns:
            colPosition.append(len(header) + len(str(r)))
            header += str(c) + ' '
        result += header + '\n'
        for x in range(len(self.rows)):
            rHead = ('%-' + str(maxRowName) + 's') % str(self.rows[x])
            for y in range(len(self.columns)):
                rHead += ('%' + str(len(str(self.columns[y]))) + 's') % str(self.data[x][y]) + ' '
            result += rHead + '\n'
        return result


def from_json(json_object):
    if 'rows' in json_object:
        return Report(json_object)
    if 'id' in json_object:
        return Key(json_object)
    return json_object


def report(url, project, user, x=None, y=None, view=None, xDrilldown=-1, yDrilldown=-1):
    values = {"project": project, "user": user, "action": "report"}
    login_token = authutil.get_token(host, port, user)
    if x is not None:
        values["x"] = x
    if y is not None:
        values["y"] = y
    if login_token is not None:
        values["ltoken"] = login_token
    if view is not None:
        values["view"] = view
    if xDrilldown != -1:
        values["xDrilldown"] = xDrilldown
    if yDrilldown != -1:
        values["yDrilldown"] = yDrilldown
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    for record in response:
        return json.loads(record, object_hook=from_json)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)

try:
    reports = report(url, project, user, "Component", "State")
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print(reports)

例: 指摘情報の検索

この例では、指定された指摘 ID に関する詳細を検索する方法を示しています。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Details(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.code = attrs["code"]
        self.name = attrs["name"]
        self.location = attrs["location"]
        self.build = attrs["build"]
        self.severity = attrs["severity"]
        self.supportLevel = attrs["supportLevel"]
        self.owner = attrs["owner"]
        self.state = attrs["state"]
        self.status = attrs["status"]
        if "history" in attrs:
            self.history = attrs["history"]
        else:
            self.history = None
        if "xSync" in attrs:
            self.xsync = attrs["xsync"]
        else:
            self.xsync = None


    def __str__(self):
        result = "Id:%s, Code:%s, Name:%s, Location:%s, Build:%s, Severity:%s, Support Level%s, Owner:%s, State:%s, Status:%s, History:%s" % (
            self.id, self.code, self.name, self.location, self.build, self.severity, self.supportLevel, self.owner,
            self.state,
            self.status, self.history)
        if self.xsync is not None:
            result = result + ", XSyncInfo:%s" % self.xsync
        return result


def from_json(json_object):
    # print json_object
    return Details(json_object)


def report(url, user, action, project, id, xsync=None):
    values = {"user": user, "action": action, "project": project, "id": id}
    if xsync is not None:
        values['include_xsync'] = xsync
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        # print "R:" ,record
        result.append(from_json(json.loads(record)))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
action = "issue_details"
url = "http://%s:%d/review/api" % (host, port)
project = "demosthenes"
id = "4"
xsync = "false"

try:
    issue_details = report(url, user, action, project, id, xsync)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Issue Details:")
    for details in issue_details:
        print(details)

例:CI に関する指摘の詳細の検索

この例では、指定された CI 指摘 ID に関する詳細を検索する方法を示します。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Details(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.code = attrs["code"]
        self.name = attrs["name"]
        self.location = attrs["location"]
        self.build = attrs["build"]
        self.severity = attrs["severity"]
        self.supportLevel = attrs["supportLevel"]
        self.owner = attrs["owner"]
        self.status = attrs["status"]
        if "history" in attrs:
            self.history = attrs["history"]
        else:
            self.history = None
        if "xSync" in attrs:
            self.xsync = attrs["xsync"]
        else:
            self.xsync = None


    def __str__(self):
        result = "Id:%s, Code:%s, Name:%s, Location:%s, Build:%s, Severity:%s, Support Level%s, Owner:%s, State:%s, Status:%s, History:%s" % (
            self.id, self.code, self.name, self.location, self.build, self.severity, self.supportLevel, self.owner,
            self.state,
            self.status, self.history)
        if self.xsync is not None:
            result = result + ", XSyncInfo:%s" % self.xsync
        return result


def from_json(json_object):
    # print json_object
    return Details(json_object)


def report(url, user, action, project, id, ci_build_name):
    values = {"user": user, "action": action, "project": project, "id": id, "ci_build_name": ci_build_name}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        # print "R:" ,record
        result.append(from_json(json.loads(record)))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
action = "ci_issue_details"
url = "http://%s:%d/review/api" % (host, port)
project = "demosthenes"
id = "1"
ci_build_name = "ci_build_1"

try:
    ci_issue_details = report(url, user, action, project, id, ci_build_name)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Issue Details:")
    for details in ci_issue_details:
        print(details)

例: 指摘ステータスの更新

この例では、特定の指摘の指摘ステータス、コメント、オーナー、バグ追跡システム ID の変更方法を説明しています。

バグ追跡システム ID を指定すると、他のすべての指摘ステータスの値は無視されます。
コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Status(object):
    def __init__(self, attrs):
        self.status_message = attrs["status_message"]

    def __str__(self):
        result = "Status message:%s" % self.status_message
        return result


def from_json(json_object):
    return Status(json_object)


def update_status(url, user, project, ids, status=None, comment=None, owner=None, bug_tracker_id=None):
    values = {'action': 'update_status', 'project': project, 'user': user, 'ids': ids}
    if status is not None:
        values['status'] = status
    if comment is not None:
        values['comment'] = comment
    if owner is not None:
        values['owner'] = owner
    if bug_tracker_id is not None:
        values['bug_tracker_id'] = bug_tracker_id
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
url = "http://%s:%d/review/api" % (host, port)
project = "demosthenes"
id = "1"
status = "Fix"
comment = "Making a status change"
owner = "jsmith" # pass "unowned" to clear the owner

try:
    status_messages = update_status(url, user, project, id, status, comment, owner)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Update Status:")
    for message in status_messages:
        print(message)

例: プロジェクトリストの表示

この例では、プロジェクト リストの表示方法を示します。

デフォルトでは、クエリはベースプロジェクトのみのリストを返します。include_streams フラグに true の値 (デフォルトは false) を指定することで、クエリにすべてのベースプロジェクトとストリームを表示させることもできます。たとえば、次の値でクエリを含めるようにします。

  • action=projects

  • user=someone

  • include_streams=true

...次の集計結果が生成されて返されます:

{"id":"project1","name":"project1","creator":"someone","description":""}

{"id":"project1_sub1","name":"project1/sub1","creator":"someone","description":"","tags":["s"]}

{"id":"project1_sub2","name":"project1/sub1/sub2","creator":"someone","description":""}

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class View(object):
    def __init__(self, attrs):
        self.name = attrs["name"]

    def __str__(self):
        result = "%s" % self.name
        return result


def from_json(json_object):
    return View(json_object)


def report(url, user, action):
    values = {"user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
action = "projects"
url = "http://%s:%d/review/api" % (host, port)

try:
    projects = report(url, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing projects:")
    for project in projects:
        print(project)

例:プロジェクトの更新

この例では、指定したプロジェクトの名前および説明の更新方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def update_project(url, name, user, action, description, new_name):
    values = {"name": name, "user": user, "action": action, "description": description, "new_name": new_name}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "demosthenes"
action = "update_project"
description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
new_name = "demosthenes2"
url = "http://%s:%d/review/api" % (host, port)

try:
    update_project(url, name, user, action, description, new_name)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project updated!")

また、このアクションを使用すると、ビルドの自動削除をオンにし、しきい値パラメーターを使用して保持する数を設定できます。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def update_project(url, name, user, action, auto_delete_builds, auto_delete_threshold):
    values = {"name": name, "user": user, "action": action, "auto_delete_builds": auto_delete_builds,
              "auto_delete_threshold": auto_delete_threshold}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "demosthenes"
action = "update_project"
auto_delete_builds = "true"
auto_delete_threshold = "30"
url = "http://%s:%d/review/api" % (host, port)

try:
    update_project(url, name, user, action, auto_delete_builds, auto_delete_threshold)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project updated!")

例:プロジェクトの作成

この例では、新しいプロジェクトの作成方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def create_project(url, name, user, action):
    values = {"name": name, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "demosthenes"
action = "create_project"
url = "http://%s:%d/review/api" % (host, port)

try:
    create_project(url, name, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project created!")

Example: Delete a project

この例では、指定されたプロジェクトの削除方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def delete_project(url, name, force, user, action):
    values = {"name": name, "force": force, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "demosthenes"
force = True
action = "delete_project"
url = "http://%s:%d/review/api" % (host, port)

try:
    delete_project(url, name, force, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project and its streams deleted!")

例: プロジェクト構成レポートの生成

この例では、指定したプロジェクトの構成レポートの生成方法を示します。 The report displays project information such as creation date, Validate version and basic code metrics.
コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Config(object):
    def __init__(self, attrs):
        self.build = attrs["build"]
        self.creationDate = attrs["creationDate"]
        self.version = attrs["version"]
        self.numberOfFiles = attrs["numberOfFiles"]
        self.cFilesAnalyzed = attrs["cFilesAnalyzed"]
        self.systemFilesAnalyzed = attrs["systemFilesAnalyzed"]
        self.linesOfCode = attrs["linesOfCode"]
        self.linesOfComments = attrs["linesOfComments"]
        self.numberOfEntities = attrs["numberOfEntities"]
        self.numberOfFunctions = attrs["numberOfFunctions"]
        self.numberOfClasses = attrs["numberOfClasses"]
        self.taxonomies = attrs["taxonomies"]

    def __str__(self):
        result = "Build:%s, Creation Date:%s, Version:%s, Number of Files:%s, C Files Analyzed:%s, System Files Analyzed:%s, Lines of Code:%s, Lines of Comments:%s. Number of Entities:%s, Number of Functions:%s, Number of Classes:%s, Taxonomies:%s" % (
            self.build, self.creationDate, self.version, self.numberOfFiles, self.cFilesAnalyzed,
            self.systemFilesAnalyzed,
            self.linesOfCode, self.linesOfComments, self.numberOfEntities, self.numberOfFunctions, self.numberOfClasses,
            self.taxonomies)
        return result


def from_json(json_object):
    return Config(json_object)


def report(url, user, action, project, build=None):
    values = {"user": user, "action": action, "project": project}
    if build is not None:
        values['build'] = build
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = json.loads(response.read(), object_hook=from_json)
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
action = "project_configuration"
url = "http://%s:%d/review/api" % (host, port)
project = "demosthenes"
build = "build_1"

try:
    result = report(url, user, action, project, build)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Project Configuration:")
    print(result)

例: ビューリストの表示

この例では、ビューリストの表示方法を示します。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class View(object):
    def __init__(self, attrs):
        self.name = attrs["name"]
        self.query = attrs["query"]
        self.creator = attrs["creator"]
        if "tags" in attrs:
            self.tags = attrs["tags"]
        else:
            self.tags = ""
        self.is_public = attrs["is_public"]

    def __str__(self):
        result = "Name:%s (Query:%s, Creator:%s, Public:%s) Tags: [" % (
            self.name, self.query, self.creator, self.is_public)
        for x in range(len(self.tags)):
            if not x:
                result = result + self.tags[x]
            else:
                result = result + ',' + self.tags[x]
        result += ']'
        return result


def from_json(json_object):
    return View(json_object)


def report(url, project, user):
    values = {"project": project, "user": user, "action": "views"}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)

try:
    views = report(url, project, user)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    for view in views:
        print(view)

例: ビューの作成

この例では、ビューの作成方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def create_view(url, user, project, name, action, query, tags):
    values = {"project": project, "user": user, "name": name, "action": action, "query": query, "tags": tags}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "Sample View"
action = "create_view"
query = "severity:1-3"
tags = "c,security"
url = "http://%s:%d/review/api" % (host, port)
try:
    create_view(url, user, project, name, action, query, tags)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("View created!")

例: ビューの更新

この例では、ビューの更新方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def update_view(url, user, project, name, newname, action, query, is_public, tags):
    values = {"project": project,
              "user": user,
              "name": name,
              "new_name": newname,
              "action": action,
              "query": query,
              "is_public": is_public,
              "tags": tags}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "Sample View"
newname = "Updated Sample View"
action = "update_view"
query = "severity:1"
tags = "c,security,important"
is_public = "true"
url = "http://%s:%d/review/api" % (host, port)
try:
    update_view(url, user, project, name, newname, action, query, is_public, tags)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("View updated!")

例: ビューの削除

この例では、ビューの削除方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def delete_view(url, user, name, project, action):
    values = {"project": project, "name": name, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "Sample View"
project = "demosthenes"
action = "delete_view"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_view(url, user, name, project, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("View deleted!")

例: モジュールリストの表示

この例では、モジュール リストの表示方法を示します。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Module(object):
    def __init__(self, attrs):
        self.name = attrs["name"]

    def __str__(self):
        result = "%s" % (self.name)
        return result


def from_json(json_object):
    return Module(json_object)


def list_modules(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "modules"
url = "http://%s:%d/review/api" % (host, port)

try:
    modules = list_modules(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing modules:")
    for module in modules:
        print(module)

例: モジュールの作成

この例では、モジュールの作成方法を示します。

アクセス制御メソッドが設定されている場合、モジュールを作成して編集するには、プロジェクト管理者の役割または 'モジュールの管理' パーミッションを持つ必要があります。モジュールでのアクセス パーミッションを追加または変更するには、'役割の割り当て' パーミッションが必要です (デフォルトでプロジェクト管理者が持つ)。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def create_module(url, user, project, name, action, allow_all, paths):
    values = {"project": project, "user": user, "name": name, "action": action, "allow_all": allow_all, "paths": paths}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "mymodule"
action = "create_module"
allow_all = "true"
paths = "**/test/*"
url = "http://%s:%d/review/api" % (host, port)
try:
    create_module(url, user, project, name, action, allow_all, paths)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Module created!")

例: モジュールの更新

この例では、モジュールの更新方法を示します。

アクセス制御メソッドが設定されている場合、モジュールを作成して編集するには、プロジェクト管理者の役割または 'モジュールの管理' パーミッションを持つ必要があります。モジュールでのアクセス パーミッションを追加または変更するには、'役割の割り当て' パーミッションが必要です (デフォルトでプロジェクト管理者が持つ)。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def update_module(url, user, project, name, new_name, action, allow_all):
    values = {"project": project, "user": user, "name": name, "new_name": new_name, "action": action,
              "allow_all": allow_all}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
name = "mymodule"
new_name = "mymodule2"
action = "update_module"
allow_all = "false"
url = "http://%s:%d/review/api" % (host, port)
try:
    update_module(url, user, project, name, new_name, action, allow_all)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Module updated!")

例: モジュールの削除

この例では、モジュールの削除方法を示します。

アクセス制御メソッドが設定されている場合、モジュールを作成して編集するには、プロジェクト管理者の役割または 'モジュールの管理' パーミッションを持つ必要があります。モジュールでのアクセス パーミッションを追加または変更するには、'役割の割り当て' パーミッションが必要です (デフォルトでプロジェクト管理者が持つ)。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def delete_module(url, user, name, project, action):
    values = {"project": project, "name": name, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
name = "mymodule"
project = "demosthenes"
action = "delete_module"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_module(url, user, name, project, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Module deleted!")

例: ビルドリストの表示

この例では、ビルド リストの表示方法を示します。ビルドの管理の詳細については、統合ビルドの管理を参照してください。

コピー
import getpass
import json
import time
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Build(object):
    def __init__(self, attrs):
        self.id = attrs["id"]  # build id
        self.name = attrs["name"]  # build name
        self.date = time.ctime(attrs["date"] / 1000)  # build date
        self.keepit = attrs["keepit"]  # sticky flag

    def __str__(self):
        result = "%s: %s" % (self.name, self.date)
        return result


def from_json(json_object):
    return Build(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "builds"
url = "http://%s:%d/review/api" % (host, port)

try:
    builds = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing builds:")
    for build in builds:
        print(build)

例: 保存するビルドの指定

この例では、毎秒ビルドが自動削除機能によって削除されないことを示します。

このアクションでは、'keepit' オプションを指定することによって特定のビルドを保持するかどうかを指定することもできます。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Build(object):
    def __init__(self, attrs):
        self.id = attrs["id"]
        self.name = attrs["name"]
        self.date = attrs["date"]

    def __str__(self):
        return "Id: %s Name:%s Date:%i" % (self.id, self.name, self.date)


def from_json(json_object):
    return Build(json_object)


def keepit(build_name, login_token):
    print("retain " + build_name)
    values = {"project": project, "user": user, "action": "update_build", "name": build_name, "keepit": "true"}
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


def retain(url, project, user):
    values = {"project": project, "user": user, "action": "builds"}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)

    i = 0
    for record in response:
        build = json.loads(record, object_hook=from_json)

        i += 1
        if not i % 2:
            keepit(build.name, login_token)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)

retain(url, project, user)

例: ビルドの削除

この例では、ビルドの削除方法を示します。ビルドの管理の詳細については、統合ビルドの管理を参照してください。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def delete_build(url, user, project, build, action):
    values = {"project": project, "name": build, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
build = "demosthenes_3"
action = "delete_build"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_build(url, user, project, build, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Build deleted!")

例:CI ビルドの作成

この例では、CI ビルドの作成方法を示します。

コピー
import getpass
import json
import time
import urllib.error
import urllib.parse
import urllib.request

import authutil


class CiBuild(object):
    def __init__(self, attrs):
        self.id = attrs["id"]  # build id
        self.name = attrs["name"]  # build name
        self.date = time.ctime(attrs["date"] / 1000)  # build date

    def __str__(self):
        result = "%s: %s" % (self.name, self.date)
        return result


def from_json(json_object):
    return CiBuild(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "ci_builds"
url = "http://%s:%d/review/api" % (host, port)

try:
    ci_builds = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Existing Ci Builds:")
    for ci_build in ci_builds:
        print(ci_build)

例:CI ビルドの更新

この例では、CI ビルドの更新方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def rename(url, user, action, project, old_ci_build_name, new_ci_build_name):
    values = {"user": user, "action": action, "project": project, "name": old_ci_build_name, "new_name": new_ci_build_name}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)
action = "update_ci_build"
old_ci_build_name = "ci_build_1"
new_ci_build_name = "win-ci_build_1"


try:
    rename(url, user, action, project, old_ci_build_name, new_ci_build_name)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Ci Build successfully renamed")

例:CI ビルドの削除

この例では、CI ビルドの削除方法を示します。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def delete_build(url, user, project, build, action):
    values = {"project": project, "name": build, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
build = "ci_build_1"
action = "delete_ci_build"
url = "http://%s:%d/review/api" % (host, port)
try:
    delete_build(url, user, project, build, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Build deleted!")

例: 有効化されたチェッカーのリストの表示

この例では、有効化されたチェッカーのリストの表示方法を示します。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class View(object):
    def __init__(self, attrs):
        self.code = attrs["code"]
        self.name = attrs["name"]
        self.enabled = attrs["enabled"]
        self.severity = attrs["severity"]
        self.supportLevel = attrs["supportLevel"]

    def __str__(self):
        result = "Code: %s\nName: %s\nEnabled: %s\nSeverity: %s\nSupport Level: %s\n" % (
            self.code, self.name, self.enabled, self.severity, self.supportLevel)
        return result


def from_json(json_object):
    return View(json_object)


def report(url, project, user, action):
    values = {"project": project, "user": user, "action": action}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    result = []
    for record in response:
        result.append(json.loads(record, object_hook=from_json))
    return result


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
action = "defect_types"
taxonomy = "C and C++"
url = "http://%s:%d/review/api" % (host, port)

try:
    defects = report(url, project, user, action)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())
else:
    print("Defect types:")
    for defect in defects:
        print(defect)

例: メトリックのレポート

次の例では、直前のビルドのプロジェクトにおける各ファイルのコメント付きおよびコメントが付いてない行の行数、実行可能ステートメント数、最大のネストレベル、および循環的複雑度メトリックをレポートします。

有効なメトリックコードのリストについては、メトリックリファレンスを参照してください。

コピー
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request

import authutil


class Metric(object):
    def __init__(self, attrs):
        self.file = attrs["filePath"]
        self.entity = attrs["entity"]
        self.tag = attrs["tag"]
        self.value = attrs["metricValue"]

    def __str__(self):
        return "%s;%s;%d" % (self.file, self.tag, self.value)


def from_json(json_object):
    if 'filePath' in json_object:
        return Metric(json_object)
    return json_object


host = "localhost"
port = 8080
user = getpass.getuser()
project = "demosthenes"
url = "http://%s:%d/review/api" % (host, port)
values = {"project": project, "user": user, "action": "metrics"}

login_token = authutil.get_token(host, port, user)
if login_token is not None:
    values["ltoken"] = login_token

values["query"] = "metric:+RNOEXSTAT,+LINESCOMM,+NCNBLOC_FILE,+RMAXLEVEL,+RCYCLOMATIC"
data = urllib.parse.urlencode(values)
data = data.encode('utf-8')
req = urllib.request.Request(url, data)
try:
    response = urllib.request.urlopen(req)
    for record in response:
        print(json.loads(record, object_hook=from_json))
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

集約された検索結果

デフォルトでは、メトリック API はファイルごとに結果を生成します。特定のクエリですべてのファイルについて集約された検索結果を生成するには、true (デフォルトは false) の値で aggregate フラグを指定します。次の例では、集約された検索結果を示します。

次の値でのクエリ:

  • action=metrics
  • user=someone
  • query=metric:+LOC_FILE
  • project=demosthenes
  • aggregate=true

...次の集計結果が生成されて返されます:

{"tag":"LOC_FILE","sum":8113.0,"min":3.0,"max":966.0,"entries":47}

aggregate フラグはデータに関連性がある場合にのみ役立ちます。つまり、メトリックの集約が可能であるか、最大値と最小値を決められる場合です。

システムファイルの検索結果からの除外

デフォルトでは、メトリック API はすべてのファイルに基づいて結果を生成します。クエリオミットシステムファイルは、値 true (デフォルトは false) で exclude_system_files フラグを指定して得ることができます。

次の値でのクエリ:

  • action=metrics
  • user=someone
  • project=demosthenes
  • aggregate=true
  • exclude_system_files=true
  • query=metric:+LOC_FILE

curl 要求の例:

curl --data "action=metrics&user=someone&project=demosthenes&exclude_system_files=true&query=metric:%2bLOC_FILE&aggregate=true" http://localhost:8080/review/api

...次の結果が生成されて返されます:

{"tag":"LOC_FILE","sum":322.0,"min":3.0,"max":68.0,"entries":13}

サーバー設定、プロジェクト、およびコード レビューのインポート

API では、コマンドラインを使用してサーバー設定、プロジェクト、またはコード レビューをインポートすることもできます。これは、次のような各方法で実行できます。

サーバー設定をインポートするには

次の例では、認証構成、パーミッション、カスタム メトリクス、レポート定義、および電子メール購読設定をインポートします。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def import_server_configuration(url, user, sourceURL, sourceAdmin, sourcePassword):
    values = {"action": "import_server_configuration",
              "user": user,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}
    if sourcePassword is not None:
        values["sourcePassword"] = sourcePassword
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()

sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"
sourcePassword = None

url = "http://%s:%d/review/api" % (host, port)

try:
    import_server_configuration(url, user, sourceURL, sourceAdmin, sourcePassword)
    print("Imported server configuration!")
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

プロジェクトをインポートするには

以下の例では、指定されたプロジェクトについて Validate が収集したデータをインポートします。

コピー
import getpass
import urllib.error
import urllib.parse
import urllib.request

import authutil


def import_project(url, user, project, sourceURL, sourceAdmin, sourcePassword):
    values = {"action": "import_project",
              "user": user,
              "project": project,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}
    if sourcePassword is not None:
        values["sourcePassword"] = sourcePassword
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


host = "localhost"
port = 8080
user = getpass.getuser()

project = "projectA"
sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"
sourcePassword = None

url = "http://%s:%d/review/api" % (host, port)

try:
    import_project(url, user, project, sourceURL, sourceAdmin, sourcePassword)
    print("Imported project!")
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

インポートステータスをチェックするには

この API メソッドを使用すると、サーバー設定、プロジェクト、またはコード レビューのインポートのステータスを確認できます。

コピー
import getpass
import json
import sys
import time
import urllib.error
import urllib.parse
import urllib.request

import authutil


class ImportStatus(object):
    def __init__(self, project, attrs):
        self.project = project
        self.stage = attrs["stage"]
        self.progress = attrs["progress"]
        self.failed = attrs["failed"]
        self.hasWarnings = attrs["hasWarnings"]
        self.projectReady = attrs["projectReady"]
        self.complete = attrs["complete"]

    def __str__(self):
        return "Project: %s\n\tStage: %s | Progress: %s%% | Failed: %s | Warnings: %s | Project Ready: %s | Complete: %s" % (
            self.project, self.stage, self.progress, self.failed, self.hasWarnings, self.projectReady, self.complete)


def import_status(url, user):
    values = {"action": "import_status", "user": user}
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    response = urllib.request.urlopen(req)
    importStatus = []
    for record in response:
        attrs = json.loads(record)
        for key in attrs.keys():
            importStatus.append(ImportStatus(key, attrs[key]))
    return importStatus


def import_project(url, user, project, sourceURL, sourceAdmin, sourcePassword=None, ):
    values = {"action": "import_project",
              "user": user,
              "project": project,
              "sourceURL": sourceURL,
              "sourceAdmin": sourceAdmin}
    if sourcePassword:
        values["sourcePassword"] = sourcePassword
    login_token = authutil.get_token(host, port, user)
    if login_token is not None:
        values["ltoken"] = login_token
    data = urllib.parse.urlencode(values)
    data = data.encode('utf-8')
    req = urllib.request.Request(url, data)
    urllib.request.urlopen(req)


def wait_for_import(url, user, project):
    is_timeout = False
    TIME_OUT = time.time() + 60 * 20
    incomplete = [project]

    if len(incomplete) == 0:
        return

    while True:
        for status in import_status(url, user):
            if status.project != project:
                continue

            # If all operations are complete then exit the loop
            if len(incomplete) == 0:
                break

            if status.project in incomplete:
                is_timeout = time.time() > TIME_OUT

            if status.complete or status.failed:
                print(status.stage)
                incomplete.pop(incomplete.index(status.project))
                break
            elif is_timeout:
                print("Import of project '%s' took longer than expected." % status.project)
                print("Check if import is still progressing.")
                sys.exit(-1)

        # If all projects are complete then exit the loop
        if len(incomplete) == 0:
            break

        time.sleep(10)


host = "localhost"
port = 8080
user = getpass.getuser()

url = "http://%s:%d/review/api" % (host, port)

project = "demosthenes"
sourceURL = "http://oldhost:8080"
sourceAdmin = "old admin user name"

try:
    import_project(url, user, project, sourceURL, sourceAdmin)
    print("Import started")
    wait_for_import(url, user, project)
except urllib.error.HTTPError as e:
    print("Request failed:", e.reason, ":", e.read())

Validate サーバーのバージョンをチェックするには

このアクションにより、Validate サーバーのバージョンを取得することができます。このアクションのための curl コマンドの例を次に示します。
curl --data "action=version&user=myself&" http://jsmith..com:8080/review/api
以下に、このコマンドからのサンプル出力を示します。
              1 {
              2 majorVersion: "10.1"
              3 minorVersion: "1"
              4 }

Validate サーバーで実行しているすべてのタスクのステータスをリストするには

このアクションにより、Validate サーバーで実行している各タスクのステータスをリストすることができます。このアクションのための curl コマンドの例を次に示します。
curl --data "action=task_status&user=myself&" http://jsmith..com:8080/review/api