Skip to content

Commit

Permalink
Merge pull request #7 from devopshq/develop
Browse files Browse the repository at this point in the history
Add WIQL support, timeout
  • Loading branch information
allburov authored Jul 24, 2017
2 parents 01666ce + 748a445 commit cb7c827
Show file tree
Hide file tree
Showing 8 changed files with 343 additions and 76 deletions.
46 changes: 44 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ TFS Python Library (TFS API Python client)
- [Quickstart](#quickstart)
- [Installation](#installation)
- [Create connection](#create-connection)
- [Timeout connection](#timeout-connection)
- [Workitem](#workitem)
- [Run Queries](#run-queries)
- [Run Saved Queries](#run-saved-queries)
- [Run WIQL](#run-wiql)
- [Changesets](#changesets)
- [Project and Team](#project--team)
- [Guide](#guide)
Expand Down Expand Up @@ -53,6 +55,14 @@ client = TFSAPI("https://tfs.tfs.ru/tfs/", project="Development/ProjectName", us
workitem = client.get_workitem(100) # Test connection with Workitem id
```

## Timeout connection
You can set CONNECT and READ timeouts ([read more](http://docs.python-requests.org/en/master/user/advanced/#timeouts))
```python
from tfs import TFSAPI
client = TFSAPI("https://tfs.tfs.ru/tfs/", user=user, password=password, connect_timeout=30, read_timeout=None)

```

## Workitem
```python
# For single Workitem
Expand Down Expand Up @@ -87,7 +97,7 @@ if childs: # Child is empty list if Workitem hasn't Child link
print("Workitem with id={} have Childs={}".format(workitem.id, ",".join([x.id for x in childs])))
```

## Run Queries
## Run Saved Queries
You can run Saved Queries and get Workitems
```python
# Set path to ProjectName in project parameter
Expand All @@ -105,6 +115,38 @@ print(quiery.column_names)
workitems = quiery.workitems
```

## Run WIQL
You can run [Work Item Query Language](https://msdn.microsoft.com/en-us/library/bb130198(v=vs.90).aspx)
```python
# Set path to ProjectName in project parameter
client = TFSAPI("https://tfs.tfs.ru/tfs/", project="Development/ProjectName", user=user, password=password)

# Run custom query
### NOTE: Fields in SELECT really ignored, wiql return Work Items with all fields
query = """SELECT
[System.Id],
[System.WorkItemType],
[System.Title],
[System.ChangedDate]
FROM workitems
WHERE
[System.WorkItemType] = 'Bug'
ORDER BY [System.ChangedDate]"""

wiql = client.run_wiql(query)

# Get founded Work Item ids
ids = wiql.workitem_ids
print("Found WI with ids={}".format(",".join(ids)))

# Get RAW query data - python dict
raw = wiql.result

# Get all found workitems
workitems = wiql.workitems
print(workitems[0]['Title'])
```

## Changesets
```python
# Get changesets from 1000 to 1002
Expand Down
6 changes: 2 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,8 @@

package_data={
'': [
'./tfs/*'

'LICENSE',
'README.md',
'../LICENSE',
'../README.md',
],
},

Expand Down
10 changes: 4 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ def request_callback_get(request, uri, headers):

@pytest.fixture(autouse=True)
def tfs_server_mock():
httpretty.register_uri(httpretty.GET, re.compile(r"http://tfs.tfs.ru(.*)"),
body=request_callback_get,
content_type="application/json")
httpretty.register_uri(httpretty.PATCH, re.compile(r"http://tfs.tfs.ru(.*)"),
body=request_callback_get,
content_type="application/json")
for method in (httpretty.GET, httpretty.POST, httpretty.PATCH):
httpretty.register_uri(method, re.compile(r"http://tfs.tfs.ru(.*)"),
body=request_callback_get,
content_type="application/json")


@pytest.fixture()
Expand Down
50 changes: 50 additions & 0 deletions tests/resources/tfs/Development/_apis/wit/wiql/response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"queryResultType": "workItem",
"columns": [
{
"name": "ID",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/System.Id",
"referenceName": "System.Id"
},
{
"name": "Severity",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/Microsoft.VSTS.Common.Severity",
"referenceName": "Microsoft.VSTS.Common.Severity"
},
{
"name": "Target Version",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/TargetVersion",
"referenceName": "TargetVersion"
}
],
"sortColumns": [
{
"field": {
"name": "Target Version",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/TargetVersion",
"referenceName": "TargetVersion"
},
"descending": false
},
{
"field": {
"name": "Severity",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/Microsoft.VSTS.Common.Severity",
"referenceName": "Microsoft.VSTS.Common.Severity"
},
"descending": false
}
],
"workItems": [
{
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/workItems\/100",
"id": 100
},
{
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/workItems\/101",
"id": 101
}
],
"asOf": "2017-07-24T06:59:38.74Z",
"queryType": "flat"
}
39 changes: 24 additions & 15 deletions tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def test_get_changesets(self, tfsapi):
assert len(changesets) == 5
assert changesets[0].id == 10

@pytest.mark.httpretty
def test_get_wiql(self, tfsapi):
wiql_query = "SELECT *"
wiql = tfsapi.run_wiql(wiql_query)

assert isinstance(wiql, Wiql)
assert wiql.workitem_ids == [100, 101]

@pytest.mark.httpretty
def test_get_projects(self, tfsapi):
projects = tfsapi.get_projects()
Expand All @@ -57,18 +65,19 @@ def test_get_teams(self, tfsapi):
assert isinstance(team, TFSObject)
assert team['name'] == 'ProjectName'

class TestHTTPClient:
def test__get_collection(self):
collection, project = TFSHTTPClient.get_collection_and_project('Development')
assert collection == 'Development'
assert project is None

def test__get_collection_and_project(self):
collection, project = TFSHTTPClient.get_collection_and_project('Development/Project')
assert collection == 'Development'
assert project == 'Project'

def test__get_collection_and_project_and_team(self):
collection, project = TFSHTTPClient.get_collection_and_project('Development/Project/Team')
assert collection == 'Development'
assert project == 'Project'

class TestHTTPClient:
def test__get_collection(self):
collection, project = TFSHTTPClient.get_collection_and_project('Development')
assert collection == 'Development'
assert project is None

def test__get_collection_and_project(self):
collection, project = TFSHTTPClient.get_collection_and_project('Development/Project')
assert collection == 'Development'
assert project == 'Project'

def test__get_collection_and_project_and_team(self):
collection, project = TFSHTTPClient.get_collection_and_project('Development/Project/Team')
assert collection == 'Development'
assert project == 'Project'
131 changes: 131 additions & 0 deletions tests/test_tfs.py → tests/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ def test_changeset_id(self, changeset):
def test_changeset_fields(self, changeset):
assert changeset['comment'] == "My Comment"

def test_changeset_fields_get(self, changeset):
assert changeset.get('comment') == "My Comment"


@pytest.mark.httpretty
def test_get_changesets_workitem(self, tfsapi):
changesets = tfsapi.get_changesets(from_=10, to_=14)
Expand Down Expand Up @@ -223,3 +227,130 @@ def test_tfsquery_column_names(self, tfsquery):
assert len(tfsquery.workitems) == 2
assert tfsquery.workitems[0].id == 100
assert tfsquery.workitems[1].id == 101


class TestWiql(object):
@pytest.fixture()
def wiql(self, tfsapi):
data_str = r"""{
"queryResultType": "workItem",
"columns": [
{
"name": "ID",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/System.Id",
"referenceName": "System.Id"
},
{
"name": "Severity",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/Microsoft.VSTS.Common.Severity",
"referenceName": "Microsoft.VSTS.Common.Severity"
},
{
"name": "Target Version",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/TargetVersion",
"referenceName": "TargetVersion"
}
],
"sortColumns": [
{
"field": {
"name": "Target Version",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/TargetVersion",
"referenceName": "TargetVersion"
},
"descending": false
},
{
"field": {
"name": "Severity",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/Microsoft.VSTS.Common.Severity",
"referenceName": "Microsoft.VSTS.Common.Severity"
},
"descending": false
}
],
"workItems": [
{
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/workItems\/100",
"id": 100
},
{
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/workItems\/101",
"id": 101
}
],
"asOf": "2017-07-24T06:59:38.74Z",
"queryType": "flat"
}"""
data_ = json.loads(data_str)
wiql = Wiql(data_, tfsapi)
yield wiql

@pytest.fixture()
def wiql_empty(self, tfsapi):
data_str = r"""{
"queryResultType": "workItem",
"columns": [
{
"name": "ID",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/System.Id",
"referenceName": "System.Id"
},
{
"name": "Severity",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/Microsoft.VSTS.Common.Severity",
"referenceName": "Microsoft.VSTS.Common.Severity"
},
{
"name": "Target Version",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/TargetVersion",
"referenceName": "TargetVersion"
}
],
"sortColumns": [
{
"field": {
"name": "Target Version",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/TargetVersion",
"referenceName": "TargetVersion"
},
"descending": false
},
{
"field": {
"name": "Severity",
"url": "https:\/\/tfs.tfs.ru\/tfs\/Development\/_apis\/wit\/fields\/Microsoft.VSTS.Common.Severity",
"referenceName": "Microsoft.VSTS.Common.Severity"
},
"descending": false
}
],
"workItems": [
],
"asOf": "2017-07-24T06:59:38.74Z",
"queryType": "flat"
}"""
data_ = json.loads(data_str)
wiql = Wiql(data_, tfsapi)
yield wiql

def test_wiql(self, wiql):
assert wiql.id is None
assert wiql["queryResultType"] == "workItem"

def test_get_wiql_workitem_ids(self, wiql):
assert wiql.workitem_ids == [100, 101]

@pytest.mark.httpretty
def test_get_wiql_workitems(self, wiql):
workitems = wiql.workitems

assert len(workitems) == 2
assert workitems[0].id == 100
assert workitems[1].id == 101

def test_wiql_empty(self, wiql_empty):
assert wiql_empty.workitem_ids == []

def test_wiql_result(self, wiql):
assert wiql._data == wiql.result
Loading

0 comments on commit cb7c827

Please sign in to comment.