#!/usr/bin/env bash
# Import your open Jira issues into Kombine as tasks. Safe to run as often as you like:
# each issue is imported once, keyed by external_ref "jira:<KEY>".
# Docs: https://kombine.dev/docs/power-users/workflows/
#
# Usage: kombine-jira-import.sh [--dry-run]
#
# Needs curl, jq, uuidgen, and these environment variables:
#   JIRA_SITE      your-company.atlassian.net
#   JIRA_EMAIL     the email you sign in to Jira with
#   JIRA_TOKEN     a Jira API token (id.atlassian.com › Security › API tokens)
#   KOMBINE_TOKEN  a Kombine personal access token with tasks: Read & write, sessions: Read
# Optional:
#   JIRA_JQL          which issues (default: assigned to you, not done)
#   KOMBINE_ACTIVITY  activity to tag new tasks with (default: none)
#   KOMBINE_API_URL   default https://api.kombine.dev/v1
set -euo pipefail

DRY_RUN=false
[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=true

for v in JIRA_SITE JIRA_EMAIL JIRA_TOKEN KOMBINE_TOKEN; do
  [[ -n "${!v:-}" ]] || { echo "missing environment variable $v" >&2; exit 1; }
done

API="${KOMBINE_API_URL:-https://api.kombine.dev/v1}"
JQL="${JIRA_JQL:-assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC}"
JIRA="https://${JIRA_SITE#https://}"

kombine() { curl -sS --fail-with-body -H "Authorization: Bearer $KOMBINE_TOKEN" -H "Content-Type: application/json" "$@"; }

# Jira: matching issues (search/jql pages with nextPageToken)
issues='[]' token=''
while :; do
  page=$(curl -sS --fail-with-body -u "$JIRA_EMAIL:$JIRA_TOKEN" -G "$JIRA/rest/api/3/search/jql" \
    --data-urlencode "jql=$JQL" --data-urlencode "fields=summary,priority" \
    --data-urlencode "maxResults=100" ${token:+--data-urlencode "nextPageToken=$token"})
  issues=$(jq -s '.[0] + .[1].issues' <(echo "$issues") <(echo "$page"))
  token=$(jq -r '.nextPageToken // empty' <<<"$page")
  [[ -z "$token" ]] && break
done
echo "Jira: $(jq length <<<"$issues") issues"

# Kombine: every jira: ref already used, including archived and deleted tasks
existing='[]' offset=0
while :; do
  page=$(kombine -G "$API/tasks" --data-urlencode "external_ref_prefix=jira:" -d limit=500 -d offset=$offset)
  existing=$(jq -s '.[0] + [.[1].data[].external_ref]' <(echo "$existing") <(echo "$page"))
  offset=$((offset + 500))
  (( offset < $(jq .total <<<"$page") )) || break
done

activity_id=''
if [[ -n "${KOMBINE_ACTIVITY:-}" ]]; then
  activity_id=$(kombine "$API/activities" | jq -r --arg n "$KOMBINE_ACTIVITY" \
    '[.data[] | select(.deleted_at == null and (.name | ascii_downcase) == ($n | ascii_downcase))][0].id // empty')
  [[ -n "$activity_id" ]] || { echo "no Kombine activity named \"$KOMBINE_ACTIVITY\"" >&2; exit 1; }
fi

created=0 skipped=0
while IFS= read -r issue; do
  key=$(jq -r .key <<<"$issue")
  if jq -e --arg r "jira:$key" 'index($r)' <<<"$existing" >/dev/null; then
    skipped=$((skipped + 1)); continue
  fi
  body=$(jq -n --argjson i "$issue" --arg id "$(uuidgen | tr A-Z a-z)" --arg url "$JIRA/browse/$key" --arg activity "$activity_id" '{
      id: $id,
      title: ("\($i.key): \($i.fields.summary)")[0:500],
      description: $url,
      priority: ({Highest:"HIGH",High:"HIGH",Medium:"MEDIUM",Low:"LOW",Lowest:"LOW"}[$i.fields.priority.name // ""] // "MEDIUM"),
      tags: ["jira"],
      external_ref: "jira:\($i.key)"
    } + (if $activity == "" then {} else {activity_id: $activity} end)')
  if $DRY_RUN; then
    echo "would create: $(jq -r .title <<<"$body")"
  else
    kombine -X POST "$API/tasks" -d "$body" >/dev/null
    echo "created: $(jq -r .title <<<"$body")"
  fi
  created=$((created + 1))
done < <(jq -c '.[]' <<<"$issues")

$DRY_RUN && verb="would create" || verb="created"
echo "Done: $verb $created, skipped $skipped already imported"
