summaryrefslogtreecommitdiff
path: root/.github
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2020-12-19 20:11:26 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2020-12-19 20:11:26 +0100
commitbd28500252d015f715e2b7a51d365a3625cc54c5 (patch)
tree3fcfcfe69a9257ce638207f9e71a12f0b681501d /.github
parentadf5aa0ab0a6e91a8e3cd659d5b91a5dcdee1b4a (diff)
downloadpsutil-bd28500252d015f715e2b7a51d365a3625cc54c5.tar.gz
improve github actions
Signed-off-by: Giampaolo Rodola <g.rodola@gmail.com>
Diffstat (limited to '.github')
-rw-r--r--.github/ISSUE_TEMPLATE/bug.md2
-rw-r--r--.github/ISSUE_TEMPLATE/enhancement.md2
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md2
-rw-r--r--.github/no-response.yml2
-rw-r--r--.github/workflows/build.yml11
-rw-r--r--.github/workflows/issues.py303
-rw-r--r--.github/workflows/issues.yml (renamed from .github/workflows/issue_bot.yml)15
7 files changed, 324 insertions, 13 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
index 096033db..24d01efa 100644
--- a/.github/ISSUE_TEMPLATE/bug.md
+++ b/.github/ISSUE_TEMPLATE/bug.md
@@ -11,7 +11,7 @@ labels: 'bug'
* Architecture: { 64bit, 32bit, ARM, PowerPC, s390 }
* Psutil version: { pip3 show psutil }
* Python version: { python3 -V }
-* Type: { core, doc, performance, scripts, tests, wheels, newapi }
+* Type: { core, doc, performance, scripts, tests, wheels, new-api, installation }
## Description
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
index 0a1cbb77..2f7d75a5 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.md
+++ b/.github/ISSUE_TEMPLATE/enhancement.md
@@ -9,7 +9,7 @@ title: "[OS] title"
## Summary
* OS: { type-or-version }
-* Type: { core, doc, performance, scripts, tests, wheels, newapi }
+* Type: { core, doc, performance, scripts, tests, wheels, new-api }
## Description
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 6b7fdee7..e8bbb2a4 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,7 +2,7 @@
* OS: { type-or-version }
* Bug fix: { yes/no }
-* Type: { core, doc, performance, scripts, tests, wheels, newapi }
+* Type: { core, doc, performance, scripts, tests, wheels, new-api }
* Fixes: { comma-separated list of issues fixed by this PR, if any }
## Description
diff --git a/.github/no-response.yml b/.github/no-response.yml
index e5afde07..56457a28 100644
--- a/.github/no-response.yml
+++ b/.github/no-response.yml
@@ -3,7 +3,7 @@
# Number of days of inactivity before an issue is closed for lack of response
daysUntilClose: 14
# Label requiring a response
-responseRequiredLabel: awaiting-response
+responseRequiredLabel: need-more-info
# Comment to post when closing an Issue for lack of response.
# Set to `false` to disable
closeComment: >
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index c8a98f79..25efdbc1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,7 +10,7 @@
# https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip
on: [push]
-name: Build
+name: build
jobs:
linux-macos-win:
name: ${{ matrix.os }}
@@ -29,6 +29,7 @@ jobs:
PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_TESTING=1 PSUTIL_DEBUG=1 python {project}/psutil/tests/test_memleaks.py
CIBW_TEST_EXTRAS: test
CIBW_SKIP: cp35-* pp*
+
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.6.0
@@ -40,15 +41,17 @@ jobs:
with:
python-version: 3.9
+ - name: Install cibuildwheel
+ run: pip install cibuildwheel
+
# - name: (Windows) install Visual C++ for Python 2.7
# if: matrix.os == 'windows-latest'
# run: |
# choco install vcpython27 -f -y
- name: Run tests
- run: |
- pip install cibuildwheel
- cibuildwheel .
+ run: cibuildwheel .
+
- name: Create wheels
uses: actions/upload-artifact@v2
with:
diff --git a/.github/workflows/issues.py b/.github/workflows/issues.py
new file mode 100644
index 00000000..a2beecc7
--- /dev/null
+++ b/.github/workflows/issues.py
@@ -0,0 +1,303 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Bot triggered by Github Actions every time a new issue, PR or comment
+is created. Assign labels, provide replies, closes issues, etc. depending
+on the situation.
+"""
+
+import os
+import re
+import sys
+
+from github import Github
+
+
+ROOT_DIR = os.path.realpath(
+ os.path.join(os.path.dirname(__file__), '..', '..'))
+SCRIPTS_DIR = os.path.join(ROOT_DIR, 'scripts')
+
+
+# --- constants
+
+
+LABELS_MAP = {
+ # platforms
+ "linux": [
+ "linux", "ubuntu", "redhat", "mint", "centos", "red hat", "archlinux",
+ "debian", "alpine", "gentoo", "fedora", "slackware", "suse", "RHEL",
+ "opensuse", "manylinux", "apt ", "apt-", "rpm", "yum", "kali",
+ "/sys/class", "/proc/net", "/proc/disk", "/proc/smaps",
+ "/proc/vmstat",
+ ],
+ "windows": [
+ "windows", "win32", "WinError", "WindowsError", "win10", "win7",
+ "win ", "mingw", "msys", "studio", "microsoft", "make.bat",
+ "CloseHandle", "GetLastError", "NtQuery", "DLL", "MSVC", "TCHAR",
+ "WCHAR", ".bat", "OpenProcess", "TerminateProcess", "appveyor",
+ "windows error", "NtWow64", "NTSTATUS", "Visual Studio",
+ ],
+ "macos": [
+ "macos", "mac ", "osx", "os x", "mojave", "sierra", "capitan",
+ "yosemite", "catalina", "mojave", "big sur", "xcode", "darwin",
+ "dylib",
+ ],
+ "aix": ["aix"],
+ "cygwin": ["cygwin"],
+ "freebsd": ["freebsd"],
+ "netbsd": ["netbsd"],
+ "openbsd": ["openbsd"],
+ "sunos": ["sunos", "solaris"],
+ "wsl": ["wsl"],
+ "unix": [
+ "psposix", "_psutil_posix", "waitpid", "statvfs", "/dev/tty",
+ "/dev/pts",
+ ],
+ "pypy": ["pypy"],
+ # types
+ "enhancement": ["enhancement"],
+ "memleak": ["memory leak", "leaks memory", "memleak", "mem leak"],
+ "api": ["idea", "proposal", "api", "feature"],
+ "performance": ["performance", "speedup", "speed up", "slow", "fast"],
+ "wheels": ["wheel", "wheels"],
+ "scripts": [
+ "example script", "examples script", "example dir", "scripts/",
+ ],
+ # bug
+ "bug": [
+ "fail", "can't execute", "can't install", "cannot execute",
+ "cannot install", "install error", "crash", "critical",
+ ],
+ # doc
+ "doc": [
+ "doc ", "document ", "documentation", "readthedocs", "pythonhosted",
+ "HISTORY", "README", "dev guide", "devguide", "sphinx", "docfix",
+ "index.rst",
+ ],
+ # tests
+ "tests": [
+ " test ", "tests", "travis", "coverage", "cirrus", "appveyor",
+ "continuous integration", "unittest", "pytest", "unit test",
+ ],
+ # critical errors
+ "priority-high": [
+ "WinError", "WindowsError", "RuntimeError", "ZeroDivisionError",
+ "SystemError", "MemoryError", "core dumped",
+ "segfault", "segmentation fault",
+ ],
+}
+
+LABELS_MAP['scripts'].extend(
+ [x for x in os.listdir(SCRIPTS_DIR) if x.endswith('.py')])
+
+OS_LABELS = [
+ "linux", "windows", "macos", "freebsd", "openbsd", "netbsd", "openbsd",
+ "bsd", "sunos", "unix", "wsl", "aix", "cygwin",
+]
+
+ILLOGICAL_PAIRS = [
+ ('bug', 'enhancement'),
+ ('doc', 'tests'),
+ ('scripts', 'doc'),
+ ('scripts', 'tests'),
+ ('bsd', 'freebsd'),
+ ('bsd', 'openbsd'),
+ ('bsd', 'netbsd'),
+]
+
+# --- replies
+
+REPLY_MISSING_PYTHON_HEADERS = """\
+It looks like you're missing `Python.h` headers. This usually means you have \
+to install them first, then retry psutil installation.
+Please read \
+[INSTALL](https://github.com/giampaolo/psutil/blob/master/INSTALL.rst) \
+instructions for your platform. \
+This is an auto-generated response based on the text you submitted. \
+If this was a mistake or you think there's a bug with psutil installation \
+process, please add a comment to reopen this issue.
+"""
+
+
+# --- utils
+
+
+def is_pr(issue):
+ return 'PullRequest' in issue.__module__
+
+
+def is_issue(issue):
+ return not is_pr(issue)
+
+
+def is_new(issue):
+ return issue.comments == 0
+
+
+def is_comment(issue):
+ return not is_new(issue)
+
+
+def has_label(issue, label):
+ assigned = [x.name for x in issue.labels]
+ return label in assigned
+
+
+def has_os_label(issue):
+ labels = set([x.name for x in issue.labels])
+ for label in OS_LABELS:
+ if label in labels:
+ return True
+ return False
+
+
+def get_repo():
+ repo = os.environ['GITHUB_REPOSITORY']
+ token = os.environ['GITHUB_TOKEN']
+ return Github(token).get_repo(repo)
+
+
+# --- actions
+
+
+def log(msg):
+ if '\n' in msg or "\r\n" in msg:
+ print(">>>\n%s\n<<<" % msg)
+ else:
+ print(">>> %s <<<" % msg)
+
+
+def add_label(issue, label):
+ def should_add(issue, label):
+ if has_label(issue, label):
+ log("already has label %r" % (label))
+ return False
+
+ for left, right in ILLOGICAL_PAIRS:
+ if label == left and has_label(issue, right):
+ log("already has label" % (label))
+ return False
+
+ return not has_label(issue, label)
+
+ if not should_add(issue, label):
+ log("should not add label %r" % label)
+ return
+
+ log("add label %r" % label)
+ issue.add_to_labels(label)
+
+
+def _guess_labels_from_text(issue, text):
+ for label, keywords in LABELS_MAP.items():
+ for keyword in keywords:
+ if keyword.lower() in text.lower():
+ yield (label, keyword)
+
+
+def add_labels_from_text(issue, text):
+ for label, keyword in _guess_labels_from_text(issue, text):
+ add_label(issue, label)
+
+
+def add_labels_from_new_body(issue, text):
+ log("start searching for template lines in new issue/PR body")
+ # add os label
+ r = re.search(r"\* OS:.*?\n", text)
+ log("search for 'OS: ...' line")
+ if r:
+ log("found")
+ add_labels_from_text(issue, r.group(0))
+ else:
+ log("not found")
+
+ # add bug/enhancement label
+ log("search for 'Bug fix: y/n' line")
+ r = re.search(r"\* Bug fix:.*?\n", text)
+ if is_pr(issue) and \
+ r is not None and \
+ not has_label(issue, "bug") and \
+ not has_label(issue, "enhancement"):
+ log("found")
+ s = r.group(0).lower()
+ if 'yes' in s:
+ add_label(issue, 'bug')
+ else:
+ add_label(issue, 'enhancement')
+ else:
+ log("not found")
+
+ # add type labels
+ log("search for 'Type: ...' line")
+ r = re.search(r"\* Type:.*?\n", text)
+ if r:
+ log("found")
+ s = r.group(0).lower()
+ if 'doc' in s:
+ add_label(issue, 'doc')
+ if 'performance' in s:
+ add_label(issue, 'performance')
+ if 'scripts' in s:
+ add_label(issue, 'scripts')
+ if 'tests' in s:
+ add_label(issue, 'tests')
+ if 'wheels' in s:
+ add_label(issue, 'wheels')
+ if 'new-api' in s:
+ add_label(issue, 'new-api')
+ if 'new-platform' in s:
+ add_label(issue, 'new-platform')
+ else:
+ log("not found")
+
+
+# --- events
+
+
+def on_new_issue(issue):
+ def has_text(text):
+ return text in issue.title.lower() or text in issue.body.lower()
+
+ log("searching for missing Python.h")
+ if has_text("missing python.h") or \
+ has_text("python.h: no such file or directory") or \
+ "#include<Python.h>\n^~~~" in issue.body.replace(' ', '') or \
+ "#include<Python.h>\r\n^~~~" in issue.body.replace(' ', ''):
+ log("found")
+ issue.create_comment(REPLY_MISSING_PYTHON_HEADERS)
+ issue.edit(state='closed')
+ return
+
+
+def on_new_pr(issue):
+ pass
+
+
+def on_new_comment(issue):
+ pass
+
+
+def main():
+ issue = get_repo().get_issue(number=int(sys.argv[1]))
+ stype = "issue" if is_issue(issue) else "PR"
+ log("running issue bot for %s %r" % (stype, issue))
+
+ if is_new(issue):
+ log("new %s\n%s" % (stype, issue.body))
+ add_labels_from_text(issue, issue.title)
+ add_labels_from_new_body(issue, issue.body)
+ if is_issue(issue):
+ on_new_issue(issue)
+ if is_pr(issue):
+ on_new_pr(issue)
+ else:
+ log("new comment: \n", issue.body)
+ on_new_comment(issue)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/.github/workflows/issue_bot.yml b/.github/workflows/issues.yml
index 223c0b6e..17355dee 100644
--- a/.github/workflows/issue_bot.yml
+++ b/.github/workflows/issues.yml
@@ -1,22 +1,27 @@
-name: Issue/PR bot
+name: issue-bot
on:
issues:
types: [opened]
pull_request:
typed: [opened]
+ issue_comment:
+ types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
+ # install python
- uses: actions/checkout@v2
- - name: Set up Python 3.8
+ - name: Install Python
uses: actions/setup-python@v2
with:
python-version: 3.8
+ # install deps
+ - name: Install deps
+ run: python -m pip install --upgrade pip PyGithub
+ # run
- name: Run
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GITHUB_ISSUE_URL: ${{ github.event.issue.url }}
run: |
- PYTHONUNBUFFERED=1 python -m pip install --upgrade pip PyGithub
- PYTHONUNBUFFERED=1 python scripts/internal/github_issue_bot.py
+ python .github/workflows/issues.py ${{ github.event.issue.number }}