You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/10/23 02:31:02 UTC

(groovy) branch master updated: add skill to see status of recent jira tickets

This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 5a81281ec6 add skill to see status of recent jira tickets
5a81281ec6 is described below

commit 5a81281ec6e894b194017a880d26149cb79dd033
Author: Paul King <pa...@asert.com.au>
AuthorDate: Fri Oct 23 12:30:41 2026 +1000

    add skill to see status of recent jira tickets
---
 .agents/skills/groovy-jira/SKILL.md       | 12 +++-
 .agents/skills/groovy-jira/jira-recent.sh | 91 +++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/.agents/skills/groovy-jira/SKILL.md b/.agents/skills/groovy-jira/SKILL.md
index cf796b0a4b..ad9474ef00 100644
--- a/.agents/skills/groovy-jira/SKILL.md
+++ b/.agents/skills/groovy-jira/SKILL.md
@@ -140,7 +140,7 @@ These are the recurring mistakes when AI tooling reaches for JIRA:
 
 ## Helper scripts
 
-Two vetted helpers ship in this skill's directory so the agent does
+Three vetted helpers ship in this skill's directory so the agent does
 not re-derive the ASF JIRA REST calls on every run — per the
 [Helper mechanisms and token economy](../../../AGENTS.md#helper-mechanisms-and-token-economy)
 policy (the JIRA REST v2 API is stable and these change rarely; the
@@ -157,8 +157,14 @@ equivalent if you need to adapt it):
   [out-dir]` → `issue.json` + a rendered `description.md`
   (fields, description, every comment), and lists attachment URLs
   for manual download.
-
-Both are read-only and anonymous (no auth, no mutation) — they do
+- [`jira-recent.sh`](jira-recent.sh) — `jira-recent.sh [days]` →
+  unresolved issues updated in the last `days` (default 30), each
+  linked to the GitHub PRs whose title names its key, grouped as
+  merged-PR-but-still-open / open PR / no open PR, plus open PRs in
+  the window naming none of the listed issues. Needs an
+  authenticated `gh` in addition to `curl` and `jq`.
+
+All are read-only (no mutation, and anonymous against JIRA) — they do
 not change the read-only / hand-back posture this skill enforces.
 Prefer them over an ad-hoc `curl`; fall back to the inline command
 only if a script is unavailable or the query needs a field they
diff --git a/.agents/skills/groovy-jira/jira-recent.sh b/.agents/skills/groovy-jira/jira-recent.sh
new file mode 100755
index 0000000000..ff0011ee27
--- /dev/null
+++ b/.agents/skills/groovy-jira/jira-recent.sh
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+# jira-recent.sh — list recently active open GROOVY issues, linked to their GitHub PRs.
+#
+# A vetted helper for a deterministic, rarely-changing operation (the
+# ASF JIRA REST v2 search endpoint joined with `gh pr list`), shipped per
+# the "Helper mechanisms and token economy" policy in AGENTS.md. The
+# curl + gh + jq below IS the documented manual equivalent — run it by
+# hand if you need to adapt it.
+#
+# Usage:
+#   ./jira-recent.sh [days]          # default: 30
+#
+# Environment:
+#   GROOVY_REPO   GitHub repo to match PRs against (default: apache/groovy)
+#   PR_LIMIT      number of most recent PRs (any state) to scan (default: 500)
+#
+# A PR is linked to an issue when its title contains the issue key
+# (GROOVY-NNNNN, or the branch-style GroovyNNNNN).
+# Output groups the unresolved issues updated in the last <days> days:
+#   - merged PR but issue still open (candidates for resolving)
+#   - open PR
+#   - no open PR (closed-unmerged PRs, if any, are still shown)
+# followed by open PRs updated in the window that name none of the listed issues.
+#
+# ASF JIRA is anonymous-readable; `gh` must be authenticated for GitHub.
+set -euo pipefail
+
+DAYS="${1:-30}"
+REPO="${GROOVY_REPO:-apache/groovy}"
+PR_LIMIT="${PR_LIMIT:-500}"
+
+for tool in curl jq gh; do
+  command -v "${tool}" >/dev/null || { echo "$0: requires ${tool} on PATH" >&2; exit 1; }
+done
+
+TMP="$(mktemp -d)"
+trap 'rm -rf "${TMP}"' EXIT
+
+curl -fsSG 'https://issues.apache.org/jira/rest/api/2/search' \
+  --data-urlencode "jql=project = GROOVY AND statusCategory != Done AND updated >= -${DAYS}d ORDER BY key DESC" \
+  --data-urlencode 'maxResults=500' \
+  --data-urlencode 'fields=summary,updated' \
+  > "${TMP}/issues.json"
+
+gh pr list --repo "${REPO}" --state all --limit "${PR_LIMIT}" \
+  --json number,title,state,updatedAt \
+  > "${TMP}/prs.json"
+
+jq -r --argjson days "${DAYS}" --slurpfile prs "${TMP}/prs.json" '
+  def prs: map("#\(.number)(\(.state))") | join(" ") | if . == "" then "-" else . end;
+  def section($title; $rows):
+    "== \($title) (\($rows | length))",
+    ($rows[] | [.key, .updated, (.prs | prs), .summary[0:100]] | @tsv),
+    "";
+
+  ($prs[0] | map(. + {keys: [.title | ascii_upcase | scan("GROOVY-?[0-9]+") | sub("^GROOVY-?"; "GROOVY-")]})) as $p
+  | [.issues[] | .key as $k
+      | {key: $k, updated: .fields.updated[0:10], summary: (.fields.summary // ""),
+         prs: [$p[] | select(any(.keys[]; . == $k))]}
+      | . + {open: any(.prs[]; .state == "OPEN"), merged: any(.prs[]; .state == "MERGED")}
+    ] as $rows
+  | ($rows | map(.key)) as $listed
+  | (now - $days * 86400 | strftime("%Y-%m-%d")) as $since
+  | "Unresolved GROOVY issues updated since \($since): \($rows | length)",
+    "",
+    section("Merged PR, issue still open"; [$rows[] | select(.merged and (.open | not))]),
+    section("Open PR"; [$rows[] | select(.open)]),
+    section("No open PR"; [$rows[] | select((.open or .merged) | not)]),
+    ([$p[] | select(.state == "OPEN" and .updatedAt[0:10] >= $since
+                    and all(.keys[]; . as $k | $listed | index($k) | not))] as $orphans
+     | "== Open PRs updated in window naming no listed issue (\($orphans | length))",
+       ($orphans[] | ["#\(.number)", .updatedAt[0:10], .title] | @tsv))
+' "${TMP}/issues.json"