oscerd commented on code in PR #345: URL: https://github.com/apache/airflow-steward/pull/345#discussion_r3318716126
########## tools/jira/README.md: ########## @@ -108,31 +217,64 @@ The bridge reads its configuration from the environment: |---|---| | `ISSUE_TRACKER_URL` | required; e.g. `https://issues.apache.org/jira` | | `ISSUE_TRACKER_PROJECT` | project key (e.g. `FOO`) | +| `JIRA_API_TOKEN` | required for write subcommands; base64-encoded `email:token` | Review Comment: Fixed — rewrote the Configuration section to explicitly state DC-only scope, and added auth notes explaining Basic vs Bearer with concrete guidance for ASF PAT users. ########## tools/jira/bridge.groovy: ########## @@ -55,6 +64,76 @@ def httpGet(String urlStr) { return new JsonSlurper().parse(conn.inputStream) } +def httpWrite(String urlStr, String method, String jsonBody) { + def url = new URL(urlStr) + def conn = url.openConnection() + conn.requestMethod = method + conn.doOutput = true + conn.setRequestProperty('Content-Type', 'application/json') + conn.setRequestProperty('Accept', 'application/json') + if (!API_TOKEN) { + System.err.println('error: JIRA_API_TOKEN is required for write operations') + System.exit(2) + } + conn.setRequestProperty('Authorization', "Basic ${API_TOKEN}") Review Comment: Fixed — added `JIRA_AUTH_SCHEME` env var (default `Basic`, accepts `Bearer`). All three auth header sites (`httpGet`, `httpWrite`, `httpMultipart`) now use `"${AUTH_SCHEME} ${API_TOKEN}"`. Added a test that verifies the Bearer header round-trips correctly. ########## tools/jira/bridge.groovy: ########## @@ -130,20 +202,172 @@ def cmd_projects(List args) { ]) } +def cmd_comment(List args) { + def key = args ? args[0] : null + validateKey(key) + String bodyFile = null + def i = 1 + while (i < args.size()) { + if (args[i] == '--body-file' && i + 1 < args.size()) { + bodyFile = args[i + 1] + i += 2 + } else { + i++ + } + } + if (!bodyFile) { + System.err.println('error: comment requires --body-file <path>') + System.exit(2) + } + def f = new File(bodyFile) + if (!f.exists()) { + System.err.println("error: body file not found: ${bodyFile}") + System.exit(2) + } + def body = f.text + def url = "${TRACKER_URL}/rest/api/2/issue/${key}/comment" + def payload = JsonOutput.toJson([body: body]) + def result = httpWrite(url, 'POST', payload) + emit([ok: true, key: key, commentId: result.id]) +} + +def cmd_transition(List args) { + def key = args ? args[0] : null + validateKey(key) + def transitionName = args.size() > 1 ? args[1] : null + if (!transitionName) { + System.err.println('error: transition requires a transition name') + System.exit(2) + } + def url = "${TRACKER_URL}/rest/api/2/issue/${key}/transitions" + def available = httpGet(url) + def match = available.transitions?.find { + it.name.equalsIgnoreCase(transitionName) + } + if (!match) { + def names = available.transitions?.collect { it.name } ?: [] + System.err.println("error: transition '${transitionName}' not found for ${key}; available: ${names}") + System.exit(3) + } + def payload = JsonOutput.toJson([transition: [id: match.id]]) + httpWrite(url, 'POST', payload) + emit([ok: true, key: key, transition: match.name, transitionId: match.id]) +} + +def cmd_label(List args) { + def key = args ? args[0] : null + validateKey(key) + List addLabels = [] + List removeLabels = [] + def i = 1 + while (i < args.size()) { + if (args[i] == '--add' && i + 1 < args.size()) { + addLabels << args[i + 1] + i += 2 + } else if (args[i] == '--remove' && i + 1 < args.size()) { + removeLabels << args[i + 1] + i += 2 + } else { + i++ + } + } + if (!addLabels && !removeLabels) { + System.err.println('error: label requires at least one --add or --remove flag') + System.exit(2) + } + def issueUrl = "${TRACKER_URL}/rest/api/2/issue/${key}?fields=labels" + def current = httpGet(issueUrl) + def labels = (current.fields?.labels ?: []) as List + labels.addAll(addLabels) + labels.removeAll(removeLabels) + labels = labels.unique() + def url = "${TRACKER_URL}/rest/api/2/issue/${key}" + def payload = JsonOutput.toJson([fields: [labels: labels]]) Review Comment: Fixed in this round — switched to `{"update": {"labels": [{"add": "x"}, {"remove": "y"}]}}`. Eliminates the GET round-trip and the race. Tests updated to assert on the atomic payload shape. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
