improve entrypoints

This commit is contained in:
riscy 2020-02-22 15:16:32 -08:00
parent bb0a3cda47
commit 4b701678a0
4 changed files with 82 additions and 63 deletions

View file

@ -12,5 +12,4 @@ install:
- pip install requests
script:
- pytest --doctest-modules melpazoid.py
- python melpazoid.py
- make pytest run

View file

@ -3,8 +3,11 @@ PACKAGE_NAME ?= NONE
.PHONY: run
run:
python melpazoid.py
.PHNY: pytest
pytest:
pytest --doctest-modules
python -m pdb -c continue melpazoid.py
.PHONY: term
test: image

View file

@ -1,30 +1,45 @@
#+TITLE melpazoid
#+OPTINS: toc:3 author:t creator:nil num:nil
#+AUTHOR Chris Rayner
#+TITLE: melpazoid
#+OPTIONS: toc:3 author:t creator:nil num:nil
#+AUTHOR: Chris Rayner
#+EMAIL: dchrisrayner@gmail.com
[[https://travis-ci.org/riscy/shx-for-emacs][https://travis-ci.org/riscy/melpazoid.svg?branch=master]]
* Description
/melpazoid/ is a bundle of scripts for testing Emacs packages, primarily
submissions to [[https://github.com/melpa/][MELPA]]. The ambition is to have checks that run in an "clean"
environment, either through CI or through a container on your local machine.
* Use Travis
Fork this repository and open a PR against it that modifies the ~.travis.yml~
file with your recipe and your clone address. The build information on your
pull request will report any discovered issues.
* How to use melpazoid
** Locally
You will need Python ≥ 3.6 (and the ~requests~ package) and Docker. A
container will be built with (hopefully) all of your requirements installed.
The output scroll will report any discovered issues.
* Local install
You will need Python >= 3.6 (along with the ~requests~ package) and Docker.
*** Test a MELPA PR
#+begin_src bash
MELPA_PR_URL='https://github.com/melpa/melpa/pull/6718' make
#+end_src
*** Test a remote package
#+begin_src bash
CLONE_URL='https://github.com/riscy/shx-for-emacs' \
RECIPE='(shx :repo "riscy/shx-for-emacs" :fetcher github)' \
make
#+end_src
*** Test a local package (work in progress)
#+begin_src bash
PKG_PATH='/path/to/package' \
PKG_NAME='package-name' \
make
#+end_src
** Use Travis
You can still use this software if you don't want to install it or its
dependencies. Fork this repository and open a PR against it that modifies the
~.travis.yml~ file with your CLONE_URL and RECIPE, for example:
** Test your MELPA PR
1. Run `make`
2. Copy and paste the URL of your MELPA PR into the console
#+begin_src yaml
env: >-
CLONE_URL='https://github.com/me/my-package-repo
RECIPE='(my-package :repo "me/my-package-repo" :fetcher github)'
#+end_src
A Docker container will be built with (hopefully) all of your requirements
installed. The output scroll will report any discovered issues.
** Test a local package
TODO
** Test a remote package
TODO
The build information on your pull request will report any discovered issues.

View file

@ -298,7 +298,6 @@ def check_maintainer(pr_data: str = None, clone_address: str = None):
def check_license(recipe_files: list, elisp_dir: str, clone_address: str = None):
print('\nLicense:')
repo_licensed = False
if clone_address:
repo_licensed = _check_license_github_api(clone_address)
if not repo_licensed:
@ -318,7 +317,7 @@ def _check_license_github_api(clone_address: str) -> bool:
repo_suffix = match.groups()[0].strip('/')
license_ = requests.get(f"{GITHUB_API}/{repo_suffix}").json().get('license')
if license_ and license_.get('name') in VALID_LICENSES_GITHUB:
print(f"- GitHub API found `{license_.get('name')}`")
print(f"- GitHub API found `{license_.get('name')}` 💯")
return True
if license_:
print(f"- {CLR_WARN}GitHub API found `{license_.get('name')}`")
@ -355,7 +354,7 @@ def _check_license_in_files(elisp_files: list):
print(f"- {CLR_ULINE}{elisp_file}{CLR_OFF} has no license text")
individual_files_licensed = False
else:
print(f"- {os.path.basename(elisp_file)} has {license_} license text")
print(f"- {os.path.basename(elisp_file)} has {license_} license text 💯")
return individual_files_licensed
@ -461,29 +460,28 @@ def yes_p(text: str) -> bool:
return not keep.startswith('n')
def check_remote_package(clone_address: str = None, recipe: str = None):
"""Check an existing MELPA package (once)."""
clone_address = clone_address or input('Clone address: ').strip()
recipe = recipe or input('Recipe (optional?): ') or ''
def check_remote_package(clone_address: str, recipe: str = ''):
"""Check a remotely-hosted package."""
with tempfile.TemporaryDirectory() as elisp_dir:
_clone(clone_address, _branch(recipe), into=elisp_dir)
run_checks(recipe, elisp_dir, clone_address)
def check_local_package(elisp_dir: str = None):
"""Check a local package (once)."""
def check_local_package(elisp_dir: str = None, package_name: str = None):
"""Check a locally-hosted package."""
elisp_dir = elisp_dir or input('Path: ').strip()
assert os.path.isdir(elisp_dir)
package_name = input(f"Name of package at {elisp_dir}: ")
package_name = package_name or input(f"Name of package at {elisp_dir}: ")
recipe = f'({package_name or "NONAME"} :repo "N/A")'
run_checks(recipe, elisp_dir)
def check_melpa_pr_loop():
"""Check MELPA pull requests (indefinitely)."""
for pr_data in _fetch_pull_requests():
recipe = _recipe(pr_data['diff_url']) # type: str
clone_address = _clone_address(pr_data['body']) # type: str
def check_melpa_pr(pr_url: str):
"""Check a PR on MELPA."""
match = re.search(MELPA_PR, pr_url) # MELPA_PR's 0th group has the number
pr_data = requests.get(f"{MELPA_PULL_API}/{match.groups()[0]}").json()
recipe: str = _recipe(pr_data['diff_url'])
clone_address: str = _clone_address(pr_data['body'])
try:
with tempfile.TemporaryDirectory() as elisp_dir:
_clone(clone_address, _branch(recipe), into=elisp_dir)
@ -493,39 +491,43 @@ def check_melpa_pr_loop():
print(f"{CLR_WARN}{err}: is {template} intact?{CLR_OFF}")
def check_melpa_pr_loop():
"""Check MELPA pull requests in a loop."""
for pr_url in _fetch_pull_requests():
check_melpa_pr(pr_url)
def _fetch_pull_requests() -> Iterator[dict]:
"""Repeatedly yield PR URL's."""
# TODO: only supports macOS (needs pbpaste or equivalents)
previous_url = None
previous_pr_url = None
while True:
print('-' * 79)
while True:
match = re.search(MELPA_PR, subprocess.check_output('pbpaste').decode())
url = match.string[: match.end()] if match else None
if match and url != previous_url:
pr_url = match.string[: match.end()] if match else None
if match and pr_url != previous_pr_url:
break
print(
'Watching clipboard for MELPA PR... '
+ ('😐' if random.randint(0, 2) else '🤨'),
end='\r',
)
time.sleep(1)
previous_url = url
print(f"Found MELPA PR {url}")
pr_data = requests.get(f"{MELPA_PULL_API}/{match.groups()[0]}").json()
if not _is_checkable_pr(pr_data['title']):
if not yes_p('PR looks invalid. Try anyway?'):
continue
yield pr_data
previous_pr_url = pr_url
print(f"Found MELPA PR {pr_url}")
yield pr_url
if __name__ == '__main__':
if set(os.environ) & {'CLONE_ADDRESS', 'RECIPE'}:
check_remote_package(
clone_address=os.environ['CLONE_ADDRESS'], recipe=os.environ['RECIPE'],
)
if 'MELPA_PR_URL' in os.environ:
check_melpa_pr(os.environ['MELPA_PR_URL'])
elif 'PKG_PATH' in os.environ and 'PKG_NAME' in os.environ:
check_local_package(os.environ['PKG_PATH'], os.environ['PKG_NAME'])
elif 'CLONE_URL' in os.environ:
if 'RECIPE' in os.environ:
check_remote_package(os.environ['CLONE_URL'], os.environ['RECIPE'])
else:
check_remote_package(os.environ['CLONE_URL'])
else:
check_melpa_pr_loop()
# check_local_package('/Users/rayner/github/shx-for-emacs')