on:
push:
branches: [main]
- paths-ignore: ["docs/**", "tests/**", "*.md"]
+ paths-ignore: ["docs/**", "tests/**", "**.md", "**.rst"]
pull_request:
- paths-ignore: ["docs/**", "tests/**", "*.md"]
+ paths-ignore: ["docs/**", "tests/**", "**.md", "**.rst"]
workflow_dispatch:
inputs:
description: "Custom Black arguments (eg. -S)"
required: false
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
+ cancel-in-progress: true
+
jobs:
analysis:
name: analysis / linux
runs-on: ubuntu-latest
+ env:
+ # Clang is less picky with the C code it's given than gcc (and may
+ # generate faster binaries too).
+ CC: clang-12
steps:
- name: Checkout this repository (full clone)
python -m pip install pip --upgrade
python -m pip install https://github.com/ichard26/diff-shades/archive/stable.zip
python -m pip install click packaging urllib3
+ python -m pip install -r .github/mypyc-requirements.txt
# After checking out old revisions, this might not exist so we'll use a copy.
cat scripts/diff_shades_gha_helper.py > helper.py
git config user.name "diff-shades-gha"
path: ${{ steps.config.outputs.baseline-analysis }}
key: ${{ steps.config.outputs.baseline-cache-key }}
- - name: Install baseline revision
+ - name: Build and install baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
- run: ${{ steps.config.outputs.baseline-setup-cmd }} && python -m pip install .
+ run: >
+ ${{ steps.config.outputs.baseline-setup-cmd }}
+ && python setup.py --use-mypyc bdist_wheel
+ && python -m pip install dist/*.whl && rm build dist -r
- name: Analyze baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
diff-shades analyze -v --work-dir projects-cache/
${{ steps.config.outputs.baseline-analysis }} -- ${{ github.event.inputs.baseline-args }}
- - name: Install target revision
+ - name: Build and install target revision
env:
GITHUB_TOKEN: ${{ github.token }}
- run: ${{ steps.config.outputs.target-setup-cmd }} && python -m pip install .
+ run: >
+ ${{ steps.config.outputs.target-setup-cmd }}
+ && python setup.py --use-mypyc bdist_wheel
+ && python -m pip install dist/*.whl
- name: Analyze target revision
run: >
python helper.py comment-body
${{ steps.config.outputs.baseline-analysis }} ${{ steps.config.outputs.target-analysis }}
${{ steps.config.outputs.baseline-sha }} ${{ steps.config.outputs.target-sha }}
+ ${{ github.event.pull_request.number }}
- name: Upload summary file (PR only)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v2
with:
- name: .pr-comment-body.md
- path: .pr-comment-body.md
+ name: .pr-comment.json
+ path: .pr-comment.json
# This is last so the diff-shades-comment workflow can still work even if we
# end up detecting failed files and failing the run.
import zipfile
from io import BytesIO
from pathlib import Path
-from typing import Any, Dict, Optional, Tuple
+from typing import Any, Optional, Tuple
import click
import urllib3
else:
from typing_extensions import Final, Literal
-COMMENT_BODY_FILE: Final = ".pr-comment-body.md"
+COMMENT_FILE: Final = ".pr-comment.json"
DIFF_STEP_NAME: Final = "Generate HTML diff report"
DOCS_URL: Final = (
"https://black.readthedocs.io/en/latest/"
print(f"::set-output name={name}::{value}")
-def http_get(
- url: str,
- is_json: bool = True,
- headers: Optional[Dict[str, str]] = None,
- **kwargs: Any,
-) -> Any:
- headers = headers or {}
+def http_get(url: str, is_json: bool = True, **kwargs: Any) -> Any:
+ headers = kwargs.get("headers") or {}
headers["User-Agent"] = USER_AGENT
if "github" in url:
if GH_API_TOKEN:
headers["Authorization"] = f"token {GH_API_TOKEN}"
headers["Accept"] = "application/vnd.github.v3+json"
- r = http.request("GET", url, headers=headers, **kwargs)
+ kwargs["headers"] = headers
+
+ r = http.request("GET", url, **kwargs)
if is_json:
data = json.loads(r.data.decode("utf-8"))
else:
@click.argument("target", type=click.Path(exists=True, path_type=Path))
@click.argument("baseline-sha")
@click.argument("target-sha")
+@click.argument("pr-num", type=int)
def comment_body(
- baseline: Path, target: Path, baseline_sha: str, target_sha: str
+ baseline: Path, target: Path, baseline_sha: str, target_sha: str, pr_num: int
) -> None:
# fmt: off
cmd = [
f"[**What is this?**]({DOCS_URL}) | [Workflow run]($workflow-run-url) |"
" [diff-shades documentation](https://github.com/ichard26/diff-shades#readme)"
)
- print(f"[INFO]: writing half-completed comment body to {COMMENT_BODY_FILE}")
- with open(COMMENT_BODY_FILE, "w", encoding="utf-8") as f:
- f.write(body)
+ print(f"[INFO]: writing comment details to {COMMENT_FILE}")
+ with open(COMMENT_FILE, "w", encoding="utf-8") as f:
+ json.dump({"body": body, "pr-number": pr_num}, f)
@main.command("comment-details", help="Get PR comment resources from a workflow run.")
@click.argument("run-id")
def comment_details(run_id: str) -> None:
data = http_get(f"https://api.github.com/repos/{REPO}/actions/runs/{run_id}")
- if data["event"] != "pull_request":
+ if data["event"] != "pull_request" or data["conclusion"] == "cancelled":
set_output("needs-comment", "false")
return
set_output("needs-comment", "true")
- pulls = data["pull_requests"]
- assert len(pulls) == 1
- pr_number = pulls[0]["number"]
- set_output("pr-number", str(pr_number))
-
- jobs_data = http_get(data["jobs_url"])
- assert len(jobs_data["jobs"]) == 1, "multiple jobs not supported nor tested"
- job = jobs_data["jobs"][0]
+ jobs = http_get(data["jobs_url"])["jobs"]
+ assert len(jobs) == 1, "multiple jobs not supported nor tested"
+ job = jobs[0]
steps = {s["name"]: s["number"] for s in job["steps"]}
diff_step = steps[DIFF_STEP_NAME]
diff_url = job["html_url"] + f"#step:{diff_step}:1"
artifacts_data = http_get(data["artifacts_url"])["artifacts"]
artifacts = {a["name"]: a["archive_download_url"] for a in artifacts_data}
- body_url = artifacts[COMMENT_BODY_FILE]
- body_zip = BytesIO(http_get(body_url, is_json=False))
- with zipfile.ZipFile(body_zip) as zfile:
- with zfile.open(COMMENT_BODY_FILE) as rf:
- body = rf.read().decode("utf-8")
+ comment_url = artifacts[COMMENT_FILE]
+ comment_zip = BytesIO(http_get(comment_url, is_json=False))
+ with zipfile.ZipFile(comment_zip) as zfile:
+ with zfile.open(COMMENT_FILE) as rf:
+ comment_data = json.loads(rf.read().decode("utf-8"))
+
+ set_output("pr-number", str(comment_data["pr-number"]))
+ body = comment_data["body"]
# It's more convenient to fill in these fields after the first workflow is done
# since this command can access the workflows API (doing it in the main workflow
# while it's still in progress seems impossible).
body = body.replace("$workflow-run-url", data["html_url"])
body = body.replace("$job-diff-url", diff_url)
- # # https://github.community/t/set-output-truncates-multiline-strings/16852/3
+ # https://github.community/t/set-output-truncates-multiline-strings/16852/3
escaped = body.replace("%", "%25").replace("\n", "%0A").replace("\r", "%0D")
set_output("comment-body", escaped)