diff options
Diffstat (limited to 'mac/.local/bin/task/taskwarrior-tui/git-issue-sync')
| -rwxr-xr-x | mac/.local/bin/task/taskwarrior-tui/git-issue-sync | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/mac/.local/bin/task/taskwarrior-tui/git-issue-sync b/mac/.local/bin/task/taskwarrior-tui/git-issue-sync new file mode 100755 index 0000000..da01bc4 --- /dev/null +++ b/mac/.local/bin/task/taskwarrior-tui/git-issue-sync @@ -0,0 +1,185 @@ +#!/bin/sh + +# github_issue_sync.sh +# Synchronizes GitHub and Linear issues with Taskwarrior + +# Set new line and tab for word splitting +IFS=' + ' + +# Logger with timestamp +log() { + echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" +} + +# Function to trim leading and trailing whitespace using sed +trim_whitespace() { + input="$1" + echo "$input" | sed 's/^[ \t]*//;s/[ \t]*$//' +} + +# Validate necessary environment variables +validate_env_vars() { + oldIFS="$IFS" + IFS=' ' + required_vars="api userid" + for var in $required_vars; do + val=$(pass show "api/linear/$var") + if [ -z "$val" ]; then + echo "Error: Environment variable $var is not set." >&2 + exit 1 + fi + done + IFS="$oldIFS" +} + +# Retrieve and format GitHub issues +get_github_issues() { + issues=$(gh api -X GET /search/issues \ + -f q='is:issue is:open assignee:TheSiahxyz' \ + --jq '.items[] | {id: .number, description: .title, repository: .repository_url, html_url: .html_url}') || { + echo "Error: Unable to fetch GitHub issues" >&2 + return 1 + } + echo "$issues" +} + +# Retrieve and format Linear issues +get_linear_issues() { + issues=$(curl -s -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: $LINEAR_API_KEY" \ + --data '{"query": "query { user(id: \"'"$LINEAR_USER_ID"'\") { id name assignedIssues(filter: { state: { name: { nin: [\"Released\", \"Canceled\"] } } }) { nodes { id title url } } } }"}' \ + https://api.linear.app/graphql | jq -c '.data.user.assignedIssues.nodes[] | {id: .id, description: .title, repository: "linear", html_url: .url}') || { + echo "Error: Unable to fetch Linear issues" >&2 + return 1 + } + echo "$issues" +} + +# Synchronize a single issue with Taskwarrior +sync_to_taskwarrior() { + issue_line="$1" + issue_id=$(echo "$issue_line" | jq -r '.id') + issue_description=$(echo "$issue_line" | jq -r '.description') + issue_repo_name=$(echo "$issue_line" | jq -r '.repository' | awk -F/ '{print $NF}') + issue_url=$(echo "$issue_line" | jq -r '.html_url') + + log "Processing Issue ID: $issue_id, Description: $issue_description" + + task_uuid=$(get_task_id_by_description "$issue_description") + + if [ -z "$task_uuid" ]; then + log "Creating new task for issue: $issue_description" + task_uuid=$(create_task "$issue_description" "+$issue_repo_name" "project:$issue_repo_name") + + if [ -n "$task_uuid" ]; then + annotate_task "$task_uuid" "$issue_url" + log "Task created and annotated for: $issue_description" + else + log "Error: Failed to create task for: $issue_description" >&2 + fi + else + log "Task already exists for: $issue_description (UUID: $task_uuid)" + fi +} + +# Mark a GitHub issue as completed in Taskwarrior +sync_github_issue() { + task_description="$1" + task_uuid=$(get_task_id_by_description "$task_description") + + if [ -n "$task_uuid" ]; then + mark_task_completed "$task_uuid" + log "Task marked as completed: $task_description (UUID: $task_uuid)" + else + log "Task UUID not found for: $task_description" >&2 + fi +} + +# Compare existing Taskwarrior tasks with current issues and mark as completed if not present +compare_and_display_tasks_not_in_issues() { + existing_task_descriptions="$1" + issues_descriptions="$2" + + log "Starting comparison of Taskwarrior tasks and current issues." + + existing_task_descriptions_array=$(echo "$existing_task_descriptions" | tr '\n' ' ') + issues_descriptions_array=$(echo "$issues_descriptions" | tr '\n' ' ') + + for task_description in $existing_task_descriptions_array; do + trimmed_task_description=$(trim_whitespace "$task_description") + issue_exists=false + + for issue_description in $issues_descriptions_array; do + trimmed_issue_description=$(trim_whitespace "$issue_description") + if [ "$(echo "$trimmed_task_description" | tr '[:upper:]' '[:lower:]')" = "$(echo "$trimmed_issue_description" | tr '[:upper:]' '[:lower:]')" ]; then + issue_exists=true + break + fi + done + + if [ "$issue_exists" = false ]; then + log "No matching issue found for task: $trimmed_task_description. Marking as completed." + sync_github_issue "$trimmed_task_description" + fi + done + + log "Comparison of Taskwarrior tasks and issues completed." +} + +# Retrieve existing Taskwarrior task descriptions with +github or +linear tags and pending status +get_existing_task_descriptions() { + task +github or +linear status:pending export | jq -r '.[] | .description' +} + +# Log retrieved issues +log_issues() { + issue_type="$1" + issues="$2" + log "Retrieved $issue_type issues: $(echo "$issues" | jq '.')" +} + +# Synchronize all issues to Taskwarrior +sync_issues_to_taskwarrior() { + issues="$1" + echo "$issues" | jq -c '.' | while IFS= read -r line; do + sync_to_taskwarrior "$line" + done +} + +# Main function to orchestrate the synchronization +main() { + if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "Not a git repository." + exit 1 + fi + validate_env_vars + + github_issues=$(get_github_issues) + linear_issues=$(get_linear_issues) + + if [ -z "$github_issues" ] && [ -z "$linear_issues" ]; then + log "No issues retrieved from GitHub or Linear. Exiting." + exit 0 + fi + + if [ -n "$github_issues" ]; then + log_issues "GitHub" "$github_issues" + sync_issues_to_taskwarrior "$github_issues" + fi + + if [ -n "$linear_issues" ]; then + log_issues "Linear" "$linear_issues" + sync_issues_to_taskwarrior "$linear_issues" + fi + + existing_task_descriptions=$(get_existing_task_descriptions) + + compare_and_display_tasks_not_in_issues "$existing_task_descriptions" "$( + echo "$github_issues" | jq -r '.description' + echo "$linear_issues" | jq -r '.description' + )" +} + +main |
