summaryrefslogtreecommitdiff
path: root/mac/.local/bin/task/taskwarrior-tui/git-issue-sync
diff options
context:
space:
mode:
Diffstat (limited to 'mac/.local/bin/task/taskwarrior-tui/git-issue-sync')
-rwxr-xr-xmac/.local/bin/task/taskwarrior-tui/git-issue-sync185
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