From d46b0470455d9ac35c80a6123007e7b45208870c Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Fri, 6 Feb 2026 23:49:40 +0000 Subject: [PATCH 1/3] Initial plan From 3651118ef8543d477bf3e8e49871f696dbe795dd Mon Sep 17 00:00:00 2001 From: "anthropic-code-agent[bot]" <242468646+Claude@users.noreply.github.com> Date: Fri, 6 Feb 2026 23:52:07 +0000 Subject: [PATCH 2/3] Update JIRA client to use API v3 Co-authored-by: zkoppert <6935431+zkoppert@users.noreply.github.com> --- jiralib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jiralib.py b/jiralib.py index a6bf0e9..4bb3c01 100644 --- a/jiralib.py +++ b/jiralib.py @@ -50,7 +50,7 @@ def __init__(self, url, user, token): self.url = url self.user = user self.token = token - self.j = JIRA(url, basic_auth=(user, token)) + self.j = JIRA(url, basic_auth=(user, token), options={"api_version": 3}) def auth(self): return self.user, self.token From 2632e22778db7719adafadc57e9dd9324b1f76c7 Mon Sep 17 00:00:00 2001 From: Zack Koppert Date: Fri, 20 Feb 2026 16:36:37 -0800 Subject: [PATCH 3/3] Fix Jira API v3 migration: correct option key, upgrade library, add configurability - Fix option key: 'api_version' -> 'rest_api_version' (the wrong key was silently ignored, causing requests to still hit /rest/api/2/ endpoints) - Upgrade jira library from ~=3.0.0 to ~=3.10.0 (adds support for the new /rest/api/3/search/jql endpoint via enhanced_search_issues) - Replace search_issues() with enhanced_search_issues() at both call sites to use the new search endpoint - Make API version configurable via --jira-api-version CLI arg, jira_api_version action input, and GH2JIRA_JIRA_API_VERSION env var (defaults to '3' for Jira Cloud, use '2' for Jira Server/Data Center) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Pipfile | 2 +- action.yml | 8 +++++++- cli.py | 13 +++++++++---- jiralib.py | 8 ++++---- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Pipfile b/Pipfile index d80ff30..70f3124 100644 --- a/Pipfile +++ b/Pipfile @@ -6,7 +6,7 @@ verify_ssl = true [packages] flask = "~=2.3.0" requests = "~=2.32.3" -jira = "~=3.0.0" +jira = "~=3.10.0" logging-formatter-anticrlf = "~=1.2.1" [dev-packages] diff --git a/action.yml b/action.yml index 544f767..7a04a62 100644 --- a/action.yml +++ b/action.yml @@ -35,6 +35,10 @@ inputs: description: 'Custom reopen state' required: false default: 'To Do' + jira_api_version: + description: 'Jira REST API version. Use "3" for Jira Cloud (default), "2" for Jira Server/Data Center.' + required: false + default: '3' runs: using: composite steps: @@ -51,6 +55,7 @@ runs: INPUTS_SYNC_DIRECTION: ${{ inputs.sync_direction }} INPUTS_ISSUE_END_STATE: ${{ inputs.issue_end_state }} INPUTS_ISSUE_REOPEN_STATE: ${{ inputs.issue_reopen_state }} + INPUTS_JIRA_API_VERSION: ${{ inputs.jira_api_version }} run: | pip3 install pipenv pipenv install @@ -68,4 +73,5 @@ runs: --jira-labels "$INPUTS_JIRA_LABELS" \ --direction "$INPUTS_SYNC_DIRECTION" \ --issue-end-state "$INPUTS_ISSUE_END_STATE" \ - --issue-reopen-state "$INPUTS_ISSUE_REOPEN_STATE" + --issue-reopen-state "$INPUTS_ISSUE_REOPEN_STATE" \ + --jira-api-version "$INPUTS_JIRA_API_VERSION" diff --git a/cli.py b/cli.py index c2aa558..8099aac 100644 --- a/cli.py +++ b/cli.py @@ -52,7 +52,7 @@ def serve(args): fail("No Webhook secret specified!") github = ghlib.GitHub(args.gh_url, args.gh_token) - jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token) + jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token, args.jira_api_version) s = Sync( github, jira.getProject(args.jira_project, args.jira_labels), @@ -81,7 +81,7 @@ def sync(args): fail("No GitHub repository specified!") github = ghlib.GitHub(args.gh_url, args.gh_token) - jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token) + jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token, args.jira_api_version) jira_project = jira.getProject( args.jira_project, args.issue_end_state, @@ -143,7 +143,7 @@ def install_hooks(args): if args.jira_url: if not args.jira_user or not args.jira_token: fail("No JIRA credentials specified!") - jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token) + jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token, args.jira_api_version) jira.create_hook("github_jira_synchronization_hook", args.hook_url, args.secret) @@ -175,7 +175,7 @@ def list_hooks(args): if not args.jira_user or not args.jira_token: fail("No JIRA credentials specified!") - jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token) + jira = jiralib.Jira(args.jira_url, args.jira_user, args.jira_token, args.jira_api_version) for h in jira.list_hooks(): print(json.dumps(h, indent=4)) @@ -203,6 +203,11 @@ def main(): ) credential_base.add_argument("--jira-project", help="JIRA project key") credential_base.add_argument("--jira-labels", help="JIRA bug label(s)") + credential_base.add_argument( + "--jira-api-version", + help="JIRA REST API version (default: 3). Use '2' for Jira Server/Data Center.", + default=os.getenv("GH2JIRA_JIRA_API_VERSION", "3"), + ) credential_base.add_argument( "--secret", help="Webhook secret. Alternatively, the GH2JIRA_SECRET may be set.", diff --git a/jiralib.py b/jiralib.py index 4bb3c01..2790f83 100644 --- a/jiralib.py +++ b/jiralib.py @@ -46,11 +46,11 @@ class Jira: - def __init__(self, url, user, token): + def __init__(self, url, user, token, api_version="3"): self.url = url self.user = user self.token = token - self.j = JIRA(url, basic_auth=(user, token), options={"api_version": 3}) + self.j = JIRA(url, basic_auth=(user, token), options={"rest_api_version": api_version}) def auth(self): return self.user, self.token @@ -119,7 +119,7 @@ def get_state_issue(self, issue_key="-"): issues = list( filter( lambda i: i.fields.summary == STATE_ISSUE_SUMMARY, - self.j.search_issues(issue_search, maxResults=0), + self.j.enhanced_search_issues(issue_search, maxResults=0), ) ) @@ -218,7 +218,7 @@ def fetch_issues(self, key): lambda i: i.is_managed(), [ JiraIssue(self, raw) - for raw in self.j.search_issues(issue_search, maxResults=0) + for raw in self.j.enhanced_search_issues(issue_search, maxResults=0) ], ) )