From 764b924d81b37c2e168ae115c52277193cf79898 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 11 Sep 2026 00:14:21 +0100 Subject: [PATCH 1/3] build: stop passing literal quotes as package_folder_prefix circuitpython-build-bundles splits --package_folder_prefix on ", " and matches each entry with str.startswith(). The gawk that builds the list wrapped it in literal double quotes, so the first and last entries came through as '"sensirion_i2c_driver' and 'sensirion_i2c_sen5x"' and matched no folder. Both libraries then fell back to legacy autodetection, which found only the top-level conftest.py, and the bundle shipped one module instead of the drivers. With only two libraries here, both entries carry a stray quote, so every release asset since the tooling moved on has been effectively empty. The same bug is in the upstream community bundle, where it silently drops the first and last library of the ls -U ordering. Also allow build.yml to be started by hand, as there was no way to re-run it without pushing. Co-Authored-By: Claude Opus 5 --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 4 ++-- build.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 32210d7..1700e45 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ name: Build CI -on: [pull_request, push] +on: [pull_request, push, workflow_dispatch] jobs: test: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 008f440..71c17f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,10 +38,10 @@ jobs: echo prefix=$( ls -RUx | gawk -F '\n' '{ match($1, /(drivers|helpers)\/(.+)\/(.+)\:/, arr) ; if (length(arr[0]) > 0 && match(arr[3], arr[2]) > 0) printf "%s, ", arr[3] }' | - gawk '{ trimmed = substr($0, 1, length($0) - 2) ; print "\"" trimmed "\"" }' + gawk '{ print substr($0, 1, length($0) - 2) }' ) >> $GITHUB_OUTPUT - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location libraries --library_depth 2 --package_folder_prefix ${{ steps.pkg-folder.outputs.prefix }} + run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location libraries --library_depth 2 --package_folder_prefix "${{ steps.pkg-folder.outputs.prefix }}" - name: Upload Release Assets uses: shogo82148/actions-upload-release-asset@v1 with: diff --git a/build.sh b/build.sh index 94ed85f..6bb1a2f 100755 --- a/build.sh +++ b/build.sh @@ -29,7 +29,7 @@ set -e P=$( ls -RUx | gawk -F '\n' '{ match($1, /(drivers|helpers)\/(.+)\/(.+)\:/, arr) ; if (length(arr[0]) > 0 && match(arr[3], arr[2]) > 0) printf "%s, ", arr[3] }' | -gawk '{ trimmed = substr($0, 1, length($0) - 2) ; print "\"" trimmed "\"" }' +gawk '{ print substr($0, 1, length($0) - 2) }' ) circuitpython-build-bundles --filename_prefix circuitpython-community-bundle --library_location libraries --library_depth 2 --package_folder_prefix "$P" From 33c7c0686f4d7f6bbac7d2b6e402bd6017c0a1eb Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 11 Sep 2026 00:22:25 +0100 Subject: [PATCH 2/3] build: refuse an empty package folder list, and validate its characters Removing the literal quotes changed one failure mode for the worse. If the gawk matches nothing, the prefix is empty; build-tools splits on ", " and matches with startswith(), and "".startswith("") is True, so every folder becomes a package (module_name came out as 'docs'). Previously the empty value reached an unquoted ${{ }} and click failed on the missing argument, which at least stopped the build. Fail loudly instead. The character check covers the part quoting cannot: ${{ }} splices the value into the run: block as text before any shell parses it, so a folder name containing a quote or backtick escapes the quotes added around the expansion. Restricting the list to what a module name can contain closes that, rather than relying on the quotes. Co-Authored-By: Claude Opus 5 --- .github/workflows/release.yml | 20 ++++++++++++++++++-- build.sh | 5 +++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71c17f6..783adac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,11 +35,27 @@ jobs: - name: Package Folder Prefix For circuitpython-build-tools (Community Bundle Specific) id: pkg-folder run: | - echo prefix=$( + prefix=$( ls -RUx | gawk -F '\n' '{ match($1, /(drivers|helpers)\/(.+)\/(.+)\:/, arr) ; if (length(arr[0]) > 0 && match(arr[3], arr[2]) > 0) printf "%s, ", arr[3] }' | gawk '{ print substr($0, 1, length($0) - 2) }' - ) >> $GITHUB_OUTPUT + ) + # An empty list is never correct: build-tools splits on ", " and matches + # with startswith(), and "".startswith("") is True, so an empty prefix + # would silently make every folder -- docs/, tests/, ci/ -- a package. + if [ -z "$prefix" ]; then + echo "::error::no package folders matched under libraries/; refusing to build an empty bundle" + exit 1 + fi + # ${{ }} splices this into the later run: block as text, before any shell + # sees it, so the quotes there cannot contain a folder name carrying a + # quote or a backtick. Allow only what a module name can be. + case "$prefix" in + *[!A-Za-z0-9_, -]*) + echo "::error::unexpected character in package folder list: $prefix" + exit 1 ;; + esac + echo "prefix=$prefix" >> "$GITHUB_OUTPUT" - name: Build assets run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location libraries --library_depth 2 --package_folder_prefix "${{ steps.pkg-folder.outputs.prefix }}" - name: Upload Release Assets diff --git a/build.sh b/build.sh index 6bb1a2f..1da0e1c 100755 --- a/build.sh +++ b/build.sh @@ -32,4 +32,9 @@ gawk -F '\n' '{ match($1, /(drivers|helpers)\/(.+)\/(.+)\:/, arr) ; if (length(a gawk '{ print substr($0, 1, length($0) - 2) }' ) +if [ -z "$P" ]; then + echo "error: no package folders matched under libraries/; refusing to build an empty bundle" >&2 + exit 1 +fi + circuitpython-build-bundles --filename_prefix circuitpython-community-bundle --library_location libraries --library_depth 2 --package_folder_prefix "$P" From f53aef093474d7a0ec7f5cd21394c02b19350bd1 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 11 Sep 2026 00:31:07 +0100 Subject: [PATCH 3/3] release: compute the prefix in the step that uses it, and sync action versions The previous commit guarded the symptom. The structure was the problem: the prefix went out through $GITHUB_OUTPUT and came back as a ${{ }} expression, which GitHub splices into the next run: block as script text before any shell parses it. That hop is worse than what it replaced. The original 'echo prefix=$( ... )' used an unquoted command substitution, so word splitting collapsed newlines into spaces and only ever one line reached $GITHUB_OUTPUT. Assigning to a variable and echoing it quoted preserves them: a directory name containing a newline writes extra variables into $GITHUB_OUTPUT, which then chain into the next step. Measured: old form 1 line, new form 3. So drop the hop. The prefix is computed in the Build assets step and passed as "$prefix" -- real shell quoting this time, since bash does the expansion rather than the templating engine. filename_prefix comes in through env for the same reason. No expression is now spliced into any run: block, and the character allowlist added in the previous commit is no longer load-bearing, so it goes. Also takes upstream's actions/checkout@v6 and actions/setup-python@v6, which is what the Node 20 deprecation notice on our runs was about. The upstream AWS S3 upload step is deliberately not adopted: it targets Adafruit's bucket. Co-Authored-By: Claude Opus 5 --- .github/workflows/build.yml | 4 ++-- .github/workflows/release.yml | 35 +++++++++++++++-------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1700e45..e9bf063 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,13 +7,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Set up Python 3 - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Versions run: | python3 --version - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 with: submodules: true - name: Fetch correct submodule shas diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 783adac..bb833aa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,20 +10,18 @@ jobs: steps: - name: Translate Repo Name For Build Tools filename_prefix id: repo-name + env: + REPO: ${{ github.repository }} run: | - echo "repo-name=$( - echo ${{ github.repository }} | - awk -F '\/' '{ print tolower($2) }' | - tr '_' '-' - )" >> $GITHUB_OUTPUT + echo "repo-name=$(echo "$REPO" | awk -F '/' '{ print tolower($2) }' | tr '_' '-')" >> "$GITHUB_OUTPUT" - name: Set up Python 3 - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Versions run: | python3 --version - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 with: submodules: true - name: Fetch correct submodule shas @@ -32,9 +30,16 @@ jobs: run: | sudo apt-get install -y gettext gawk pip install -r requirements.txt - - name: Package Folder Prefix For circuitpython-build-tools (Community Bundle Specific) - id: pkg-folder + - name: Build assets + env: + # Passed as environment, not spliced into the script by the expression. + FILENAME_PREFIX: ${{ steps.repo-name.outputs.repo-name }} run: | + # Computed in the step that consumes it. Going via $GITHUB_OUTPUT and an + # expression would put a directory name into the next step as script text: + # a newline in it writes extra variables to $GITHUB_OUTPUT, and a quote or + # backtick escapes whatever quoting that step uses. Held in a shell + # variable it stays exactly one argument. prefix=$( ls -RUx | gawk -F '\n' '{ match($1, /(drivers|helpers)\/(.+)\/(.+)\:/, arr) ; if (length(arr[0]) > 0 && match(arr[3], arr[2]) > 0) printf "%s, ", arr[3] }' | @@ -47,17 +52,7 @@ jobs: echo "::error::no package folders matched under libraries/; refusing to build an empty bundle" exit 1 fi - # ${{ }} splices this into the later run: block as text, before any shell - # sees it, so the quotes there cannot contain a folder name carrying a - # quote or a backtick. Allow only what a module name can be. - case "$prefix" in - *[!A-Za-z0-9_, -]*) - echo "::error::unexpected character in package folder list: $prefix" - exit 1 ;; - esac - echo "prefix=$prefix" >> "$GITHUB_OUTPUT" - - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location libraries --library_depth 2 --package_folder_prefix "${{ steps.pkg-folder.outputs.prefix }}" + circuitpython-build-bundles --filename_prefix "$FILENAME_PREFIX" --library_location libraries --library_depth 2 --package_folder_prefix "$prefix" - name: Upload Release Assets uses: shogo82148/actions-upload-release-asset@v1 with: