You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ja...@apache.org on 2026/10/22 08:13:01 UTC
(mynewt-nimble) branch master updated (bec71bd42 -> d80b9c1cb)
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
from bec71bd42 asf.yaml: Add branch protection ruleset
new 954a51fbb ci: Disable pr-size-labeler comment on XL pull requests
new 751b5dcc3 ci: Replace pull_request_target workflows with scheduled one
new d3af3ba1d ci: Cache newt binary between runs
new 7e69d46f3 ci: Cache external repositories between runs
new 2f9a46076 ci: Add ccache support for build jobs
new 91c408c32 ci: Add support for splitting apps build into shards
new 42bb81a04 ci: Merge build workflows into single workflow
new f8d2948dd ci: Remove superseded caches at end of build workflow
new 5853d57d2 ci: Cancel superseded build runs on master
new b4421f7fd ci: Run unit tests in quiet mode
new 5b54f0269 ci: Run PR maintenance every 15 minutes
new 3a0e5ed95 ci: Mark inactive pull requests as stale
new bda63e8e6 ci: Add informative workflows-outdated label
new 44b2b6380 ci: Label all pull requests based on paths in PR maintenance
new e818469aa ci: Make workflows-update label informative
new b7c1eddc8 ci: Update PR maintenance labels only for changed pull requests
new 9b102d3c9 ci: Build GCC test target with all releases in single job
new 1e1b75f32 ci: Add explicit least-privilege permissions to compliance workflow
new d80b9c1cb ci: Use single project file for all jobs
The 19 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.github/actions/cache-cleanup/action.yml | 107 +++++++
.github/actions/ccache-restore/action.yml | 78 +++++
.github/actions/ccache-save/action.yml | 67 ++++
.github/actions/gcc-target-build/action.yml | 65 ++++
.github/actions/newt-install/action.yml | 180 +++++++++++
.github/actions/newt-project-restore/action.yml | 57 ++++
.github/actions/newt-project/action.yml | 124 +++++++
.github/project_newt_test_all.yml | 39 ---
.github/scripts/checkout_repos.sh | 54 ++++
.github/scripts/pr_maintenance.py | 361 +++++++++++++++++++++
.github/test_build_apps.sh | 11 +
.github/workflows/add_ci_label.yml | 94 ------
.github/workflows/build.yml | 408 ++++++++++++++++++++++++
.github/workflows/build_all_apps.yml | 71 -----
.github/workflows/build_cc_target.yml | 72 -----
.github/workflows/build_ports.yml | 103 ------
.github/workflows/build_targets.yml | 87 -----
.github/workflows/check_workflows.yml | 73 -----
.github/workflows/compliance_check.yml | 5 +
.github/workflows/labeler.yml | 15 +-
.github/workflows/newt_test_all.yml | 73 -----
.github/workflows/ports_syscfg_check.yml | 20 +-
.github/workflows/pr_maintenance.yml | 69 ++++
.github/workflows/stale.yml | 59 ++++
README.md | 20 +-
25 files changed, 1655 insertions(+), 657 deletions(-)
create mode 100644 .github/actions/cache-cleanup/action.yml
create mode 100644 .github/actions/ccache-restore/action.yml
create mode 100644 .github/actions/ccache-save/action.yml
create mode 100644 .github/actions/gcc-target-build/action.yml
create mode 100644 .github/actions/newt-install/action.yml
create mode 100644 .github/actions/newt-project-restore/action.yml
create mode 100644 .github/actions/newt-project/action.yml
delete mode 100644 .github/project_newt_test_all.yml
create mode 100755 .github/scripts/checkout_repos.sh
create mode 100644 .github/scripts/pr_maintenance.py
delete mode 100644 .github/workflows/add_ci_label.yml
create mode 100644 .github/workflows/build.yml
delete mode 100644 .github/workflows/build_all_apps.yml
delete mode 100644 .github/workflows/build_cc_target.yml
delete mode 100644 .github/workflows/build_ports.yml
delete mode 100644 .github/workflows/build_targets.yml
delete mode 100644 .github/workflows/check_workflows.yml
delete mode 100644 .github/workflows/newt_test_all.yml
create mode 100644 .github/workflows/pr_maintenance.yml
create mode 100644 .github/workflows/stale.yml
(mynewt-nimble) 12/19: ci: Mark inactive pull requests as stale
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 3a0e5ed95bf87c55ad10acb350b0ddb74ce2acf6
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 13:47:12 2026 +0200
ci: Mark inactive pull requests as stale
Pull requests without activity for 12 months are marked with 'stale'
label by actions/stale, run monthly, with a comment asking for rebase
if still valid. Stale pull requests are never closed automatically and
label is removed by next run after any update or comment.
PR maintenance skips pull requests without activity for 12 months. As
adding stale label updates pull request, those with the label are also
skipped as long as head commit is older than 12 months, so a rebased
pull request is handled without waiting for next stale run.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 24 +++++++++++++++-
.github/workflows/stale.yml | 59 +++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/.github/scripts/pr_maintenance.py b/.github/scripts/pr_maintenance.py
index 20f0b4dfd..84f49039f 100644
--- a/.github/scripts/pr_maintenance.py
+++ b/.github/scripts/pr_maintenance.py
@@ -30,6 +30,10 @@ is done through GitHub API using gh tool.
- Pull requests with new head commit are reported for path based
labeling, which is done by actions/labeler in the workflow.
+Pull requests without activity for MAX_AGE_DAYS are skipped, also
+when marked with 'stale' label (set by stale workflow) until new commit
+is pushed.
+
'Check workflows' status also marks pull request head as processed: it
is tied to head commit and its description contains base branch
workflows tree it was checked against, so only new or changed pull
@@ -49,8 +53,12 @@ import sys
CI_LABEL = "needs-ci-approval"
WORKFLOWS_LABEL = "workflows-update"
STATUS_CONTEXT = "Check workflows"
+STALE_LABEL = "stale"
SKIPPED = f"Skipped, '{WORKFLOWS_LABEL}' label present"
+# Keep in sync with days-before-pr-stale in stale.yml
+MAX_AGE_DAYS = 365
+
# Runs never approved stay waiting forever, skip old ones
CI_RUNS_MAX_AGE_DAYS = 30
@@ -83,6 +91,7 @@ query (
}
nodes {
number
+ updatedAt
headRefOid
baseRefName
labels(first: 100) {
@@ -99,6 +108,7 @@ query (
nodes {
commit {
oid
+ committedDate
status {
context(name: $context) {
state
@@ -160,11 +170,21 @@ def list_pulls():
"-f", f"query={PULLS_QUERY}",
"-f", f"owner={owner}", "-f", f"repo={repo}",
"-f", f"context={STATUS_CONTEXT}"))
+ since = (date.today() - timedelta(days=MAX_AGE_DAYS)).isoformat()
pulls = []
+ skipped = 0
for page in pages:
for node in page["data"]["repository"]["pullRequests"]["nodes"]:
+ labels = [l["name"] for l in node["labels"]["nodes"]]
commit = node["commits"]["nodes"][0]["commit"]
+ # Adding stale label updates pull request, stale workflow
+ # removes label only on its next run but rebase is new commit
+ if node["updatedAt"] < since or \
+ (STALE_LABEL in labels and commit["committedDate"] < since):
+ skipped += 1
+ continue
+
# Commits list is limited, skip pull request if head is missing
if commit["oid"] != node["headRefOid"]:
print(f"#{node['number']}: head commit not found, skipping")
@@ -174,12 +194,14 @@ def list_pulls():
pulls.append({
"number": node["number"],
"head": commit["oid"],
- "labels": [l["name"] for l in node["labels"]["nodes"]],
+ "labels": labels,
"status": (commit["status"] or {}).get("context"),
"base_name": node["baseRefName"],
"base_head": base.get("oid"),
})
+ print(f"{skipped} stale pull requests skipped")
+
trees = workflows_trees([p["head"] for p in pulls] +
[p["base_head"] for p in pulls if p["base_head"]])
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 000000000..4047c57b7
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,59 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Marks pull requests without activity for 12 months as stale. Stale pull
+# requests are never closed, stale label is removed by next run after any
+# update or comment. Pull request maintenance workflow skips stale pull
+# requests until new commit is pushed.
+
+name: Stale pull requests
+
+on:
+ schedule:
+ - cron: '30 2 1 * *'
+ workflow_dispatch:
+
+permissions:
+ # Required for storing action state between runs
+ actions: write
+ issues: write
+ pull-requests: write
+
+concurrency:
+ group: ${{ github.workflow }}
+
+jobs:
+ stale:
+ if: github.repository == 'apache/mynewt-nimble'
+ runs-on: ubuntu-slim
+ steps:
+ - uses: actions/stale@v11
+ with:
+ # Keep in sync with MAX_AGE_DAYS in pr_maintenance.py
+ days-before-pr-stale: 365
+ days-before-pr-close: -1
+ days-before-issue-stale: -1
+ days-before-issue-close: -1
+ stale-pr-label: stale
+ stale-pr-message: >-
+ This pull request had no activity for 12 months and is marked
+ as stale. If it is still valid, please rebase it on current
+ base branch. Stale pull requests are not closed automatically,
+ the label is removed on any update or comment.
+ operations-per-run: 200
(mynewt-nimble) 05/19: ci: Add ccache support for build jobs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 2f9a460762b1d53574dd98507977f0e65db94425
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 14 00:54:42 2026 +0200
ci: Add ccache support for build jobs
Build jobs compile same sources on every run. Add composite actions
that set up ccache in front of compilers used by newt and restore and
save ccache directory, and use them in all build and test jobs on
Linux. Ports Makefiles already use ccache, so ports job only needs
ccache directory to be restored and saved.
ccache directory is saved only from master branch, so pull requests
use cache from latest master build. Before saving, entries not used
by current job are removed so that cache does not grow over time.
If job had no cache misses, restored cache already contains everything
used by job and is not saved again.
CodeQL job is not using ccache as compilations served from cache
would not be seen by CodeQL.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/ccache-restore/action.yml | 77 +++++++++++++++++++++++++++++++
.github/actions/ccache-save/action.yml | 67 +++++++++++++++++++++++++++
.github/workflows/build_all_apps.yml | 11 ++++-
.github/workflows/build_cc_target.yml | 9 ++++
.github/workflows/build_ports.yml | 9 ++++
.github/workflows/build_targets.yml | 11 ++++-
.github/workflows/newt_test_all.yml | 11 ++++-
7 files changed, 192 insertions(+), 3 deletions(-)
diff --git a/.github/actions/ccache-restore/action.yml b/.github/actions/ccache-restore/action.yml
new file mode 100644
index 000000000..13ae7ab5c
--- /dev/null
+++ b/.github/actions/ccache-restore/action.yml
@@ -0,0 +1,77 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Restore ccache
+description: >
+ Install ccache, put it in front of compilers used by newt and restore
+ ccache directory from cache. Must be used after toolchain is installed
+ so that ccache wrappers are found in PATH before real compilers.
+ Supported only on Linux, does nothing on other systems.
+
+inputs:
+ key:
+ description: Cache key, unique for job (and matrix entry)
+ required: true
+ max-size:
+ description: Maximum size of ccache directory
+ required: false
+ default: 500M
+
+runs:
+ using: composite
+ steps:
+ - name: Set up ccache
+ if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ if ! command -v ccache > /dev/null; then
+ sudo apt-get update
+ sudo apt-get install -y ccache
+ fi
+ # Wrappers named as compilers used by newt, ccache finds real
+ # compiler by skipping its own directory in PATH.
+ dir="$RUNNER_TEMP/ccache-bin"
+ mkdir -p "$dir"
+ for c in arm-none-eabi-gcc arm-none-eabi-g++ gcc g++; do
+ ln -sf "$(command -v ccache)" "$dir/$c"
+ done
+ echo "$dir" >> "$GITHUB_PATH"
+ {
+ echo "CCACHE_DIR=$RUNNER_TEMP/ccache"
+ echo "CCACHE_BASEDIR=$GITHUB_WORKSPACE"
+ echo "CCACHE_NOHASHDIR=true"
+ echo "CCACHE_COMPILERCHECK=content"
+ echo "CCACHE_MAXSIZE=${{ inputs.max-size }}"
+ echo "CCACHE_JOB_START=$(date +%s)"
+ } >> "$GITHUB_ENV"
+
+ - name: Restore ccache directory
+ if: runner.os == 'Linux'
+ uses: actions/cache/restore@v6
+ with:
+ path: ${{ runner.temp }}/ccache
+ key: ccache-${{ inputs.key }}-${{ github.sha }}
+ restore-keys: ccache-${{ inputs.key }}-
+
+ - name: Reset ccache statistics
+ if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ ccache --version | head -1
+ ccache --zero-stats
diff --git a/.github/actions/ccache-save/action.yml b/.github/actions/ccache-save/action.yml
new file mode 100644
index 000000000..bcea10b67
--- /dev/null
+++ b/.github/actions/ccache-save/action.yml
@@ -0,0 +1,67 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Save ccache
+description: >
+ Show ccache statistics, drop cache entries not used by current job and
+ save ccache directory to cache. Cache is saved only from master branch
+ since only caches from default branch are available to pull requests,
+ and only if there were cache misses, since otherwise restored cache
+ already contains everything used by job.
+ Supported only on Linux, does nothing on other systems.
+
+inputs:
+ key:
+ description: Cache key, same as used for ccache-restore
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: Show ccache statistics
+ id: stats
+ if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ ccache --show-stats
+ misses=$(ccache --print-stats | awk '$1 == "cache_miss" { print $2 }')
+ echo "misses=${misses:-unknown}" >> "$GITHUB_OUTPUT"
+
+ - name: Remove unused ccache entries
+ if: >-
+ runner.os == 'Linux' && github.ref == 'refs/heads/master' &&
+ github.event_name != 'pull_request' &&
+ steps.stats.outputs.misses != '0'
+ shell: bash
+ run: |
+ # Keep only entries used by this job so that cache size does not
+ # grow over time with stale entries.
+ age=$(( $(date +%s) - CCACHE_JOB_START + 60 ))
+ ccache --evict-older-than "${age}s"
+ ccache --show-stats | grep -i 'cache size' || true
+
+ - name: Save ccache directory
+ if: >-
+ runner.os == 'Linux' && github.ref == 'refs/heads/master' &&
+ github.event_name != 'pull_request' &&
+ steps.stats.outputs.misses != '0'
+ uses: actions/cache/save@v6
+ with:
+ path: ${{ runner.temp }}/ccache
+ key: ccache-${{ inputs.key }}-${{ github.run_id }}-${{ github.run_attempt }}
diff --git a/.github/workflows/build_all_apps.yml b/.github/workflows/build_all_apps.yml
index c619501d9..8dbc306e8 100644
--- a/.github/workflows/build_all_apps.yml
+++ b/.github/workflows/build_all_apps.yml
@@ -42,7 +42,7 @@ jobs:
shell: bash
run: |
sudo apt-get update
- sudo apt-get install -y gcc-multilib
+ sudo apt-get install -y gcc-multilib ccache
- name: Install newt
uses: ./.github/actions/newt-install
- name: Set up project
@@ -52,9 +52,18 @@ jobs:
- name: Remove project targets
shell: bash
run: rm -rf build/targets
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: apps
- name: Build applications
shell: bash
run: |
cd build
bash ../.github/test_build_apps.sh
cd ..
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: apps
diff --git a/.github/workflows/build_cc_target.yml b/.github/workflows/build_cc_target.yml
index 3e0c7cabd..e4d30c465 100644
--- a/.github/workflows/build_cc_target.yml
+++ b/.github/workflows/build_cc_target.yml
@@ -46,6 +46,10 @@ jobs:
uses: ./.github/actions/newt-install
- name: Set up project
uses: ./.github/actions/newt-project
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: gcc-target-${{ matrix.gcc }}
- name: Build test target
shell: bash
run: |
@@ -55,3 +59,8 @@ jobs:
newt target set cc_test app="@apache-mynewt-nimble/apps/btshell"
cp -f ../.github/test_build_apps_syscfg.yml targets/cc_test/syscfg.yml
newt build cc_test
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: gcc-target-${{ matrix.gcc }}
diff --git a/.github/workflows/build_ports.yml b/.github/workflows/build_ports.yml
index 7297cc801..f8b48d4b1 100644
--- a/.github/workflows/build_ports.yml
+++ b/.github/workflows/build_ports.yml
@@ -68,6 +68,10 @@ jobs:
echo "LIBRARY_PATH=${{ github.workspace }}/mbedtls_install/lib" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=${{ github.workspace }}/mbedtls_install/lib" >> $GITHUB_ENV
echo "MBEDTLS_DIR=${{ github.workspace }}/mbedtls_install" >> $GITHUB_ENV
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: ports
- name: Build example ports
shell: bash
run: |
@@ -101,3 +105,8 @@ jobs:
>> nuttx-build/apps/wireless/bluetooth/nimble/include/syscfg/syscfg.h
make -C nuttx-build/nuttx olddefconfig
make -C nuttx-build/nuttx
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: ports
diff --git a/.github/workflows/build_targets.yml b/.github/workflows/build_targets.yml
index 97de444c4..c9a808587 100644
--- a/.github/workflows/build_targets.yml
+++ b/.github/workflows/build_targets.yml
@@ -47,7 +47,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
- sudo apt-get install -y gcc-multilib
+ sudo apt-get install -y gcc-multilib ccache
- name: Install newt
uses: ./.github/actions/newt-install
- name: Set up project
@@ -55,6 +55,10 @@ jobs:
- name: Remove project targets
shell: bash
run: rm -rf build/targets
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: targets
- name: Build targets
shell: bash
run: |
@@ -72,3 +76,8 @@ jobs:
ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0'
rm -rf targets
cd ..
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: targets
diff --git a/.github/workflows/newt_test_all.yml b/.github/workflows/newt_test_all.yml
index 20d14114a..959918e79 100644
--- a/.github/workflows/newt_test_all.yml
+++ b/.github/workflows/newt_test_all.yml
@@ -39,13 +39,17 @@ jobs:
shell: bash
run: |
sudo apt-get update
- sudo apt-get install -y gcc-multilib
+ sudo apt-get install -y gcc-multilib ccache
- name: Install newt
uses: ./.github/actions/newt-install
- name: Set up project
uses: ./.github/actions/newt-project
with:
project: .github/project_newt_test_all.yml
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: unit-tests
- name: Switch to main mcuboot
# This is temporary until next mcuboot release is available
shell: bash
@@ -58,3 +62,8 @@ jobs:
run: |
cd build
newt test all
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: unit-tests
(mynewt-nimble) 15/19: ci: Make workflows-update label informative
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit e818469aa6ccc509005ed55d1eb17756827a3d95
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 16:28:14 2026 +0200
ci: Make workflows-update label informative
Workflow runs of contributors without write access need approval
anyway, so 'Check workflows' status adds little. Remove it and set
'workflows-update' label on pull requests modifying .github compared
to their merge base instead, same as other PR maintenance labels.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 139 ++++++++---------------------------
.github/workflows/pr_maintenance.yml | 18 +----
2 files changed, 34 insertions(+), 123 deletions(-)
diff --git a/.github/scripts/pr_maintenance.py b/.github/scripts/pr_maintenance.py
index 896996c23..8b6f07a6d 100644
--- a/.github/scripts/pr_maintenance.py
+++ b/.github/scripts/pr_maintenance.py
@@ -25,25 +25,18 @@ is done through GitHub API using gh tool.
- 'needs-ci-approval' label is set on pull requests with workflow runs
waiting for approval on their head commit, and removed otherwise.
- 'workflows-outdated' label is set on pull requests if .github of
- base branch changed since merge base, and removed otherwise. It is
- informative only.
-- 'Check workflows' commit status reports whether .github of pull
- request head matches base branch ('workflows-update' label skips the
- check).
+ base branch changed since merge base, and removed otherwise.
+- 'workflows-update' label is set on pull requests modifying .github
+ (compared to merge base), and removed otherwise.
- All pull requests are reported for path based labeling, which is
done by actions/labeler in the workflow.
+Workflows labels are informative only, workflow runs of contributors
+without write access need approval anyway.
+
Pull requests without activity for MAX_AGE_DAYS are skipped, also
when marked with 'stale' label (set by stale workflow) until new commit
is pushed.
-
-'Check workflows' status is tied to head commit and its description
-contains base branch .github tree it was checked against, so it is
-reported only for new or changed pull requests.
-
-Usage:
- pr_maintenance.py check - update labels, write step outputs
- pr_maintenance.py report - report statuses from STATUSES variable
"""
from datetime import date, timedelta
@@ -53,11 +46,9 @@ import subprocess
import sys
CI_LABEL = "needs-ci-approval"
-WORKFLOWS_LABEL = "workflows-update"
+UPDATE_LABEL = "workflows-update"
OUTDATED_LABEL = "workflows-outdated"
-STATUS_CONTEXT = "Check workflows"
STALE_LABEL = "stale"
-SKIPPED = f"Skipped, '{WORKFLOWS_LABEL}' label present"
# Keep in sync with days-before-pr-stale in stale.yml
MAX_AGE_DAYS = 365
@@ -65,9 +56,6 @@ MAX_AGE_DAYS = 365
# Runs never approved stay waiting forever, skip old ones
CI_RUNS_MAX_AGE_DAYS = 30
-# Limit API usage, remaining pull requests are handled by next runs
-MAX_PULLS_PER_RUN = 20
-
# .github trees are queried with object() which returns null if path
# doesn't exist, Commit.file() fails whole query (and gh pagination) instead
TREES_PER_QUERY = 100
@@ -78,7 +66,6 @@ PULLS_QUERY = """
query (
$owner: String!
$repo: String!
- $context: String!
$endCursor: String
) {
repository(owner: $owner, name: $repo) {
@@ -96,7 +83,6 @@ query (
number
updatedAt
headRefOid
- baseRefName
labels(first: 100) {
nodes {
name
@@ -112,12 +98,6 @@ query (
commit {
oid
committedDate
- status {
- context(name: $context) {
- state
- description
- }
- }
}
}
}
@@ -177,8 +157,7 @@ def list_pulls():
owner, repo = REPO.split("/")
pages = json.loads(gh("api", "graphql", "--paginate", "--slurp",
"-f", f"query={PULLS_QUERY}",
- "-f", f"owner={owner}", "-f", f"repo={repo}",
- "-f", f"context={STATUS_CONTEXT}"))
+ "-f", f"owner={owner}", "-f", f"repo={repo}"))
since = (date.today() - timedelta(days=MAX_AGE_DAYS)).isoformat()
pulls = []
skipped = 0
@@ -204,8 +183,6 @@ def list_pulls():
"number": node["number"],
"head": commit["oid"],
"labels": labels,
- "status": (commit["status"] or {}).get("context"),
- "base_name": node["baseRefName"],
"base_head": base.get("oid"),
})
@@ -220,7 +197,6 @@ def list_pulls():
base_tree = trees.get(pull["base_head"])
pull["tree"] = trees[pull["head"]]
pull["base_tree"] = base_tree
- pull["base"] = f"{pull['base_name']}@{(base_tree or 'none')[:12]}"
# Same tree as base means pull request neither modifies .github
# nor is out of date, merge base is not needed
@@ -299,69 +275,10 @@ def update_outdated_label(pulls):
lambda p: p["base_tree"] != p["merge_base_tree"])
-def workflows_status(pull):
- """Returns status to report, or None if reported one is up to date"""
- status = pull["status"]
-
- if WORKFLOWS_LABEL in pull["labels"]:
- new = {"state": "success", "description": SKIPPED}
- elif pull["tree"] == pull["base_tree"]:
- new = {"state": "success",
- "description": f".github matches {pull['base']}"}
- else:
- new = {"state": "failure",
- "description": f".github differs from {pull['base']}, "
- f"rebase or apply '{WORKFLOWS_LABEL}' label"}
-
- if status and (status["state"], status["description"]) == \
- (new["state"], new["description"]):
- return None
-
- return {"sha": pull["head"], **new}
-
-
-def check():
- """
- Updates CI approval and outdated labels, returns number of errors
- and step outputs:
- pr-numbers - newline separated pull requests for path based labeling
- statuses - JSON list of workflows commit statuses to report
- """
- pulls, errors = list_pulls()
- print(f"{len(pulls)} open pull requests")
- errors += update_ci_label(pulls)
- # Pull requests without merge base tree failed and were reported
- pulls_ok = [p for p in pulls if "merge_base_tree" in p]
- errors += update_outdated_label(pulls_ok)
- statuses = [s for s in map(workflows_status, pulls_ok) if s]
- statuses = statuses[:MAX_PULLS_PER_RUN]
-
- for status in statuses:
- print(f"{status['sha']}: {status['description']}")
-
- return errors, {
- "pr-numbers": "\n".join(str(p["number"]) for p in pulls),
- "statuses": json.dumps(statuses),
- }
-
-
-def report(statuses, target_url):
- """Reports statuses computed by check(), returns number of errors"""
- errors = 0
-
- for status in statuses:
- try:
- gh("api", "-X", "POST", f"repos/{REPO}/statuses/{status['sha']}",
- "-f", f"state={status['state']}",
- "-f", f"description={status['description']}",
- "-f", f"context={STATUS_CONTEXT}",
- "-f", f"target_url={target_url}")
- print(f"{status['sha']}: {status['state']}")
- except subprocess.CalledProcessError as e:
- error(f"{status['sha']}: {e.stderr.strip()}")
- errors += 1
-
- return errors
+def update_update_label(pulls):
+ """Returns number of errors"""
+ return sync_label(pulls, UPDATE_LABEL, "FBCA04",
+ lambda p: p["tree"] != p["merge_base_tree"])
def write_outputs(outputs):
@@ -374,20 +291,24 @@ def write_outputs(outputs):
def main():
- if sys.argv[1:] == ["check"]:
- try:
- errors, outputs = check()
- except subprocess.CalledProcessError as e:
- sys.exit(f"Failed to list pull requests: {e.stderr.strip()}")
- # Outputs are written even on errors so following steps can
- # handle pull requests that were processed successfully
- write_outputs(outputs)
- elif sys.argv[1:] == ["report"]:
- url = f"{os.environ['GITHUB_SERVER_URL']}/{REPO}/actions/runs/" \
- f"{os.environ['GITHUB_RUN_ID']}"
- errors = report(json.loads(os.environ["STATUSES"]), url)
- else:
- sys.exit(__doc__)
+ """
+ Updates labels and writes step outputs:
+ pr-numbers - newline separated pull requests for path based labeling
+ """
+ try:
+ pulls, errors = list_pulls()
+ except subprocess.CalledProcessError as e:
+ sys.exit(f"Failed to list pull requests: {e.stderr.strip()}")
+
+ print(f"{len(pulls)} open pull requests")
+ # Written first so following step can handle pull requests even if
+ # updating labels fails
+ write_outputs({"pr-numbers": "\n".join(str(p["number"]) for p in pulls)})
+ errors += update_ci_label(pulls)
+ # Pull requests without merge base tree failed and were reported
+ pulls = [p for p in pulls if "merge_base_tree" in p]
+ errors += update_outdated_label(pulls)
+ errors += update_update_label(pulls)
if errors:
sys.exit(f"{errors} error(s) occurred")
diff --git a/.github/workflows/pr_maintenance.yml b/.github/workflows/pr_maintenance.yml
index 0d4cd123a..c65e240bd 100644
--- a/.github/workflows/pr_maintenance.yml
+++ b/.github/workflows/pr_maintenance.yml
@@ -18,7 +18,7 @@
#
-# Maintenance of open pull requests (labels and workflows status check).
+# Maintenance of open pull requests labels.
# This runs periodically from master instead of pull_request_target, so
# no pull request code or configuration is used with elevated privileges.
@@ -34,7 +34,6 @@ permissions:
contents: read
issues: write
pull-requests: write
- statuses: write
concurrency:
group: ${{ github.workflow }}
@@ -52,13 +51,13 @@ jobs:
sparse-checkout: .github
persist-credentials: false
- - name: Check pull requests
+ - name: Update pull requests labels
id: check
env:
GH_TOKEN: ${{ github.token }}
- run: python3 .github/scripts/pr_maintenance.py check
+ run: python3 .github/scripts/pr_maintenance.py
- # Following steps run also if previous step failed, so that error in
+ # Following step runs also if previous step failed, so that error in
# one pull request doesn't block processing of others
- name: Assign labels based on paths
@@ -68,12 +67,3 @@ jobs:
pr-number: ${{ steps.check.outputs.pr-numbers }}
sync-labels: true
configuration-path: .github/labeler_cfg.yml
-
- - name: Report workflows status
- if: >-
- ${{ !cancelled() && steps.check.outputs.statuses != '' &&
- steps.check.outputs.statuses != '[]' }}
- env:
- GH_TOKEN: ${{ github.token }}
- STATUSES: ${{ steps.check.outputs.statuses }}
- run: python3 .github/scripts/pr_maintenance.py report
(mynewt-nimble) 07/19: ci: Merge build workflows into single workflow
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 42bb81a04b734e5f0cd76bdfe6d41ce12afb690b
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 14 00:55:50 2026 +0200
ci: Merge build workflows into single workflow
Each build and test workflow downloaded all external repositories on
its own and applications job built everything sequentially.
Merge targets, GCC target, apps, ports and unit tests workflows into
single workflow. Prepare job downloads repositories once and passes
them to all Linux jobs using newt as workflow artifact, so those jobs
don't run newt upgrade at all. Only .git directories of repositories
are packed and jobs check out working trees after restore. Prepare job
also saves repositories cache. Unit tests job replaces project file
with one limiting repositories to those for which tests should be run.
Windows and macOS jobs still set up project on their own.
Newt is built once per run, for all platforms used by workflow, and
passed to other jobs as artifact, so it is never built several times
in parallel when cache is empty. Newt is cross-compiled, as it doesn't
use cgo.
Applications are split into shards built in parallel jobs. Number of
GCC target jobs running in parallel is limited to fit ASF job
concurrency limit per workflow.
README is updated to show single badge for merged workflow.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/newt-install/action.yml | 112 +++++++-
.github/actions/newt-project-restore/action.yml | 65 +++++
.github/workflows/build.yml | 359 ++++++++++++++++++++++++
.github/workflows/build_all_apps.yml | 69 -----
.github/workflows/build_cc_target.yml | 66 -----
.github/workflows/build_ports.yml | 112 --------
.github/workflows/build_targets.yml | 83 ------
.github/workflows/newt_test_all.yml | 69 -----
README.md | 20 +-
9 files changed, 526 insertions(+), 429 deletions(-)
diff --git a/.github/actions/newt-install/action.yml b/.github/actions/newt-install/action.yml
index 58e406799..55e203bde 100644
--- a/.github/actions/newt-install/action.yml
+++ b/.github/actions/newt-install/action.yml
@@ -20,13 +20,70 @@
name: Install newt
description: >
Install newt built from master branch of apache/mynewt-newt. Built
- binary is cached per newt commit, so newt is rebuilt only when newt
- master branch changes.
+ binaries are cached per newt commit, so newt is rebuilt only when newt
+ master branch changes. Newt can also be taken from artifact uploaded
+ by another job of the same workflow run, so that it is built only once.
+
+inputs:
+ platforms:
+ description: >
+ Space separated list of GOOS/GOARCH platforms to build newt for, in
+ addition to platform of the runner. Binaries are stored in
+ directory provided by dist output.
+ required: false
+ default: ''
+ artifact:
+ description: >
+ Name of artifact with newt binaries (dist directory) uploaded by
+ another job. If set, newt is taken from it instead of being built.
+ required: false
+ default: ''
+
+outputs:
+ dist:
+ description: Directory with newt binaries, one subdirectory per platform
+ value: ${{ steps.platform.outputs.dist }}
runs:
using: composite
steps:
+ - name: Get platforms
+ id: platform
+ shell: bash
+ env:
+ RUNNER_OS: ${{ runner.os }}
+ RUNNER_ARCH: ${{ runner.arch }}
+ PLATFORMS: ${{ inputs.platforms }}
+ run: |
+ case "$RUNNER_OS" in
+ Linux) goos=linux ;;
+ Windows) goos=windows ;;
+ macOS) goos=darwin ;;
+ esac
+ case "$RUNNER_ARCH" in
+ X64) goarch=amd64 ;;
+ ARM64) goarch=arm64 ;;
+ esac
+ if [ -z "$goos" ] || [ -z "$goarch" ]; then
+ echo "::error::Unsupported runner $RUNNER_OS $RUNNER_ARCH"
+ exit 1
+ fi
+ host="$goos/$goarch"
+ all=$(echo "$host $PLATFORMS" | tr ' ' '\n' | grep . | sort -u | tr '\n' ' ')
+ echo "host=$host" >> "$GITHUB_OUTPUT"
+ echo "all=${all% }" >> "$GITHUB_OUTPUT"
+ # Relative to workspace, to avoid Windows paths in bash steps
+ echo "dist=.newt-dist" >> "$GITHUB_OUTPUT"
+
+ - name: Download newt
+ if: inputs.artifact != ''
+ uses: actions/download-artifact@v8
+ with:
+ name: ${{ inputs.artifact }}
+ path: ${{ steps.platform.outputs.dist }}
+
- name: Get newt master commit
+ if: inputs.artifact == ''
id: newt
shell: bash
run: |
@@ -37,15 +94,18 @@ runs:
fi
echo "newt master is at $sha"
echo "sha=$sha" >> "$GITHUB_OUTPUT"
+ echo "platforms=$(echo ${{ steps.platform.outputs.all }} | tr '/ ' '_-')" >> "$GITHUB_OUTPUT"
- name: Restore newt from cache
+ if: inputs.artifact == ''
id: cache
uses: actions/cache/restore@v6
with:
- path: ${{ github.workspace }}/.newt-bin
- key: newt-${{ runner.os }}-${{ runner.arch }}-${{ steps.newt.outputs.sha }}
+ path: ${{ steps.platform.outputs.dist }}
+ key: newt-${{ runner.os }}-${{ steps.newt.outputs.sha }}-${{ steps.newt.outputs.platforms }}
- name: Report newt cache status
+ if: inputs.artifact == ''
shell: bash
env:
CACHE_HIT: ${{ steps.cache.outputs.cache-hit }}
@@ -58,35 +118,63 @@ runs:
fi
- name: Set up Go
- if: steps.cache.outputs.cache-hit != 'true'
+ if: inputs.artifact == '' && steps.cache.outputs.cache-hit != 'true'
uses: actions/setup-go@v7
with:
go-version: 'stable'
cache: false
- name: Build newt
- if: steps.cache.outputs.cache-hit != 'true'
+ if: inputs.artifact == '' && steps.cache.outputs.cache-hit != 'true'
shell: bash
env:
- GOBIN: ${{ github.workspace }}/.newt-bin
+ CGO_ENABLED: 0
+ GOPATH: ${{ runner.temp }}/newt-gopath
+ NEWT_SHA: ${{ steps.newt.outputs.sha }}
+ PLATFORMS: ${{ steps.platform.outputs.all }}
+ DIST: ${{ steps.platform.outputs.dist }}
run: |
go version
- go install mynewt.apache.org/newt/newt@${{ steps.newt.outputs.sha }}
+ for platform in $PLATFORMS; do
+ goos=${platform%/*}
+ goarch=${platform#*/}
+ echo "Building newt for $platform"
+ GOOS=$goos GOARCH=$goarch \
+ go install "mynewt.apache.org/newt/newt@$NEWT_SHA"
+ # Cross compiled binaries are installed to GOOS_GOARCH subdirectory
+ src="$GOPATH/bin/${goos}_${goarch}"
+ [ -d "$src" ] || src="$GOPATH/bin"
+ mkdir -p "$DIST/${goos}_${goarch}"
+ cp "$src"/newt* "$DIST/${goos}_${goarch}/"
+ done
+ ls -lR "$DIST"
# Only master saves cache, so that it is shared with all pull
# requests instead of being duplicated in each pull request scope
- name: Save newt to cache
if: >-
- steps.cache.outputs.cache-hit != 'true' &&
+ inputs.artifact == '' && steps.cache.outputs.cache-hit != 'true' &&
github.ref == 'refs/heads/master' &&
github.event_name != 'pull_request'
uses: actions/cache/save@v6
with:
- path: ${{ github.workspace }}/.newt-bin
+ path: ${{ steps.platform.outputs.dist }}
key: ${{ steps.cache.outputs.cache-primary-key }}
- name: Add newt to PATH
shell: bash
+ env:
+ HOST: ${{ steps.platform.outputs.host }}
+ DIST: ${{ steps.platform.outputs.dist }}
run: |
- echo "${{ github.workspace }}/.newt-bin" >> "$GITHUB_PATH"
- "${{ github.workspace }}/.newt-bin/newt" version
+ src="$DIST/$(echo "$HOST" | tr / _)"
+ if ! ls "$src"/newt* > /dev/null 2>&1; then
+ echo "::error::newt for $HOST not found"
+ exit 1
+ fi
+ mkdir -p .newt-bin
+ cp "$src"/newt* .newt-bin/
+ # Artifacts don't preserve file permissions
+ chmod +x .newt-bin/newt*
+ echo "$GITHUB_WORKSPACE/.newt-bin" >> "$GITHUB_PATH"
+ .newt-bin/newt version
diff --git a/.github/actions/newt-project-restore/action.yml b/.github/actions/newt-project-restore/action.yml
new file mode 100644
index 000000000..80db00ce7
--- /dev/null
+++ b/.github/actions/newt-project-restore/action.yml
@@ -0,0 +1,65 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Restore newt project
+description: >
+ Restore newt and newt project prepared by prepare job of the same
+ workflow run, so that external repositories are downloaded only once
+ per run. Project contains only .git directories of repositories,
+ working trees are checked out after restore. Project file is replaced
+ with one provided by job.
+
+inputs:
+ project:
+ description: Project file to use (relative to repository root)
+ required: false
+ default: .github/project.yml
+ path:
+ description: Directory to restore project to
+ required: false
+ default: build
+
+runs:
+ using: composite
+ steps:
+ - name: Download project
+ uses: actions/download-artifact@v8
+ with:
+ name: newt-project
+ path: ${{ runner.temp }}/newt-project
+
+ - name: Extract project
+ shell: bash
+ run: |
+ mkdir -p "${{ inputs.path }}"
+ zstd -d -c "$RUNNER_TEMP/newt-project/newt-project.tar.zst" | tar -x -C "${{ inputs.path }}"
+ rm -rf "$RUNNER_TEMP/newt-project"
+ mv "${{ inputs.path }}/.newt-bin" "$GITHUB_WORKSPACE/.newt-bin"
+ echo "$GITHUB_WORKSPACE/.newt-bin" >> "$GITHUB_PATH"
+ bash "$GITHUB_WORKSPACE/.github/scripts/checkout_repos.sh" "${{ inputs.path }}"
+
+ # Repositories were set up by prepare job for tested commit, so
+ # only project file needs to be updated. Project file may limit
+ # repositories used by newt (e.g. for unit tests).
+ - name: Set up project file
+ shell: bash
+ run: |
+ cp -f "${{ inputs.project }}" "${{ inputs.path }}/project.yml"
+ cd "${{ inputs.path }}"
+ newt info
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..894a9b849
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,359 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Build
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ # Builds newt once per run for all platforms used by jobs of this
+ # workflow, other jobs take newt from artifact uploaded by this job.
+ newt:
+ name: Build newt
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - name: Build newt
+ id: newt
+ uses: ./.github/actions/newt-install
+ with:
+ platforms: windows/amd64 darwin/arm64
+ - name: Upload newt
+ uses: actions/upload-artifact@v7
+ with:
+ name: newt
+ path: ${{ steps.newt.outputs.dist }}
+ include-hidden-files: true
+ if-no-files-found: error
+ retention-days: 1
+
+ # Downloads external repositories once per run, all Linux jobs use
+ # project prepared by this job.
+ prepare:
+ name: Prepare project
+ needs: newt
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - name: Install newt
+ uses: ./.github/actions/newt-install
+ with:
+ artifact: newt
+ - name: Set up project
+ uses: ./.github/actions/newt-project
+ with:
+ save-cache: true
+ # Only .git directories of repositories are packed, working trees
+ # are checked out by jobs restoring project
+ - name: Pack project
+ shell: bash
+ run: |
+ cp -r .newt-bin build/.newt-bin
+ cd build
+ {
+ find . -mindepth 1 -maxdepth 1 ! -name repos
+ find repos -mindepth 1 -maxdepth 1 -name '.*'
+ find repos -mindepth 2 -maxdepth 2 -name .git
+ } | tar -cf - -T - | zstd -T0 -3 -o ../newt-project.tar.zst
+ ls -lh ../newt-project.tar.zst
+ - name: Upload project
+ uses: actions/upload-artifact@v7
+ with:
+ name: newt-project
+ path: newt-project.tar.zst
+ compression-level: 0
+ retention-days: 1
+
+ apps:
+ name: Build all apps
+ needs: prepare
+ strategy:
+ fail-fast: false
+ matrix:
+ shard: [0, 1]
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
+ with:
+ release: '15.2.Rel1'
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y gcc-multilib ccache
+ - name: Restore project
+ uses: ./.github/actions/newt-project-restore
+ - name: Remove project targets
+ shell: bash
+ run: rm -rf build/targets
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: apps-${{ matrix.shard }}
+ - name: Build applications
+ shell: bash
+ env:
+ SHARD_INDEX: ${{ matrix.shard }}
+ SHARD_TOTAL: 2
+ run: |
+ cd build
+ bash ../.github/test_build_apps.sh
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: apps-${{ matrix.shard }}
+
+ targets:
+ name: Build all test targets
+ needs: prepare
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
+ with:
+ release: '15.2.Rel1'
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y gcc-multilib ccache
+ - name: Restore project
+ uses: ./.github/actions/newt-project-restore
+ - name: Remove project targets
+ shell: bash
+ run: rm -rf build/targets
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: targets
+ - name: Build targets
+ shell: bash
+ run: |
+ cp -r .github/targets build/targets
+ cd build
+ ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0'
+ rm -rf targets
+ - name: Build Linux-only targets
+ shell: bash
+ run: |
+ cp -r .github/targets_linux build/targets
+ cd build
+ ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0'
+ rm -rf targets
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: targets
+
+ targets-other-os:
+ name: Build all test targets
+ needs: newt
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [windows-latest, macos-latest]
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v7
+ - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
+ with:
+ release: '15.2.Rel1'
+ - name: Install newt
+ uses: ./.github/actions/newt-install
+ with:
+ artifact: newt
+ - name: Set up project
+ uses: ./.github/actions/newt-project
+ - name: Remove project targets
+ shell: bash
+ run: rm -rf build/targets
+ - name: Build targets
+ shell: bash
+ run: |
+ cp -r .github/targets build/targets
+ cd build
+ ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0'
+ rm -rf targets
+
+ gcc-target:
+ name: Build GCC test target
+ needs: prepare
+ strategy:
+ fail-fast: false
+ # Limit number of parallel jobs, ASF policy limits job concurrency
+ # level per workflow
+ max-parallel: 4
+ matrix:
+ gcc: ['15.2.Rel1', '14.2.Rel1', '13.2.Rel1', '12.2.Rel1', '11.3.Rel1', '10.3-2021.10', '9-2020-q2', '8-2019-q3']
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
+ with:
+ release: ${{ matrix.gcc }}
+ - name: Restore project
+ uses: ./.github/actions/newt-project-restore
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: gcc-target-${{ matrix.gcc }}
+ - name: Build test target
+ shell: bash
+ run: |
+ cd build
+ newt target create cc_test
+ newt target set cc_test bsp="@apache-mynewt-core/hw/bsp/nordic_pca10056"
+ newt target set cc_test app="@apache-mynewt-nimble/apps/btshell"
+ cp -f ../.github/test_build_apps_syscfg.yml targets/cc_test/syscfg.yml
+ newt build cc_test
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: gcc-target-${{ matrix.gcc }}
+
+ unit-tests:
+ name: Run unit tests
+ needs: prepare
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y gcc-multilib ccache
+ # Unit tests project limits repositories to those which tests
+ # should be run for
+ - name: Restore project
+ uses: ./.github/actions/newt-project-restore
+ with:
+ project: .github/project_newt_test_all.yml
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: unit-tests
+ - name: Switch to main mcuboot
+ # This is temporary until next mcuboot release is available
+ shell: bash
+ run: |
+ cd build/repos/mcuboot
+ git fetch --depth=1 origin main
+ git checkout --detach FETCH_HEAD
+ - name: newt test all
+ run: |
+ cd build
+ newt test all
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: unit-tests
+
+ ports:
+ name: Build ports
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v7
+ - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
+ with:
+ release: '15.2.Rel1'
+ - name: Install Dependencies
+ shell: bash
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y make ccache gcc-multilib g++-multilib kconfig-frontends libmbedtls-dev cmake build-essential
+ - name: Cache 32-bit Mbed TLS 3.6
+ id: cache-mbedtls
+ uses: actions/cache@v6
+ with:
+ path: ${{ github.workspace }}/mbedtls_install
+ key: ${{ runner.os }}-mbedtls-3.6.5
+ - name: Compile Mbed TLS 3.6 (On Cache Miss)
+ if: steps.cache-mbedtls.outputs.cache-hit != 'true'
+ run: |
+ git clone --depth 1 --branch mbedtls-3.6.5 --recursive https://github.com/Mbed-TLS/mbedtls.git
+ cd mbedtls
+ cmake -B build \
+ -DCMAKE_C_FLAGS="-m32" \
+ -DCMAKE_SHARED_LINKER_FLAGS="-m32" \
+ -DCMAKE_EXE_LINKER_FLAGS="-m32" \
+ -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/mbedtls_install \
+ -DUSE_SHARED_MBEDTLS_LIBRARY=On \
+ -DENABLE_TESTING=Off
+ cmake --build build --target install
+ - name: Export Mbed TLS Environment Paths
+ run: |
+ echo "CPATH=${{ github.workspace }}/mbedtls_install/include" >> $GITHUB_ENV
+ echo "LIBRARY_PATH=${{ github.workspace }}/mbedtls_install/lib" >> $GITHUB_ENV
+ echo "LD_LIBRARY_PATH=${{ github.workspace }}/mbedtls_install/lib" >> $GITHUB_ENV
+ echo "MBEDTLS_DIR=${{ github.workspace }}/mbedtls_install" >> $GITHUB_ENV
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: ports
+ - name: Build example ports
+ shell: bash
+ run: |
+ make -C porting/examples/dummy/ clean all
+ make -C porting/examples/linux/ clean all
+ make -C porting/examples/linux_blemesh/ clean all
+ make -C porting/examples/linux_blemesh_shell/ clean all
+ make -C porting/npl/linux/test/ clean all test
+ - name: Build RIOT port
+ shell: bash
+ if: success() || failure()
+ continue-on-error: true
+ run: |
+ git clone --depth=1 https://github.com/RIOT-OS/RIOT
+ rm RIOT/pkg/nimble/patches/ -rf
+ sed -i 's|PKG_URL.*|PKG_URL = '$(pwd)'|' RIOT/pkg/nimble/Makefile
+ sed -i 's|PKG_VERSION.*|PKG_VERSION = '${{ github.sha }}'|' RIOT/pkg/nimble/Makefile
+ make -C RIOT/examples/networking/ble/nimble/nimble_gatt
+ - name: Build Nuttx port
+ shell: bash
+ if: success() || failure()
+ continue-on-error: true
+ run: |
+ mkdir nuttx-build
+ git clone --depth=1 https://github.com/apache/nuttx.git nuttx-build/nuttx
+ git clone --depth=1 https://github.com/apache/nuttx-apps nuttx-build/apps
+ ./nuttx-build/nuttx/tools/configure.sh -l nrf52840-dk:sdc_nimble
+ kconfig-tweak --file nuttx-build/nuttx/.config --set-str NIMBLE_REF ${{ github.sha }}
+ kconfig-tweak --file nuttx-build/nuttx/.config --enable NIMBLE_PORTING_EXAMPLE
+ echo '#include "../../../../mynewt-nimble/porting/examples/nuttx/include/syscfg/syscfg.h"'\
+ >> nuttx-build/apps/wireless/bluetooth/nimble/include/syscfg/syscfg.h
+ make -C nuttx-build/nuttx olddefconfig
+ make -C nuttx-build/nuttx
+ - name: Save ccache
+ if: always()
+ uses: ./.github/actions/ccache-save
+ with:
+ key: ports
diff --git a/.github/workflows/build_all_apps.yml b/.github/workflows/build_all_apps.yml
deleted file mode 100644
index 8dbc306e8..000000000
--- a/.github/workflows/build_all_apps.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: Apps
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
- cancel-in-progress: true
-
-jobs:
- targets:
- name: Build all apps
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v7
- - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
- with:
- release: '15.2.Rel1'
- - name: Install Dependencies
- shell: bash
- run: |
- sudo apt-get update
- sudo apt-get install -y gcc-multilib ccache
- - name: Install newt
- uses: ./.github/actions/newt-install
- - name: Set up project
- uses: ./.github/actions/newt-project
- with:
- save-cache: true
- - name: Remove project targets
- shell: bash
- run: rm -rf build/targets
- - name: Restore ccache
- uses: ./.github/actions/ccache-restore
- with:
- key: apps
- - name: Build applications
- shell: bash
- run: |
- cd build
- bash ../.github/test_build_apps.sh
- cd ..
- - name: Save ccache
- if: always()
- uses: ./.github/actions/ccache-save
- with:
- key: apps
diff --git a/.github/workflows/build_cc_target.yml b/.github/workflows/build_cc_target.yml
deleted file mode 100644
index e4d30c465..000000000
--- a/.github/workflows/build_cc_target.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: GCC target
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
- cancel-in-progress: true
-
-jobs:
- targets:
- name: Build GCC test target
- strategy:
- fail-fast: false
- matrix:
- gcc: ['15.2.Rel1', '14.2.Rel1', '13.2.Rel1', '12.2.Rel1', '11.3.Rel1', '10.3-2021.10', '9-2020-q2', '8-2019-q3']
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v7
- - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
- with:
- release: ${{ matrix.gcc }}
- - name: Install newt
- uses: ./.github/actions/newt-install
- - name: Set up project
- uses: ./.github/actions/newt-project
- - name: Restore ccache
- uses: ./.github/actions/ccache-restore
- with:
- key: gcc-target-${{ matrix.gcc }}
- - name: Build test target
- shell: bash
- run: |
- cd build
- newt target create cc_test
- newt target set cc_test bsp="@apache-mynewt-core/hw/bsp/nordic_pca10056"
- newt target set cc_test app="@apache-mynewt-nimble/apps/btshell"
- cp -f ../.github/test_build_apps_syscfg.yml targets/cc_test/syscfg.yml
- newt build cc_test
- - name: Save ccache
- if: always()
- uses: ./.github/actions/ccache-save
- with:
- key: gcc-target-${{ matrix.gcc }}
diff --git a/.github/workflows/build_ports.yml b/.github/workflows/build_ports.yml
deleted file mode 100644
index f8b48d4b1..000000000
--- a/.github/workflows/build_ports.yml
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: Ports
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
- cancel-in-progress: true
-
-jobs:
- ports:
- name: Build ports
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v7
- - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
- with:
- release: '15.2.Rel1'
- - name: Install Dependencies
- shell: bash
- run: |
- sudo apt-get update
- sudo apt-get install -y make ccache gcc-multilib g++-multilib kconfig-frontends libmbedtls-dev cmake build-essential
- - name: Cache 32-bit Mbed TLS 3.6
- id: cache-mbedtls
- uses: actions/cache@v6
- with:
- path: ${{ github.workspace }}/mbedtls_install
- key: ${{ runner.os }}-mbedtls-3.6.5
- - name: Compile Mbed TLS 3.6 (On Cache Miss)
- if: steps.cache-mbedtls.outputs.cache-hit != 'true'
- run: |
- git clone --depth 1 --branch mbedtls-3.6.5 --recursive https://github.com/Mbed-TLS/mbedtls.git
- cd mbedtls
- cmake -B build \
- -DCMAKE_C_FLAGS="-m32" \
- -DCMAKE_SHARED_LINKER_FLAGS="-m32" \
- -DCMAKE_EXE_LINKER_FLAGS="-m32" \
- -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/mbedtls_install \
- -DUSE_SHARED_MBEDTLS_LIBRARY=On \
- -DENABLE_TESTING=Off
- cmake --build build --target install
- - name: Export Mbed TLS Environment Paths
- run: |
- echo "CPATH=${{ github.workspace }}/mbedtls_install/include" >> $GITHUB_ENV
- echo "LIBRARY_PATH=${{ github.workspace }}/mbedtls_install/lib" >> $GITHUB_ENV
- echo "LD_LIBRARY_PATH=${{ github.workspace }}/mbedtls_install/lib" >> $GITHUB_ENV
- echo "MBEDTLS_DIR=${{ github.workspace }}/mbedtls_install" >> $GITHUB_ENV
- - name: Restore ccache
- uses: ./.github/actions/ccache-restore
- with:
- key: ports
- - name: Build example ports
- shell: bash
- run: |
- make -C porting/examples/dummy/ clean all
- make -C porting/examples/linux/ clean all
- make -C porting/examples/linux_blemesh/ clean all
- make -C porting/examples/linux_blemesh_shell/ clean all
- make -C porting/npl/linux/test/ clean all test
- - name: Build RIOT port
- shell: bash
- if: success() || failure()
- continue-on-error: true
- run: |
- git clone --depth=1 https://github.com/RIOT-OS/RIOT
- rm RIOT/pkg/nimble/patches/ -rf
- sed -i 's|PKG_URL.*|PKG_URL = '$(pwd)'|' RIOT/pkg/nimble/Makefile
- sed -i 's|PKG_VERSION.*|PKG_VERSION = '${{ github.sha }}'|' RIOT/pkg/nimble/Makefile
- make -C RIOT/examples/networking/ble/nimble/nimble_gatt
- - name: Build Nuttx port
- shell: bash
- if: success() || failure()
- continue-on-error: true
- run: |
- mkdir nuttx-build
- git clone --depth=1 https://github.com/apache/nuttx.git nuttx-build/nuttx
- git clone --depth=1 https://github.com/apache/nuttx-apps nuttx-build/apps
- ./nuttx-build/nuttx/tools/configure.sh -l nrf52840-dk:sdc_nimble
- kconfig-tweak --file nuttx-build/nuttx/.config --set-str NIMBLE_REF ${{ github.sha }}
- kconfig-tweak --file nuttx-build/nuttx/.config --enable NIMBLE_PORTING_EXAMPLE
- echo '#include "../../../../mynewt-nimble/porting/examples/nuttx/include/syscfg/syscfg.h"'\
- >> nuttx-build/apps/wireless/bluetooth/nimble/include/syscfg/syscfg.h
- make -C nuttx-build/nuttx olddefconfig
- make -C nuttx-build/nuttx
- - name: Save ccache
- if: always()
- uses: ./.github/actions/ccache-save
- with:
- key: ports
diff --git a/.github/workflows/build_targets.yml b/.github/workflows/build_targets.yml
deleted file mode 100644
index c9a808587..000000000
--- a/.github/workflows/build_targets.yml
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: Targets
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
- cancel-in-progress: true
-
-jobs:
- targets:
- name: Build all test targets
- strategy:
- fail-fast: false
- matrix:
- os: [ubuntu-latest, windows-latest, macos-latest]
- runs-on: ${{ matrix.os }}
- steps:
- - uses: actions/checkout@v7
- - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
- with:
- release: '15.2.Rel1'
- - name: Install Dependencies
- shell: bash
- if: matrix.os == 'ubuntu-latest'
- run: |
- sudo apt-get update
- sudo apt-get install -y gcc-multilib ccache
- - name: Install newt
- uses: ./.github/actions/newt-install
- - name: Set up project
- uses: ./.github/actions/newt-project
- - name: Remove project targets
- shell: bash
- run: rm -rf build/targets
- - name: Restore ccache
- uses: ./.github/actions/ccache-restore
- with:
- key: targets
- - name: Build targets
- shell: bash
- run: |
- cp -r .github/targets build/targets
- cd build
- ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0'
- rm -rf targets
- cd ..
- - name: Build Linux-only targets
- shell: bash
- if: matrix.os == 'ubuntu-latest'
- run: |
- cp -r .github/targets_linux build/targets
- cd build
- ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0'
- rm -rf targets
- cd ..
- - name: Save ccache
- if: always()
- uses: ./.github/actions/ccache-save
- with:
- key: targets
diff --git a/.github/workflows/newt_test_all.yml b/.github/workflows/newt_test_all.yml
deleted file mode 100644
index 959918e79..000000000
--- a/.github/workflows/newt_test_all.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: Unit tests
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
- cancel-in-progress: true
-
-jobs:
- newt_test:
- name: Run newt test all
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v7
- - name: Install Dependencies
- shell: bash
- run: |
- sudo apt-get update
- sudo apt-get install -y gcc-multilib ccache
- - name: Install newt
- uses: ./.github/actions/newt-install
- - name: Set up project
- uses: ./.github/actions/newt-project
- with:
- project: .github/project_newt_test_all.yml
- - name: Restore ccache
- uses: ./.github/actions/ccache-restore
- with:
- key: unit-tests
- - name: Switch to main mcuboot
- # This is temporary until next mcuboot release is available
- shell: bash
- run: |
- cd build/repos/mcuboot
- git fetch --depth=1 origin main
- git checkout --detach FETCH_HEAD
- - name: newt test all
- shell: bash
- run: |
- cd build
- newt test all
- - name: Save ccache
- if: always()
- uses: ./.github/actions/ccache-save
- with:
- key: unit-tests
diff --git a/README.md b/README.md
index b98513a23..fc3ebbd6c 100644
--- a/README.md
+++ b/README.md
@@ -25,24 +25,8 @@
## Overview
-<a href="https://github.com/apache/mynewt-nimble/actions/workflows/build_targets.yml">
- <img src="https://github.com/apache/mynewt-nimble/actions/workflows/build_targets.yml/badge.svg">
-<a/>
-
-<a href="https://github.com/apache/mynewt-nimble/actions/workflows/build_cc_target.yml">
- <img src="https://github.com/apache/mynewt-nimble/actions/workflows/build_cc_target.yml/badge.svg">
-<a/>
-
-<a href="https://github.com/apache/mynewt-nimble/actions/workflows/build_ports.yml">
- <img src="https://github.com/apache/mynewt-nimble/actions/workflows/build_ports.yml/badge.svg">
-<a/>
-
-<a href="https://github.com/apache/mynewt-nimble/actions/workflows/newt_test_all.yml">
- <img src="https://github.com/apache/mynewt-nimble/actions/workflows/newt_test_all.yml/badge.svg">
-<a/>
-
-<a href="https://github.com/apache/mynewt-nimble/actions/workflows/build_all_apps.yml">
- <img src="https://github.com/apache/mynewt-nimble/actions/workflows/build_all_apps.yml/badge.svg">
+<a href="https://github.com/apache/mynewt-nimble/actions/workflows/build.yml">
+ <img src="https://github.com/apache/mynewt-nimble/actions/workflows/build.yml/badge.svg">
<a/>
<p>
(mynewt-nimble) 01/19: ci: Disable pr-size-labeler comment on XL pull requests
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 954a51fbb96bbd9df6ef119ddd5b5bd3b39a61fe
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Fri Oct 16 16:32:41 2026 +0200
ci: Disable pr-size-labeler comment on XL pull requests
pr-size-labeler v1.10.0 failed to post comment on XL pull requests due
to malformed request, so only size label was added. This was fixed in
v1.10.1 and after update to v1.12.0 comment is posted on each pull
request labeled as XL.
Set empty message so that only label is added, as before.
Assisted-by: Claude:claude-opus-5-5
---
.github/workflows/labeler.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 930a77513..9c5950d56 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -43,3 +43,5 @@ jobs:
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ignore_file_deletions: true
+ # Label only, don't comment on XL pull requests
+ message_if_xl: ''
(mynewt-nimble) 10/19: ci: Run unit tests in quiet mode
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit b4421f7fdae514f4c547fa1458710e73383942f5
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 01:43:29 2026 +0200
ci: Run unit tests in quiet mode
Build output of all unit tests is long and makes it hard to find
failures in CI logs. Run newt test in quiet mode, which still prints
tested packages, details of build and test failures, and summary.
Assisted-by: Claude:claude-opus-5-5
---
.github/workflows/build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 479aaf5fb..1759c6c4f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -271,7 +271,7 @@ jobs:
- name: newt test all
run: |
cd build
- newt test all
+ newt test -q all
- name: Save ccache
if: always()
uses: ./.github/actions/ccache-save
(mynewt-nimble) 11/19: ci: Run PR maintenance every 15 minutes
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 5b54f0269477455a287438b9ffc444a96d5a3905
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 13:21:23 2026 +0200
ci: Run PR maintenance every 15 minutes
Labels and workflows status don't need to be updated every 5 minutes,
committers' pull requests wait for CI runs about as long anyway. Run
PR maintenance less often to reduce load on ASF GitHub Actions.
Assisted-by: Claude:claude-opus-5-5
---
.github/workflows/pr_maintenance.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr_maintenance.yml b/.github/workflows/pr_maintenance.yml
index 5d5c0b323..0d4cd123a 100644
--- a/.github/workflows/pr_maintenance.yml
+++ b/.github/workflows/pr_maintenance.yml
@@ -26,7 +26,7 @@ name: Pull request maintenance
on:
schedule:
- - cron: '*/5 * * * *'
+ - cron: '*/15 * * * *'
workflow_dispatch:
permissions:
(mynewt-nimble) 13/19: ci: Add informative workflows-outdated label
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit bda63e8e64c15b468a0635cb2c55a7b509924760
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 16:12:33 2026 +0200
ci: Add informative workflows-outdated label
PR maintenance sets 'workflows-outdated' label on pull requests if
.github of base branch changed since their merge base, and removes it
otherwise. The label is informative only. Merge base is queried only
for pull requests with .github different from base branch.
Whole .github is compared instead of .github/workflows only, also for
'Check workflows' status, as workflows use actions and scripts from it.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 132 +++++++++++++++++++++++++-------------
1 file changed, 89 insertions(+), 43 deletions(-)
diff --git a/.github/scripts/pr_maintenance.py b/.github/scripts/pr_maintenance.py
index 84f49039f..217d37988 100644
--- a/.github/scripts/pr_maintenance.py
+++ b/.github/scripts/pr_maintenance.py
@@ -24,9 +24,12 @@ is done through GitHub API using gh tool.
- 'needs-ci-approval' label is set on pull requests with workflow runs
waiting for approval on their head commit, and removed otherwise.
-- 'Check workflows' commit status reports whether .github/workflows of
- pull request head matches base branch ('workflows-update' label skips
- the check).
+- 'workflows-outdated' label is set on pull requests if .github of
+ base branch changed since merge base, and removed otherwise. It is
+ informative only.
+- 'Check workflows' commit status reports whether .github of pull
+ request head matches base branch ('workflows-update' label skips the
+ check).
- Pull requests with new head commit are reported for path based
labeling, which is done by actions/labeler in the workflow.
@@ -35,9 +38,9 @@ when marked with 'stale' label (set by stale workflow) until new commit
is pushed.
'Check workflows' status also marks pull request head as processed: it
-is tied to head commit and its description contains base branch
-workflows tree it was checked against, so only new or changed pull
-requests are processed.
+is tied to head commit and its description contains base branch .github
+tree it was checked against, so only new or changed pull requests are
+processed.
Usage:
pr_maintenance.py check - update labels, write step outputs
@@ -52,6 +55,7 @@ import sys
CI_LABEL = "needs-ci-approval"
WORKFLOWS_LABEL = "workflows-update"
+OUTDATED_LABEL = "workflows-outdated"
STATUS_CONTEXT = "Check workflows"
STALE_LABEL = "stale"
SKIPPED = f"Skipped, '{WORKFLOWS_LABEL}' label present"
@@ -65,7 +69,7 @@ CI_RUNS_MAX_AGE_DAYS = 30
# Limit API usage, remaining pull requests are handled by next runs
MAX_PULLS_PER_RUN = 20
-# Workflows trees are queried with object() which returns null if path
+# .github trees are queried with object() which returns null if path
# doesn't exist, Commit.file() fails whole query (and gh pagination) instead
TREES_PER_QUERY = 100
@@ -132,7 +136,7 @@ query ($owner: String!, $repo: String!) {
}
"""
-TREE_FIELD = 'c%d: object(expression: "%s:.github/workflows") { oid }'
+TREE_FIELD = 'c%d: object(expression: "%s:.github") { oid }'
def gh(*args):
@@ -145,8 +149,8 @@ def error(message):
print(f"::error::{message}")
-def workflows_trees(commits):
- """Returns dict of commit to its .github/workflows tree (or None)"""
+def github_trees(commits):
+ """Returns dict of commit to its .github tree (or None)"""
owner, repo = REPO.split("/")
commits = sorted(set(commits))
trees = {}
@@ -164,7 +168,13 @@ def workflows_trees(commits):
return trees
+def merge_base(base, head):
+ return gh("api", f"repos/{REPO}/compare/{base}...{head}?per_page=1",
+ "--jq", ".merge_base_commit.sha").strip()
+
+
def list_pulls():
+ """Returns list of pull requests and number of errors"""
owner, repo = REPO.split("/")
pages = json.loads(gh("api", "graphql", "--paginate", "--slurp",
"-f", f"query={PULLS_QUERY}",
@@ -202,54 +212,65 @@ def list_pulls():
print(f"{skipped} stale pull requests skipped")
- trees = workflows_trees([p["head"] for p in pulls] +
- [p["base_head"] for p in pulls if p["base_head"]])
+ trees = github_trees([p["head"] for p in pulls] +
+ [p["base_head"] for p in pulls if p["base_head"]])
+ merge_bases = {}
+ errors = 0
for pull in pulls:
- base_head = pull.pop("base_head")
- base_name = pull.pop("base_name")
- base_tree = trees.get(base_head)
+ base_tree = trees.get(pull["base_head"])
pull["tree"] = trees[pull["head"]]
pull["base_tree"] = base_tree
- pull["base"] = f"{base_name}@{(base_tree or 'none')[:12]}"
+ pull["base"] = f"{pull['base_name']}@{(base_tree or 'none')[:12]}"
- return pulls
+ # Same tree as base means pull request neither modifies .github
+ # nor is out of date, merge base is not needed
+ if pull["tree"] == base_tree or not pull["base_head"]:
+ pull["merge_base_tree"] = base_tree
+ continue
+ try:
+ merge_bases[pull["number"]] = merge_base(pull["base_head"],
+ pull["head"])
+ except subprocess.CalledProcessError as e:
+ error(f"#{pull['number']}: {e.stderr.strip()}")
+ errors += 1
-def update_ci_label(pulls):
- """Returns number of errors"""
- since = date.today() - timedelta(days=CI_RUNS_MAX_AGE_DAYS)
- try:
- waiting = set(gh("api", "--paginate",
- f"repos/{REPO}/actions/runs?status=action_required"
- f"&created=>={since.isoformat()}&per_page=100",
- "--jq", ".workflow_runs[].head_sha").split())
- except subprocess.CalledProcessError as e:
- error(f"Failed to list workflow runs: {e.stderr.strip()}")
- return 1
+ trees = github_trees(merge_bases.values())
+ for pull in pulls:
+ if pull["number"] in merge_bases:
+ pull["merge_base_tree"] = trees[merge_bases[pull["number"]]]
+
+ return pulls, errors
+
+def sync_label(pulls, label, color, wanted):
+ """
+ Sets label on pull requests for which wanted() returns True and
+ removes it from others, returns number of errors
+ """
issue = f"repos/{REPO}/issues"
label_created = False
errors = 0
for pull in pulls:
- has_label = CI_LABEL in pull["labels"]
- if (pull["head"] in waiting) == has_label:
+ has_label = label in pull["labels"]
+ if wanted(pull) == has_label:
continue
try:
if has_label:
gh("api", "-X", "DELETE",
- f"{issue}/{pull['number']}/labels/{CI_LABEL}")
- print(f"#{pull['number']}: removed '{CI_LABEL}' label")
+ f"{issue}/{pull['number']}/labels/{label}")
+ print(f"#{pull['number']}: removed '{label}' label")
else:
if not label_created:
- gh("label", "create", CI_LABEL, "-R", REPO, "--force",
- "--color", "E3650b")
+ gh("label", "create", label, "-R", REPO, "--force",
+ "--color", color)
label_created = True
gh("api", "-X", "POST", f"{issue}/{pull['number']}/labels",
- "-f", f"labels[]={CI_LABEL}")
- print(f"#{pull['number']}: added '{CI_LABEL}' label")
+ "-f", f"labels[]={label}")
+ print(f"#{pull['number']}: added '{label}' label")
except subprocess.CalledProcessError as e:
error(f"#{pull['number']}: {e.stderr.strip()}")
errors += 1
@@ -257,6 +278,28 @@ def update_ci_label(pulls):
return errors
+def update_ci_label(pulls):
+ """Returns number of errors"""
+ since = date.today() - timedelta(days=CI_RUNS_MAX_AGE_DAYS)
+ try:
+ waiting = set(gh("api", "--paginate",
+ f"repos/{REPO}/actions/runs?status=action_required"
+ f"&created=>={since.isoformat()}&per_page=100",
+ "--jq", ".workflow_runs[].head_sha").split())
+ except subprocess.CalledProcessError as e:
+ error(f"Failed to list workflow runs: {e.stderr.strip()}")
+ return 1
+
+ return sync_label(pulls, CI_LABEL, "E3650b",
+ lambda p: p["head"] in waiting)
+
+
+def update_outdated_label(pulls):
+ """Returns number of errors"""
+ return sync_label(pulls, OUTDATED_LABEL, "FEF2C0",
+ lambda p: p["base_tree"] != p["merge_base_tree"])
+
+
def workflows_status(pull):
"""Returns status to report, or None if reported one is up to date"""
status = pull["status"]
@@ -265,10 +308,10 @@ def workflows_status(pull):
new = {"state": "success", "description": SKIPPED}
elif pull["tree"] == pull["base_tree"]:
new = {"state": "success",
- "description": f"Workflows match {pull['base']}"}
+ "description": f".github matches {pull['base']}"}
else:
new = {"state": "failure",
- "description": f"Workflows differ from {pull['base']}, "
+ "description": f".github differs from {pull['base']}, "
f"rebase or apply '{WORKFLOWS_LABEL}' label"}
if status and (status["state"], status["description"]) == \
@@ -280,15 +323,18 @@ def workflows_status(pull):
def check():
"""
- Updates CI approval label and returns number of errors and step
- outputs:
+ Updates CI approval and outdated labels, returns number of errors
+ and step outputs:
pr-numbers - newline separated pull requests for path based labeling
statuses - JSON list of workflows commit statuses to report
"""
- pulls = list_pulls()
+ pulls, errors = list_pulls()
print(f"{len(pulls)} open pull requests")
- errors = update_ci_label(pulls)
- statuses = [s for s in map(workflows_status, pulls) if s]
+ errors += update_ci_label(pulls)
+ # Pull requests without merge base tree failed and were reported
+ pulls_ok = [p for p in pulls if "merge_base_tree" in p]
+ errors += update_outdated_label(pulls_ok)
+ statuses = [s for s in map(workflows_status, pulls_ok) if s]
statuses = statuses[:MAX_PULLS_PER_RUN]
reported = {s["sha"] for s in statuses}
(mynewt-nimble) 06/19: ci: Add support for splitting apps build into shards
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 91c408c32451fce018d07c0c8e5f2501f54e8d51
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 14 00:54:54 2026 +0200
ci: Add support for splitting apps build into shards
Applications build script builds all applications sequentially in
single job, each of them twice (with default and all-enabled config).
Add support for building only applications assigned to selected shard
(SHARD_INDEX of SHARD_TOTAL) so that build can be split between
multiple CI jobs. By default everything is built, as before.
Assisted-by: Claude:claude-opus-5-5
---
.github/test_build_apps.sh | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/.github/test_build_apps.sh b/.github/test_build_apps.sh
index cbf25cfff..f723614c9 100755
--- a/.github/test_build_apps.sh
+++ b/.github/test_build_apps.sh
@@ -19,6 +19,12 @@
EXIT_CODE=0
+# Build only items assigned to this shard (for splitting build between
+# CI jobs), by default everything is built.
+SHARD_INDEX=${SHARD_INDEX:-0}
+SHARD_TOTAL=${SHARD_TOTAL:-1}
+ITEM_INDEX=0
+
APPS=$(basename -a `ls -d repos/apache-mynewt-nimble/apps/*/`)
IGNORED_APPS="mesh_badge"
@@ -31,6 +37,11 @@ for app in ${APPS}; do
continue
fi
+ ITEM_INDEX=$((ITEM_INDEX + 1))
+ if [ $(( (ITEM_INDEX - 1) % SHARD_TOTAL )) -ne $SHARD_INDEX ]; then
+ continue
+ fi
+
echo "Testing $app"
target="test-$app"
(mynewt-nimble) 08/19: ci: Remove superseded caches at end of build workflow
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit f8d2948dd6abe94f3e8882ea8a2328f65bbdfdd9
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Fri Oct 16 16:37:45 2026 +0200
ci: Remove superseded caches at end of build workflow
Caches are saved only from master and each ccache entry gets unique
key, but only newest entry of each kind is used by following runs.
Older entries only take space from repository cache quota until
GitHub evicts them, possibly together with entries still in use.
Remove superseded caches in last job of build workflow, right after
caches are saved. Only that job has write access to caches, jobs
building code still have read-only token. Entries of ccache are
ordered by run ID and attempt from key, so that entry saved by older
run that completed after newer one never replaces entry saved by
newer run, other caches by creation time.
Cleanup action is same as in apache-mynewt-core.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/cache-cleanup/action.yml | 107 +++++++++++++++++++++++++++++++
.github/workflows/build.yml | 20 ++++++
2 files changed, 127 insertions(+)
diff --git a/.github/actions/cache-cleanup/action.yml b/.github/actions/cache-cleanup/action.yml
new file mode 100644
index 000000000..a1f6b4561
--- /dev/null
+++ b/.github/actions/cache-cleanup/action.yml
@@ -0,0 +1,107 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Remove superseded caches
+description: >
+ Remove caches superseded by newer ones. Caches are saved only from
+ master branch with unique keys (e.g. ccache-<job>-<run_id>-<attempt>)
+ and only newest entry of each kind is used by later runs, so older
+ entries only take space from repository cache quota. Should be used
+ from job run after all jobs saving caches are completed. Requires
+ actions: write permission.
+
+runs:
+ using: composite
+ steps:
+ - uses: actions/github-script@v9
+ with:
+ script: |
+ // Kind of cache is identified by all capture groups of
+ // matching pattern. Entries of ccache are ordered by run ID
+ // and attempt from key, so that entry saved by older run
+ // completed after newer one never replaces newer entry,
+ // other caches by creation time.
+ const families = [
+ {
+ re: /^(ccache-.+)-(\d+)-(\d+)$/,
+ name: (m) => m[1],
+ order: (m) => [Number(m[2]), Number(m[3])],
+ },
+ {
+ re: /^(newt-repos-[^-]+)-[0-9a-f]+$/,
+ name: (m) => m[1],
+ },
+ {
+ re: /^(newt-[^-]+)-[0-9a-f]{40}-(.+)$/,
+ name: (m) => `${m[1]}-${m[2]}`,
+ },
+ ];
+
+ const caches = await github.paginate(
+ github.rest.actions.getActionsCacheList,
+ { ...context.repo, ref: 'refs/heads/master', per_page: 100 });
+
+ const newer = (a, b) => {
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] !== b[i]) {
+ return a[i] > b[i];
+ }
+ }
+ return false;
+ };
+
+ const newest = new Map();
+ const stale = [];
+ for (const cache of caches) {
+ for (const family of families) {
+ const m = cache.key.match(family.re);
+ if (!m) {
+ continue;
+ }
+ const name = family.name(m);
+ const order = family.order ?
+ family.order(m) : [Date.parse(cache.created_at)];
+ const current = newest.get(name);
+ if (!current) {
+ newest.set(name, { cache, order });
+ } else if (newer(order, current.order)) {
+ stale.push(current.cache);
+ newest.set(name, { cache, order });
+ } else {
+ stale.push(cache);
+ }
+ break;
+ }
+ }
+
+ for (const cache of stale) {
+ core.info(`Removing ${cache.key} (${cache.size_in_bytes} bytes)`);
+ try {
+ await github.rest.actions.deleteActionsCacheById({
+ ...context.repo,
+ cache_id: cache.id,
+ });
+ } catch (e) {
+ // Cache may be already removed by GitHub or other run
+ if (e.status !== 404) {
+ throw e;
+ }
+ }
+ }
+ core.info(`Kept ${newest.size} caches, removed ${stale.length}`);
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 894a9b849..7f8ea709f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -357,3 +357,23 @@ jobs:
uses: ./.github/actions/ccache-save
with:
key: ports
+
+ # Jobs save caches with unique keys, remove entries superseded by
+ # caches saved in this run. Separate job, so that only it has write
+ # access to caches and none of jobs building code does.
+ cache-cleanup:
+ name: Remove superseded caches
+ needs: [newt, prepare, apps, targets, gcc-target, unit-tests, ports]
+ if: >-
+ !cancelled() && github.ref == 'refs/heads/master' &&
+ github.event_name != 'pull_request'
+ runs-on: ubuntu-slim
+ permissions:
+ actions: write
+ contents: read
+ steps:
+ - uses: actions/checkout@v7
+ with:
+ sparse-checkout: .github/actions
+ - name: Remove superseded caches
+ uses: ./.github/actions/cache-cleanup
(mynewt-nimble) 04/19: ci: Cache external repositories between runs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 7e69d46f3147c9dff067bab12338cce6f64b762b
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Fri Oct 16 16:36:01 2026 +0200
ci: Cache external repositories between runs
Each job using newt downloaded all external repositories with newt
upgrade. Add composite action for setting up newt project which
restores repositories from cache before upgrade, so only changes
since cache was created are fetched.
Only .git directories are cached and working trees (including
initialized submodules) are checked out after restore, since git packs
are smaller than compressed working trees. Index is removed before
checkout, as it contains file stats from system that created it. This
also lets single cache created on Linux be used on Windows and macOS,
each system checks out files with its own git settings. Repositories
still appearing modified after checkout are removed, as newt silently
skips upgrade of modified repositories.
apache-mynewt-nimble downloaded by newt is replaced with tested commit,
as before, and is removed before saving cache so it is never cached.
apache-mynewt-core is cached but excluded from cache key, as it is
tracked at master and changes often.
Single cache is shared by all projects as newt skips repositories not
used by project. Cache is saved only from master branch by apps job,
which uses project with all repositories, and only when external
repositories versions changed. Caches from default branch are also
available to pull requests.
mcuboot main used by unit tests is now checked out as detached HEAD,
as local main branch restored from cache may point to old upstream
main and, since repository is shallow, git would reject its update
as non-fast-forward.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/newt-project/action.yml | 125 +++++++++++++++++++++++++++++++
.github/scripts/checkout_repos.sh | 54 +++++++++++++
.github/workflows/build_all_apps.yml | 16 ++--
.github/workflows/build_cc_target.yml | 12 +--
.github/workflows/build_targets.yml | 14 +---
.github/workflows/newt_test_all.yml | 18 ++---
.github/workflows/ports_syscfg_check.yml | 11 +--
7 files changed, 199 insertions(+), 51 deletions(-)
diff --git a/.github/actions/newt-project/action.yml b/.github/actions/newt-project/action.yml
new file mode 100644
index 000000000..11c746dcd
--- /dev/null
+++ b/.github/actions/newt-project/action.yml
@@ -0,0 +1,125 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Set up newt project
+description: >
+ Create newt project for testing current commit. External repositories
+ are restored from cache and then upgraded by newt, so only changes
+ since cache was created are downloaded. apache-mynewt-nimble is
+ replaced with tested commit and is not cached. Only .git directories
+ are cached and working trees are checked out after restore, which
+ keeps cache small and lets each system check out files with its own
+ git settings. Cache is created on Linux and shared with other
+ systems. Single cache is shared by all projects since newt skips
+ repositories not used by project. Cache should be saved only by one
+ job using project with all repositories and only from master branch,
+ since only caches from default branch are available to pull requests.
+
+inputs:
+ project:
+ description: Project file to use (relative to repository root)
+ required: false
+ default: .github/project.yml
+ path:
+ description: Directory to create project in
+ required: false
+ default: build
+ save-cache:
+ description: Save repositories to cache (Linux and master branch only)
+ required: false
+ default: 'false'
+
+runs:
+ using: composite
+ steps:
+ - name: Create project
+ id: project
+ shell: bash
+ run: |
+ newt new "${{ inputs.path }}"
+ cp -f "${{ inputs.project }}" "${{ inputs.path }}/project.yml"
+ echo "cache-prefix=newt-repos-git-" >> "$GITHUB_OUTPUT"
+
+ - name: Restore repositories from cache
+ id: restore
+ uses: actions/cache/restore@v6
+ with:
+ path: ${{ inputs.path }}/repos/*/.git
+ key: ${{ steps.project.outputs.cache-prefix }}${{ github.sha }}
+ restore-keys: ${{ steps.project.outputs.cache-prefix }}
+ # Cache is created on Linux, Windows needs this to restore it
+ enableCrossOsArchive: true
+
+ # newt silently skips upgrade of modified repositories, so remove
+ # those still appearing modified after checkout (e.g. due to line
+ # endings on Windows), so that they are cloned again.
+ - name: Check out restored repositories
+ if: steps.restore.outputs.cache-matched-key != ''
+ shell: bash
+ working-directory: ${{ inputs.path }}
+ run: |
+ bash "$GITHUB_WORKSPACE/.github/scripts/checkout_repos.sh" .
+ for d in repos/*/; do
+ if [ -n "$(git -C "$d" status --porcelain --untracked-files=no)" ]; then
+ echo "::warning::$d modified after restore from cache, removing"
+ rm -rf "$d"
+ fi
+ done
+
+ # apache-mynewt-nimble version downloaded by newt is not used, it is
+ # replaced with tested commit later. Upgrade is not repeated after
+ # that, as newt would switch apache-mynewt-nimble back to version
+ # required by apache-mynewt-core.
+ - name: Upgrade repositories
+ shell: bash
+ working-directory: ${{ inputs.path }}
+ run: |
+ newt upgrade --shallow=1
+ rm -rf repos/apache-mynewt-nimble
+
+ # Cache key is based on external repositories versions only, so new
+ # cache is created only when dependencies change and not on every
+ # commit to apache-mynewt-core.
+ - name: Compute repositories cache key
+ id: key
+ shell: bash
+ working-directory: ${{ inputs.path }}
+ run: |
+ hash=$(for d in repos/*/; do
+ [ "$d" = "repos/apache-mynewt-core/" ] && continue
+ echo "$d $(git -C "$d" rev-parse HEAD)"
+ done | git hash-object --stdin | cut -c1-16)
+ echo "key=${{ steps.project.outputs.cache-prefix }}$hash" >> "$GITHUB_OUTPUT"
+
+ - name: Save repositories to cache
+ if: >-
+ inputs.save-cache == 'true' && runner.os == 'Linux' &&
+ github.ref == 'refs/heads/master' &&
+ github.event_name != 'pull_request' &&
+ steps.restore.outputs.cache-matched-key != steps.key.outputs.key
+ uses: actions/cache/save@v6
+ with:
+ path: ${{ inputs.path }}/repos/*/.git
+ key: ${{ steps.key.outputs.key }}
+ enableCrossOsArchive: true
+
+ - name: Use tested apache-mynewt-nimble
+ shell: bash
+ run: |
+ git clone -q . "${{ inputs.path }}/repos/apache-mynewt-nimble"
diff --git a/.github/scripts/checkout_repos.sh b/.github/scripts/checkout_repos.sh
new file mode 100755
index 000000000..395e199f6
--- /dev/null
+++ b/.github/scripts/checkout_repos.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Recreate working trees of project repositories restored from cache or
+# artifact. Only .git directories are stored there, since working trees
+# can be checked out from those and are bigger after compression.
+# Submodules initialized when repository was cloned are checked out
+# from repositories stored in .git/modules.
+#
+# Usage: checkout_repos.sh <project directory>
+
+set -e
+
+cd "$1"
+
+for d in repos/*/; do
+ [ -d "$d.git" ] || continue
+
+ # .git may come from other system, use settings of this one
+ opts=()
+ if [ "$RUNNER_OS" = "Windows" ]; then
+ opts=(-c core.symlinks=false -c core.filemode=false)
+ git -C "$d" config core.symlinks false
+ git -C "$d" config core.filemode false
+ fi
+
+ # Index contains file stats from system that created it
+ rm -f "$d.git/index"
+ git -C "$d" reset -q --hard
+
+ if [ -f "$d.gitmodules" ]; then
+ git "${opts[@]}" -C "$d" submodule update -q --recursive
+ if [ "$RUNNER_OS" = "Windows" ]; then
+ git -C "$d" submodule foreach -q --recursive \
+ "git config core.symlinks false; git config core.filemode false"
+ fi
+ fi
+done
diff --git a/.github/workflows/build_all_apps.yml b/.github/workflows/build_all_apps.yml
index b15519fad..c619501d9 100644
--- a/.github/workflows/build_all_apps.yml
+++ b/.github/workflows/build_all_apps.yml
@@ -45,17 +45,13 @@ jobs:
sudo apt-get install -y gcc-multilib
- name: Install newt
uses: ./.github/actions/newt-install
- - name: Setup project
+ - name: Set up project
+ uses: ./.github/actions/newt-project
+ with:
+ save-cache: true
+ - name: Remove project targets
shell: bash
- run: |
- newt new build
- cp -f .github/project.yml build/project.yml
- cd build
- newt upgrade --shallow=1
- rm -rf targets
- rm -rf repos/apache-mynewt-nimble
- git clone .. repos/apache-mynewt-nimble
- cd ..
+ run: rm -rf build/targets
- name: Build applications
shell: bash
run: |
diff --git a/.github/workflows/build_cc_target.yml b/.github/workflows/build_cc_target.yml
index 2fd069355..3e0c7cabd 100644
--- a/.github/workflows/build_cc_target.yml
+++ b/.github/workflows/build_cc_target.yml
@@ -44,16 +44,8 @@ jobs:
release: ${{ matrix.gcc }}
- name: Install newt
uses: ./.github/actions/newt-install
- - name: Setup project
- shell: bash
- run: |
- newt new build
- cp -f .github/project.yml build/project.yml
- cd build
- newt upgrade --shallow=1
- rm -rf repos/apache-mynewt-nimble
- git clone .. repos/apache-mynewt-nimble
- cd ..
+ - name: Set up project
+ uses: ./.github/actions/newt-project
- name: Build test target
shell: bash
run: |
diff --git a/.github/workflows/build_targets.yml b/.github/workflows/build_targets.yml
index df595a03f..97de444c4 100644
--- a/.github/workflows/build_targets.yml
+++ b/.github/workflows/build_targets.yml
@@ -50,17 +50,11 @@ jobs:
sudo apt-get install -y gcc-multilib
- name: Install newt
uses: ./.github/actions/newt-install
- - name: Setup project
+ - name: Set up project
+ uses: ./.github/actions/newt-project
+ - name: Remove project targets
shell: bash
- run: |
- newt new build
- cp -f .github/project.yml build/project.yml
- cd build
- newt upgrade --shallow=1
- rm -rf targets
- rm -rf repos/apache-mynewt-nimble
- git clone .. repos/apache-mynewt-nimble
- cd ..
+ run: rm -rf build/targets
- name: Build targets
shell: bash
run: |
diff --git a/.github/workflows/newt_test_all.yml b/.github/workflows/newt_test_all.yml
index 03797238c..20d14114a 100644
--- a/.github/workflows/newt_test_all.yml
+++ b/.github/workflows/newt_test_all.yml
@@ -42,23 +42,17 @@ jobs:
sudo apt-get install -y gcc-multilib
- name: Install newt
uses: ./.github/actions/newt-install
- - name: Setup project
- shell: bash
- run: |
- newt new build
- cp -f .github/project_newt_test_all.yml build/project.yml
- cd build
- newt upgrade --shallow=1
- rm -rf repos/apache-mynewt-nimble
- git clone .. repos/apache-mynewt-nimble
- cd ..
+ - name: Set up project
+ uses: ./.github/actions/newt-project
+ with:
+ project: .github/project_newt_test_all.yml
- name: Switch to main mcuboot
# This is temporary until next mcuboot release is available
shell: bash
run: |
cd build/repos/mcuboot
- git fetch origin main:main
- git checkout main
+ git fetch --depth=1 origin main
+ git checkout --detach FETCH_HEAD
- name: newt test all
shell: bash
run: |
diff --git a/.github/workflows/ports_syscfg_check.yml b/.github/workflows/ports_syscfg_check.yml
index 01a4476de..e24ed9e7d 100644
--- a/.github/workflows/ports_syscfg_check.yml
+++ b/.github/workflows/ports_syscfg_check.yml
@@ -46,15 +46,8 @@ jobs:
sudo apt-get install -y gcc-multilib
- name: Install newt
uses: ./.github/actions/newt-install
- - name: Setup project
- shell: bash
- run: |
- newt new build
- cp -f .github/project.yml build/project.yml
- cd build
- newt upgrade --shallow=1
- rm -rf repos/apache-mynewt-nimble
- git clone .. repos/apache-mynewt-nimble
+ - name: Set up project
+ uses: ./.github/actions/newt-project
- name: Build ports tests targets
shell: bash
run: |
(mynewt-nimble) 03/19: ci: Cache newt binary between runs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit d3af3ba1defb1656c855c432a23e6747b5a8ac4b
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 14 00:53:42 2026 +0200
ci: Cache newt binary between runs
Each build job compiled newt from source with go install. Add
composite action that builds newt from current master commit of
apache/mynewt-newt and caches built binary keyed by that commit, so
newt is rebuilt only when newt master changes. Newt is installed from
exact commit which also avoids delays in module proxy picking up
latest master.
Cache is saved only from master branch, pull requests use cache saved
by master.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/newt-install/action.yml | 92 ++++++++++++++++++++++++++++++++
.github/workflows/build_all_apps.yml | 9 +---
.github/workflows/build_cc_target.yml | 9 +---
.github/workflows/build_targets.yml | 9 +---
.github/workflows/newt_test_all.yml | 9 +---
.github/workflows/ports_syscfg_check.yml | 9 +---
6 files changed, 97 insertions(+), 40 deletions(-)
diff --git a/.github/actions/newt-install/action.yml b/.github/actions/newt-install/action.yml
new file mode 100644
index 000000000..58e406799
--- /dev/null
+++ b/.github/actions/newt-install/action.yml
@@ -0,0 +1,92 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Install newt
+description: >
+ Install newt built from master branch of apache/mynewt-newt. Built
+ binary is cached per newt commit, so newt is rebuilt only when newt
+ master branch changes.
+
+runs:
+ using: composite
+ steps:
+ - name: Get newt master commit
+ id: newt
+ shell: bash
+ run: |
+ sha=$(git ls-remote https://github.com/apache/mynewt-newt.git refs/heads/master | cut -f1)
+ if [ -z "$sha" ]; then
+ echo "::error::Failed to get newt master commit"
+ exit 1
+ fi
+ echo "newt master is at $sha"
+ echo "sha=$sha" >> "$GITHUB_OUTPUT"
+
+ - name: Restore newt from cache
+ id: cache
+ uses: actions/cache/restore@v6
+ with:
+ path: ${{ github.workspace }}/.newt-bin
+ key: newt-${{ runner.os }}-${{ runner.arch }}-${{ steps.newt.outputs.sha }}
+
+ - name: Report newt cache status
+ shell: bash
+ env:
+ CACHE_HIT: ${{ steps.cache.outputs.cache-hit }}
+ CACHE_KEY: ${{ steps.cache.outputs.cache-primary-key }}
+ run: |
+ if [ "$CACHE_HIT" = "true" ]; then
+ echo "newt cache hit: using cached build ($CACHE_KEY)"
+ else
+ echo "newt cache miss: building newt from source ($CACHE_KEY)"
+ fi
+
+ - name: Set up Go
+ if: steps.cache.outputs.cache-hit != 'true'
+ uses: actions/setup-go@v7
+ with:
+ go-version: 'stable'
+ cache: false
+
+ - name: Build newt
+ if: steps.cache.outputs.cache-hit != 'true'
+ shell: bash
+ env:
+ GOBIN: ${{ github.workspace }}/.newt-bin
+ run: |
+ go version
+ go install mynewt.apache.org/newt/newt@${{ steps.newt.outputs.sha }}
+
+ # Only master saves cache, so that it is shared with all pull
+ # requests instead of being duplicated in each pull request scope
+ - name: Save newt to cache
+ if: >-
+ steps.cache.outputs.cache-hit != 'true' &&
+ github.ref == 'refs/heads/master' &&
+ github.event_name != 'pull_request'
+ uses: actions/cache/save@v6
+ with:
+ path: ${{ github.workspace }}/.newt-bin
+ key: ${{ steps.cache.outputs.cache-primary-key }}
+
+ - name: Add newt to PATH
+ shell: bash
+ run: |
+ echo "${{ github.workspace }}/.newt-bin" >> "$GITHUB_PATH"
+ "${{ github.workspace }}/.newt-bin/newt" version
diff --git a/.github/workflows/build_all_apps.yml b/.github/workflows/build_all_apps.yml
index b4fbf365c..b15519fad 100644
--- a/.github/workflows/build_all_apps.yml
+++ b/.github/workflows/build_all_apps.yml
@@ -35,10 +35,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- - uses: actions/setup-go@v7
- with:
- go-version: 'stable'
- cache: false
- uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
with:
release: '15.2.Rel1'
@@ -48,10 +44,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-multilib
- name: Install newt
- shell: bash
- run: |
- go version
- go install mynewt.apache.org/newt/newt@latest
+ uses: ./.github/actions/newt-install
- name: Setup project
shell: bash
run: |
diff --git a/.github/workflows/build_cc_target.yml b/.github/workflows/build_cc_target.yml
index 60e218fb6..2fd069355 100644
--- a/.github/workflows/build_cc_target.yml
+++ b/.github/workflows/build_cc_target.yml
@@ -39,18 +39,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- - uses: actions/setup-go@v7
- with:
- go-version: 'stable'
- cache: false
- uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
with:
release: ${{ matrix.gcc }}
- name: Install newt
- shell: bash
- run: |
- go version
- go install mynewt.apache.org/newt/newt@latest
+ uses: ./.github/actions/newt-install
- name: Setup project
shell: bash
run: |
diff --git a/.github/workflows/build_targets.yml b/.github/workflows/build_targets.yml
index e75d34799..df595a03f 100644
--- a/.github/workflows/build_targets.yml
+++ b/.github/workflows/build_targets.yml
@@ -39,10 +39,6 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- - uses: actions/setup-go@v7
- with:
- go-version: 'stable'
- cache: false
- uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
with:
release: '15.2.Rel1'
@@ -53,10 +49,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-multilib
- name: Install newt
- shell: bash
- run: |
- go version
- go install mynewt.apache.org/newt/newt@latest
+ uses: ./.github/actions/newt-install
- name: Setup project
shell: bash
run: |
diff --git a/.github/workflows/newt_test_all.yml b/.github/workflows/newt_test_all.yml
index 289270279..03797238c 100644
--- a/.github/workflows/newt_test_all.yml
+++ b/.github/workflows/newt_test_all.yml
@@ -35,20 +35,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- - uses: actions/setup-go@v7
- with:
- go-version: 'stable'
- cache: false
- name: Install Dependencies
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y gcc-multilib
- name: Install newt
- shell: bash
- run: |
- go version
- go install mynewt.apache.org/newt/newt@latest
+ uses: ./.github/actions/newt-install
- name: Setup project
shell: bash
run: |
diff --git a/.github/workflows/ports_syscfg_check.yml b/.github/workflows/ports_syscfg_check.yml
index e49b33c58..01a4476de 100644
--- a/.github/workflows/ports_syscfg_check.yml
+++ b/.github/workflows/ports_syscfg_check.yml
@@ -36,10 +36,6 @@ jobs:
if: github.event.repository.fork == false
steps:
- uses: actions/checkout@v7
- - uses: actions/setup-go@v7
- with:
- go-version: 'stable'
- cache: false
- uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
with:
release: '15.2.Rel1'
@@ -49,10 +45,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-multilib
- name: Install newt
- shell: bash
- run: |
- go version
- go install mynewt.apache.org/newt/newt@latest
+ uses: ./.github/actions/newt-install
- name: Setup project
shell: bash
run: |
(mynewt-nimble) 17/19: ci: Build GCC test target with all releases in single job
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 9b102d3c93a626ade0b057051666e6e1cedd8dda
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 21:47:09 2026 +0200
ci: Build GCC test target with all releases in single job
GCC test target was built in matrix job, one job per toolchain release.
Each of those 8 jobs restored project artifact and own ccache for
building single target, which took longer than the build itself.
Build all releases in single job instead, same as in
apache-mynewt-core. Project and ccache are restored once and new
gcc-target-build composite action installs each release, builds target
with it and removes it afterwards. Builds for remaining releases run
even if one fails, so job reports all failing releases. All releases
share single ccache with bigger size limit, entries are separated by
CCACHE_COMPILERCHECK=content.
This also lowers number of concurrent jobs in workflow, which is
limited by ASF policy.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/ccache-restore/action.yml | 3 +-
.github/actions/gcc-target-build/action.yml | 65 ++++++++++++++++++++++++++++
.github/workflows/build.yml | 66 +++++++++++++++++++++--------
3 files changed, 116 insertions(+), 18 deletions(-)
diff --git a/.github/actions/ccache-restore/action.yml b/.github/actions/ccache-restore/action.yml
index 13ae7ab5c..e754643ca 100644
--- a/.github/actions/ccache-restore/action.yml
+++ b/.github/actions/ccache-restore/action.yml
@@ -21,7 +21,8 @@ name: Restore ccache
description: >
Install ccache, put it in front of compilers used by newt and restore
ccache directory from cache. Must be used after toolchain is installed
- so that ccache wrappers are found in PATH before real compilers.
+ so that ccache wrappers are found in PATH before real compilers (unless
+ job sets PATH itself, see gcc-target-build).
Supported only on Linux, does nothing on other systems.
inputs:
diff --git a/.github/actions/gcc-target-build/action.yml b/.github/actions/gcc-target-build/action.yml
new file mode 100644
index 000000000..92c409988
--- /dev/null
+++ b/.github/actions/gcc-target-build/action.yml
@@ -0,0 +1,65 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Build GCC test target
+description: >
+ Install given release of GNU Arm Embedded Toolchain, build cc_test
+ target with it and remove it afterwards. Used to build test target with
+ many toolchain releases in single job. Expects project with cc_test
+ target restored in build directory and ccache restored.
+
+inputs:
+ release:
+ description: GNU Arm Embedded Toolchain release name
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: Install toolchain
+ id: gcc
+ uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
+ with:
+ release: ${{ inputs.release }}
+
+ - name: Build target
+ shell: bash
+ env:
+ GCC_PATH: ${{ steps.gcc.outputs.path }}
+ run: |
+ # Toolchain action only prepends to PATH so it also contains
+ # previously installed releases. Set PATH explicitly, ccache
+ # wrappers first so that they find this toolchain as next one.
+ export PATH="$RUNNER_TEMP/ccache-bin:$GCC_PATH:$PATH"
+ arm-none-eabi-gcc --version | head -1
+ cd build
+ # Command lines are same for all releases, so newt would not
+ # rebuild objects built with previous toolchain release.
+ rm -rf bin
+ newt build cc_test
+
+ - name: Remove toolchain
+ if: always() && steps.gcc.outputs.path != ''
+ shell: bash
+ env:
+ GCC_PATH: ${{ steps.gcc.outputs.path }}
+ run: |
+ # Toolchain is installed in directory in home directory
+ dir="${GCC_PATH#"$HOME"/}"
+ rm -rf "$HOME/${dir%%/*}"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1759c6c4f..48fce2ac8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -207,26 +207,13 @@ jobs:
gcc-target:
name: Build GCC test target
needs: prepare
- strategy:
- fail-fast: false
- # Limit number of parallel jobs, ASF policy limits job concurrency
- # level per workflow
- max-parallel: 4
- matrix:
- gcc: ['15.2.Rel1', '14.2.Rel1', '13.2.Rel1', '12.2.Rel1', '11.3.Rel1', '10.3-2021.10', '9-2020-q2', '8-2019-q3']
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- - uses: carlosperate/arm-none-eabi-gcc-action@v1.14.0
- with:
- release: ${{ matrix.gcc }}
- name: Restore project
uses: ./.github/actions/newt-project-restore
- - name: Restore ccache
- uses: ./.github/actions/ccache-restore
- with:
- key: gcc-target-${{ matrix.gcc }}
- - name: Build test target
+ - name: Create test target
+ id: target
shell: bash
run: |
cd build
@@ -234,12 +221,57 @@ jobs:
newt target set cc_test bsp="@apache-mynewt-core/hw/bsp/nordic_pca10056"
newt target set cc_test app="@apache-mynewt-nimble/apps/btshell"
cp -f ../.github/test_build_apps_syscfg.yml targets/cc_test/syscfg.yml
- newt build cc_test
+ - name: Restore ccache
+ uses: ./.github/actions/ccache-restore
+ with:
+ key: gcc-target
+ max-size: 1G
+ # Build with remaining releases even if build with one fails
+ - name: Build with GCC 15.2.Rel1
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 15.2.Rel1
+ - name: Build with GCC 14.2.Rel1
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 14.2.Rel1
+ - name: Build with GCC 13.2.Rel1
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 13.2.Rel1
+ - name: Build with GCC 12.2.Rel1
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 12.2.Rel1
+ - name: Build with GCC 11.3.Rel1
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 11.3.Rel1
+ - name: Build with GCC 10.3-2021.10
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 10.3-2021.10
+ - name: Build with GCC 9-2020-q2
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 9-2020-q2
+ - name: Build with GCC 8-2019-q3
+ if: ${{ !cancelled() && steps.target.outcome == 'success' }}
+ uses: ./.github/actions/gcc-target-build
+ with:
+ release: 8-2019-q3
- name: Save ccache
if: always()
uses: ./.github/actions/ccache-save
with:
- key: gcc-target-${{ matrix.gcc }}
+ key: gcc-target
unit-tests:
name: Run unit tests
(mynewt-nimble) 19/19: ci: Use single project file for all jobs
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit d80b9c1cb336c510502ab3dd84518b4baeaeb956
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 23:07:14 2026 +0200
ci: Use single project file for all jobs
Unit tests used separate project file with list of allowed
repositories, to avoid downloading repositories not needed for tests.
Repositories are now downloaded once per run by prepare job and cached
between runs, so this is no longer needed. The allowed list also had
to be kept in sync with dependencies of apache-mynewt-core, e.g.
coremqtt repository needed by net/mqtt/coremqtt was missing.
Use default project file for unit tests, same as in apache-mynewt-core.
newt-project-restore no longer replaces project file and is now same
as in apache-mynewt-core.
Assisted-by: Claude:claude-opus-5-5
---
.github/actions/newt-project-restore/action.yml | 14 ++-------
.github/actions/newt-project/action.yml | 7 ++---
.github/project_newt_test_all.yml | 39 -------------------------
.github/workflows/build.yml | 4 ---
4 files changed, 6 insertions(+), 58 deletions(-)
diff --git a/.github/actions/newt-project-restore/action.yml b/.github/actions/newt-project-restore/action.yml
index 80db00ce7..7a1692a13 100644
--- a/.github/actions/newt-project-restore/action.yml
+++ b/.github/actions/newt-project-restore/action.yml
@@ -22,14 +22,9 @@ description: >
Restore newt and newt project prepared by prepare job of the same
workflow run, so that external repositories are downloaded only once
per run. Project contains only .git directories of repositories,
- working trees are checked out after restore. Project file is replaced
- with one provided by job.
+ working trees are checked out after restore.
inputs:
- project:
- description: Project file to use (relative to repository root)
- required: false
- default: .github/project.yml
path:
description: Directory to restore project to
required: false
@@ -54,12 +49,9 @@ runs:
echo "$GITHUB_WORKSPACE/.newt-bin" >> "$GITHUB_PATH"
bash "$GITHUB_WORKSPACE/.github/scripts/checkout_repos.sh" "${{ inputs.path }}"
- # Repositories were set up by prepare job for tested commit, so
- # only project file needs to be updated. Project file may limit
- # repositories used by newt (e.g. for unit tests).
- - name: Set up project file
+ # Project was set up and upgraded by prepare job for tested commit
+ - name: Show project info
shell: bash
run: |
- cp -f "${{ inputs.project }}" "${{ inputs.path }}/project.yml"
cd "${{ inputs.path }}"
newt info
diff --git a/.github/actions/newt-project/action.yml b/.github/actions/newt-project/action.yml
index 11c746dcd..8bdf82c62 100644
--- a/.github/actions/newt-project/action.yml
+++ b/.github/actions/newt-project/action.yml
@@ -26,10 +26,9 @@ description: >
are cached and working trees are checked out after restore, which
keeps cache small and lets each system check out files with its own
git settings. Cache is created on Linux and shared with other
- systems. Single cache is shared by all projects since newt skips
- repositories not used by project. Cache should be saved only by one
- job using project with all repositories and only from master branch,
- since only caches from default branch are available to pull requests.
+ systems. Cache should be saved only by one job and only from master
+ branch, since only caches from default branch are available to pull
+ requests.
inputs:
project:
diff --git a/.github/project_newt_test_all.yml b/.github/project_newt_test_all.yml
deleted file mode 100644
index 1db688523..000000000
--- a/.github/project_newt_test_all.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-project.name: "my_project"
-
-project.repositories:
- - apache-mynewt-core
-
-# Use github's distribution mechanism for core ASF libraries.
-# This provides mirroring automatically for us.
-#
-repository.apache-mynewt-core:
- type: github
- vers: 0.0.0
- user: apache
- repo: mynewt-core
-
-project.repositories.allowed:
- - apache-mynewt-core
- - apache-mynewt-nimble
- - mcuboot
- - mbedtls
- - tinycbor
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 48fce2ac8..bb0fbe7e9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -283,12 +283,8 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y gcc-multilib ccache
- # Unit tests project limits repositories to those which tests
- # should be run for
- name: Restore project
uses: ./.github/actions/newt-project-restore
- with:
- project: .github/project_newt_test_all.yml
- name: Restore ccache
uses: ./.github/actions/ccache-restore
with:
(mynewt-nimble) 02/19: ci: Replace pull_request_target workflows with scheduled one
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 751b5dcc3f86332cd33ed213730114efef65b9de
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 14 00:58:14 2026 +0200
ci: Replace pull_request_target workflows with scheduled one
Labeling, CI approval label and workflows check workflows used
pull_request_target, which runs in privileged context for every pull
request event.
Replace them with single workflow scheduled on master which handles
open pull requests through API only, without using any pull request
code. This is same as in apache-mynewt-core. CI approval label is now
set based on workflow runs waiting for approval instead of author
permissions, and is removed once runs are approved. Size labeler
supports only pull request events and is kept in labeler workflow,
without checking out any code.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 335 ++++++++++++++++++++++++++++++++++
.github/workflows/add_ci_label.yml | 94 ----------
.github/workflows/check_workflows.yml | 73 --------
.github/workflows/labeler.yml | 13 +-
.github/workflows/pr_maintenance.yml | 79 ++++++++
5 files changed, 417 insertions(+), 177 deletions(-)
diff --git a/.github/scripts/pr_maintenance.py b/.github/scripts/pr_maintenance.py
new file mode 100644
index 000000000..20f0b4dfd
--- /dev/null
+++ b/.github/scripts/pr_maintenance.py
@@ -0,0 +1,335 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+Periodic maintenance of open pull requests, run by scheduled workflow on
+master. Pull request code is never checked out or executed, everything
+is done through GitHub API using gh tool.
+
+- 'needs-ci-approval' label is set on pull requests with workflow runs
+ waiting for approval on their head commit, and removed otherwise.
+- 'Check workflows' commit status reports whether .github/workflows of
+ pull request head matches base branch ('workflows-update' label skips
+ the check).
+- Pull requests with new head commit are reported for path based
+ labeling, which is done by actions/labeler in the workflow.
+
+'Check workflows' status also marks pull request head as processed: it
+is tied to head commit and its description contains base branch
+workflows tree it was checked against, so only new or changed pull
+requests are processed.
+
+Usage:
+ pr_maintenance.py check - update labels, write step outputs
+ pr_maintenance.py report - report statuses from STATUSES variable
+"""
+
+from datetime import date, timedelta
+import json
+import os
+import subprocess
+import sys
+
+CI_LABEL = "needs-ci-approval"
+WORKFLOWS_LABEL = "workflows-update"
+STATUS_CONTEXT = "Check workflows"
+SKIPPED = f"Skipped, '{WORKFLOWS_LABEL}' label present"
+
+# Runs never approved stay waiting forever, skip old ones
+CI_RUNS_MAX_AGE_DAYS = 30
+
+# Limit API usage, remaining pull requests are handled by next runs
+MAX_PULLS_PER_RUN = 20
+
+# Workflows trees are queried with object() which returns null if path
+# doesn't exist, Commit.file() fails whole query (and gh pagination) instead
+TREES_PER_QUERY = 100
+
+REPO = os.environ.get("GITHUB_REPOSITORY", "")
+
+PULLS_QUERY = """
+query (
+ $owner: String!
+ $repo: String!
+ $context: String!
+ $endCursor: String
+) {
+ repository(owner: $owner, name: $repo) {
+ pullRequests(
+ states: OPEN
+ first: 50
+ after: $endCursor
+ orderBy: { field: UPDATED_AT, direction: DESC }
+ ) {
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ nodes {
+ number
+ headRefOid
+ baseRefName
+ labels(first: 100) {
+ nodes {
+ name
+ }
+ }
+ baseRef {
+ target {
+ oid
+ }
+ }
+ commits(last: 1) {
+ nodes {
+ commit {
+ oid
+ status {
+ context(name: $context) {
+ state
+ description
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+
+TREES_QUERY = """
+query ($owner: String!, $repo: String!) {
+ repository(owner: $owner, name: $repo) {
+%s
+ }
+}
+"""
+
+TREE_FIELD = 'c%d: object(expression: "%s:.github/workflows") { oid }'
+
+
+def gh(*args):
+ """Runs gh command, returns its output"""
+ return subprocess.run(["gh", *args], check=True, capture_output=True,
+ text=True).stdout
+
+
+def error(message):
+ print(f"::error::{message}")
+
+
+def workflows_trees(commits):
+ """Returns dict of commit to its .github/workflows tree (or None)"""
+ owner, repo = REPO.split("/")
+ commits = sorted(set(commits))
+ trees = {}
+
+ for i in range(0, len(commits), TREES_PER_QUERY):
+ chunk = commits[i:i + TREES_PER_QUERY]
+ fields = "\n".join(TREE_FIELD % (n, c) for n, c in enumerate(chunk))
+ data = json.loads(gh("api", "graphql",
+ "-f", f"query={TREES_QUERY % fields}",
+ "-f", f"owner={owner}", "-f", f"repo={repo}"))
+ result = data["data"]["repository"]
+ for n, c in enumerate(chunk):
+ trees[c] = (result[f"c{n}"] or {}).get("oid")
+
+ return trees
+
+
+def list_pulls():
+ owner, repo = REPO.split("/")
+ pages = json.loads(gh("api", "graphql", "--paginate", "--slurp",
+ "-f", f"query={PULLS_QUERY}",
+ "-f", f"owner={owner}", "-f", f"repo={repo}",
+ "-f", f"context={STATUS_CONTEXT}"))
+ pulls = []
+
+ for page in pages:
+ for node in page["data"]["repository"]["pullRequests"]["nodes"]:
+ commit = node["commits"]["nodes"][0]["commit"]
+ # Commits list is limited, skip pull request if head is missing
+ if commit["oid"] != node["headRefOid"]:
+ print(f"#{node['number']}: head commit not found, skipping")
+ continue
+
+ base = (node["baseRef"] or {}).get("target") or {}
+ pulls.append({
+ "number": node["number"],
+ "head": commit["oid"],
+ "labels": [l["name"] for l in node["labels"]["nodes"]],
+ "status": (commit["status"] or {}).get("context"),
+ "base_name": node["baseRefName"],
+ "base_head": base.get("oid"),
+ })
+
+ trees = workflows_trees([p["head"] for p in pulls] +
+ [p["base_head"] for p in pulls if p["base_head"]])
+
+ for pull in pulls:
+ base_head = pull.pop("base_head")
+ base_name = pull.pop("base_name")
+ base_tree = trees.get(base_head)
+ pull["tree"] = trees[pull["head"]]
+ pull["base_tree"] = base_tree
+ pull["base"] = f"{base_name}@{(base_tree or 'none')[:12]}"
+
+ return pulls
+
+
+def update_ci_label(pulls):
+ """Returns number of errors"""
+ since = date.today() - timedelta(days=CI_RUNS_MAX_AGE_DAYS)
+ try:
+ waiting = set(gh("api", "--paginate",
+ f"repos/{REPO}/actions/runs?status=action_required"
+ f"&created=>={since.isoformat()}&per_page=100",
+ "--jq", ".workflow_runs[].head_sha").split())
+ except subprocess.CalledProcessError as e:
+ error(f"Failed to list workflow runs: {e.stderr.strip()}")
+ return 1
+
+ issue = f"repos/{REPO}/issues"
+ label_created = False
+ errors = 0
+
+ for pull in pulls:
+ has_label = CI_LABEL in pull["labels"]
+ if (pull["head"] in waiting) == has_label:
+ continue
+
+ try:
+ if has_label:
+ gh("api", "-X", "DELETE",
+ f"{issue}/{pull['number']}/labels/{CI_LABEL}")
+ print(f"#{pull['number']}: removed '{CI_LABEL}' label")
+ else:
+ if not label_created:
+ gh("label", "create", CI_LABEL, "-R", REPO, "--force",
+ "--color", "E3650b")
+ label_created = True
+ gh("api", "-X", "POST", f"{issue}/{pull['number']}/labels",
+ "-f", f"labels[]={CI_LABEL}")
+ print(f"#{pull['number']}: added '{CI_LABEL}' label")
+ except subprocess.CalledProcessError as e:
+ error(f"#{pull['number']}: {e.stderr.strip()}")
+ errors += 1
+
+ return errors
+
+
+def workflows_status(pull):
+ """Returns status to report, or None if reported one is up to date"""
+ status = pull["status"]
+
+ if WORKFLOWS_LABEL in pull["labels"]:
+ new = {"state": "success", "description": SKIPPED}
+ elif pull["tree"] == pull["base_tree"]:
+ new = {"state": "success",
+ "description": f"Workflows match {pull['base']}"}
+ else:
+ new = {"state": "failure",
+ "description": f"Workflows differ from {pull['base']}, "
+ f"rebase or apply '{WORKFLOWS_LABEL}' label"}
+
+ if status and (status["state"], status["description"]) == \
+ (new["state"], new["description"]):
+ return None
+
+ return {"sha": pull["head"], **new}
+
+
+def check():
+ """
+ Updates CI approval label and returns number of errors and step
+ outputs:
+ pr-numbers - newline separated pull requests for path based labeling
+ statuses - JSON list of workflows commit statuses to report
+ """
+ pulls = list_pulls()
+ print(f"{len(pulls)} open pull requests")
+ errors = update_ci_label(pulls)
+ statuses = [s for s in map(workflows_status, pulls) if s]
+ statuses = statuses[:MAX_PULLS_PER_RUN]
+ reported = {s["sha"] for s in statuses}
+
+ # No status on head commit means pull request was updated
+ labels = [str(p["number"]) for p in pulls
+ if not p["status"] and p["head"] in reported]
+
+ for status in statuses:
+ print(f"{status['sha']}: {status['description']}")
+
+ return errors, {
+ "pr-numbers": "\n".join(labels),
+ "statuses": json.dumps(statuses),
+ }
+
+
+def report(statuses, target_url):
+ """Reports statuses computed by check(), returns number of errors"""
+ errors = 0
+
+ for status in statuses:
+ try:
+ gh("api", "-X", "POST", f"repos/{REPO}/statuses/{status['sha']}",
+ "-f", f"state={status['state']}",
+ "-f", f"description={status['description']}",
+ "-f", f"context={STATUS_CONTEXT}",
+ "-f", f"target_url={target_url}")
+ print(f"{status['sha']}: {status['state']}")
+ except subprocess.CalledProcessError as e:
+ error(f"{status['sha']}: {e.stderr.strip()}")
+ errors += 1
+
+ return errors
+
+
+def write_outputs(outputs):
+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+ for key, value in outputs.items():
+ if "\n" in value:
+ f.write(f"{key}<<EOF\n{value}\nEOF\n")
+ else:
+ f.write(f"{key}={value}\n")
+
+
+def main():
+ if sys.argv[1:] == ["check"]:
+ try:
+ errors, outputs = check()
+ except subprocess.CalledProcessError as e:
+ sys.exit(f"Failed to list pull requests: {e.stderr.strip()}")
+ # Outputs are written even on errors so following steps can
+ # handle pull requests that were processed successfully
+ write_outputs(outputs)
+ elif sys.argv[1:] == ["report"]:
+ url = f"{os.environ['GITHUB_SERVER_URL']}/{REPO}/actions/runs/" \
+ f"{os.environ['GITHUB_RUN_ID']}"
+ errors = report(json.loads(os.environ["STATUSES"]), url)
+ else:
+ sys.exit(__doc__)
+
+ if errors:
+ sys.exit(f"{errors} error(s) occurred")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/add_ci_label.yml b/.github/workflows/add_ci_label.yml
deleted file mode 100644
index 3bff33c37..000000000
--- a/.github/workflows/add_ci_label.yml
+++ /dev/null
@@ -1,94 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: Informative CI status
-
-on:
- pull_request_target:
- types: [opened, ready_for_review, reopened, synchronize]
-
-permissions:
- contents: read
- issues: write
- pull-requests: write
-
-jobs:
- add-label:
- runs-on: ubuntu-slim
- steps:
- - uses: actions/github-script@v7
- with:
- script: |
- const pr = context.payload.pull_request;
-
- // Get author's effective repo permission: admin|maintain|write|triage|read|none
- let permission = 'unknown';
- try {
- const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
- ...context.repo,
- username: pr.user.login,
- });
- permission = data.permission || 'unknown';
- } catch (e) {
- permission = 'none';
- core.warning(`Could not fetch collaborator permission: ${e.status || ''} ${e.message}`);
- }
-
- const trusted = ['admin','maintain','write'].includes(permission);
-
- const info = {
- number: pr.number,
- title: pr.title,
- author: pr.user.login,
- author_association: pr.author_association,
- author_permission: permission,
- trusted_by_permission: trusted,
- base_repo: pr.base.repo.full_name,
- head_repo: pr.head.repo.full_name,
- is_fork: !!pr.head.repo.fork,
- };
- core.info('PR author info:\n' + JSON.stringify(info, null, 2));
-
- // Only add the label if the author does NOT have write-level permission
- if (!trusted) {
- const label = 'needs-ci-approval';
- try {
- // Ensure the label exists (422 = already exists)
- try {
- await github.request('POST /repos/{owner}/{repo}/labels', {
- ...context.repo,
- name: label,
- color: 'E3650b',
- });
- } catch (e) {
- if (e.status !== 422) throw e;
- }
-
- await github.rest.issues.addLabels({
- ...context.repo,
- issue_number: context.issue.number,
- labels: [label],
- });
- core.info(`Added '${label}' to PR #${context.issue.number}`);
- } catch (e) {
- core.setFailed(`Failed to label PR: ${e.status || ''} ${e.message}`);
- }
- } else {
- core.info('Author has write-level permission; not adding label.');
- }
diff --git a/.github/workflows/check_workflows.yml b/.github/workflows/check_workflows.yml
deleted file mode 100644
index 6c1dc46d4..000000000
--- a/.github/workflows/check_workflows.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-name: Check workflows status
-
-on:
- pull_request_target:
- types: [opened, synchronize, reopened, labeled, unlabeled]
-
-permissions:
- pull-requests: read
- contents: read
-
-jobs:
- check-workflows:
- runs-on: ubuntu-slim
- steps:
- - name: Check out master branch (base)
- uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.base.ref }}
- path: master_branch
-
- - name: Check out PR branch (head)
- uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
- path: pr_branch
- allow-unsafe-pr-checkout: true
- persist-credentials: false
-
- - name: Check for label override
- id: label_check
- uses: actions/github-script@v7
- with:
- script: |
- const labelName = 'workflows-update';
- const labels = await github.rest.issues.listLabelsOnIssue({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.payload.pull_request.number,
- });
- const hasLabel = labels.data.some(label => label.name === labelName);
- core.setOutput('skip', hasLabel);
-
- - name: Compare workflows between master and PR
- if: steps.label_check.outputs.skip != 'true'
- run: |
- echo "Checking if .github/workflows/ differs from master..."
- diff -r master_branch/.github/workflows pr_branch/.github/workflows || {
- echo "::error::Workflows differ from master. Please rebase or apply 'workflows-update' label to bypass.";
- exit 1;
- }
-
- - name: Skip message if label present
- if: steps.label_check.outputs.skip == 'true'
- run: echo "Skipping workflows check because 'workflows-update' label is present."
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 9c5950d56..465f8b2a6 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -17,7 +17,7 @@
# under the License.
#
-name: "Pull Request Labeler"
+name: "Pull Request Size Labeler"
on:
- pull_request_target
@@ -27,17 +27,10 @@ jobs:
contents: read
pull-requests: write
issues: write
+ # pr-size-labeler is Docker action which is not supported by
+ # ubuntu-slim runner
runs-on: ubuntu-latest
steps:
- - name: Checkout repository
- uses: actions/checkout@v7
-
- - name: Assign labels based on paths
- uses: actions/labeler@v7
- with:
- sync-labels: true
- configuration-path: .github/labeler_cfg.yml
-
- name: Assign labels based on the PR's size
uses: codelytv/pr-size-labeler@v1.12.0
with:
diff --git a/.github/workflows/pr_maintenance.yml b/.github/workflows/pr_maintenance.yml
new file mode 100644
index 000000000..5d5c0b323
--- /dev/null
+++ b/.github/workflows/pr_maintenance.yml
@@ -0,0 +1,79 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+# Maintenance of open pull requests (labels and workflows status check).
+# This runs periodically from master instead of pull_request_target, so
+# no pull request code or configuration is used with elevated privileges.
+
+name: Pull request maintenance
+
+on:
+ schedule:
+ - cron: '*/5 * * * *'
+ workflow_dispatch:
+
+permissions:
+ actions: read
+ contents: read
+ issues: write
+ pull-requests: write
+ statuses: write
+
+concurrency:
+ group: ${{ github.workflow }}
+
+jobs:
+ maintenance:
+ if: github.repository == 'apache/mynewt-nimble'
+ runs-on: ubuntu-slim
+ # Shorter than schedule interval, so that hung run doesn't delay
+ # following ones
+ timeout-minutes: 4
+ steps:
+ - uses: actions/checkout@v7
+ with:
+ sparse-checkout: .github
+ persist-credentials: false
+
+ - name: Check pull requests
+ id: check
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: python3 .github/scripts/pr_maintenance.py check
+
+ # Following steps run also if previous step failed, so that error in
+ # one pull request doesn't block processing of others
+
+ - name: Assign labels based on paths
+ if: ${{ !cancelled() && steps.check.outputs.pr-numbers != '' }}
+ uses: actions/labeler@v7
+ with:
+ pr-number: ${{ steps.check.outputs.pr-numbers }}
+ sync-labels: true
+ configuration-path: .github/labeler_cfg.yml
+
+ - name: Report workflows status
+ if: >-
+ ${{ !cancelled() && steps.check.outputs.statuses != '' &&
+ steps.check.outputs.statuses != '[]' }}
+ env:
+ GH_TOKEN: ${{ github.token }}
+ STATUSES: ${{ steps.check.outputs.statuses }}
+ run: python3 .github/scripts/pr_maintenance.py report
(mynewt-nimble) 16/19: ci: Update PR maintenance labels only for changed pull requests
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit b7c1eddc8f61c31f298be5f7bda415c0fb956c64
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 17:06:04 2026 +0200
ci: Update PR maintenance labels only for changed pull requests
Merge base was queried on each run for every pull request with .github
different from base branch, and path labeler was run for all pull
requests, although their labels change only if pull request or .github
of its base branch changes.
Use previous successful run of the workflow as reference: process only
pull requests updated since it started (any push or base change updates
pull request) and all pull requests on base branch if its .github tree
differs from the one of previous run head commit. Failed run doesn't
count, so pull requests are processed again by next run. Changes of PR
maintenance itself are in .github, so all pull requests are processed
after they are merged.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 61 +++++++++++++++++++++++++++++++++------
1 file changed, 52 insertions(+), 9 deletions(-)
diff --git a/.github/scripts/pr_maintenance.py b/.github/scripts/pr_maintenance.py
index 8b6f07a6d..a0d89d82a 100644
--- a/.github/scripts/pr_maintenance.py
+++ b/.github/scripts/pr_maintenance.py
@@ -28,8 +28,8 @@ is done through GitHub API using gh tool.
base branch changed since merge base, and removed otherwise.
- 'workflows-update' label is set on pull requests modifying .github
(compared to merge base), and removed otherwise.
-- All pull requests are reported for path based labeling, which is
- done by actions/labeler in the workflow.
+- Pull requests are reported for path based labeling, which is done by
+ actions/labeler in the workflow.
Workflows labels are informative only, workflow runs of contributors
without write access need approval anyway.
@@ -37,6 +37,10 @@ without write access need approval anyway.
Pull requests without activity for MAX_AGE_DAYS are skipped, also
when marked with 'stale' label (set by stale workflow) until new commit
is pushed.
+
+Workflows and path labels are updated only for pull requests changed
+since previous successful run, unless .github of their base branch
+changed too. Merge base and labels can't change otherwise.
"""
from datetime import date, timedelta
@@ -61,6 +65,9 @@ CI_RUNS_MAX_AGE_DAYS = 30
TREES_PER_QUERY = 100
REPO = os.environ.get("GITHUB_REPOSITORY", "")
+BRANCH = os.environ.get("GITHUB_REF_NAME", "master")
+WORKFLOW = os.environ.get("GITHUB_WORKFLOW_REF",
+ "pr_maintenance.yml").split("@")[0].split("/")[-1]
PULLS_QUERY = """
query (
@@ -83,6 +90,7 @@ query (
number
updatedAt
headRefOid
+ baseRefName
labels(first: 100) {
nodes {
name
@@ -152,8 +160,23 @@ def merge_base(base, head):
"--jq", ".merge_base_commit.sha").strip()
+def previous_run():
+ """Returns previous successful run of this workflow, or None"""
+ try:
+ return json.loads(gh("api", f"repos/{REPO}/actions/workflows/"
+ f"{WORKFLOW}/runs?branch={BRANCH}"
+ f"&status=success&per_page=1",
+ "--jq", ".workflow_runs[0]"))
+ except subprocess.CalledProcessError as e:
+ print(f"Failed to get previous run: {e.stderr.strip()}")
+ return None
+
+
def list_pulls():
- """Returns list of pull requests and number of errors"""
+ """
+ Returns list of pull requests and number of errors. Merge base tree
+ is set only for pull requests marked as changed.
+ """
owner, repo = REPO.split("/")
pages = json.loads(gh("api", "graphql", "--paginate", "--slurp",
"-f", f"query={PULLS_QUERY}",
@@ -183,13 +206,21 @@ def list_pulls():
"number": node["number"],
"head": commit["oid"],
"labels": labels,
+ "updated": node["updatedAt"],
+ "base_name": node["baseRefName"],
"base_head": base.get("oid"),
})
print(f"{skipped} stale pull requests skipped")
+ previous = previous_run()
+ if previous:
+ print(f"Previous run started {previous['created_at']} on "
+ f"{previous['head_sha']}")
+
trees = github_trees([p["head"] for p in pulls] +
- [p["base_head"] for p in pulls if p["base_head"]])
+ [p["base_head"] for p in pulls if p["base_head"]] +
+ ([previous["head_sha"]] if previous else []))
merge_bases = {}
errors = 0
@@ -198,6 +229,16 @@ def list_pulls():
pull["tree"] = trees[pull["head"]]
pull["base_tree"] = base_tree
+ # Previous run started before last update of pull request (any
+ # push or base change updates it) or before .github of base
+ # branch changed, so its labels may be out of date
+ pull["changed"] = not previous or \
+ pull["updated"] >= previous["created_at"] or \
+ pull["base_name"] != previous["head_branch"] or \
+ base_tree != trees[previous["head_sha"]]
+ if not pull["changed"]:
+ continue
+
# Same tree as base means pull request neither modifies .github
# nor is out of date, merge base is not needed
if pull["tree"] == base_tree or not pull["base_head"]:
@@ -300,15 +341,17 @@ def main():
except subprocess.CalledProcessError as e:
sys.exit(f"Failed to list pull requests: {e.stderr.strip()}")
- print(f"{len(pulls)} open pull requests")
+ changed = [p for p in pulls if p["changed"]]
+ print(f"{len(pulls)} open pull requests, {len(changed)} changed")
# Written first so following step can handle pull requests even if
# updating labels fails
- write_outputs({"pr-numbers": "\n".join(str(p["number"]) for p in pulls)})
+ write_outputs({"pr-numbers": "\n".join(str(p["number"])
+ for p in changed)})
errors += update_ci_label(pulls)
# Pull requests without merge base tree failed and were reported
- pulls = [p for p in pulls if "merge_base_tree" in p]
- errors += update_outdated_label(pulls)
- errors += update_update_label(pulls)
+ changed = [p for p in changed if "merge_base_tree" in p]
+ errors += update_outdated_label(changed)
+ errors += update_update_label(changed)
if errors:
sys.exit(f"{errors} error(s) occurred")
(mynewt-nimble) 14/19: ci: Label all pull requests based on paths in PR maintenance
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 44b2b638008e6b12ca5e540ae2ec849d9938b4d7
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 16:27:35 2026 +0200
ci: Label all pull requests based on paths in PR maintenance
Path based labeling was done only for pull requests with new head
commit, detected by missing 'Check workflows' status. Label all pull
requests on each run instead, so labeling doesn't depend on the status
and labeler configuration changes are applied to open pull requests.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/.github/scripts/pr_maintenance.py b/.github/scripts/pr_maintenance.py
index 217d37988..896996c23 100644
--- a/.github/scripts/pr_maintenance.py
+++ b/.github/scripts/pr_maintenance.py
@@ -30,17 +30,16 @@ is done through GitHub API using gh tool.
- 'Check workflows' commit status reports whether .github of pull
request head matches base branch ('workflows-update' label skips the
check).
-- Pull requests with new head commit are reported for path based
- labeling, which is done by actions/labeler in the workflow.
+- All pull requests are reported for path based labeling, which is
+ done by actions/labeler in the workflow.
Pull requests without activity for MAX_AGE_DAYS are skipped, also
when marked with 'stale' label (set by stale workflow) until new commit
is pushed.
-'Check workflows' status also marks pull request head as processed: it
-is tied to head commit and its description contains base branch .github
-tree it was checked against, so only new or changed pull requests are
-processed.
+'Check workflows' status is tied to head commit and its description
+contains base branch .github tree it was checked against, so it is
+reported only for new or changed pull requests.
Usage:
pr_maintenance.py check - update labels, write step outputs
@@ -336,17 +335,12 @@ def check():
errors += update_outdated_label(pulls_ok)
statuses = [s for s in map(workflows_status, pulls_ok) if s]
statuses = statuses[:MAX_PULLS_PER_RUN]
- reported = {s["sha"] for s in statuses}
-
- # No status on head commit means pull request was updated
- labels = [str(p["number"]) for p in pulls
- if not p["status"] and p["head"] in reported]
for status in statuses:
print(f"{status['sha']}: {status['description']}")
return errors, {
- "pr-numbers": "\n".join(labels),
+ "pr-numbers": "\n".join(str(p["number"]) for p in pulls),
"statuses": json.dumps(statuses),
}
(mynewt-nimble) 09/19: ci: Cancel superseded build runs on master
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 5853d57d2a2c6f4b20924157dc847fb7f4f44933
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Fri Oct 16 16:37:55 2026 +0200
ci: Cancel superseded build runs on master
Runs for pushes to master used commit SHA as concurrency group, so
when several commits were merged in short time, runs for all of them
were building in parallel until completed. This wastes CI resources
and makes those runs save caches in parallel.
Use branch as concurrency group for push events, so that new push to
master cancels in-progress run, same as is done for pull requests.
Assisted-by: Claude:claude-opus-5-5
---
.github/workflows/build.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7f8ea709f..479aaf5fb 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -25,8 +25,9 @@ on:
- master
pull_request:
+# New push to master or pull request cancels its in-progress run
concurrency:
- group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
(mynewt-nimble) 18/19: ci: Add explicit least-privilege permissions to compliance workflow
Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 1e1b75f326d58dd5b42beb9acc4cb9b949b0ee5c
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 21 21:47:41 2026 +0200
ci: Add explicit least-privilege permissions to compliance workflow
Compliance workflow inherited the repository default GITHUB_TOKEN
scope. It only checks out code and reads pull request labels, so
declare read-only permissions explicitly, same as in
apache-mynewt-core.
Assisted-by: Claude:claude-opus-5-5
---
.github/workflows/compliance_check.yml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/.github/workflows/compliance_check.yml b/.github/workflows/compliance_check.yml
index 395bc2bc7..ea86934dd 100644
--- a/.github/workflows/compliance_check.yml
+++ b/.github/workflows/compliance_check.yml
@@ -27,6 +27,11 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
+permissions:
+ contents: read
+ issues: read
+ pull-requests: read
+
jobs:
style_check:
name: Coding style