From ceaa69d49e4c0a7ea4046b2cbef63314988ea9f6 Mon Sep 17 00:00:00 2001 From: viloforge Date: Sun, 6 Apr 2025 12:16:09 +0300 Subject: [PATCH 1/3] updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index efae27c..1033b00 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,10 @@ Taskra is a powerful command-line tool for managing Jira projects, issues, workl The recommended way to install Taskra is with [pipx](https://pipx.pypa.io/), which keeps it isolated and easy to upgrade or uninstall: ```bash -pipx install git+https://github.com/yourusername/taskra.git +pipx install taskra ``` -This will install the latest stable release from the `main` branch. +This will install the latest stable release published on PyPI. --- From bb9121c2b47a6198660e6cd1f3aea20dfb16da9f Mon Sep 17 00:00:00 2001 From: viloforge Date: Sun, 6 Apr 2025 12:21:09 +0300 Subject: [PATCH 2/3] added ci workflow and improvied publish.yml --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 19 +++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..db74496 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + branches: + - develop + - feature/** + pull_request: + branches: + - develop + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Poetry + run: | + curl -sSL https://install.python-poetry.org | python3 - + echo "export PATH=$HOME/.local/bin:$PATH" >> $GITHUB_ENV + + - name: Install dependencies + run: poetry install --with dev,test + + - name: Run tests + run: poetry run pytest \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e8f1c85..c277881 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,14 +4,28 @@ on: push: branches: - main + workflow_dispatch: + inputs: + release_type: + description: 'Release type (patch, minor, major)' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major jobs: build-publish: runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 @@ -28,9 +42,10 @@ jobs: git config user.name "GitHub Actions" git config user.email "actions@github.com" - - name: Bump patch version + - name: Bump version run: | - poetry version patch + RELEASE_TYPE="${{ github.event.inputs.release_type || 'patch' }}" + poetry version $RELEASE_TYPE git add pyproject.toml git commit -m "ci: bump version [skip ci]" git tag v$(poetry version -s) From 31adeb1f2f43a7f6cdcfca379168b679b0eb84a6 Mon Sep 17 00:00:00 2001 From: viloforge Date: Thu, 10 Apr 2025 08:34:13 +0300 Subject: [PATCH 3/3] Add 'taskra config validate' command to verify Jira authentication and permissions; add 'taskra config update' command for interactive account updates; implement PermissionsService for permission checks --- .github/workflows/publish.yml | 4 +- .vscode/settings.json | 35 +++++- docs/project_overview.md | 185 +++++++++++++++++++++++++++++ taskra.code-workspace | 42 +++++++ taskra/api/services/permissions.py | 40 +++++++ taskra/cmd/commands/config.py | 117 ++++++++++++++++++ 6 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 docs/project_overview.md create mode 100644 taskra.code-workspace create mode 100644 taskra/api/services/permissions.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c277881..4f700f5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -35,7 +35,7 @@ jobs: - name: Install Poetry run: | curl -sSL https://install.python-poetry.org | python3 - - echo "export PATH=$HOME/.local/bin:$PATH" >> $GITHUB_ENV + echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Configure git run: | @@ -47,7 +47,7 @@ jobs: RELEASE_TYPE="${{ github.event.inputs.release_type || 'patch' }}" poetry version $RELEASE_TYPE git add pyproject.toml - git commit -m "ci: bump version [skip ci]" + git commit -m "ci: bump version [skip ci]" || echo "No changes to commit" git tag v$(poetry version -s) - name: Push version bump and tags diff --git a/.vscode/settings.json b/.vscode/settings.json index c466a1f..f69ecac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,38 @@ ], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, - "makefile.configureOnOpen": false + "makefile.configureOnOpen": false, + "mcp": { + "servers": { + "mcp-atlassian": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "mcp/atlassian", + "--jira-url=https://viloforge.atlassian.net", + "--jira-username=viloforge@outlook.com", + "--jira-token=${input:jira_token}", + "--confluence-url=https://viloforge.atlassian.net", + "--confluence-username=viloforge@outlook.com", + "--confluence-token=${input:confluence_token}" + ] + } + }, + "inputs": [ + { + "id": "jira_token", + "type": "promptString", + "description": "Jira API Token", + "password": true + }, + { + "id": "confluence_token", + "type": "promptString", + "description": "Confluence API Token", + "password": true + } + ] + } } \ No newline at end of file diff --git a/docs/project_overview.md b/docs/project_overview.md new file mode 100644 index 0000000..9d1e8c2 --- /dev/null +++ b/docs/project_overview.md @@ -0,0 +1,185 @@ +# Taskra Project Documentation + +Welcome to the Taskra Project documentation. This is the central repository for all documentation related to the Taskra CLI tool. + +## Project Overview + +Taskra is a command-line interface (CLI) tool designed to streamline task and worklog management. The project provides functionalities for tracking issues, managing projects, generating reports, and logging work time. + +## Current Status: In Development (April 2025) + +All major components are currently in active development with significant progress made on core modules. + +## Project Architecture + +Taskra follows a modular architecture with the following key components: + +### 1. Core Module (TASKRA-1) - In Progress +- Issues management (core/issues.py) +- Projects management (core/projects.py) +- Reports generation (core/reports.py) +- Tickets management (core/tickets.py) +- Users management (core/users.py) +- Worklogs tracking (core/worklogs.py) +- Comments handling (core/comments.py) + +### 2. API Implementation (TASKRA-2) - In Progress +- Authentication (api/auth.py) +- Client functionality (api/client.py) +- API models and data structures +- API services for external communication +- API utilities + +### 3. Command Line Interface (TASKRA-3) - In Progress +- Main CLI entrypoint (cmd/main.py) +- Command structure and handling +- CLI utilities and helpers +- Command-specific implementations + +### 4. Configuration Management (TASKRA-4) - In Progress +- Account configuration (config/account.py) +- Configuration commands (config/config_cmd.py) +- Configuration manager (config/manager.py) +- Core configuration functionality (config/config.py) + +### 5. Presentation Layer (TASKRA-5) - In Progress +- Base presentation components (presentation/base.py) +- Error handling and display (presentation/errors.py) +- Issue presentation (presentation/issues.py) +- Project presentation (presentation/projects.py) +- Report presentation (presentation/reports.py) +- Worklog presentation (presentation/worklogs.py) + +### 6. Utilities and Helpers (TASKRA-6) - In Progress +- Caching mechanisms (utils/cache.py) +- Debugging tools (utils/debug.py) +- Model adapters (utils/model_adapters.py) +- Model caching (utils/model_cache.py) +- Performance optimization (utils/optimization.py) +- Serialization utilities (utils/serialization.py) + +## Jira Tickets and Epics + +The Taskra project is organized into 6 main epics, each representing a key component of the system, with various tasks that implement specific features. + +### Epics + +#### TASKRA-1: Core Module Implementation +This epic covers the essential components that manage various aspects of the application, including issues management, projects management, reports generation, tickets management, users management, worklogs tracking, and comments handling. + +**Status:** In Progress + +#### TASKRA-2: API Implementation +This epic includes authentication, client functionality, API models and data structures, API services for external communication, and API utilities. It handles all external service integration and data exchange. + +**Status:** In Progress + +#### TASKRA-3: Command Line Interface +This epic covers the main CLI entrypoint, command structure and handling, CLI utilities and helpers, and command-specific implementations. It provides the user-facing interface for the application. + +**Status:** In Progress + +#### TASKRA-4: Configuration Management +This epic manages application settings, user preferences, and persistent configuration, including account configuration, configuration commands, configuration manager, and core configuration functionality. + +**Status:** In Progress + +#### TASKRA-5: Presentation Layer +This epic handles formatting and displaying information to users, including base presentation components, error handling and display, issue presentation, project presentation, report presentation, and worklog presentation. + +**Status:** In Progress + +#### TASKRA-6: Utilities and Helpers +This epic provides cross-cutting concerns and helper functionality used throughout the application, including caching mechanisms, debugging tools, model adapters, model caching, performance optimization, and serialization utilities. + +**Status:** In Progress + +### Completed Tasks + +#### TASKRA-7: Implement Worklog Tracking Functionality +This task implemented worklog tracking functionality in core/worklogs.py, including creating, reading, updating, and deleting worklog entries, searching and filtering worklogs, calculating time spent on issues, and tracking worklog history. + +**Status:** Done + +#### TASKRA-8: Implement Issues Management Functionality +This task implemented the core issues management functionality in core/issues.py, including creating, reading, updating, and deleting issues, searching and filtering issues, tracking issue status changes, and handling issue relationships. + +**Status:** Done + +#### TASKRA-9: Implement Projects Management Functionality +This task implemented the core projects management functionality in core/projects.py, including listing and retrieving projects, filtering projects by criteria, handling project metadata, and project status tracking. + +**Status:** Done + +#### TASKRA-10: Implement Jira Authentication +This task implemented Jira authentication functionality in api/auth.py, including handling Jira API token-based authentication, managing authentication sessions, implementing credential storage and retrieval, and error handling for authentication failures. + +**Status:** Done + +### Ticket Relationships and Dependencies + +The epics represent the main components of the system, while the tasks implement specific features within those components. The completed tasks (TASKRA-7 through TASKRA-10) have provided the foundation for the ongoing epic implementations. As more tasks are completed, the epics will move toward completion. + +## Completed Tasks + +The following components have been fully implemented: + +- ✅ Worklog tracking functionality (TASKRA-7) +- ✅ Issues management functionality (TASKRA-8) +- ✅ Projects management functionality (TASKRA-9) +- ✅ Jira authentication (TASKRA-10) + +## Development Guidelines + +### Project Structure +The project follows a modular architecture with clear separation of concerns: +``` +taskra/ +├── api/ # API layer for external services +├── cmd/ # Command-line interface +├── config/ # Configuration management +├── core/ # Core business logic +├── presentation/ # User interface components +└── utils/ # Utilities and helpers +``` + +### Testing +- Unit tests are located in the tests/ directory +- Integration tests ensure components work together correctly +- Test fixtures provide consistent test data + +### Development Workflow +1. Pick an issue from the backlog +2. Develop the feature or fix +3. Write tests to validate functionality +4. Submit for review +5. Integrate into main branch + +## Getting Started + +To get started with Taskra development: + +1. Clone the repository +2. Install dependencies using Poetry: + ```bash + poetry install + ``` +3. Run the tests: + ```bash + poetry run pytest + ``` +4. Explore the codebase to understand the structure + +## Resources + +- [GitHub Repository](#) (Link to be added) +- [Jira Board](https://viloforge.atlassian.net/browse/TASKRA) +- [Development Guidelines](#) (Link to be added) + +## Contact + +For questions about this project, please contact the project maintainer. + +--- + +*Last updated: April 6, 2025* \ No newline at end of file diff --git a/taskra.code-workspace b/taskra.code-workspace new file mode 100644 index 0000000..3a6a7c5 --- /dev/null +++ b/taskra.code-workspace @@ -0,0 +1,42 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "mcp": { + "servers": { + "mcp-atlassian": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "mcp/atlassian", + "--jira-url=https://viloforge.atlassian.net", + "--jira-username=viloforge@outlook.com", + "--jira-token=${input:jira_token}", + "--confluence-url=https://viloforge.atlassian.net", + "--confluence-username=viloforge@outlook.com", + "--confluence-token=${input:confluence_token}" + ] + } + }, + "inputs": [ + { + "id": "jira_token", + "type": "promptString", + "description": "Jira API Token", + "password": true + }, + { + "id": "confluence_token", + "type": "promptString", + "description": "Confluence API Token", + "password": true + } + ] + } + } +} \ No newline at end of file diff --git a/taskra/api/services/permissions.py b/taskra/api/services/permissions.py new file mode 100644 index 0000000..25024bd --- /dev/null +++ b/taskra/api/services/permissions.py @@ -0,0 +1,40 @@ +from .base import BaseService + +class PermissionsService(BaseService): + """Service for checking Jira user permissions.""" + + def get_permissions(self): + """ + Fetch current user's permissions. + + Returns: + dict: Permissions response from Jira + """ + return self.client.get("/rest/api/3/mypermissions") + + def has_required_permissions(self, required=None): + """ + Check if user has all required permissions. + + Args: + required (list): List of permission keys to check + + Returns: + tuple: (bool, list of missing permissions) + """ + if required is None: + required = [ + "BROWSE_PROJECTS", + "CREATE_ISSUES", + "EDIT_ISSUES", + "WORK_ON_ISSUES", + "ADD_COMMENTS" + ] + permissions_data = self.get_permissions() + permissions = permissions_data.get("permissions", {}) + missing = [] + for key in required: + perm = permissions.get(key) + if not perm or not perm.get("havePermission"): + missing.append(key) + return (len(missing) == 0, missing) diff --git a/taskra/cmd/commands/config.py b/taskra/cmd/commands/config.py index c05e8e3..e85f501 100644 --- a/taskra/cmd/commands/config.py +++ b/taskra/cmd/commands/config.py @@ -167,3 +167,120 @@ def show_current(): env_account = os.environ.get("TASKRA_ACCOUNT") if env_account and env_account == account["name"]: console.print("[dim](Set via TASKRA_ACCOUNT environment variable)[/dim]") + +@config_cmd.command("validate") +@click.option("--config-name", "-n", help="Account config name to validate (default if omitted)") +def validate_config(config_name: Optional[str]): + """Validate Jira credentials and permissions for an account.""" + from ...config.account import list_accounts, get_current_account, validate_credentials + from ...api.client import JiraClient + from ...api.services.users import UserService + from ...api.services.permissions import PermissionsService + + # Load account info + account = None + if config_name: + accounts = list_accounts() + for acc in accounts: + if acc["name"] == config_name: + account = acc + break + if not account: + console.print(f"[bold red]Account '{config_name}' not found.[/bold red]") + return + else: + account = get_current_account() + if not account: + console.print("[bold red]No default account configured.[/bold red]") + return + + url = account.get("url") + email = account.get("email") + token = account.get("token") + + if not token: + # token may not be included in list_accounts(), so reload full config + from ...config.manager import config_manager + config = config_manager.read_config() + acc_data = config.get("accounts", {}).get(account["name"], {}) + token = acc_data.get("token") + + console.print(f"Validating account: [bold]{account['name']}[/bold] ({email})") + + # Step 1: Validate credentials + auth_ok = validate_credentials(url, email, token) + if not auth_ok: + console.print("[bold red]✗ Authentication failed. Invalid credentials.[/bold red]") + return + console.print("[bold green]✓ Authentication successful[/bold green]") + + # Step 2: Check permissions + try: + client = JiraClient(base_url=url, email=email, api_token=token) + perm_service = PermissionsService(client) + ok, missing = perm_service.has_required_permissions() + if ok: + console.print("[bold green]✓ Required Jira permissions granted[/bold green]") + else: + console.print("[bold yellow]⚠ Missing permissions:[/bold yellow] " + ", ".join(missing)) + except Exception as e: + console.print(f"[bold red]Error checking permissions:[/bold red] {str(e)}") + +@config_cmd.command("update") +@click.option("--config-name", "-n", help="Account config name to update (default if omitted)") +def update_account(config_name: Optional[str]): + """Update an existing Jira account configuration.""" + from ...config.account import list_accounts, get_current_account, validate_credentials + from ...config.manager import config_manager + + # Load account info + account = None + if config_name: + accounts = list_accounts() + for acc in accounts: + if acc["name"] == config_name: + account = acc + break + if not account: + console.print(f"[bold red]Account '{config_name}' not found.[/bold red]") + return + else: + account = get_current_account() + if not account: + console.print("[bold red]No default account configured.[/bold red]") + return + + # Load full config to get token + config = config_manager.read_config() + acc_data = config.get("accounts", {}).get(account["name"], {}) + + # Prompt user for new values, defaulting to current + console.print(f"Updating account: [bold]{account['name']}[/bold]") + new_url = click.prompt("Jira URL", default=acc_data.get("url", ""), show_default=True) + new_email = click.prompt("Email", default=acc_data.get("email", ""), show_default=True) + new_token = click.prompt("API token (leave blank to keep existing)", default="", hide_input=True, show_default=False) + + # If token left blank, keep existing + if not new_token: + new_token = acc_data.get("token", "") + + # Validate new credentials + console.print("Validating updated credentials...") + if not validate_credentials(new_url, new_email, new_token): + console.print("[bold red]✗ Invalid credentials. Update aborted.[/bold red]") + return + + # Save updated account info + def update_func(cfg): + accounts = cfg.get("accounts", {}) + if account["name"] not in accounts: + console.print(f"[bold red]Account '{account['name']}' not found during update.[/bold red]") + return cfg + accounts[account["name"]]["url"] = new_url + accounts[account["name"]]["email"] = new_email + accounts[account["name"]]["token"] = new_token + cfg["accounts"] = accounts + return cfg + + config_manager.update_config(update_func) + console.print(f"[bold green]✓ Account '{account['name']}' updated successfully.[/bold green]")