diff --git a/.github/workflows/assigner-workflow.yml b/.github/workflows/assigner-workflow.yml new file mode 100644 index 00000000000..e6025835b41 --- /dev/null +++ b/.github/workflows/assigner-workflow.yml @@ -0,0 +1,83 @@ +name: Pull Request Assigner Completion Workflow + +# read-write repo token +# access to secrets +on: + workflow_run: + workflows: ["Pull Request Assigner"] + types: + - completed + +permissions: + contents: read + +jobs: + assignment: + name: Pull Request Assignment + runs-on: ubuntu-24.04 + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + + steps: + - name: Check out source code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false + - name: Download artifacts + id: download-artifacts + uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 + with: + workflow: assigner.yml + run_id: ${{ github.event.workflow_run.id }} + if_no_artifact_found: ignore + + - name: Load PR number + if: steps.download-artifacts.outputs.found_artifact == 'true' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + let fs = require("fs"); + let pr_number = Number(fs.readFileSync("./pr/NR")); + core.exportVariable("PR_NUM", pr_number); + + - name: Check PR number + if: steps.download-artifacts.outputs.found_artifact == 'true' + id: check-pr + uses: carpentries/actions/check-valid-pr@2e20fd5ee53b691e27455ce7ca3b16ea885140e8 # v0.15.0 + with: + pr: ${{ env.PR_NUM }} + sha: ${{ github.event.workflow_run.head_sha }} + + - name: Validate PR number + if: | + steps.download-artifacts.outputs.found_artifact == 'true' && + steps.check-pr.outputs.VALID != 'true' + run: | + echo "ABORT: PR number validation failed!" + exit 1 + + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: 3.12 + cache: pip + cache-dependency-path: scripts/requirements-actions.txt + + - name: Install Python packages + run: | + pip install -r scripts/requirements-actions.txt --require-hashes + + - name: Run assignment script + env: + GITHUB_TOKEN: ${{ secrets.ZB_PR_ASSIGNER_GITHUB_TOKEN }} + run: | + if [ -f "./pr/manifest_areas.json" ]; then + ARGS="--areas ./pr/manifest_areas.json" + else + ARGS="" + fi + python3 scripts/set_assignees.py -P ${{ env.PR_NUM }} -M MAINTAINERS.yml -v \ + --repo ${{ github.event.repository.name }} ${ARGS} diff --git a/.github/workflows/assigner.yml b/.github/workflows/assigner.yml index a986067d5f8..7cdca3ca391 100644 --- a/.github/workflows/assigner.yml +++ b/.github/workflows/assigner.yml @@ -1,7 +1,7 @@ name: Pull Request Assigner on: - pull_request_target: + pull_request: types: - opened - synchronize @@ -28,37 +28,65 @@ jobs: issues: write # to add assignees to issues steps: - - name: Check out source code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Check out source code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false - - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: - python-version: 3.12 - cache: pip - cache-dependency-path: scripts/requirements-actions.txt + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: 3.12 + cache: pip + cache-dependency-path: scripts/requirements-actions.txt - - name: Install Python packages - run: | - pip install -r scripts/requirements-actions.txt --require-hashes + - name: Install Python packages + run: | + pip install -r scripts/requirements-actions.txt --require-hashes - - name: Run assignment script - env: - GITHUB_TOKEN: ${{ secrets.ZB_PR_ASSIGNER_GITHUB_TOKEN }} - run: | - FLAGS="-v" - FLAGS+=" -o ${{ github.event.repository.owner.login }}" - FLAGS+=" -r ${{ github.event.repository.name }}" - FLAGS+=" -M MAINTAINERS.yml" - if [ "${{ github.event_name }}" = "pull_request_target" ]; then - FLAGS+=" -P ${{ github.event.pull_request.number }}" - elif [ "${{ github.event_name }}" = "issues" ]; then + - name: west setup + if: > + github.event_name == 'pull_request' + run: | + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + west init -l . || true + mkdir -p ./pr + + - name: Run assignment script + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + FLAGS="-v" + FLAGS+=" -o ${{ github.event.repository.owner.login }}" + FLAGS+=" -r ${{ github.event.repository.name }}" + FLAGS+=" -M MAINTAINERS.yml" + if [ "${{ github.event_name }}" = "pull_request" ]; then + FLAGS+=" -P ${{ github.event.pull_request.number }} --manifest -c origin/${{ github.base_ref }}.." + python3 scripts/set_assignees.py $FLAGS + cp -f manifest_areas.json ./pr/ + elif [ "${{ github.event_name }}" = "issues" ]; then FLAGS+=" -I ${{ github.event.issue.number }}" - elif [ "${{ github.event_name }}" = "schedule" ]; then + python3 scripts/set_assignees.py $FLAGS + elif [ "${{ github.event_name }}" = "schedule" ]; then FLAGS+=" --modules" - else - echo "Unknown event: ${{ github.event_name }}" - exit 1 - fi + python3 scripts/set_assignees.py $FLAGS + else + echo "Unknown event: ${{ github.event_name }}" + exit 1 + fi + + + - name: Save PR number + if: > + github.event_name == 'pull_request' + run: | + echo ${{ github.event.number }} > ./pr/NR + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + if: > + github.event_name == 'pull_request' + with: + name: pr + path: pr/ - python3 scripts/set_assignees.py $FLAGS diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index d5f214be9fb..6f9a4bbc1c4 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -360,6 +360,12 @@ jobs: junit.html junit.xml + - name: Upload test results to Codecov + if: ${{ !cancelled() && (github.event_name == 'push') }} + uses: codecov/test-results-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + - name: Publish Unit Test Results uses: EnricoMi/publish-unit-test-result-action@3a74b2957438d0b6e2e61d67b05318aa25c9e6c6 # v2.20.0 with: diff --git a/scripts/get_maintainer.py b/scripts/get_maintainer.py index 855a6bf3950..7ca14d9a773 100755 --- a/scripts/get_maintainer.py +++ b/scripts/get_maintainer.py @@ -109,6 +109,18 @@ def _parse_args(): nargs="?", help="List all areas maintained by maintainer.") + + area_parser = subparsers.add_parser( + "area", + help="List area(s) by name") + area_parser.add_argument( + "name", + metavar="AREA", + nargs="?", + help="List all areas with the given name.") + + area_parser.set_defaults(cmd_fn=Maintainers._area_cmd) + # New arguments for filtering areas_parser.add_argument( "--without-maintainers", @@ -220,6 +232,12 @@ def __init__(self, filename=None): self.areas[area_name] = area + def name2areas(self, name): + """ + Returns a list of Area instances for the areas that match 'name'. + """ + return [area for area in self.areas.values() if area.name == name] + def path2areas(self, path): """ Returns a list of Area instances for the areas that contain 'path', @@ -262,6 +280,14 @@ def __repr__(self): # Command-line subcommands # + def _area_cmd(self, args): + # 'area' subcommand implementation + + res = set() + areas = self.name2areas(args.name) + res.update(areas) + _print_areas(res) + def _path_cmd(self, args): # 'path' subcommand implementation diff --git a/scripts/set_assignees.py b/scripts/set_assignees.py index a428f102cfe..913067f7b45 100755 --- a/scripts/set_assignees.py +++ b/scripts/set_assignees.py @@ -8,16 +8,21 @@ import os import time import datetime +import json from github import Github, GithubException from github.GithubException import UnknownObjectException from collections import defaultdict from west.manifest import Manifest from west.manifest import ManifestProject +from git import Repo +from pathlib import Path TOP_DIR = os.path.join(os.path.dirname(__file__)) sys.path.insert(0, os.path.join(TOP_DIR, "scripts")) from get_maintainer import Maintainers +zephyr_base = os.getenv('ZEPHYR_BASE', os.path.join(TOP_DIR, '..')) + def log(s): if args.verbose > 0: print(s, file=sys.stdout) @@ -50,11 +55,73 @@ def parse_args(): parser.add_argument("-r", "--repo", default="zephyr", help="Github repository") + parser.add_argument("-c", "--commits", default=None, + help="Commit range in the form: a..b") + + parser.add_argument("--manifest", action="store_true", default=False, + help="Dump manifest changes") + + parser.add_argument("--areas", default=None, + help="Load list of areas from file generated by --manifest") + parser.add_argument("-v", "--verbose", action="count", default=0, help="Verbose Output") args = parser.parse_args() + +def process_manifest(): + log("Processing manifest changes") + repo = Repo(zephyr_base) + old_manifest_content = repo.git.show(f"{args.commits[:-2]}:west.yml") + with open("west_old.yml", "w") as manifest: + manifest.write(old_manifest_content) + old_manifest = Manifest.from_file("west_old.yml") + new_manifest = Manifest.from_file("west.yml") + old_projs = set((p.name, p.revision) for p in old_manifest.projects) + new_projs = set((p.name, p.revision) for p in new_manifest.projects) + # Removed projects + rprojs = set(filter(lambda p: p[0] not in list(p[0] for p in new_projs), + old_projs - new_projs)) + # Updated projects + uprojs = set(filter(lambda p: p[0] in list(p[0] for p in old_projs), + new_projs - old_projs)) + # Added projects + aprojs = new_projs - old_projs - uprojs + + # All projs + projs = rprojs | uprojs | aprojs + projs_names = [name for name, rev in projs] + + log(f"found modified projects: {projs_names}") + areas = [] + for p in projs_names: + areas.append(f'West project: {p}') + + log(f'manifest areas: {areas}') + return areas + + +def dump_manifest_changes(gh, maintainer_file, number): + gh_repo = gh.get_repo(f"{args.org}/{args.repo}") + pr = gh_repo.get_pull(number) + fn = list(pr.get_files()) + areas = [] + for changed_file in fn: + log(f"file: {changed_file.filename}") + + if changed_file.filename in ['west.yml','submanifests/optional.yaml']: + changed_areas = process_manifest() + for _area in changed_areas: + area_match = maintainer_file.name2areas(_area) + if area_match: + areas.extend(area_match) + + log(f"Areas: {areas}") + # now dump the list of areas into a json file + with open("manifest_areas.json", "w") as f: + json.dump([area.name for area in areas], f, indent=4) + def process_pr(gh, maintainer_file, number): gh_repo = gh.get_repo(f"{args.org}/{args.repo}") @@ -67,13 +134,8 @@ def process_pr(gh, maintainer_file, number): found_maintainers = defaultdict(int) num_files = 0 - all_areas = set() fn = list(pr.get_files()) - for changed_file in fn: - if changed_file.filename in ['west.yml','submanifests/optional.yaml']: - break - if pr.commits == 1 and (pr.additions <= 1 and pr.deletions <= 1): labels = {'size: XS'} @@ -82,14 +144,28 @@ def process_pr(gh, maintainer_file, number): return for changed_file in fn: + num_files += 1 log(f"file: {changed_file.filename}") - areas = maintainer_file.path2areas(changed_file.filename) + + areas = [] + if changed_file.filename in ['west.yml','submanifests/optional.yaml']: + if args.areas and Path(args.areas).is_file(): + with open(args.areas, "r") as f: + parsed_areas = json.load(f) + for _area in parsed_areas: + area_match = maintainer_file.name2areas(_area) + if area_match: + areas.extend(area_match) + else: + log(f"Manifest changes detected but no --areas file specified, skipping...") + continue + else: + areas = maintainer_file.path2areas(changed_file.filename) if not areas: continue - all_areas.update(areas) is_instance = False sorted_areas = sorted(areas, key=lambda x: 'Platform' in x.name, reverse=True) for area in sorted_areas: @@ -358,7 +434,9 @@ def main(): gh = Github(token) maintainer_file = Maintainers(args.maintainer_file) - if args.pull_request: + if args.pull_request and args.manifest: + dump_manifest_changes(gh, maintainer_file, args.pull_request) + elif args.pull_request: process_pr(gh, maintainer_file, args.pull_request) elif args.issue: process_issue(gh, maintainer_file, args.issue) diff --git a/subsys/tracing/Kconfig b/subsys/tracing/Kconfig index 5e3d349345b..a61f8b83784 100644 --- a/subsys/tracing/Kconfig +++ b/subsys/tracing/Kconfig @@ -1,4 +1,5 @@ # Debug configuration options +# dummy # Copyright (c) 2015 Wind River Systems, Inc. # SPDX-License-Identifier: Apache-2.0 diff --git a/west.yml b/west.yml index 831aa11ce7b..5f85be5b864 100644 --- a/west.yml +++ b/west.yml @@ -121,11 +121,12 @@ manifest: path: modules/hal/cmsis groups: - hal + - foo - name: cmsis-dsp revision: 97512610ec92058f0119450b9e743eeb7e95b5c8 path: modules/lib/cmsis-dsp - name: cmsis-nn - revision: e9328d612ea3ea7d0d210d3ac16ea8667c01abdd + revision: f9328d612ea3ea7d0d210d3ac16ea8667c01abdd path: modules/lib/cmsis-nn - name: cmsis_6 repo-path: CMSIS_6