Skip to content
Closed
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
24 changes: 11 additions & 13 deletions .ci/gen_certs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
# ///

import argparse
import os
import sys
from pathlib import Path

import trustme

Expand All @@ -17,43 +17,41 @@ def main() -> None:
parser.add_argument(
"-d",
"--dir",
default=os.getcwd(),
default=".",
help="Directory where certificates and keys are written to. Defaults to cwd.",
)

args = parser.parse_args(sys.argv[1:])
cert_dir = args.dir
cert_dir = Path(args.dir)

if not os.path.isdir(cert_dir):
if not cert_dir.is_dir():
raise ValueError(f"--dir={cert_dir} is not a directory")

key_type = trustme.KeyType["ECDSA"]

# Generate the CA certificate
ca = trustme.CA(key_type=key_type)
# Write the certificate the client should trust
ca_cert_path = os.path.join(cert_dir, "ca.pem")
ca_cert_path = cert_dir / "ca.pem"
ca.cert_pem.write_to_path(path=ca_cert_path)

# Generate the server certificate
server_cert = ca.issue_cert("localhost", "127.0.0.1", "::1", key_type=key_type)
# Write the certificate and private key the server should use
server_key_path = os.path.join(cert_dir, "server.key")
server_cert_path = os.path.join(cert_dir, "server.pem")
server_key_path = cert_dir / "server.key"
server_cert_path = cert_dir / "server.pem"
server_cert.private_key_pem.write_to_path(path=server_key_path)
with open(server_cert_path, mode="w") as f:
f.truncate()
server_cert_path.write_text("")
for blob in server_cert.cert_chain_pems:
blob.write_to_path(path=server_cert_path, append=True)

# Generate the client certificate
client_cert = ca.issue_cert("admin@example.com", common_name="admin", key_type=key_type)
# Write the certificate and private key the client should use
client_key_path = os.path.join(cert_dir, "client.key")
client_cert_path = os.path.join(cert_dir, "client.pem")
client_key_path = cert_dir / "client.key"
client_cert_path = cert_dir / "client.pem"
client_cert.private_key_pem.write_to_path(path=client_key_path)
with open(client_cert_path, mode="w") as f:
f.truncate()
client_cert_path.write_text("")
for blob in client_cert.cert_chain_pems:
blob.write_to_path(path=client_cert_path, append=True)

Expand Down
4 changes: 4 additions & 0 deletions .ci/run_container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ else
fi
export PULP_CONTENT_ORIGIN

PULP_SECRET_KEY="$(python3 -c "import secrets; print(secrets.token_urlsafe(50))")"
export PULP_SECRET_KEY

"${CONTAINER_RUNTIME}" \
run ${RM:+--rm} \
--env S6_KEEP_ENV=1 \
Expand All @@ -79,6 +82,7 @@ export PULP_CONTENT_ORIGIN
${PULP_DOMAIN_ENABLED:+--env PULP_DOMAIN_ENABLED} \
${PULP_ENABLED_PLUGINS:+--env PULP_ENABLED_PLUGINS} \
--env PULP_CONTENT_ORIGIN \
--env PULP_SECRET_KEY \
--detach \
--name "pulp-ephemeral" \
--volume "${PULP_CLI_TEST_TMPDIR}/settings:/etc/pulp${SELINUX:+:Z}" \
Expand Down
36 changes: 36 additions & 0 deletions .ci/scripts/check_changelog_snippets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/env python3
# /// script
# requires-python = ">=3.11"
# dependencies = [
# ]
# ///
import re
import sys
from pathlib import Path

import tomllib

EXCEPTIONS = [
".TEMPLATE.md",
".gitkeep",
"pulp-glue-deb",
]


def snippet_valid(path: Path, changelog_exts: list[str]) -> bool:
return (path.name in EXCEPTIONS) or (
path.suffix in changelog_exts
and (path.stem.startswith("+") or re.fullmatch(r"\d*", path.stem))
)


if __name__ == "__main__":
with Path("pyproject.toml").open("rb") as fp:
pyproject_toml = tomllib.load(fp)
changelog_exts = [
f".{item['directory']}" for item in pyproject_toml["tool"]["towncrier"]["type"]
]
matches = Path("CHANGES").rglob("*")
invalid_snippets = ", ".join(f"'{s}'" for s in matches if not snippet_valid(s, changelog_exts))
if invalid_snippets:
sys.exit(f"LINT: Invalid changelog entries: {invalid_snippets}.")
4 changes: 2 additions & 2 deletions .ci/scripts/check_cli_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ def dependencies(path: Path) -> t.Iterator[Requirement]:
base_path = Path(__file__).parent.parent.parent
glue_path = base_path / GLUE_DIR

cli_dependency = next((r for r in dependencies(base_path) if r.name == "pulp-cli"))
glue_dependency = next((r for r in dependencies(glue_path) if r.name == "pulp-glue"))
cli_dependency = next(r for r in dependencies(base_path) if r.name == "pulp-cli")
glue_dependency = next(r for r in dependencies(glue_path) if r.name == "pulp-glue")

if cli_dependency.specifier != glue_dependency.specifier:
print("🪢 CLI and GLUE dependencies mismatch:")
Expand Down
4 changes: 2 additions & 2 deletions .ci/scripts/check_click_for_mypy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# "packaging>=25.0,<25.1",
# ]
# ///

import sys
from importlib import metadata

from packaging.version import Version
Expand All @@ -15,4 +15,4 @@
if click_version < Version("8.1.1"):
print("🚧 Linting with mypy is currently only supported with click>=8.1.1. 🚧")
print("🔧 Please run `pip install click>=8.1.1` first. 🔨")
exit(1)
sys.exit(1)
23 changes: 12 additions & 11 deletions .ci/scripts/collect_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
# ///

import itertools
import os
import re
import typing as t
from pathlib import Path

import tomllib
from git import GitCommandError, Repo
from packaging.version import Version
from packaging.version import parse as parse_version

# Read Towncrier settings
with open("pyproject.toml", "rb") as fp:
with Path("pyproject.toml").open("rb") as fp:
tc_settings = tomllib.load(fp)["tool"]["towncrier"]

CHANGELOG_FILE = tc_settings.get("filename", "NEWS.rst")
Expand Down Expand Up @@ -51,37 +53,36 @@
)


def get_changelog(repo, branch):
def get_changelog(repo: Repo, branch: str) -> str:
branch_tc_settings = tomllib.loads(repo.git.show(f"{branch}:pyproject.toml"))["tool"][
"towncrier"
]
branch_changelog_file = branch_tc_settings.get("filename", "NEWS.rst")
return repo.git.show(f"{branch}:{branch_changelog_file}") + "\n"


def _tokenize_changes(splits):
def _tokenize_changes(splits: list[str]) -> t.Iterator[list[Version | str]]:
assert len(splits) % 3 == 0
for i in range(len(splits) // 3):
title = splits[3 * i]
version = parse_version(splits[3 * i + 1])
yield [version, title + splits[3 * i + 2]]


def split_changelog(changelog):
def split_changelog(changelog: str) -> tuple[str, list[list[Version | str]]]:
preamble, rest = changelog.split(START_STRING, maxsplit=1)
split_rest = re.split(TITLE_REGEX, rest)
return preamble + START_STRING + split_rest[0], list(_tokenize_changes(split_rest[1:]))


def main():
repo = Repo(os.getcwd())
def main() -> None:
repo = Repo(Path.cwd())
remote = repo.remotes[0]
branches = [ref for ref in remote.refs if re.match(r"^([0-9]+)\.([0-9]+)$", ref.remote_head)]
branches.sort(key=lambda ref: parse_version(ref.remote_head), reverse=True)
branches = [ref.name for ref in branches]

with open(CHANGELOG_FILE) as f:
main_changelog = f.read()
main_changelog = Path(CHANGELOG_FILE).read_text()
preamble, main_changes = split_changelog(main_changelog)
old_length = len(main_changes)

Expand All @@ -92,7 +93,7 @@ def main():
except GitCommandError:
print("No changelog found on this branch.")
continue
dummy, changes = split_changelog(changelog)
_dummy, changes = split_changelog(changelog)
new_changes = sorted(main_changes + changes, key=lambda x: x[0], reverse=True)
# Now remove duplicates (retain the first one)
main_changes = [new_changes[0]]
Expand All @@ -103,7 +104,7 @@ def main():
new_length = len(main_changes)
if old_length < new_length:
print(f"{new_length - old_length} new versions have been added.")
with open(CHANGELOG_FILE, "w") as fp:
with Path(CHANGELOG_FILE).open("w") as fp:
fp.write(preamble)
fp.writelines(change[1] for change in main_changes)

Expand Down
4 changes: 2 additions & 2 deletions .ci/scripts/pr_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
from git import Repo


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

with open("pyproject.toml", "rb") as fp:
with Path("pyproject.toml").open("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+)")
Expand Down
2 changes: 1 addition & 1 deletion .ci/scripts/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ towncrier build --yes --version "${NEW_VERSION}"
bump-my-version bump release --commit --message "Release {new_version}" --tag --tag-name "{new_version}" --tag-message "Release {new_version}" --allow-dirty
bump-my-version bump patch --commit

git push origin "${BRANCH}" "${NEW_VERSION}"
git push --atomic origin "${BRANCH}" "${NEW_VERSION}"
17 changes: 10 additions & 7 deletions .ci/scripts/validate_commit_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
from pathlib import Path

import tomllib
from github import Github

with open("pyproject.toml", "rb") as fp:
with Path("pyproject.toml").open("rb") as fp:
PYPROJECT_TOML = tomllib.load(fp)
KEYWORDS = ["fixes", "closes"]
BLOCKING_REGEX = [
Expand All @@ -36,11 +35,13 @@
if any(re.match(pattern, message) for pattern in BLOCKING_REGEX):
sys.exit("This PR is not ready for consumption.")

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


def check_status(issue: str) -> None:
from github import Github

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

gi = repo.get_issue(int(issue))
if gi.pull_request:
sys.exit(f"Error: issue #{issue} is a pull request.")
Expand All @@ -61,15 +62,17 @@ def check_changelog(issue: str) -> None:
print(f"Checking commit message for {sha[0:7]}.")

# validate the issue attached to the commit
issue_regex = r"(?:{keywords})[\s:]+#(\d+)".format(keywords=("|").join(KEYWORDS))
issue_regex = r"(?:{keywords})[\s:]+#(\d+)".format(
keywords=("|").join(re.escape(k) for k in KEYWORDS)
)
issues = re.findall(issue_regex, message, re.IGNORECASE)
cherry_pick_regex = r"^\s*\(cherry picked from commit [0-9a-f]*\)\s*$"
cherry_pick = re.search(cherry_pick_regex, message, re.MULTILINE)

if issues:
for issue in issues:
if not cherry_pick:
check_status(issue)
check_changelog(issue)
check_status(issue)

print(f"Commit message for {sha[0:7]} passed.")
10 changes: 8 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ name: "Build"
on:
workflow_call:

defaults:
run:
working-directory: "pulp-cli-deb"

jobs:
build:
runs-on: "ubuntu-latest"
steps:
- name: "Checkout"
uses: "actions/checkout@v6"
with:
path: "pulp-cli-deb"
- name: "Set up Python"
uses: "actions/setup-python@v6"
with:
Expand All @@ -22,14 +28,14 @@ jobs:
- name: "Build wheels"
run: |
make build
touch .root
touch ../.root
- name: "Upload wheels"
uses: "actions/upload-artifact@v6"
with:
name: "pulp_cli_packages"
path: |
.root
dist/
pulp-cli-deb/dist/
if-no-files-found: "error"
retention-days: 5
...
9 changes: 6 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
name: "CodeQL"

on:
push:
branches:
- "main"
workflow_call:

defaults:
run:
working-directory: "pulp-cli-deb"

jobs:
analyze:
name: "Analyze"
Expand All @@ -19,6 +20,8 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v6"
with:
path: "pulp-cli-deb"
- name: "Initialize CodeQL"
uses: "github/codeql-action/init@v4"
with:
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/collect_changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@ on:
workflow_call:
workflow_dispatch:

defaults:
run:
working-directory: "pulp-cli-deb"

jobs:
collect-changes:
permissions:
contents: "write"
pull-requests: "write"
runs-on: "ubuntu-latest"
steps:
- name: "Checkout"
uses: "actions/checkout@v6"
with:
path: "pulp-cli-deb"
fetch-depth: 0
- name: "Set up Python"
uses: "actions/setup-python@v6"
Expand All @@ -32,16 +40,16 @@ jobs:
uses: "peter-evans/create-pull-request@v8"
id: "create_pr"
with:
token: "${{ secrets.RELEASE_TOKEN }}"
title: "Update Changelog"
body: ""
branch: "update_changes"
delete-branch: true
path: "pulp-cli-deb"
- name: "Mark PR automerge"
run: |
gh pr merge --rebase --auto "${{ steps.create_pr.outputs.pull-request-number }}"
if: "steps.create_pr.outputs.pull-request-number"
env:
GH_TOKEN: "${{ secrets.RELEASE_TOKEN }}"
GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
continue-on-error: true
...
Loading
Loading