Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: providing some actions with issues, queues and users from API #8

Merged
merged 2 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/code-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ jobs:
python-version: '3.11'
- run: pip install --upgrade pip
- run: make install
- run: make test-cov
- run: make test
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-added-large-files

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.0.287'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ test: ##@Testing Test application with pytest
$(TEST)

test-cov: ##@Testing Test application with pytest and create coverage report
$(TEST) --cov=$(APPLICATION_NAME) --cov-report html --cov-fail-under=85
$(TEST) --cov=$(APPLICATION_NAME) --cov-report html --cov-fail-under=85 --cov-config pyproject.toml

lint: ##@Code Check code with pylint
lint: ##@Code Check code with ruff
poetry run python3 -m ruff $(CODE) tests

format: ##@Code Reformat code with ruff and black
format: ##@Code Reformat code with ruff
poetry run python3 -m ruff $(CODE) tests --fix

precommit: # Code Check code with pre-commit hooks
pre-commit run --all-files

clean: ##@Code Clean directory from garbage files
rm -fr *.egg-info dist
46 changes: 44 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,44 @@
# ya_tracker_client
Async Yandex Tracker Client
# Yandex Tracker Client (or Yet Another Tracker Client)

Async Yandex Tracker Client based on aiohttp and pydantic (v2)

# Current library capabilities

- Working with queues
- Getting information about issues, priorities and transitions
- Working with issue relationships
- Getting user information

# TBD

## Issues

- [ ] Перенести задачу в другую очередь
- [ ] Узнать количество задач
- [ ] Найти задачи
- [ ] Освободить ресурсы просмотра прокрутки
- [ ] Выполнить переход в статус
- [ ] Получить историю изменений задачи

## Queues - automation

- [ ] Создать автодействие
- [ ] Получить параметры автодействия
- [ ] Создать триггер
- [ ] Получить параметры триггера

# TBD in a long run

- Checklists
- Projects
- Comments
- Macros
- Internal links
- Attachments
- Tables of tasks
- Components
- Import
- Package operations
- Time scoring
- Issues fields
- Users
18 changes: 13 additions & 5 deletions examples/get_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,28 @@

load_dotenv()
# from registered application at Yandex OAuth - https://oauth.yandex.ru/
API_TOKEN = os.getenv('API_TOKEN')
API_TOKEN = os.getenv("API_TOKEN")
# from admin panel at Yandex Tracker - https://tracker.yandex.ru/admin/orgs
API_ORGANISATION_ID = os.getenv('API_ORGANISATION_ID')
API_ORGANISATION_ID = os.getenv("API_ORGANISATION_ID")


async def main() -> None:
client = YaTrackerClient(
organisation_id=API_ORGANISATION_ID,
oauth_token=API_TOKEN,
)
issue = await client.get_issue('TRACKER-1')
print(issue)

me = await client.get_myself()
print(me)

me = await client.get_user(me.login, me.uid)
print(me)

all_me = await client.get_users()
print(all_me)

await client.stop()


if __name__ == '__main__':
if __name__ == "__main__":
run(main())
630 changes: 554 additions & 76 deletions poetry.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ coverage = "^7.3.1"
pytest-asyncio = "^0.21.1"
pytest-cov = "^4.1.0"
ruff = "^0.0.287"
greenlet = "^2.0.2"
polyfactory = "^2.8.2"
gevent = "^23.9.1"
pre-commit = "^3.4.0"

[tool.poetry.group.examples.dependencies]
python-dotenv = "^1.0.0"
Expand Down Expand Up @@ -63,7 +64,7 @@ directory = "pytest-cov-report"

[tool.coverage.run]
branch = true
concurrency = ['thread', 'greenlet']
concurrency = ['gevent']

[tool.pytest.ini_options]
asyncio_mode = "auto"
Expand All @@ -83,4 +84,4 @@ max-complexity = 10

[tool.ruff.isort]
known-local-folder = ["ya_tacker_client"]
lines-after-imports = 2
lines-after-imports = 2
13 changes: 11 additions & 2 deletions ya_tracker_client/domain/client/base.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from abc import ABC, abstractmethod
from http import HTTPStatus
from json import dumps
from logging import getLogger
from typing import Any

from aiohttp import BytesPayload

from ya_tracker_client.domain.client.errors import (
ClientAuthError,
ClientError,
Expand Down Expand Up @@ -55,11 +58,17 @@ async def request(
payload: dict[str, Any] | None = None,
) -> bytes:
uri = f"{self._base_url}/{self._api_version}{uri}"

bytes_payload = BytesPayload(
value=bytes(dumps(payload), encoding="utf-8"),
content_type="application/json",
)

status, body = await self._make_request(
method=method,
url=uri,
params=params,
data=payload,
data=bytes_payload,
)
self._check_status(status, body)
return body
Expand All @@ -70,7 +79,7 @@ async def _make_request(
method: str,
url: str,
params: dict[str, Any] | None = None,
data: bytes | None = None,
data: bytes | BytesPayload | None = None,
) -> tuple[int, bytes]:
"""
Get raw response from via http-client.
Expand Down
51 changes: 36 additions & 15 deletions ya_tracker_client/domain/entities/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from pydantic import AliasChoices, Field

from ya_tracker_client.domain.entities.base import AbstractEntity
from ya_tracker_client.domain.entities.issue_type import IssueType
from ya_tracker_client.domain.entities.priority import Priority
from ya_tracker_client.domain.entities.queue import Queue
from ya_tracker_client.domain.entities.queue import QueueIdentifier, QueueShort
from ya_tracker_client.domain.entities.sprint import Sprint
from ya_tracker_client.domain.entities.status import Status
from ya_tracker_client.domain.entities.user import User
from ya_tracker_client.domain.entities.user import UserShort


class IssueShort(AbstractEntity):
Expand All @@ -17,13 +18,6 @@ class IssueShort(AbstractEntity):
display: str


class IssueType(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: str
key: str
display: str


class Issue(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: str
Expand All @@ -36,19 +30,46 @@ class Issue(AbstractEntity):
sprint: list[Sprint] | None = None
type: IssueType
priority: Priority
followers: list[User] | None = None
queue: Queue
previous_queue: Queue | None = None
followers: list[UserShort] | None = None
queue: QueueShort
previous_queue: QueueShort | None = None
favorite: bool
assignee: User | None = None
assignee: UserShort | None = None

last_comment_update_at: datetime | None = None
aliases: list[str] | None = None
updated_by: User | None = None
updated_by: UserShort | None = None
created_at: datetime = Field(validation_alias=AliasChoices("createdAt", "created_at"))
created_by: User = Field(validation_alias=AliasChoices("createdBy", "created_by"))
created_by: UserShort = Field(validation_alias=AliasChoices("createdBy", "created_by"))
votes: int
updated_at: datetime | None = None
status: Status
previous_status: Status | None = None
direction: str | None = None


class IssueCreate(AbstractEntity):
summary: str
queue: QueueIdentifier | str | int
parent: IssueShort | str | None = None
description: str | None = None
sprint: list[Sprint | str] | None = None
type: IssueType | None = None
priority: Priority | None = None
followers: list[UserShort | str] | None = None
assignee: list[UserShort | str] | None = None
unique: str | None = None
attachment_ids: list[str] | None = Field(
default=None,
validation_alias=AliasChoices("attachmentIds", "attachment_ids"),
)


class IssueEdit(AbstractEntity):
summary: str | None = None
parent: IssueShort | str | None = None
description: str | None = None
sprint: list[Sprint | str] | None = None
type: IssueType | None = None
priority: Priority | None = None
followers: list[UserShort | str] | None = None
47 changes: 47 additions & 0 deletions ya_tracker_client/domain/entities/issue_relationship.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from datetime import datetime
from enum import Enum

from pydantic import AliasChoices, Field

from ya_tracker_client.domain.entities.base import AbstractEntity
from ya_tracker_client.domain.entities.issue import IssueShort
from ya_tracker_client.domain.entities.issue_status import IssueStatus
from ya_tracker_client.domain.entities.user import UserShort


class IssueRelationshipTypeEnum(str, Enum):
RELATES = "relates"
IS_DEPENDENT_BY = "is dependent by"
DEPENDS_ON = "depends on"
IS_SUBTASK_FOR = "is subtask for"
IS_PARENT_TASK_FOR = "is parent task for"
DUPLICATES = "duplicates"
IS_DUPLICATED_BY = "is duplicated by"
IS_EPIC_OF = "is epic of"
HAS_EPIC = "has epic"


class IssueRelationshipType(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: str
inward: str
outward: str


class IssueRelationship(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: int
type: IssueRelationshipType
direction: str
object: IssueShort
created_at: datetime = Field(validation_alias=AliasChoices("createdAt", "created_at"))
updated_at: datetime = Field(validation_alias=AliasChoices("updatedAt", "updated_at"))
created_by: UserShort = Field(validation_alias=AliasChoices("createdBy", "created_by"))
updated_by: UserShort = Field(validation_alias=AliasChoices("updatedBy", "updated_by"))
assignee: UserShort | None = None
status: IssueStatus


class IssueRelationshipCreate(AbstractEntity):
issue: str
relationship: IssueRelationshipTypeEnum
10 changes: 10 additions & 0 deletions ya_tracker_client/domain/entities/issue_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import AliasChoices, Field

from ya_tracker_client.domain.entities.base import AbstractEntity


class IssueStatus(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: str
key: str
display: str
10 changes: 10 additions & 0 deletions ya_tracker_client/domain/entities/issue_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import AliasChoices, Field

from ya_tracker_client.domain.entities.base import AbstractEntity


class IssueType(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: str
key: str
display: str
12 changes: 12 additions & 0 deletions ya_tracker_client/domain/entities/issue_type_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pydantic import AliasChoices, Field

from ya_tracker_client.domain.entities.base import AbstractEntity
from ya_tracker_client.domain.entities.issue_type import IssueType
from ya_tracker_client.domain.entities.resolution import ResolutionShort
from ya_tracker_client.domain.entities.workflow import WorkflowShort


class IssueTypeConfig(AbstractEntity):
issue_type: IssueType = Field(validation_alias=AliasChoices("issueType", "issue_type"))
workflow: WorkflowShort
resolutions: list[ResolutionShort]
2 changes: 1 addition & 1 deletion ya_tracker_client/domain/entities/priority.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

class Priority(AbstractEntity):
url: str = Field(validation_alias=AliasChoices("self", "url"))
id: str
id: int
key: str
display: str | None = None
version: int | None = None
Expand Down
Loading
Loading