From a24aa16581a606dfdbf507abbc5c9cad6f110e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 12:39:39 +0100 Subject: [PATCH 01/11] Remove Jira references to issue checks and issue link comments --- .github/workflows/dev_pr/helpers.js | 21 ------ .github/workflows/dev_pr/issue_check.js | 91 +------------------------ .github/workflows/dev_pr/link.js | 30 +------- 3 files changed, 2 insertions(+), 140 deletions(-) diff --git a/.github/workflows/dev_pr/helpers.js b/.github/workflows/dev_pr/helpers.js index e4da5050d5d..32cb516eb6e 100644 --- a/.github/workflows/dev_pr/helpers.js +++ b/.github/workflows/dev_pr/helpers.js @@ -47,27 +47,6 @@ function detectIssue(title) { return null; } -/** - * Retrieves information about a JIRA issue. - * @param {String} jiraID - * @returns {Object} the information about a JIRA issue. - */ -async function getJiraInfo(jiraID) { - const jiraURL = `https://issues.apache.org/jira/rest/api/2/issue/${jiraID}`; - - return new Promise((resolve) => { - https.get(jiraURL, res => { - let data = ''; - - res.on('data', chunk => { data += chunk }) - - res.on('end', () => { - resolve(JSON.parse(data)); - }) - }) - }); -} - /** * Retrieves information about a GitHub issue. * @param {String} issueID diff --git a/.github/workflows/dev_pr/issue_check.js b/.github/workflows/dev_pr/issue_check.js index fb5d986dff2..f778f70c0f1 100644 --- a/.github/workflows/dev_pr/issue_check.js +++ b/.github/workflows/dev_pr/issue_check.js @@ -17,91 +17,6 @@ const helpers = require("./helpers.js"); -/** - * Performs checks on the JIRA Issue: - * - The issue is started in JIRA. - * - The issue contains components. - * - * @param {Object} github - * @param {Object} context - * @param {String} pullRequestNumber - * @param {String} jiraID - */ -async function verifyJIRAIssue(github, context, pullRequestNumber, jiraID) { - const ticketInfo = await helpers.getJiraInfo(jiraID); - if(!ticketInfo["fields"]["components"].length) { - await commentMissingComponents(github, context, pullRequestNumber); - } - - if(ticketInfo["fields"]["status"]["id"] == 1) { - // "status": {"name":"Open","id":"1" - // "description":"The issue is open and ready for the assignee to start work on it.", - await commentNotStartedTicket(github, context, pullRequestNumber); - } -} - -/** - * Adds a comment to add components on the JIRA ticket. - * - * @param {Object} github - * @param {Object} context - * @param {String} pullRequestNumber - */ -async function commentMissingComponents(github, context, pullRequestNumber) { - const {data: comments} = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pullRequestNumber, - per_page: 100 - }); - - var found = false; - for(var i=0; i { const title = context.payload.pull_request.title; const issue = helpers.detectIssue(title) if (issue){ - if (issue.kind == "jira") { - await verifyJIRAIssue(github, context, pullRequestNumber, issue.id); - } else if(issue.kind == "github") { - await verifyGitHubIssue(github, context, pullRequestNumber, issue.id); - } + await verifyGitHubIssue(github, context, pullRequestNumber, issue.id); } }; diff --git a/.github/workflows/dev_pr/link.js b/.github/workflows/dev_pr/link.js index a70dbc604c3..f7877f41dd5 100644 --- a/.github/workflows/dev_pr/link.js +++ b/.github/workflows/dev_pr/link.js @@ -47,30 +47,6 @@ async function haveComment(github, context, pullRequestNumber, message) { return false; } -/** - * Adds a comment on the Pull Request linking the JIRA issue. - * - * @param {Object} github - * @param {Object} context - * @param {String} pullRequestNumber - * @param {String} jiraID - */ -async function commentJIRAURL(github, context, pullRequestNumber, jiraID) { - const issueInfo = await helpers.getJiraInfo(jiraID); - const jiraURL = `https://issues.apache.org/jira/browse/${jiraID}`; - if (await haveComment(github, context, pullRequestNumber, jiraURL)) { - return; - } - if (issueInfo){ - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pullRequestNumber, - body: jiraURL - }); - } -} - /** * Adds a comment on the Pull Request linking the GitHub issue. * @@ -102,10 +78,6 @@ module.exports = async ({github, context}) => { const title = context.payload.pull_request.title; const issue = helpers.detectIssue(title); if (issue){ - if (issue.kind == "jira") { - await commentJIRAURL(github, context, pullRequestNumber, issue.id); - } else if (issue.kind == "github") { - await commentGitHubURL(github, context, pullRequestNumber, issue.id); - } + await commentGitHubURL(github, context, pullRequestNumber, issue.id); } }; From 6b158a66ab6e0300ca1e0bd2d3ebe9cd72a96bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 12:40:02 +0100 Subject: [PATCH 02/11] Remove Jira references to PR templates --- .github/pull_request_template.md | 4 ---- .github/workflows/dev_pr/title_check.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ddcdb5ebfd9..3839d3e2fc8 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -19,10 +19,6 @@ or MINOR: [${COMPONENT}] ${SUMMARY} -In the case of PARQUET issues on JIRA the title also supports: - - PARQUET-${JIRA_ISSUE_ID}: [${COMPONENT}] ${SUMMARY} - --> ### Rationale for this change diff --git a/.github/workflows/dev_pr/title_check.md b/.github/workflows/dev_pr/title_check.md index c810d747794..8de10a2962e 100644 --- a/.github/workflows/dev_pr/title_check.md +++ b/.github/workflows/dev_pr/title_check.md @@ -31,10 +31,6 @@ or MINOR: [${COMPONENT}] ${SUMMARY} -In the case of PARQUET issues on JIRA the title also supports: - - PARQUET-${JIRA_ISSUE_ID}: [${COMPONENT}] ${SUMMARY} - See also: * [Other pull requests](https://github.com/apache/arrow/pulls/) From 14861abcab5f2af884f1097a7d9b4757c52e33ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 12:40:22 +0100 Subject: [PATCH 03/11] Remove references to JIRA on contributing guide --- .github/CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index beb126eaf94..646097da873 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -45,8 +45,8 @@ issues][3] for the Apache Arrow project. Comment on the issue and/or contact [dev@arrow.apache.org](https://lists.apache.org/list.html?dev@arrow.apache.org) with your questions and ideas. -If you’d like to report a bug but don’t have time to fix it, you can still post -it on JIRA, or email the mailing list +If you’d like to report a bug but don’t have time to fix it, you can still create +a GitHub issue, or email the mailing list [dev@arrow.apache.org](https://lists.apache.org/list.html?dev@arrow.apache.org) To contribute a patch: @@ -57,8 +57,8 @@ harder to merge in a large change with a lot of disjoint features. GitHub](https://github.com/apache/arrow/issues). 3. Submit the patch as a GitHub pull request against the main branch. For a tutorial, see the GitHub guides on [forking a repo](https://help.github.com/en/articles/fork-a-repo) -and [sending a pull request](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork). So that your pull request syncs with the JIRA issue, prefix your pull request -name with the JIRA issue id (ex: [ARROW-767: [C++] Filesystem abstraction](https://github.com/apache/arrow/pull/4225)) +and [sending a pull request](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork). Prefix your pull request +name with the GitHub issue id (ex: [ARROW-767: [C++] Filesystem abstraction](https://github.com/apache/arrow/pull/4225)) 4. Make sure that your code passes the unit tests. You can find instructions how to run the unit tests for each Arrow component in its respective README file. From 0de567f9678b43e9632ef6ba74751019b83448c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 12:40:35 +0100 Subject: [PATCH 04/11] Remove Jira reference from commentor bot --- .github/workflows/dev_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev_pr.yml b/.github/workflows/dev_pr.yml index 4e37432afaa..96bf3993f82 100644 --- a/.github/workflows/dev_pr.yml +++ b/.github/workflows/dev_pr.yml @@ -49,7 +49,7 @@ jobs: ref: main persist-credentials: false - - name: Comment JIRA link + - name: Add Issue link if: | (github.event.action == 'opened' || github.event.action == 'edited') From b8d383012c7040417ba69e4686fd414b810aefb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 15:14:25 +0100 Subject: [PATCH 05/11] Fix merge script and tests to remove JIRA references --- .github/workflows/dev.yml | 2 +- dev/README.md | 9 +- dev/merge_arrow_pr.py | 178 ++------------------ dev/test_merge_arrow_pr.py | 325 +++++++++++++------------------------ 4 files changed, 127 insertions(+), 387 deletions(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index e4d3cae96a1..52eae68c4f4 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -124,7 +124,7 @@ jobs: shell: bash run: | gem install test-unit - pip install "cython>=0.29.31" setuptools pytest jira setuptools-scm + pip install "cython>=0.29.31" setuptools pytest requests setuptools-scm - name: Run Release Test env: ARROW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/dev/README.md b/dev/README.md index d35dd231bbc..c813aa64178 100644 --- a/dev/README.md +++ b/dev/README.md @@ -51,8 +51,7 @@ you'll have to install Python dependencies yourself and then run The merge script requires tokens for access control. There are two options for configuring your tokens: environment variables or a configuration file. -> Note: Arrow only requires a GitHub token. Parquet can use GitHub or -JIRA tokens. +> Note: Arrow and Parquet only requires a GitHub token. #### Pass tokens via Environment Variables @@ -61,12 +60,6 @@ The merge script uses the GitHub REST API. You must set a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). You need to add `workflow` scope to the Personal Access Token. -You can specify the -[Personal Access Token](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) -of your JIRA account in the -`APACHE_JIRA_TOKEN` environment variable. -If the variable is not set, the script will ask you for it. - #### Pass tokens via configuration file ``` diff --git a/dev/merge_arrow_pr.py b/dev/merge_arrow_pr.py index 6694d2373b8..e67075823b4 100755 --- a/dev/merge_arrow_pr.py +++ b/dev/merge_arrow_pr.py @@ -30,7 +30,6 @@ # variables. # # Configuration environment variables: -# - APACHE_JIRA_TOKEN: your Apache JIRA Personal Access Token # - ARROW_GITHUB_API_TOKEN: a GitHub API token to use for API requests # - ARROW_GITHUB_ORG: the GitHub organisation ('apache' by default) # - DEBUG: use for testing to avoid pushing to apache (0 by default) @@ -44,15 +43,6 @@ import requests import getpass -try: - import jira.client - import jira.exceptions -except ImportError: - print("Could not find jira library. " - "Run 'pip install jira' to install.") - print("Exiting without trying to close the associated JIRA.") - sys.exit(1) - # Remote name which points to the GitHub site ORG_NAME = ( os.environ.get("ARROW_GITHUB_ORG") or @@ -68,9 +58,6 @@ print("**************** DEBUGGING ****************") -JIRA_API_BASE = "https://issues.apache.org/jira" - - def get_json(url, headers=None): response = requests.get(url, headers=headers) if response.status_code != 200: @@ -135,92 +122,6 @@ def fix_version_from_branch(versions): ) -class JiraIssue(object): - - def __init__(self, jira_con, jira_id, project, cmd): - self.jira_con = jira_con - self.jira_id = jira_id - self.project = project - self.cmd = cmd - - try: - self.issue = jira_con.issue(jira_id) - except Exception as e: - self.cmd.fail("ASF JIRA could not find %s\n%s" % (jira_id, e)) - - @property - def current_fix_versions(self): - return self.issue.fields.fixVersions - - @property - def current_versions(self): - # Only suggest versions starting with a number, like 0.x but not JS-0.x - all_versions = self.jira_con.project_versions(self.project) - unreleased_versions = [x for x in all_versions - if not x.raw['released']] - - mainline_versions = self._filter_mainline_versions(unreleased_versions) - return mainline_versions - - def _filter_mainline_versions(self, versions): - if self.project == 'PARQUET': - mainline_regex = re.compile(r'cpp-\d.*') - else: - mainline_regex = re.compile(r'\d.*') - - return [x for x in versions if mainline_regex.match(x.name)] - - def resolve(self, fix_version, comment, *args): - fields = self.issue.fields - cur_status = fields.status.name - - if cur_status == "Resolved" or cur_status == "Closed": - self.cmd.fail("JIRA issue %s already has status '%s'" - % (self.jira_id, cur_status)) - - resolve = [x for x in self.jira_con.transitions(self.jira_id) - if x['name'] == "Resolve Issue"][0] - - # ARROW-6915: do not overwrite existing fix versions corresponding to - # point releases - fix_versions = [v.raw for v in self.jira_con.project_versions( - self.project) if v.name == fix_version] - fix_version_names = set(x['name'] for x in fix_versions) - for version in self.current_fix_versions: - major, minor, patch = version.name.split('.') - if patch != '0' and version.name not in fix_version_names: - fix_versions.append(version.raw) - - if DEBUG: - print("JIRA issue %s untouched -> %s" % - (self.jira_id, [v["name"] for v in fix_versions])) - else: - self.jira_con.transition_issue(self.jira_id, resolve["id"], - comment=comment, - fixVersions=fix_versions) - print("Successfully resolved %s!" % (self.jira_id)) - - self.issue = self.jira_con.issue(self.jira_id) - self.show() - - def show(self): - fields = self.issue.fields - print(format_issue_output("jira", self.jira_id, fields.status.name, - fields.summary, fields.assignee, - fields.components)) - - def github_issue_id(self): - try: - last_jira_comment = self.issue.fields.comment.comments[-1].body - except Exception: - # If no comment found or other issues ignore - return None - matches = MIGRATION_COMMENT_REGEX.search(last_jira_comment) - if matches: - values = matches.groupdict() - return "GH-" + values['issue_id'] - - class GitHubIssue(object): def __init__(self, github_api, github_id, cmd): @@ -328,12 +229,13 @@ def format_issue_output(issue_type, issue_id, status, else: components = ', '.join((getattr(x, "name", x) for x in components)) - if issue_type == "jira": - url = '/'.join((JIRA_API_BASE, 'browse', issue_id)) - else: - url = ( - f'https://github.com/{ORG_NAME}/{PROJECT_NAME}/issues/{issue_id}' - ) + url_id = issue_id + if "GH" in issue_id: + url_id = issue_id.replace("GH-", "") + + url = ( + f'https://github.com/{ORG_NAME}/{PROJECT_NAME}/issues/{url_id}' + ) return """=== {} {} === Summary\t\t{} @@ -476,19 +378,12 @@ def continue_maybe(self, prompt): class PullRequest(object): GITHUB_PR_TITLE_PATTERN = re.compile(r'^GH-([0-9]+)\b.*$') - # We can merge PARQUET patches from JIRA or GH prefixed issues - JIRA_SUPPORTED_PROJECTS = ['PARQUET'] - JIRA_PR_TITLE_REGEXEN = [ - (project, re.compile(r'^(' + project + r'-[0-9]+)\b.*$')) - for project in JIRA_SUPPORTED_PROJECTS - ] - JIRA_UNSUPPORTED_ARROW = re.compile(r'^(ARROW-[0-9]+)\b.*$') - - def __init__(self, cmd, github_api, git_remote, jira_con, number): + + def __init__(self, cmd, github_api, git_remote, number): + breakpoint() self.cmd = cmd self._github_api = github_api self.git_remote = git_remote - self.con = jira_con self.number = number self._pr_data = github_api.get_pr_data(number) try: @@ -536,28 +431,8 @@ def _get_issue(self): github_id = m.group(1) return GitHubIssue(self._github_api, github_id, self.cmd) - m = self.JIRA_UNSUPPORTED_ARROW.search(self.title) - if m: - old_jira_id = m.group(1) - jira_issue = JiraIssue(self.con, old_jira_id, 'ARROW', self.cmd) - self.cmd.fail("PR titles with ARROW- prefixed tickets on JIRA " - "are unsupported, update the PR title from " - f"{old_jira_id}. Possible GitHub id could be: " - f"{jira_issue.github_issue_id()}") - - for project, regex in self.JIRA_PR_TITLE_REGEXEN: - m = regex.search(self.title) - if m: - jira_id = m.group(1) - return JiraIssue(self.con, jira_id, project, self.cmd) - - options = ' or '.join( - '{0}-XXX'.format(project) - for project in self.JIRA_SUPPORTED_PROJECTS + ["GH"] - ) - self.cmd.fail("PR title should be prefixed by a GitHub ID or a " - "Jira ID, like: {0}, but found {1}".format( - options, self.title)) + self.cmd.fail("PR title should be prefixed by a GitHub ID, like: " + "GH-XXX, but found {0}".format(self.title)) def merge(self): """ @@ -706,31 +581,6 @@ def load_configuration(): return config -def get_credentials(cmd): - token = None - - config = load_configuration() - if "jira" in config.sections(): - token = config["jira"].get("token") - - # Fallback to environment variables - if not token: - token = os.environ.get("APACHE_JIRA_TOKEN") - - # Fallback to user tty prompt - if not token: - token = cmd.prompt("Env APACHE_JIRA_TOKEN not set, " - "please enter your Jira API token " - "(Jira personal access token):") - - return token - - -def connect_jira(cmd): - return jira.client.JIRA(options={'server': JIRA_API_BASE}, - token_auth=get_credentials(cmd)) - - def get_pr_num(): if len(sys.argv) == 2: return sys.argv[1] @@ -752,9 +602,7 @@ def cli(): os.chdir(ARROW_HOME) github_api = GitHubAPI(PROJECT_NAME, cmd) - - jira_con = connect_jira(cmd) - pr = PullRequest(cmd, github_api, ORG_NAME, jira_con, pr_num) + pr = PullRequest(cmd, github_api, ORG_NAME, pr_num) if pr.is_merged: print("Pull request %s has already been merged" % pr_num) diff --git a/dev/test_merge_arrow_pr.py b/dev/test_merge_arrow_pr.py index 0067c10414c..1db07ca91a4 100755 --- a/dev/test_merge_arrow_pr.py +++ b/dev/test_merge_arrow_pr.py @@ -25,99 +25,77 @@ FakeIssue = namedtuple('issue', ['fields']) -FakeFields = namedtuple('fields', ['status', 'summary', 'assignee', - 'components', 'fixVersions', 'milestone']) -FakeAssignee = namedtuple('assignee', ['displayName']) -FakeStatus = namedtuple('status', ['name']) -FakeComponent = namedtuple('component', ['name']) -FakeVersion = namedtuple('version', ['name', 'raw']) -FakeMilestone = namedtuple('milestone', ['state']) +FakeFields = namedtuple( + 'fields', ['assignees', 'labels', 'milestone', 'state', 'title']) +FakeAssignee = namedtuple('assignees', ['login']) +FakeLabel = namedtuple('label', ['name']) +FakeMilestone = namedtuple('milestone', ['title', 'state']) RAW_VERSION_JSON = [ - {'name': 'JS-0.4.0', 'released': False}, - {'name': '1.0.0', 'released': False}, - {'name': '2.0.0', 'released': False}, - {'name': '0.9.0', 'released': False}, - {'name': '0.10.0', 'released': False}, - {'name': '0.8.0', 'released': True}, - {'name': '0.7.0', 'released': True} + {'title': 'JS-0.4.0', 'state': 'open'}, + {'title': '1.0.0', 'state': 'open'}, + {'title': '2.0.0', 'state': 'open'}, + {'title': '0.9.0', 'state': 'open'}, + {'title': '0.10.0', 'state': 'open'}, + {'title': '0.8.0', 'state': 'closed'}, + {'title': '0.7.0', 'state': 'closed'} ] - -SOURCE_VERSIONS = [FakeVersion(raw['name'], raw) +SOURCE_VERSIONS = [FakeMilestone(raw['title'], raw['state']) for raw in RAW_VERSION_JSON] - -TRANSITIONS = [{'name': 'Resolve Issue', 'id': 1}] - -jira_id = 'ARROW-1234' -status = FakeStatus('In Progress') -fields = FakeFields(status, 'issue summary', FakeAssignee('groundhog'), - [FakeComponent('C++'), FakeComponent('Format')], - [], FakeMilestone('closed')._asdict()) +fake_issue_id = 'GH-1234' +fields = FakeFields([FakeAssignee('groundhog')._asdict()], + [FakeLabel('Component: C++')._asdict(), + FakeLabel('Component: Format')._asdict()], + FakeMilestone('', 'open')._asdict(), + 'open', '[C++][Format] The issue Title') FAKE_ISSUE_1 = FakeIssue(fields) -class FakeJIRA: +class FakeGitHub: - def __init__(self, issue=None, project_versions=None, transitions=None, - current_fix_versions=None): - self._issue = issue + def __init__(self, issues=None, project_versions=None, state='open'): + self._issues = issues self._project_versions = project_versions - self._transitions = transitions - - def issue(self, jira_id): - return self._issue + self._state = state + self._transitions = [] - def transitions(self, jira_id): - return self._transitions - - def transition_issue(self, jira_id, transition_id, comment=None, - fixVersions=None): - self.captured_transition = { - 'jira_id': jira_id, - 'transition_id': transition_id, - 'comment': comment, - 'fixVersions': fixVersions - } + @property + def issue(self): + return self._issues[fake_issue_id].fields._asdict() @property def current_versions(self): - all_versions = self._project_versions or SOURCE_VERSIONS return [ - v for v in all_versions if not v.raw.get("released") - ] + ['0.11.0'] + v.title for v in self._project_versions if not v.state == 'closed' + ] @property def current_fix_versions(self): return 'JS-0.4.0' - def project_versions(self, project): - return self._project_versions - + @property + def state(self): + return self._state -class FakeGitHub: + def get_issue_data(self, issue_id): + return self._issues.get(issue_id).fields._asdict() - def __init__(self, issue=None, project_versions=None): - self._issue = issue - self._project_versions = project_versions + def get_milestones(self): + return [v._asdict() for v in self._project_versions] - @property - def issue(self): - return self._issue.fields._asdict() + def assign_milestone(self, issue_id, milestone): + self._transitions.append( + {'action': 'assign_milestone', 'issue_id': issue_id, + 'milestone': milestone}) - @property - def current_versions(self): - all_versions = self._project_versions or SOURCE_VERSIONS - return [ - v for v in all_versions if not v.raw.get("released") - ] + ['0.11.0'] + def close_issue(self, issue_id, comment): + self._transitions.append( + {'action': 'close_issue', 'issue_id': issue_id, 'comment': comment}) @property - def current_fix_versions(self): - return 'JS-0.4.0' - - def project_versions(self, project): - return self._project_versions + def captured_transitions(self): + return self._transitions class FakeCLI: @@ -135,23 +113,23 @@ def fail(self, msg): raise Exception(msg) -def test_jira_fix_versions(): - jira = FakeJIRA(project_versions=SOURCE_VERSIONS, - transitions=TRANSITIONS) +def test_gh_fix_versions(): + gh = FakeGitHub(issues={fake_issue_id: FAKE_ISSUE_1}, + project_versions=SOURCE_VERSIONS) - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) + issue = merge_arrow_pr.GitHubIssue(gh, fake_issue_id, FakeCLI()) fix_version = merge_arrow_pr.get_candidate_fix_version( issue.current_versions ) assert fix_version == '1.0.0' -def test_jira_fix_versions_filters_maintenance(): +def test_gh_fix_versions_filters_maintenance(): maintenance_branches = ["maint-1.0.0"] - jira = FakeJIRA(project_versions=SOURCE_VERSIONS, - transitions=TRANSITIONS) + gh = FakeGitHub(issues={fake_issue_id: FAKE_ISSUE_1}, + project_versions=SOURCE_VERSIONS) - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) + issue = merge_arrow_pr.GitHubIssue(gh, fake_issue_id, FakeCLI()) fix_version = merge_arrow_pr.get_candidate_fix_version( issue.current_versions, maintenance_branches=maintenance_branches @@ -159,102 +137,72 @@ def test_jira_fix_versions_filters_maintenance(): assert fix_version == '2.0.0' -def test_jira_only_suggest_major_release(): +def test_gh_only_suggest_major_release(): versions_json = [ - {'name': '0.9.1', 'released': False}, - {'name': '0.10.0', 'released': False}, - {'name': '1.0.0', 'released': False}, + {'name': '0.9.1', 'state': "open"}, + {'name': '0.10.0', 'state': "open"}, + {'name': '1.0.0', 'state': "open"}, ] - versions = [FakeVersion(raw['name'], raw) for raw in versions_json] + versions = [FakeMilestone(raw['name'], raw['state']) for raw in versions_json] - jira = FakeJIRA(project_versions=versions, transitions=TRANSITIONS) - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) + gh = FakeGitHub(issues={fake_issue_id: FAKE_ISSUE_1}, project_versions=versions) + issue = merge_arrow_pr.GitHubIssue(gh, fake_issue_id, FakeCLI()) fix_version = merge_arrow_pr.get_candidate_fix_version( issue.current_versions ) assert fix_version == '1.0.0' -def test_jira_parquet_no_suggest_non_cpp(): - # ARROW-7351 - versions_json = [ - {'name': 'cpp-1.5.0', 'released': True}, - {'name': 'cpp-1.6.0', 'released': False}, - {'name': 'cpp-1.7.0', 'released': False}, - {'name': 'cpp-2.0.0', 'released': False}, - {'name': '1.11.0', 'released': False}, - {'name': '1.12.0', 'released': False}, - {'name': '2.0.0', 'released': False} - ] - - versions = [FakeVersion(raw['name'], raw) - for raw in versions_json] - - jira = FakeJIRA(project_versions=versions, transitions=TRANSITIONS) - issue = merge_arrow_pr.JiraIssue(jira, 'PARQUET-1713', 'PARQUET', - FakeCLI()) - fix_version = merge_arrow_pr.get_candidate_fix_version( - issue.current_versions - ) - assert fix_version == 'cpp-2.0.0' - - -def test_jira_invalid_issue(): +def test_gh_invalid_issue(): class Mock: - def issue(self, jira_id): + def issue(self, gh_id): raise Exception("not found") with pytest.raises(Exception): - merge_arrow_pr.JiraIssue(Mock(), 'ARROW-1234', 'ARROW', FakeCLI()) + merge_arrow_pr.GitHubIssue(Mock(), fake_issue_id, FakeCLI()) -def test_jira_resolve(): - jira = FakeJIRA(issue=FAKE_ISSUE_1, - project_versions=SOURCE_VERSIONS, - transitions=TRANSITIONS) +def test_gh_resolve(): + gh = FakeGitHub(issues={fake_issue_id: FAKE_ISSUE_1}, + project_versions=SOURCE_VERSIONS) my_comment = 'my comment' fix_version = "0.10.0" - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) - issue.resolve(fix_version, my_comment) + issue = merge_arrow_pr.GitHubIssue(gh, fake_issue_id, FakeCLI()) + issue.resolve(fix_version, my_comment, pr_body="") - assert jira.captured_transition == { - 'jira_id': 'ARROW-1234', - 'transition_id': 1, - 'comment': my_comment, - 'fixVersions': [{'name': '0.10.0', 'released': False}] - } + assert len(gh.captured_transitions) == 2 + assert gh.captured_transitions[0]['action'] == 'assign_milestone' + assert gh.captured_transitions[1]['action'] == 'close_issue' + assert gh.captured_transitions[1]['comment'] == my_comment + assert gh.captured_transitions[0]['milestone'] == fix_version -def test_jira_resolve_non_mainline(): - jira = FakeJIRA(issue=FAKE_ISSUE_1, - project_versions=SOURCE_VERSIONS, - transitions=TRANSITIONS) +def test_gh_resolve_non_mainline(): + gh = FakeGitHub(issues={fake_issue_id: FAKE_ISSUE_1}, + project_versions=SOURCE_VERSIONS) my_comment = 'my comment' fix_version = "JS-0.4.0" - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) - issue.resolve(fix_version, my_comment) + issue = merge_arrow_pr.GitHubIssue(gh, fake_issue_id, FakeCLI()) + issue.resolve(fix_version, my_comment, "") - assert jira.captured_transition == { - 'jira_id': 'ARROW-1234', - 'transition_id': 1, - 'comment': my_comment, - 'fixVersions': [{'name': 'JS-0.4.0', 'released': False}] - } + assert len(gh.captured_transitions) == 2 + assert gh.captured_transitions[1]['comment'] == my_comment + assert gh.captured_transitions[0]['milestone'] == fix_version -def test_jira_resolve_released_fix_version(): +def test_gh_resolve_released_fix_version(): # ARROW-5083 - jira = FakeGitHub(issue=FAKE_ISSUE_1, - project_versions=SOURCE_VERSIONS) + gh = FakeGitHub(issues={fake_issue_id: FAKE_ISSUE_1}, + project_versions=SOURCE_VERSIONS) cmd = FakeCLI(responses=['1.0.0']) - fix_versions_json = merge_arrow_pr.prompt_for_fix_version(cmd, jira) + fix_versions_json = merge_arrow_pr.prompt_for_fix_version(cmd, gh) assert fix_versions_json == "1.0.0" @@ -283,107 +231,58 @@ def test_multiple_authors_bad_input(): assert distinct_other_authors == [a0, a1] -def test_jira_already_resolved(): - status = FakeStatus('Resolved') - fields = FakeFields(status, 'issue summary', FakeAssignee('groundhog'), - [FakeComponent('Java')], [], None) +def test_gh_already_resolved(): + fields = FakeFields([FakeAssignee('groundhog')._asdict()], + [FakeLabel('Component: Java')._asdict()], + FakeMilestone('', 'open')._asdict(), + 'closed', '[Java] The issue Title') issue = FakeIssue(fields) - jira = FakeJIRA(issue=issue, - project_versions=SOURCE_VERSIONS, - transitions=TRANSITIONS) + gh = FakeGitHub(issues={fake_issue_id: issue}, + project_versions=SOURCE_VERSIONS) - fix_versions = [SOURCE_VERSIONS[0].raw] - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) + fix_versions = [SOURCE_VERSIONS[0]._asdict()] + issue = merge_arrow_pr.GitHubIssue(gh, fake_issue_id, FakeCLI()) with pytest.raises(Exception, - match="ARROW-1234 already has status 'Resolved'"): - issue.resolve(fix_versions, "") - - -def test_no_unset_point_release_fix_version(): - # ARROW-6915: We have had the problem of issues marked with a point release - # having their fix versions overwritten by the merge tool. This verifies - # that existing patch release versions are carried over - status = FakeStatus('In Progress') - - versions_json = { - '0.14.2': {'name': '0.14.2', 'id': 1}, - '0.15.1': {'name': '0.15.1', 'id': 2}, - '0.16.0': {'name': '0.16.0', 'id': 3}, - '0.17.0': {'name': '0.17.0', 'id': 4} - } - - fields = FakeFields(status, 'summary', FakeAssignee('someone'), - [FakeComponent('Java')], - [FakeVersion(v, versions_json[v]) - for v in ['0.17.0', '0.15.1', '0.14.2']], None) - issue = FakeIssue(fields) - - jira = FakeJIRA( - issue=issue, - project_versions=[ - FakeVersion(v, vdata) for v, vdata in versions_json.items() - ], - transitions=TRANSITIONS - ) - - issue = merge_arrow_pr.JiraIssue(jira, 'ARROW-1234', 'ARROW', FakeCLI()) - issue.resolve('0.16.0', "a comment") - - assert jira.captured_transition == { - 'jira_id': 'ARROW-1234', - 'transition_id': 1, - 'comment': 'a comment', - 'fixVersions': [versions_json[v] - for v in ['0.16.0', '0.15.1', '0.14.2']] - } - - issue.resolve([versions_json['0.15.1']], "a comment") - - assert jira.captured_transition == { - 'jira_id': 'ARROW-1234', - 'transition_id': 1, - 'comment': 'a comment', - 'fixVersions': [versions_json[v] for v in ['0.15.1', '0.14.2']] - } + match="GitHub issue GH-1234 already has status 'closed'"): + issue.resolve(fix_versions, "", "") -def test_jira_output_no_components(): +def test_gh_output_no_components(): # ARROW-5472 status = 'Interesting work' - components = [] output = merge_arrow_pr.format_issue_output( - "jira", 'ARROW-1234', 'Resolved', status, - FakeAssignee('Foo Bar'), components + 'github', 'GH-1234', 'Resolved', status, + 'username', [] ) - assert output == """=== JIRA ARROW-1234 === + assert output == """=== GITHUB GH-1234 === Summary\t\tInteresting work -Assignee\tFoo Bar +Assignee\tusername Components\tNO COMPONENTS!!! Status\t\tResolved -URL\t\thttps://issues.apache.org/jira/browse/ARROW-1234""" +URL\t\thttps://github.com/apache/arrow/issues/1234""" output = merge_arrow_pr.format_issue_output( - "jira", 'ARROW-1234', 'Resolved', status, FakeAssignee('Foo Bar'), - [FakeComponent('C++'), FakeComponent('Python')] + 'github', 'GH-1234', 'Resolved', status, 'username', + [FakeLabel('C++'), FakeLabel('Python')] ) - assert output == """=== JIRA ARROW-1234 === + assert output == """=== GITHUB GH-1234 === Summary\t\tInteresting work -Assignee\tFoo Bar +Assignee\tusername Components\tC++, Python Status\t\tResolved -URL\t\thttps://issues.apache.org/jira/browse/ARROW-1234""" +URL\t\thttps://github.com/apache/arrow/issues/1234""" def test_sorting_versions(): versions_json = [ - {'name': '11.0.0', 'released': False}, - {'name': '9.0.0', 'released': False}, - {'name': '10.0.0', 'released': False}, + {'title': '11.0.0', 'state': 'open'}, + {'title': '9.0.0', 'state': 'open'}, + {'title': '10.0.0', 'state': 'open'}, ] - versions = [FakeVersion(raw['name'], raw) for raw in versions_json] - fix_version = merge_arrow_pr.get_candidate_fix_version(versions) + versions = [FakeMilestone(raw['title'], raw['state']) for raw in versions_json] + fix_version = merge_arrow_pr.get_candidate_fix_version([x.title for x in versions]) assert fix_version == "9.0.0" From c4c0a3374c3b0f7846892cfd37f37834e02c9200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 16:24:34 +0100 Subject: [PATCH 06/11] More unnecessary remnants --- .github/workflows/dev_pr/helpers.js | 10 ++-------- CONTRIBUTING.md | 3 +-- dev/merge.conf.sample | 4 ---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/dev_pr/helpers.js b/.github/workflows/dev_pr/helpers.js index 32cb516eb6e..1a93b428e0a 100644 --- a/.github/workflows/dev_pr/helpers.js +++ b/.github/workflows/dev_pr/helpers.js @@ -24,10 +24,8 @@ const https = require('https'); * @returns {Issue} or null if no issue detected. * * @typedef {Object} Issue - * @property {string} kind - The kind of issue: minor, jira or github - * @property {string} id - The id of the issue: - * PARQUET-XXXX for jira - * The numeric issue id for github + * @property {string} kind - The kind of issue: minor or github + * @property {string} id - The numeric issue id of the issue */ function detectIssue(title) { if (!title) { @@ -36,10 +34,6 @@ function detectIssue(title) { if (title.startsWith("MINOR: ")) { return {"kind": "minor"}; } - const matched_jira = /^(WIP:?\s*)?((PARQUET)-\d+)/.exec(title); - if (matched_jira) { - return {"kind": "jira", "id": matched_jira[2]}; - } const matched_gh = /^(WIP:?\s*)?GH-(\d+)/.exec(title); if (matched_gh) { return {"kind": "github", "id": matched_gh[2]}; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 03ce556add2..dc7d7a2244a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,8 +29,7 @@ To be assigned to an issue, add a comment "take" to that issue. Before you create a new bug entry, we recommend you first search among existing Arrow issues in -[Jira](https://issues.apache.org/jira/issues/?jql=project%20%3D%20ARROW%20AND%20status%20%3D%20Open) -or [GitHub](https://github.com/apache/arrow/issues). +[GitHub](https://github.com/apache/arrow/issues). We conventionally prefix the issue title with the component name in brackets, such as "[C++][Python] Ensure no validity bitmap in diff --git a/dev/merge.conf.sample b/dev/merge.conf.sample index c50ef85d70f..db436f31eac 100644 --- a/dev/merge.conf.sample +++ b/dev/merge.conf.sample @@ -18,10 +18,6 @@ # Configuration for the merge_arrow_pr.py tool # Install a copy of this file at ~/.config/arrow/merge.conf -[jira] -# issues.apache.org Jira personal access token -token=abc123 - [github] # GitHub's personal access token. "workflow" scope is needed. api_token=ghp_ABC From 652098f4716b819a6978438095ea51f16ddf6843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 16:30:08 +0100 Subject: [PATCH 07/11] Remove stray debugging breakpoint --- dev/merge_arrow_pr.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/merge_arrow_pr.py b/dev/merge_arrow_pr.py index e67075823b4..1d845132d03 100755 --- a/dev/merge_arrow_pr.py +++ b/dev/merge_arrow_pr.py @@ -380,7 +380,6 @@ class PullRequest(object): GITHUB_PR_TITLE_PATTERN = re.compile(r'^GH-([0-9]+)\b.*$') def __init__(self, cmd, github_api, git_remote, number): - breakpoint() self.cmd = cmd self._github_api = github_api self.git_remote = git_remote From 23580519966fd4fc7162d444f49be601ffb3e284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Wed, 4 Dec 2024 18:59:15 +0100 Subject: [PATCH 08/11] Remove jira from dev/requirements_merge_arrow_pr.txt --- dev/requirements_merge_arrow_pr.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/requirements_merge_arrow_pr.txt b/dev/requirements_merge_arrow_pr.txt index 99909e434a5..f2293605cf1 100644 --- a/dev/requirements_merge_arrow_pr.txt +++ b/dev/requirements_merge_arrow_pr.txt @@ -1,2 +1 @@ -jira requests From a97583d36665096cca49d0d89d4c7eb7b1516b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Thu, 5 Dec 2024 09:32:17 +0100 Subject: [PATCH 09/11] Remove unnecessary parenthesis on string Co-authored-by: Sutou Kouhei --- dev/merge_arrow_pr.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dev/merge_arrow_pr.py b/dev/merge_arrow_pr.py index 1d845132d03..fe1dc1e7929 100755 --- a/dev/merge_arrow_pr.py +++ b/dev/merge_arrow_pr.py @@ -233,9 +233,7 @@ def format_issue_output(issue_type, issue_id, status, if "GH" in issue_id: url_id = issue_id.replace("GH-", "") - url = ( - f'https://github.com/{ORG_NAME}/{PROJECT_NAME}/issues/{url_id}' - ) + url = f'https://github.com/{ORG_NAME}/{PROJECT_NAME}/issues/{url_id}' return """=== {} {} === Summary\t\t{} From 14a71b256e26d410987b08c0c924cbcdde7f73e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Cumplido?= Date: Thu, 5 Dec 2024 09:40:02 +0100 Subject: [PATCH 10/11] Minor fix to doc sample pr title to use GH- instead of ARROW- prefix --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 646097da873..82d7da0a8d3 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -58,7 +58,7 @@ GitHub](https://github.com/apache/arrow/issues). 3. Submit the patch as a GitHub pull request against the main branch. For a tutorial, see the GitHub guides on [forking a repo](https://help.github.com/en/articles/fork-a-repo) and [sending a pull request](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork). Prefix your pull request -name with the GitHub issue id (ex: [ARROW-767: [C++] Filesystem abstraction](https://github.com/apache/arrow/pull/4225)) +name with the GitHub issue id (ex: [GH-767: [C++] Filesystem abstraction](https://github.com/apache/arrow/pull/4225)) 4. Make sure that your code passes the unit tests. You can find instructions how to run the unit tests for each Arrow component in its respective README file. From 0972db096558661b6d869229ec7d5dfc184853d9 Mon Sep 17 00:00:00 2001 From: Jacob Wujciak-Jens Date: Fri, 6 Dec 2024 00:27:52 +0100 Subject: [PATCH 11/11] remove jira link from r docs --- r/vignettes/install.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/r/vignettes/install.Rmd b/r/vignettes/install.Rmd index 07d858c6cd6..69780bd64df 100644 --- a/r/vignettes/install.Rmd +++ b/r/vignettes/install.Rmd @@ -433,7 +433,7 @@ compatible with the current version of the R package. Please check the "Known installation issues" below to see if any apply, and if none apply, set the environment variable `ARROW_R_DEV=TRUE` for more verbose output and try installing again. Then, -please [report an issue](https://issues.apache.org/jira/projects/ARROW/issues) +please [report an issue](https://github.com/apache/arrow/issues/new/choose) and include the full installation output. ### Using system libraries @@ -465,7 +465,7 @@ update the libarrow system packages. If the R package finds and downloads a prebuilt binary of libarrow, but then the arrow package can't be loaded, perhaps with "undefined symbols" errors, -please [report an issue](https://issues.apache.org/jira/projects/ARROW/issues). +please [report an issue](https://github.com/apache/arrow/issues/new/choose). This is likely a compiler mismatch and may be resolvable by setting some environment variables to instruct R to compile the packages to match libarrow. @@ -475,7 +475,7 @@ instead of downloading the prebuilt binary. That should guarantee that the compiler settings match. If a prebuilt libarrow binary wasn't found for your operating system but you think it should have been, -please [report an issue](https://issues.apache.org/jira/projects/ARROW/issues) and share the console output. +please [report an issue](https://github.com/apache/arrow/issues/new/choose) and share the console output. You may also set the environment variable `ARROW_R_DEV=TRUE` for additional debug messages. @@ -485,7 +485,7 @@ If building libarrow from source fails, check the error message. (If you don't see an error message, only the `----- NOTE -----`, set the environment variable `ARROW_R_DEV=TRUE` to increase verbosity and retry installation.) The install script should work everywhere, so if libarrow fails to compile, -please [report an issue](https://issues.apache.org/jira/projects/ARROW/issues) +please [report an issue](https://github.com/apache/arrow/issues/new/choose) so that we can improve the script. ## Contributing