From 4756c58af48ebb55451a8ae5cc8a4e7763cabd51 Mon Sep 17 00:00:00 2001 From: Taewoon Kim Date: Sat, 7 Nov 2026 02:22:28 +0900 Subject: [PATCH 1/3] CI: classify issues by type and package from plain words Issues opened with gh issue create or by hand had no dropdown and got no labels. Add bug, documentation, enhancement (title words), python, github_actions, and jvm/native from plain words. Only existing labels, only added. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/classify-issue.yml | 39 +++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/.github/workflows/classify-issue.yml b/.github/workflows/classify-issue.yml index 362febb3..f653adc0 100644 --- a/.github/workflows/classify-issue.yml +++ b/.github/workflows/classify-issue.yml @@ -1,9 +1,18 @@ # Labels a new issue from rules (adapted from ArcadeData/arcadedb's classify-issue.yml, minus # the model call: upstream asks Claude which labels fit, this repository has no API token, so a -# keyword table does it). The package comes from the "Package" dropdown of the bug form; the topic -# labels come from words in the title and body. Only labels that already exist in the repository -# are applied, and only added, never removed, so a person's labels always win. A wrong guess is -# fixed by hand like any label. +# keyword table does it). Only labels that already exist in the repository are applied, and only +# added, never removed, so a person's labels always win. A wrong guess is fixed by hand like any +# label. One issue may get several labels. The groups: +# package jvm, native: the "Package" dropdown of the bug form, else plain words in the title +# or body ("arcadedb-jvm", "JPype", "native build"); an issue opened with +# `gh issue create` or by hand has no dropdown. +# topic vector, performance, concurrency, timeseries: words in the title and body. +# type bug, documentation, enhancement: words in the TITLE only (a body mentions "error" +# or "example" too often to say what the issue is). The issue forms set bug and +# enhancement themselves; this covers the issues they do not. +# language python: Python words in the title or body. +# CI github_actions: CI, workflow and runner words in the title or body. +# `dependencies` is left to Dependabot. # # Try the rules on a real issue without touching it: run the workflow by hand (dry run by default) # and read the log. @@ -56,8 +65,30 @@ jobs: if (/arcadedb-jvm/i.test(pkg)) wanted.add('jvm'); if (/native/i.test(pkg)) wanted.add('native'); + // Without the dropdown: plain words. "native" alone in the title is enough (titles + // start with "Native:"); in the body only a phrase is, because the engine text + // mentions it in passing. + if (/\b(arcadedb-jvm|jvm (build|wheel|package)|jpype)\b/i.test(text) || /\bjvm\b/i.test(title)) { + wanted.add('jvm'); + } + if (/\bnative (build|wheel|package)s?\b/i.test(text) || /\bnative\b/i.test(title)) { + wanted.add('native'); + } + + // label -> pattern over the title only (the type of the issue) + const titleRules = { + bug: /\b(crash(es|ed)?|died|dies|fail(s|ed|ure|ures)?|errors?|raises?|wrong|regression|returns None|TypeError|exceptions?|hangs?)\b/i, + documentation: /\b(docs?|documentation|pages?|user guide|README|examples?)\b/i, + enhancement: /\b(support for|expose|feature|columnar|facets?|proposal|request)\b|\badd\b.*\boption\b/i, + }; + for (const [label, pattern] of Object.entries(titleRules)) { + if (pattern.test(title)) wanted.add(label); + } + // label -> pattern over title and body const rules = { + python: /\b(python|wheels?|pip|uv add|import arcadedb|pytest|jpype)\b/i, + github_actions: /\b(ci|workflows?|github actions|runners?)\b/i, vector: /\b(vectors?|jvector|hnsw|embeddings?|find_nearest|knn)\b/i, performance: /\b(slow|slower|performance|latency|throughput|benchmarks?|speed)\b/i, concurrency: /\b(threads?|concurrent|concurrency|deadlocks?|race conditions?|locks?)\b/i, From d44cd2f5b8d9d0a2e3a29cb6265ecddb7bb92082 Mon Sep 17 00:00:00 2001 From: Taewoon Kim Date: Sat, 7 Nov 2026 02:23:54 +0900 Subject: [PATCH 2/3] CI: classify-issue also sets the open release milestone on a new issue Same selection as assign-milestone.yml; never replaces an existing milestone; a dry run logs it. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/classify-issue.yml | 33 +++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/classify-issue.yml b/.github/workflows/classify-issue.yml index f653adc0..d0469759 100644 --- a/.github/workflows/classify-issue.yml +++ b/.github/workflows/classify-issue.yml @@ -14,6 +14,10 @@ # CI github_actions: CI, workflow and runner words in the title or body. # `dependencies` is left to Dependabot. # +# Milestone: a newly opened issue with no milestone gets the open release milestone, chosen as in +# assign-milestone.yml (earliest due date, ties the lower number; no open milestone, nothing is +# set). An existing milestone is never replaced. A dry run logs the milestone it would set. +# # Try the rules on a real issue without touching it: run the workflow by hand (dry run by default) # and read the log. name: Classify issue @@ -106,9 +110,32 @@ jobs: const labels = [...wanted].filter(l => existing.has(l)).sort(); core.info(`#${issue.number} "${title}": package="${pkg}", labels=[${labels.join(', ')}]`); - if (labels.length === 0) return; + + // The open milestone with the earliest due date (ties: the lower number), as in + // assign-milestone.yml. Only when the issue has none. + let milestone = null; + if (issue.milestone) { + core.info(`#${issue.number}: already in milestone "${issue.milestone.title}".`); + } else { + const open = await github.paginate(github.rest.issues.listMilestones, { + owner, repo, state: 'open', per_page: 100, + }); + const byDue = (a, b) => + (a.due_on ? Date.parse(a.due_on) : Infinity) - (b.due_on ? Date.parse(b.due_on) : Infinity) || + a.number - b.number; + milestone = open.sort(byDue)[0] || null; + core.info(milestone + ? `#${issue.number}: milestone would be "${milestone.title}".` + : 'No open milestone, nothing to assign.'); + } + if (process.env.DRY_RUN === 'true') { - core.info('dry run: no label applied.'); + core.info('dry run: no label or milestone applied.'); return; } - await github.rest.issues.addLabels({ owner, repo, issue_number: issue.number, labels }); + if (labels.length > 0) { + await github.rest.issues.addLabels({ owner, repo, issue_number: issue.number, labels }); + } + if (milestone) { + await github.rest.issues.update({ owner, repo, issue_number: issue.number, milestone: milestone.number }); + } From 7bfc82e4c65bdd47aa0cbfa7c54fd8199acfb942 Mon Sep 17 00:00:00 2001 From: Taewoon Kim Date: Sat, 7 Nov 2026 02:25:48 +0900 Subject: [PATCH 3/3] CI: classify-issue lets a title that names a package decide it alone Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/classify-issue.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/classify-issue.yml b/.github/workflows/classify-issue.yml index d0469759..45ce8771 100644 --- a/.github/workflows/classify-issue.yml +++ b/.github/workflows/classify-issue.yml @@ -69,14 +69,17 @@ jobs: if (/arcadedb-jvm/i.test(pkg)) wanted.add('jvm'); if (/native/i.test(pkg)) wanted.add('native'); - // Without the dropdown: plain words. "native" alone in the title is enough (titles - // start with "Native:"); in the body only a phrase is, because the engine text - // mentions it in passing. - if (/\b(arcadedb-jvm|jvm (build|wheel|package)|jpype)\b/i.test(text) || /\bjvm\b/i.test(title)) { - wanted.add('jvm'); - } - if (/\bnative (build|wheel|package)s?\b/i.test(text) || /\bnative\b/i.test(title)) { - wanted.add('native'); + // Without the dropdown: plain words. A title that names a package decides alone ("Native: + // ..." says which build; the body then mentions the other one in passing). Otherwise the + // body counts, but only for a package name or a phrase ("native build", "JPype"). + const titleJvm = /\bjvm\b/i.test(title) || /\barcadedb-jvm\b/i.test(title); + const titleNative = /\bnative\b/i.test(title); + if (titleJvm || titleNative) { + if (titleJvm) wanted.add('jvm'); + if (titleNative) wanted.add('native'); + } else { + if (/\b(arcadedb-jvm|jvm (build|wheel|package)|jpype)\b/i.test(text)) wanted.add('jvm'); + if (/\bnative (build|wheel|package)s?\b/i.test(text)) wanted.add('native'); } // label -> pattern over the title only (the type of the issue)