Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport [3.49] Streamline CI #668

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .ci/scripts/pr_labels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/env python3

# This script is running with elevated privileges from the main branch against pull requests.

import re
import sys
import tomllib
from pathlib import Path

from git import Repo


def main():
assert len(sys.argv) == 3

with open("pyproject.toml", "rb") as fp:
PYPROJECT_TOML = tomllib.load(fp)
BLOCKING_REGEX = re.compile(r"DRAFT|WIP|NO\s*MERGE|DO\s*NOT\s*MERGE|EXPERIMENT")
ISSUE_REGEX = re.compile(r"(?:fixes|closes)[\s:]+#(\d+)")
CHERRY_PICK_REGEX = re.compile(r"^\s*\(cherry picked from commit [0-9a-f]*\)\s*$")
try:
CHANGELOG_EXTS = {
f".{item['directory']}" for item in PYPROJECT_TOML["tool"]["towncrier"]["type"]
}
except KeyError:
CHANGELOG_EXTS = {"feature", "bugfix", "doc", "removal", "misc"}

repo = Repo(".")

base_commit = repo.commit(sys.argv[1])
head_commit = repo.commit(sys.argv[2])

pr_commits = list(repo.iter_commits(f"{base_commit}..{head_commit}"))

labels = {
"multi-commit": len(pr_commits) > 1,
"cherry-pick": False,
"no-issue": False,
"no-changelog": False,
"wip": False,
}
for commit in pr_commits:
labels["wip"] |= BLOCKING_REGEX.search(commit.summary) is not None
no_issue = ISSUE_REGEX.search(commit.message, re.IGNORECASE) is None
labels["no-issue"] |= no_issue
cherry_pick = CHERRY_PICK_REGEX.search(commit.message) is not None
labels["cherry-pick"] |= cherry_pick
changelog_snippets = [
k
for k in commit.stats.files
if k.startswith("CHANGES/") and Path(k).suffix in CHANGELOG_EXTS
]
labels["no-changelog"] |= not changelog_snippets

print("ADD_LABELS=" + ",".join((k for k, v in labels.items() if v)))
print("REMOVE_LABELS=" + ",".join((k for k, v in labels.items() if not v)))


if __name__ == "__main__":
main()
57 changes: 26 additions & 31 deletions .ci/scripts/validate_commit_message.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
# WARNING: DO NOT EDIT!
#
# This file was generated by plugin_template, and is managed by bootstrap.py. Please use
# bootstrap.py to update this file.
# This file was generated by plugin_template and copied over to this repository :)
#
# For more info visit https://github.com/pulp/plugin_template

import glob
import os
import re
import subprocess
import sys

from pathlib import Path
import subprocess
import os
import warnings
from github import Github

KEYWORDS = ["fixes", "closes", "re", "ref"]
NO_ISSUE = "[noissue]"
CHANGELOG_EXTS = [".feature", ".bugfix", ".doc", ".removal", ".misc", ".deprecation", ".dev"]
CHANGELOG_EXTS = [".feature", ".bugfix", ".doc", ".removal", ".misc", ".deprecation"]
KEYWORDS = ["fixes", "closes"]

sha = sys.argv[1]
message = subprocess.check_output(["git", "log", "--format=%B", "-n 1", sha]).decode("utf-8")

g = Github(os.environ.get("GITHUB_TOKEN"))
repo = g.get_repo("pulp/pulp-oci-images")

Expand All @@ -27,41 +26,37 @@ def __check_status(issue):
gi = repo.get_issue(int(issue))
if gi.pull_request:
sys.exit(f"Error: issue #{issue} is a pull request.")
if gi.closed_at:
if gi.closed_at and "cherry picked from commit" not in message:
warnings.warn(
"When backporting, use the -x flag to append a line that says "
"'(cherry picked from commit ...)' to the original commit message."
)
sys.exit(f"Error: issue #{issue} is closed.")


def __check_changelog(issue):
matches = glob.glob("CHANGES/{issue}.*".format(issue=issue))
matches = list(Path("CHANGES").rglob(f"{issue}.*"))

if len(matches) < 1:
sys.exit("Could not find changelog entry in CHANGES/ for {issue}.".format(issue=issue))
sys.exit(f"Could not find changelog entry in CHANGES/ for {issue}.")
for match in matches:
if os.path.splitext(match)[1] not in CHANGELOG_EXTS:
sys.exit("Invalid extension for changelog entry '{match}'.".format(match=match))
if match.suffix not in CHANGELOG_EXTS:
sys.exit(f"Invalid extension for changelog entry '{match}'.")
if match.suffix == ".feature" and "cherry picked from commit" in message:
sys.exit(f"Can not backport '{match}' as it is a feature.")


print("Checking commit message for {sha}.".format(sha=sha[0:7]))

# validate the issue attached to the commit
if NO_ISSUE in message:
print("Commit {sha} has no issue attached. Skipping issue check".format(sha=sha[0:7]))
elif "Merge" in message and "cherry picked from commit" in message:
pass
else:
regex = r"(?:{keywords})[\s:]+#(\d+)".format(keywords=("|").join(KEYWORDS))
pattern = re.compile(regex, re.IGNORECASE)
regex = r"(?:{keywords})[\s:]+#(\d+)".format(keywords=("|").join(KEYWORDS))
pattern = re.compile(regex, re.IGNORECASE)

issues = pattern.findall(message)
issues = pattern.findall(message)

if issues:
for issue in pattern.findall(message):
__check_status(issue)
__check_changelog(issue)
else:
sys.exit(
"Error: no attached issues found for {sha}. If this was intentional, add "
" '{tag}' to the commit message.".format(sha=sha[0:7], tag=NO_ISSUE)
)
if issues:
for issue in pattern.findall(message):
__check_status(issue)
__check_changelog(issue)

print("Commit message for {sha} passed.".format(sha=sha[0:7]))
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: pulp-oci-images CI

on:
pull_request:
paths:
- "images/**"
- ".github/**"
- ".ci/**"
env:
COLORTERM: 'yes'
TERM: 'xterm-256color'
Expand Down
66 changes: 66 additions & 0 deletions .github/workflows/pr_checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# WARNING: DO NOT EDIT!
#
# This file was generated by plugin_template and copied over to this repository :)
#
# For more info visit https://github.com/pulp/plugin_template

---
name: "Pulp-OCI-Images PR static checks"
on:
pull_request_target:
types: ["opened", "synchronize", "reopened"]

# This workflow runs with elevated permissions.
# Do not even think about running a single bit of code from the PR.
# Static analysis should be fine however.

concurrency:
group: "${{ github.event.pull_request.number }}-${{ github.workflow }}"
cancel-in-progress: true

jobs:
apply_labels:
runs-on: "ubuntu-latest"
name: "Label PR"
permissions:
pull-requests: "write"
steps:
- uses: "actions/checkout@v4"
with:
fetch-depth: 0
- uses: "actions/setup-python@v5"
with:
python-version: "3.11"
- name: "Determine PR labels"
run: |
pip install GitPython==3.1.42
git fetch origin ${{ github.event.pull_request.head.sha }}
python .ci/scripts/pr_labels.py "origin/${{ github.base_ref }}" "${{ github.event.pull_request.head.sha }}" >> "$GITHUB_ENV"
- uses: "actions/github-script@v7"
name: "Apply PR Labels"
with:
script: |
const { ADD_LABELS, REMOVE_LABELS } = process.env;

if (REMOVE_LABELS.length) {
for await (const labelName of REMOVE_LABELS.split(",")) {
try {
await github.rest.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: labelName,
});
} catch(err) {
}
}
}
if (ADD_LABELS.length) {
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ADD_LABELS.split(","),
});
}
...
Loading