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

Setup CODEOWNERS #1669

Merged
merged 9 commits into from
Dec 6, 2024
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
19 changes: 19 additions & 0 deletions .github/workflows/check-task-owners.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,22 @@ jobs:
- name: Check task owners
run: |
./hack/check-task-owners.sh
- name: Check renovate.json groups
run: |
#!/bin/bash
set -euo pipefail
renovate_content=$(cat renovate.json)
./hack/update_renovate_json_based_on_codeowners.py -o renovate.json
uptodate=$(jq --argjson previous "$renovate_content" '$previous == .' renovate.json)
echo "renovate.json is up to date: $uptodate"
if [[ $uptodate == false ]]; then
echo
git --no-pager diff -- renovate.json
echo
echo "To apply the updates, run: ./hack/update_renovate_json_based_on_codeowners.py -o renovate.json"
exit 1
fi
115 changes: 115 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

* @konflux-ci/build-maintainers

# renovate groupName=build
/task/acs-deploy-check @konflux-ci/build-maintainers
/task/acs-image-check @konflux-ci/build-maintainers
/task/acs-image-scan @konflux-ci/build-maintainers
/task/apply-tags @konflux-ci/build-maintainers
/task/build-image-index @konflux-ci/build-maintainers
/task/build-image-manifest @konflux-ci/build-maintainers
/task/buildah @konflux-ci/build-maintainers
/task/buildah-10gb @konflux-ci/build-maintainers
/task/buildah-20gb @konflux-ci/build-maintainers
/task/buildah-24gb @konflux-ci/build-maintainers
/task/buildah-6gb @konflux-ci/build-maintainers
/task/buildah-8gb @konflux-ci/build-maintainers
/task/buildah-min @konflux-ci/build-maintainers
/task/buildah-oci-ta @konflux-ci/build-maintainers
/task/buildah-remote @konflux-ci/build-maintainers
/task/buildah-remote-oci-ta @konflux-ci/build-maintainers
/task/buildah-rhtap @konflux-ci/build-maintainers
/task/download-sbom-from-url-in-attestation @konflux-ci/build-maintainers
/task/gather-deploy-images @konflux-ci/build-maintainers
/task/git-clone @konflux-ci/build-maintainers
/task/git-clone-oci-ta @konflux-ci/build-maintainers
/task/init @konflux-ci/build-maintainers
/task/push-dockerfile @konflux-ci/build-maintainers
/task/push-dockerfile-oci-ta @konflux-ci/build-maintainers
/task/show-sbom @konflux-ci/build-maintainers
/task/show-sbom-rhdh @konflux-ci/build-maintainers
/task/slack-webhook-notification @konflux-ci/build-maintainers
/task/source-build @konflux-ci/build-maintainers
/task/source-build-oci-ta @konflux-ci/build-maintainers
/task/summary @konflux-ci/build-maintainers
/task/update-deployment @konflux-ci/build-maintainers
/task/update-infra-deployments @konflux-ci/build-maintainers
/task/upload-sbom-to-trustification @konflux-ci/build-maintainers

# renovate groupName=build
/task/prefetch-dependencies @konflux-ci/build-maintainers @brunoapimentel @eskultety @taylormadore
/task/prefetch-dependencies-oci-ta @konflux-ci/build-maintainers @brunoapimentel @eskultety @taylormadore

# renovate groupName=build
/task/generate-labels @konflux-ci/build-maintainers @ralphbean

# renovate groupName=ec
/task/tkn-bundle @konflux-ci/ec
/task/tkn-bundle-oci-ta @konflux-ci/ec
/task/verify-enterprise-contract @konflux-ci/ec

# renovate groupName=integration
/task/clair-scan @konflux-ci/integration-service-maintainers
/task/clamav-scan @konflux-ci/integration-service-maintainers
/task/deprecated-image-check @konflux-ci/integration-service-maintainers
/task/fbc-related-image-check @konflux-ci/integration-service-maintainers
/task/fbc-validation @konflux-ci/integration-service-maintainers
/task/inspect-image @konflux-ci/integration-service-maintainers
/task/sbom-json-check @konflux-ci/integration-service-maintainers
/task/validate-fbc @konflux-ci/integration-service-maintainers

# renovate groupName=integration
/task/coverity-availability-check @konflux-ci/integration-service-maintainers @kdudka
/task/coverity-availability-check-oci-ta @konflux-ci/integration-service-maintainers @kdudka
/task/sast-coverity-check @konflux-ci/integration-service-maintainers @kdudka
/task/sast-coverity-check-oci-ta @konflux-ci/integration-service-maintainers @kdudka
/task/sast-shell-check @konflux-ci/integration-service-maintainers @kdudka
/task/sast-shell-check-oci-ta @konflux-ci/integration-service-maintainers @kdudka
/task/sast-snyk-check @konflux-ci/integration-service-maintainers @kdudka
/task/sast-snyk-check-oci-ta @konflux-ci/integration-service-maintainers @kdudka
/task/sast-unicode-check @konflux-ci/integration-service-maintainers @kdudka
/task/sast-unicode-check-oci-ta @konflux-ci/integration-service-maintainers @kdudka

# renovate groupName=preflight
/task/ecosystem-cert-preflight-checks @acornett21 @bcrochet @komish @skattoju

# renovate groupName=eaas
/task/provision-env-with-ephemeral-namespace @amisstea @avi-biton @gbenhaim @omeramsc @yftacherzog

# renovate groupName=rpm-tasks
/task/generate-odcs-compose @amisstea @avi-biton @gbenhaim @yftacherzog
/task/rpms-signature-scan @amisstea @avi-biton @gbenhaim @yftacherzog
/task/verify-signed-rpms @amisstea @avi-biton @gbenhaim @yftacherzog

# renovate groupName=eaas
/stepactions/eaas-copy-secrets-to-ephemeral-cluster @amisstea @avi-biton @hmariset @omeramsc @yftacherzog
/stepactions/eaas-create-ephemeral-cluster-hypershift-aws @amisstea @avi-biton @hmariset @omeramsc @yftacherzog
/stepactions/eaas-get-ephemeral-cluster-credentials @amisstea @avi-biton @hmariset @omeramsc @yftacherzog
/stepactions/eaas-get-latest-openshift-version-by-prefix @amisstea @avi-biton @hmariset @omeramsc @yftacherzog
/stepactions/eaas-get-supported-ephemeral-cluster-versions @amisstea @avi-biton @hmariset @omeramsc @yftacherzog
/task/eaas-provision-space @amisstea @avi-biton @hmariset @omeramsc @yftacherzog

# renovate groupName=build-vm-image
/task/build-vm-image @arewm @brianwcook @ralphbean @scoheb

# renovate groupName=rpm-ostree
/task/rpm-ostree @cgwalters
/task/rpm-ostree-oci-ta @cgwalters

# renovate groupName=opm
/task/operator-sdk-generate-bundle @gurnben @jbpratt
/task/opm-get-bundle-version @gurnben @jbpratt
/task/opm-render-bundles @gurnben @jbpratt

# renovate groupName=maven
/task/build-maven-zip @ligangty @yma96
/task/build-maven-zip-oci-ta @ligangty @yma96

# renovate groupName=oci-copy
/task/oci-copy @ralphbean
/task/oci-copy-oci-ta @ralphbean

# These are auto-generated and often require changes when tasks change.
# Allow anyone with write access to approve the changes.
/pipelines/*/README.md
48 changes: 30 additions & 18 deletions hack/check-task-owners.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail

check_result=$(mktemp)
shopt -s nullglob

# Check the OWNERS file is present for each task
find task/ -mindepth 1 -maxdepth 1 -type d | \
while read -r task_dir; do
owners_file="$task_dir/OWNERS"
if [ ! -e "$owners_file" ]; then
echo "error: missing owners file $owners_file" >>"$check_result"
continue
fi
approvers=$(yq '.approvers[]' $owners_file)
reviewers=$(yq '.reviwers[]' $owners_file)
if [ -z "$approvers" ] && [ -z "$reviewers" ]; then
echo "error: $task_dir/OWNERS don't have atleast 1 approver and 1 reviewer" >>"$check_result"
codeowners_to_gitignore() {
# drop comments and the root '*' pattern, extract the pattern from each line
awk '/^[^#]/ && !/^\*\s/ { print $1 }' "$1"
}

temp_gitignore=$(mktemp --tmpdir "codeowners-gitignore.XXXX")
trap 'rm "$temp_gitignore"' EXIT
codeowners_to_gitignore CODEOWNERS > "$temp_gitignore"

important_dirs=$(
for f in task/* stepactions/*; do
if [[ -d "$f" ]]; then
echo "$f"
fi
done
done | sort
)

if [ -s "$check_result" ]; then
cat "$check_result"
echo "Please add OWNERS file with atleast 1 approver and 1 reviewer"
codeowned_dirs=$(
# CODEOWNERS is roughly a .gitignore file, so check which dirs are "ignored" by CODEOWNERS
echo "$important_dirs" |
git -c "core.excludesFile=$temp_gitignore" check-ignore --no-index --stdin |
sort
)

missing_owners=$(comm -23 <(echo "$important_dirs") <(echo "$codeowned_dirs"))

if [[ -n "$missing_owners" ]]; then
echo "Missing CODEOWNERS:" >&2
# shellcheck disable=SC2001 # can't use ${variable//search/replace} instead
sed 's/^/ /' <<< "$missing_owners" >&2
exit 1
fi

113 changes: 113 additions & 0 deletions hack/update_renovate_json_based_on_codeowners.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python
import argparse
import json
import re
from itertools import groupby
from pathlib import Path
from typing import Any, Iterable, Iterator, TypedDict


class PackageRule(TypedDict):
groupName: str
matchFileNames: list[str]


def get_renovate_packagerules(codeowners_content: str) -> Iterator[PackageRule]:
lines = map(str.strip, codeowners_content.splitlines())
rules: list[PackageRule] = []

for isempty, lines_group in groupby(lines, key=lambda line: not line):
if not isempty and (rule := _process_owner_group(lines_group)):
rules.append(rule)

rules.sort(key=lambda rule: rule["groupName"])

for groupname, rules_group in groupby(rules, key=lambda rule: rule["groupName"]):
merged_patterns = set()
for rule in rules_group:
merged_patterns.update(rule["matchFileNames"])
yield {"groupName": groupname, "matchFileNames": sorted(merged_patterns)}


def _process_owner_group(group: Iterable[str]) -> PackageRule | None:
"""Process a group of CODEOWNERS.

If the group has a '# renovate groupName=' directive, return a packageRules object.
Otherwise, return None.
"""
renovate_directive_pat = re.compile(r"#\s*renovate\s+groupName=(.*)")

patterns = []
groupname = None

for line in group:
if not line.startswith("#"):
pattern, *_ = line.split(maxsplit=1)
patterns.append(pattern)
elif m := renovate_directive_pat.match(line):
groupname = m.group(1)

if not groupname:
return None

patterns = list(map(_codeowners_pattern_to_glob_pattern, patterns))
return {"groupName": groupname, "matchFileNames": patterns}



def _codeowners_pattern_to_glob_pattern(codeowners_pattern: str) -> str:
if codeowners_pattern.startswith("/"):
glob_pattern = codeowners_pattern.lstrip("/")
else:
glob_pattern = f"**/{codeowners_pattern}"

if not glob_pattern.endswith("**") and any(p.is_dir() for p in Path().glob(glob_pattern)):
glob_pattern += "/**"

return glob_pattern


def merge_to_existing_rules(
existing_rules: Iterable[dict[str, Any]], new_rules: Iterable[PackageRule]
) -> list[dict[str, Any]]:
merged_rules = list(existing_rules)
for new_rule in new_rules:
for i, existing_rule in enumerate(merged_rules):
if existing_rule.get("groupName") == new_rule["groupName"]:
merged_rules[i] = existing_rule | new_rule
break
else:
merged_rules.append(dict(new_rule))

return merged_rules


def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output-file", type=Path)
args = ap.parse_args()

output_file: Path | None = args.output_file

codeowners_path = Path("CODEOWNERS")
renovate_json_path = Path("renovate.json")

codeowners_package_rules = get_renovate_packagerules(codeowners_path.read_text())

renovate_json = json.loads(renovate_json_path.read_text())

package_rules = merge_to_existing_rules(
renovate_json.get("packageRules", []),
codeowners_package_rules,
)

renovate_json["packageRules"] = package_rules
if output_file:
with output_file.open("w") as f:
print(json.dumps(renovate_json, indent=2), file=f)
else:
print(json.dumps(renovate_json, indent=2))


if __name__ == "__main__":
main()
Loading
Loading