From 89866ef88e54eeb35fa2c4f1e4719bc6e789f7cb Mon Sep 17 00:00:00 2001 From: Luca Bello Date: Mon, 23 Feb 2026 16:30:29 +0100 Subject: [PATCH 1/4] feat: add support for rock monorepos --- .github/workflows/rock-pull-request.yaml | 107 +++++++++++++++++- .github/workflows/rock-release-dev.yaml | 87 ++++++++++++-- .../workflows/rock-release-oci-factory.yaml | 84 +++++++++++++- .github/workflows/rock-update.yaml | 44 +++++-- 4 files changed, 295 insertions(+), 27 deletions(-) diff --git a/.github/workflows/rock-pull-request.yaml b/.github/workflows/rock-pull-request.yaml index eee00e9d..5945cdf6 100644 --- a/.github/workflows/rock-pull-request.yaml +++ b/.github/workflows/rock-pull-request.yaml @@ -2,6 +2,17 @@ name: Pull Request on: workflow_call: + inputs: + rock-path: + description: "Path to the rock root (relative to monorepo-path when set)" + required: false + default: "." + type: string + monorepo-path: + description: "Path to the monorepo root for rocks (relative to repository root)" + required: false + default: "" + type: string jobs: @@ -10,21 +21,91 @@ jobs: runs-on: ubuntu-24.04 outputs: versions: ${{ steps.changed-versions.outputs.versions }} + is_monorepo: ${{ steps.detect-layout.outputs.is_monorepo }} + rock_path: ${{ steps.detect-layout.outputs.rock_path }} + base_path: ${{ steps.detect-layout.outputs.base_path }} + full_path: ${{ steps.detect-layout.outputs.full_path }} steps: - name: Checkout repository uses: actions/checkout@v4 + - name: Detect rock layout + id: detect-layout + env: + ROCK_PATH_INPUT: ${{ inputs.rock-path }} + MONOREPO_PATH_INPUT: ${{ inputs.monorepo-path }} + run: | + # Normalize rock path and infer monorepo mode from monorepo-path or layout. + rock_path="${ROCK_PATH_INPUT:-.}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi + monorepo_path="${MONOREPO_PATH_INPUT:-}" + monorepo_path="${monorepo_path%/}" + if [[ -n "$monorepo_path" ]]; then + base_path="$monorepo_path" + is_monorepo="true" + else + base_path="." + if find "${base_path%/}/${rock_path}" -mindepth 1 -maxdepth 1 -type d -name '[0-9]*' | grep -q .; then + is_monorepo="false" + else + is_monorepo="true" + fi + fi + # Build the full path to the rock root used by later steps. + if [[ "$rock_path" == "." ]]; then + full_path="$base_path" + else + full_path="$base_path/$rock_path" + fi + full_path="${full_path#./}" + if [[ "$full_path" == "" ]]; then + full_path="." + fi + echo "rock_path=$rock_path" >> "$GITHUB_OUTPUT" + echo "base_path=$base_path" >> "$GITHUB_OUTPUT" + echo "full_path=$full_path" >> "$GITHUB_OUTPUT" + echo "is_monorepo=$is_monorepo" >> "$GITHUB_OUTPUT" - name: Find rockcraft.yaml changes id: changed-files uses: tj-actions/changed-files@v46 with: - files: "**/rockcraft.yaml" + path: ${{ steps.detect-layout.outputs.base_path }} + files: "${{ steps.detect-layout.outputs.rock_path }}/**/rockcraft.yaml" - name: Extract the versions id: changed-versions env: # CHANGED_FILES is a space-separated list CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} + IS_MONOREPO: ${{ steps.detect-layout.outputs.is_monorepo }} + ROCK_PATH: ${{ steps.detect-layout.outputs.rock_path }} run: | - versions="${CHANGED_FILES//\/rockcraft.yaml/}" # space-separated versions + versions="" + path_prefix="" + if [[ "$ROCK_PATH" != "." ]]; then + path_prefix="$ROCK_PATH/" + fi + # Convert changed rockcraft.yaml files into version tokens. + for file in $CHANGED_FILES; do + if [[ -n "$path_prefix" && "$file" != "$path_prefix"* ]]; then + continue + fi + relative="$file" + if [[ -n "$path_prefix" ]]; then + relative="${file#"$path_prefix"}" + fi + if [[ "$IS_MONOREPO" == "true" ]]; then + rock_name="${relative%%/*}" + remainder="${relative#*/}" + version="${remainder%%/*}" + versions="$versions $rock_name:$version" + else + version="${relative%%/*}" + versions="$versions $version" + fi + done + versions="${versions# }" echo "versions=$versions" echo "versions=$versions" >> "$GITHUB_OUTPUT" @@ -63,10 +144,24 @@ jobs: run: df -h - name: Pack and test the rocks run: | - for version in ${{ needs.changes.outputs.versions }}; do - just pack "$version" - just test "$version" - just clean "$version" + rock_path="${{ needs.changes.outputs.full_path }}" + is_monorepo="${{ needs.changes.outputs.is_monorepo }}" + cd "$rock_path" + for target in ${{ needs.changes.outputs.versions }}; do + if [[ "$is_monorepo" == "true" ]]; then + rock_name="${target%%:*}" + version="${target#*:}" + # Monorepo: pass rock name and version. + just pack "$rock_name" "$version" + just test "$rock_name" "$version" + just clean "$rock_name" "$version" + else + # Single rock: pass version only. + version="$target" + just pack "$version" + just test "$version" + just clean "$version" + fi done - name: Print disk utilization after packing if: ${{ (runner.debug == '1') }} diff --git a/.github/workflows/rock-release-dev.yaml b/.github/workflows/rock-release-dev.yaml index ae82e4f2..de3ebf1b 100644 --- a/.github/workflows/rock-release-dev.yaml +++ b/.github/workflows/rock-release-dev.yaml @@ -7,6 +7,16 @@ on: description: "Name of the application for which to build the rock" required: true type: string + rock-path: + description: "Path to the rock root (relative to monorepo-path when set)" + required: false + default: "." + type: string + monorepo-path: + description: "Path to the monorepo root for rocks (relative to repository root)" + required: false + default: "" + type: string secrets: OBSERVABILITY_NOCTUA_TOKEN: required: true @@ -24,36 +34,97 @@ jobs: # Install Syft curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \ | sh -s -- -b /usr/local/bin + - name: Resolve rock context + id: rock-context + env: + ROCK_NAME: ${{ inputs.rock-name }} + ROCK_PATH_INPUT: ${{ inputs.rock-path }} + MONOREPO_PATH_INPUT: ${{ inputs.monorepo-path }} + run: | + # Normalize inputs and decide monorepo mode based on monorepo-path or layout. + rock_path="${ROCK_PATH_INPUT:-.}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi + monorepo_path="${MONOREPO_PATH_INPUT:-}" + monorepo_path="${monorepo_path%/}" + if [[ -n "$monorepo_path" ]]; then + base_path="$monorepo_path" + is_monorepo="true" + else + base_path="." + if find "${base_path%/}/${rock_path}" -mindepth 1 -maxdepth 1 -type d -name '[0-9]*' | grep -q .; then + is_monorepo="false" + else + is_monorepo="true" + fi + fi + # Build the full path to the rock root and resolve the latest version. + if [[ "$rock_path" == "." ]]; then + full_path="$base_path" + else + full_path="$base_path/$rock_path" + fi + full_path="${full_path#./}" + if [[ "$full_path" == "" ]]; then + full_path="." + fi + rock_dir="$full_path" + if [[ "$is_monorepo" == "true" ]]; then + rock_dir="$full_path/$ROCK_NAME" + fi + latest_version="$(find "$rock_dir" -maxdepth 1 -type d -name '[0-9]*' | sort -V | tail -n1 | sed 's@.*/@@')" + if [[ -z "$latest_version" ]]; then + echo "No version directories found under $rock_dir" >&2 + exit 1 + fi + version_dir="$rock_dir/$latest_version" + # Export derived paths and mode for downstream steps. + echo "rock_path=$rock_path" >> "$GITHUB_OUTPUT" + echo "base_path=$base_path" >> "$GITHUB_OUTPUT" + echo "full_path=$full_path" >> "$GITHUB_OUTPUT" + echo "rock_dir=$rock_dir" >> "$GITHUB_OUTPUT" + echo "latest_version=$latest_version" >> "$GITHUB_OUTPUT" + echo "version_dir=$version_dir" >> "$GITHUB_OUTPUT" + echo "is_monorepo=$is_monorepo" >> "$GITHUB_OUTPUT" - name: Build rock + working-directory: ${{ steps.rock-context.outputs.rock_dir }} + env: + ROCK_NAME: ${{ inputs.rock-name }} + IS_MONOREPO: ${{ steps.rock-context.outputs.is_monorepo }} + LATEST_VERSION: ${{ steps.rock-context.outputs.latest_version }} run: | - latest_version="$(find . -maxdepth 1 -type d -name '[0-9]*' | sort -V | tail -n1 | sed 's@./@@')" - just pack "$latest_version" + # Use rock-name + version for monorepos, otherwise version-only. + if [[ "$IS_MONOREPO" == "true" ]]; then + just pack "$ROCK_NAME" "$LATEST_VERSION" + else + just pack "$LATEST_VERSION" + fi - name: Upload rock to ghcr.io + working-directory: ${{ steps.rock-context.outputs.version_dir }} env: ROCK_NAME: ${{ inputs.rock-name }} OBSERVABILITY_NOCTUA_TOKEN: ${{ secrets.OBSERVABILITY_NOCTUA_TOKEN }} run: | - latest_version="$(find . -maxdepth 1 -type d -name '[0-9]*' | sort -V | tail -n1 | sed 's@./@@')" - cd "$latest_version" sudo skopeo --insecure-policy copy \ "oci-archive:$(realpath ./*.rock)" \ "docker://ghcr.io/canonical/$ROCK_NAME:dev" \ --dest-creds "observability-noctua-bot:$OBSERVABILITY_NOCTUA_TOKEN" - name: Create SBOM + working-directory: ${{ steps.rock-context.outputs.version_dir }} env: ROCK_NAME: ${{ inputs.rock-name }} run: | - latest_version="$(find . -maxdepth 1 -type d -name '[0-9]*' | sort -V | tail -n1 | sed 's@./@@')" - cd "$latest_version" # shellcheck disable=SC2086 # glob passed to realpath can't be wrapped syft "$(realpath ./${ROCK_NAME}_*.rock)" -o "spdx-json=${ROCK_NAME}.sbom.json" - name: Upload SBOM uses: actions/upload-artifact@v4 with: name: ${{ inputs.rock-name }}-sbom - path: "${{ inputs.rock-name}}.sbom.json" + path: "${{ steps.rock-context.outputs.version_dir }}/${{ inputs.rock-name}}.sbom.json" - name: Upload locally built rock artifact uses: actions/upload-artifact@v4 with: name: ${{ inputs.rock-name }}-rock - path: "${{ inputs.rock-name }}_*.rock" + path: "${{ steps.rock-context.outputs.version_dir }}/${{ inputs.rock-name }}_*.rock" diff --git a/.github/workflows/rock-release-oci-factory.yaml b/.github/workflows/rock-release-oci-factory.yaml index 17c4ed0e..6c0f927f 100644 --- a/.github/workflows/rock-release-oci-factory.yaml +++ b/.github/workflows/rock-release-oci-factory.yaml @@ -11,6 +11,16 @@ on: description: "Name of the application for which to build the rock" required: true type: string + rock-path: + description: "Path to the rock root (relative to monorepo-path when set)" + required: false + default: "." + type: string + monorepo-path: + description: "Path to the monorepo root for rocks (relative to repository root)" + required: false + default: "" + type: string risk-track: description: "Risk track on which to release the rock" required: false @@ -38,8 +48,8 @@ jobs: id: changed-files uses: tj-actions/changed-files@v46 with: - path: rock - files: '**/rockcraft.yaml' + path: rock/${{ inputs.monorepo-path || '.' }} + files: '${{ inputs.rock-path }}/**/rockcraft.yaml' - name: Sync the OCI Factory fork id: fork-sync if: steps.changed-files.outputs.all_changed_and_modified_files != '' @@ -64,16 +74,78 @@ jobs: shell: bash # The for-loop parsing is bash-specific env: ROCK_NAME: ${{ inputs.rock-name }} + ROCK_PATH_INPUT: ${{ inputs.rock-path }} + MONOREPO_PATH_INPUT: ${{ inputs.monorepo-path }} # CHANGED_FILES is a space-separated list CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_and_modified_files }} RISK_TRACK: ${{ inputs.risk-track }} run: | TRACK=${RISK_TRACK:-stable} - cd rock + # Normalize rock path and determine monorepo mode from monorepo-path or layout. + rock_path="${ROCK_PATH_INPUT:-.}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi + monorepo_path="${MONOREPO_PATH_INPUT:-}" + monorepo_path="${monorepo_path%/}" + if [[ -n "$monorepo_path" ]]; then + base_path="$monorepo_path" + is_monorepo="true" + else + base_path="." + if find "rock/${base_path%/}/${rock_path}" -mindepth 1 -maxdepth 1 -type d -name '[0-9]*' | grep -q .; then + is_monorepo="false" + else + is_monorepo="true" + fi + fi + # Build the full path to the rock root and move into it. + if [[ "$rock_path" == "." ]]; then + full_path="$base_path" + else + full_path="$base_path/$rock_path" + fi + full_path="${full_path#./}" + if [[ "$full_path" == "" ]]; then + full_path="." + fi + cd "rock/$full_path" # Export current time to create a unique branch name for the fork echo "now_epoch=$(date -d now +%s)" >> "$GITHUB_OUTPUT" sha="$(git rev-parse HEAD)" - versions="${CHANGED_FILES//\/rockcraft.yaml/}" # space-separated versions + versions="" + path_prefix="" + if [[ "$rock_path" != "." ]]; then + path_prefix="$rock_path/" + fi + # Extract version numbers from changed rockcraft.yaml files. + for file in $CHANGED_FILES; do + if [[ -n "$path_prefix" && "$file" != "$path_prefix"* ]]; then + continue + fi + relative="$file" + if [[ -n "$path_prefix" ]]; then + relative="${file#"$path_prefix"}" + fi + if [[ "$is_monorepo" == "true" ]]; then + if [[ "$relative" == "$ROCK_NAME/"* ]]; then + remainder="${relative#*/}" + version="${remainder%%/*}" + versions="$versions $version" + fi + else + version="${relative%%/*}" + versions="$versions $version" + fi + done + versions="${versions# }" + if [[ -z "$versions" ]]; then + echo "No changed rockcraft.yaml files for $ROCK_NAME" >&2 + echo "has_versions=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "has_versions=true" >> "$GITHUB_OUTPUT" # Build the --version flags for noctua versions_flags="$(for v in $versions; do echo -n "--version=$v "; done)" # Generate the manifest via noctua @@ -87,7 +159,7 @@ jobs: > "$GITHUB_WORKSPACE/oci-factory/oci/$ROCK_NAME/image.yaml" - name: Commit to the fork id: fork-commit - if: steps.changed-files.outputs.all_changed_and_modified_files != '' + if: steps.update-releases.outputs.has_versions == 'true' uses: EndBug/add-and-commit@v9 with: add: 'oci/${{ inputs.rock-name }}/image.yaml' @@ -96,7 +168,7 @@ jobs: new_branch: 'update-${{ steps.update-releases.outputs.now_epoch }}' push: 'origin update-${{ steps.update-releases.outputs.now_epoch }} --force' - name: Open a PR from the fork to upstream - if: steps.changed-files.outputs.all_changed_and_modified_files != '' + if: steps.update-releases.outputs.has_versions == 'true' id: upstream-pr env: GH_TOKEN: "${{ secrets.OBSERVABILITY_NOCTUA_TOKEN }}" diff --git a/.github/workflows/rock-update.yaml b/.github/workflows/rock-update.yaml index 5dc00f78..14eeca56 100644 --- a/.github/workflows/rock-update.yaml +++ b/.github/workflows/rock-update.yaml @@ -12,6 +12,11 @@ on: description: "Name of the application for which to build the rock" required: true type: string + rock-path: + description: "Path to the rock root (relative to repository root)" + required: false + default: "." + type: string source-repo: description: "Repository of the source application in 'org/repo' form" required: true @@ -105,13 +110,20 @@ jobs: if: steps.latest-release.outputs.release != '' shell: bash run: | + # Normalize rock path and derive the upstream version. + rock_path="${{ inputs.rock-path }}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi source_tag="${{ steps.latest-release.outputs.release }}" version="${source_tag#v}" # Explicitly filter for specific rocks because we'd rather notice if a new rock has a different release schema version="${version#mimir-}" # Filter out opentelemetry-collector prefixes version=${version#"cmd/builder/v"} - if [ ! -f "$GITHUB_WORKSPACE/main/$version/rockcraft.yaml" ]; then + # Only continue if this version folder does not already exist. + if [ ! -f "$GITHUB_WORKSPACE/main/$rock_path/$version/rockcraft.yaml" ]; then echo "version=$version" >> "$GITHUB_OUTPUT" echo "release=${{steps.latest-release.outputs.release}}" >> "$GITHUB_OUTPUT" echo "New upstream release ${{steps.latest-release.outputs.release}} found" @@ -133,34 +145,52 @@ jobs: SOURCE_TAG: "${{ steps.check.outputs.release }}" VERSION: "${{ steps.check.outputs.version }}" run: | - latest_rockcraft_file="$(find "$GITHUB_WORKSPACE/main/" -name "rockcraft.yaml" | sort -V | tail -n1)" - cp -r "$(dirname "$latest_rockcraft_file")" "$GITHUB_WORKSPACE/main/$VERSION" + # Copy the latest rockcraft folder and update version/source-tag fields. + rock_path="${{ inputs.rock-path }}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi + latest_rockcraft_file="$(find "$GITHUB_WORKSPACE/main/$rock_path" -name "rockcraft.yaml" | sort -V | tail -n1)" + cp -r "$(dirname "$latest_rockcraft_file")" "$GITHUB_WORKSPACE/main/$rock_path/$VERSION" source_tag="$SOURCE_TAG" version="$VERSION" yq -i \ '.version = strenv(version) | .parts.${{ inputs.rock-name }}["source-tag"] = strenv(source_tag)' \ - "$GITHUB_WORKSPACE/main/$VERSION/rockcraft.yaml" + "$GITHUB_WORKSPACE/main/$rock_path/$VERSION/rockcraft.yaml" - name: Update the Go version if: inputs.check-go && steps.check.outputs.release != '' env: VERSION: "${{ steps.check.outputs.version }}" run: | + # Update the Go build snap to match the application source. + rock_path="${{ inputs.rock-path }}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi go_version="$(grep -Po "^go \K(\S+)" "$GITHUB_WORKSPACE/application-src/go.mod")" \ # Delete the Go dependency and add the updated one yq -i 'del(.parts.${{ inputs.rock-name }}.build-snaps.[] | select(. == "go/*"))' \ - "$GITHUB_WORKSPACE/main/$VERSION/rockcraft.yaml" + "$GITHUB_WORKSPACE/main/$rock_path/$VERSION/rockcraft.yaml" # Snap channels are named after major.minor only, so cut the go version to that format go_major_minor="$(echo "$go_version" | sed -E "s/([0-9]+\.[0-9]+).*/\1/")" go_v="$go_major_minor" yq -i \ '.parts.${{ inputs.rock-name }}.build-snaps += "go/"+strenv(go_v)+"/stable"' \ - "$GITHUB_WORKSPACE/main/$VERSION/rockcraft.yaml" + "$GITHUB_WORKSPACE/main/$rock_path/$VERSION/rockcraft.yaml" - name: Update other build dependencies if: steps.check.outputs.release != '' && inputs.update-script != '' env: VERSION: "${{ steps.check.outputs.version }}" run: | + # Expose paths for the custom update script. + rock_path="${{ inputs.rock-path }}" + rock_path="${rock_path%/}" + if [[ "$rock_path" == "" ]]; then + rock_path="." + fi export application_src="$GITHUB_WORKSPACE/application-src" - export rockcraft_yaml="$GITHUB_WORKSPACE/main/$VERSION/rockcraft.yaml" + export rockcraft_yaml="$GITHUB_WORKSPACE/main/$rock_path/$VERSION/rockcraft.yaml" cat > update-script.sh << EOF ${{ inputs.update-script }} EOF From 99262e17f4f6ff781a16d68b7fb09f35231bac5d Mon Sep 17 00:00:00 2001 From: Luca Bello Date: Mon, 23 Feb 2026 16:35:23 +0100 Subject: [PATCH 2/4] fix lint --- .github/workflows/rock-pull-request.yaml | 14 +++++++++----- .github/workflows/rock-release-dev.yaml | 16 +++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/rock-pull-request.yaml b/.github/workflows/rock-pull-request.yaml index 5945cdf6..78706bea 100644 --- a/.github/workflows/rock-pull-request.yaml +++ b/.github/workflows/rock-pull-request.yaml @@ -63,10 +63,12 @@ jobs: if [[ "$full_path" == "" ]]; then full_path="." fi - echo "rock_path=$rock_path" >> "$GITHUB_OUTPUT" - echo "base_path=$base_path" >> "$GITHUB_OUTPUT" - echo "full_path=$full_path" >> "$GITHUB_OUTPUT" - echo "is_monorepo=$is_monorepo" >> "$GITHUB_OUTPUT" + { + echo "rock_path=$rock_path" + echo "base_path=$base_path" + echo "full_path=$full_path" + echo "is_monorepo=$is_monorepo" + } >> "$GITHUB_OUTPUT" - name: Find rockcraft.yaml changes id: changed-files uses: tj-actions/changed-files@v46 @@ -107,7 +109,9 @@ jobs: done versions="${versions# }" echo "versions=$versions" - echo "versions=$versions" >> "$GITHUB_OUTPUT" + { + echo "versions=$versions" + } >> "$GITHUB_OUTPUT" tests: name: Tests diff --git a/.github/workflows/rock-release-dev.yaml b/.github/workflows/rock-release-dev.yaml index de3ebf1b..4c24f731 100644 --- a/.github/workflows/rock-release-dev.yaml +++ b/.github/workflows/rock-release-dev.yaml @@ -81,13 +81,15 @@ jobs: fi version_dir="$rock_dir/$latest_version" # Export derived paths and mode for downstream steps. - echo "rock_path=$rock_path" >> "$GITHUB_OUTPUT" - echo "base_path=$base_path" >> "$GITHUB_OUTPUT" - echo "full_path=$full_path" >> "$GITHUB_OUTPUT" - echo "rock_dir=$rock_dir" >> "$GITHUB_OUTPUT" - echo "latest_version=$latest_version" >> "$GITHUB_OUTPUT" - echo "version_dir=$version_dir" >> "$GITHUB_OUTPUT" - echo "is_monorepo=$is_monorepo" >> "$GITHUB_OUTPUT" + { + echo "rock_path=$rock_path" + echo "base_path=$base_path" + echo "full_path=$full_path" + echo "rock_dir=$rock_dir" + echo "latest_version=$latest_version" + echo "version_dir=$version_dir" + echo "is_monorepo=$is_monorepo" + } >> "$GITHUB_OUTPUT" - name: Build rock working-directory: ${{ steps.rock-context.outputs.rock_dir }} env: From cf030c89d0aa944ba16b0208e041cdea50709b43 Mon Sep 17 00:00:00 2001 From: Luca Bello Date: Thu, 26 Feb 2026 10:54:19 +0100 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20Fluffy=20approves=20these=20change?= =?UTF-8?q?s=20=F0=90=94=8C=D5=9E.=CB=AC=20.=D5=9E=F0=90=A6=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/rock-pull-request.yaml | 67 +++++++------------ .github/workflows/rock-release-dev.yaml | 59 ++++++---------- .../workflows/rock-release-oci-factory.yaml | 50 ++++---------- 3 files changed, 58 insertions(+), 118 deletions(-) diff --git a/.github/workflows/rock-pull-request.yaml b/.github/workflows/rock-pull-request.yaml index 78706bea..c3cd4e30 100644 --- a/.github/workflows/rock-pull-request.yaml +++ b/.github/workflows/rock-pull-request.yaml @@ -4,15 +4,10 @@ on: workflow_call: inputs: rock-path: - description: "Path to the rock root (relative to monorepo-path when set)" + description: "Path to the rock root" required: false default: "." type: string - monorepo-path: - description: "Path to the monorepo root for rocks (relative to repository root)" - required: false - default: "" - type: string jobs: @@ -23,8 +18,8 @@ jobs: versions: ${{ steps.changed-versions.outputs.versions }} is_monorepo: ${{ steps.detect-layout.outputs.is_monorepo }} rock_path: ${{ steps.detect-layout.outputs.rock_path }} - base_path: ${{ steps.detect-layout.outputs.base_path }} - full_path: ${{ steps.detect-layout.outputs.full_path }} + just_dir: ${{ steps.detect-layout.outputs.just_dir }} + rock_name: ${{ steps.detect-layout.outputs.rock_name }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -32,48 +27,37 @@ jobs: id: detect-layout env: ROCK_PATH_INPUT: ${{ inputs.rock-path }} - MONOREPO_PATH_INPUT: ${{ inputs.monorepo-path }} run: | - # Normalize rock path and infer monorepo mode from monorepo-path or layout. + # Normalize the configured rock path. rock_path="${ROCK_PATH_INPUT:-.}" rock_path="${rock_path%/}" if [[ "$rock_path" == "" ]]; then rock_path="." fi - monorepo_path="${MONOREPO_PATH_INPUT:-}" - monorepo_path="${monorepo_path%/}" - if [[ -n "$monorepo_path" ]]; then - base_path="$monorepo_path" - is_monorepo="true" - else - base_path="." - if find "${base_path%/}/${rock_path}" -mindepth 1 -maxdepth 1 -type d -name '[0-9]*' | grep -q .; then - is_monorepo="false" - else - is_monorepo="true" - fi - fi - # Build the full path to the rock root used by later steps. - if [[ "$rock_path" == "." ]]; then - full_path="$base_path" + + # If rock-path has a justfile, it's a single-rock repo. + # Otherwise treat it as a rock folder inside a monorepo and run just one level up. + if [[ -f "$rock_path/justfile" ]]; then + is_monorepo="false" + just_dir="$rock_path" + rock_name="" else - full_path="$base_path/$rock_path" - fi - full_path="${full_path#./}" - if [[ "$full_path" == "" ]]; then - full_path="." + is_monorepo="true" + just_dir="$(dirname "$rock_path")" + rock_name="$(basename "$rock_path")" fi + { echo "rock_path=$rock_path" - echo "base_path=$base_path" - echo "full_path=$full_path" + echo "just_dir=$just_dir" + echo "rock_name=$rock_name" echo "is_monorepo=$is_monorepo" } >> "$GITHUB_OUTPUT" - name: Find rockcraft.yaml changes id: changed-files uses: tj-actions/changed-files@v46 with: - path: ${{ steps.detect-layout.outputs.base_path }} + path: . files: "${{ steps.detect-layout.outputs.rock_path }}/**/rockcraft.yaml" - name: Extract the versions id: changed-versions @@ -82,6 +66,7 @@ jobs: CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} IS_MONOREPO: ${{ steps.detect-layout.outputs.is_monorepo }} ROCK_PATH: ${{ steps.detect-layout.outputs.rock_path }} + ROCK_NAME: ${{ steps.detect-layout.outputs.rock_name }} run: | versions="" path_prefix="" @@ -98,10 +83,8 @@ jobs: relative="${file#"$path_prefix"}" fi if [[ "$IS_MONOREPO" == "true" ]]; then - rock_name="${relative%%/*}" - remainder="${relative#*/}" - version="${remainder%%/*}" - versions="$versions $rock_name:$version" + version="${relative%%/*}" + versions="$versions $version" else version="${relative%%/*}" versions="$versions $version" @@ -148,20 +131,18 @@ jobs: run: df -h - name: Pack and test the rocks run: | - rock_path="${{ needs.changes.outputs.full_path }}" + rock_path="${{ needs.changes.outputs.just_dir }}" is_monorepo="${{ needs.changes.outputs.is_monorepo }}" + rock_name="${{ needs.changes.outputs.rock_name }}" cd "$rock_path" - for target in ${{ needs.changes.outputs.versions }}; do + for version in ${{ needs.changes.outputs.versions }}; do if [[ "$is_monorepo" == "true" ]]; then - rock_name="${target%%:*}" - version="${target#*:}" # Monorepo: pass rock name and version. just pack "$rock_name" "$version" just test "$rock_name" "$version" just clean "$rock_name" "$version" else # Single rock: pass version only. - version="$target" just pack "$version" just test "$version" just clean "$version" diff --git a/.github/workflows/rock-release-dev.yaml b/.github/workflows/rock-release-dev.yaml index 4c24f731..95f93f7e 100644 --- a/.github/workflows/rock-release-dev.yaml +++ b/.github/workflows/rock-release-dev.yaml @@ -8,15 +8,10 @@ on: required: true type: string rock-path: - description: "Path to the rock root (relative to monorepo-path when set)" + description: "Path to the rock root" required: false default: "." type: string - monorepo-path: - description: "Path to the monorepo root for rocks (relative to repository root)" - required: false - default: "" - type: string secrets: OBSERVABILITY_NOCTUA_TOKEN: required: true @@ -37,43 +32,29 @@ jobs: - name: Resolve rock context id: rock-context env: - ROCK_NAME: ${{ inputs.rock-name }} ROCK_PATH_INPUT: ${{ inputs.rock-path }} - MONOREPO_PATH_INPUT: ${{ inputs.monorepo-path }} run: | - # Normalize inputs and decide monorepo mode based on monorepo-path or layout. + # Normalize the configured rock path. rock_path="${ROCK_PATH_INPUT:-.}" rock_path="${rock_path%/}" if [[ "$rock_path" == "" ]]; then rock_path="." fi - monorepo_path="${MONOREPO_PATH_INPUT:-}" - monorepo_path="${monorepo_path%/}" - if [[ -n "$monorepo_path" ]]; then - base_path="$monorepo_path" - is_monorepo="true" - else - base_path="." - if find "${base_path%/}/${rock_path}" -mindepth 1 -maxdepth 1 -type d -name '[0-9]*' | grep -q .; then - is_monorepo="false" - else - is_monorepo="true" - fi - fi - # Build the full path to the rock root and resolve the latest version. - if [[ "$rock_path" == "." ]]; then - full_path="$base_path" + + # Detect mode from the presence of a justfile in the provided rock path. + if [[ -f "$rock_path/justfile" ]]; then + is_monorepo="false" + just_dir="$rock_path" + rock_dir="$rock_path" + just_rock_name="" else - full_path="$base_path/$rock_path" - fi - full_path="${full_path#./}" - if [[ "$full_path" == "" ]]; then - full_path="." - fi - rock_dir="$full_path" - if [[ "$is_monorepo" == "true" ]]; then - rock_dir="$full_path/$ROCK_NAME" + is_monorepo="true" + rock_dir="$rock_path" + just_dir="$(dirname "$rock_path")" + just_rock_name="$(basename "$rock_path")" fi + + # Resolve the latest version directory under the selected rock path. latest_version="$(find "$rock_dir" -maxdepth 1 -type d -name '[0-9]*' | sort -V | tail -n1 | sed 's@.*/@@')" if [[ -z "$latest_version" ]]; then echo "No version directories found under $rock_dir" >&2 @@ -83,23 +64,23 @@ jobs: # Export derived paths and mode for downstream steps. { echo "rock_path=$rock_path" - echo "base_path=$base_path" - echo "full_path=$full_path" + echo "just_dir=$just_dir" + echo "just_rock_name=$just_rock_name" echo "rock_dir=$rock_dir" echo "latest_version=$latest_version" echo "version_dir=$version_dir" echo "is_monorepo=$is_monorepo" } >> "$GITHUB_OUTPUT" - name: Build rock - working-directory: ${{ steps.rock-context.outputs.rock_dir }} + working-directory: ${{ steps.rock-context.outputs.just_dir }} env: - ROCK_NAME: ${{ inputs.rock-name }} + JUST_ROCK_NAME: ${{ steps.rock-context.outputs.just_rock_name }} IS_MONOREPO: ${{ steps.rock-context.outputs.is_monorepo }} LATEST_VERSION: ${{ steps.rock-context.outputs.latest_version }} run: | # Use rock-name + version for monorepos, otherwise version-only. if [[ "$IS_MONOREPO" == "true" ]]; then - just pack "$ROCK_NAME" "$LATEST_VERSION" + just pack "$JUST_ROCK_NAME" "$LATEST_VERSION" else just pack "$LATEST_VERSION" fi diff --git a/.github/workflows/rock-release-oci-factory.yaml b/.github/workflows/rock-release-oci-factory.yaml index 6c0f927f..d533e595 100644 --- a/.github/workflows/rock-release-oci-factory.yaml +++ b/.github/workflows/rock-release-oci-factory.yaml @@ -12,15 +12,10 @@ on: required: true type: string rock-path: - description: "Path to the rock root (relative to monorepo-path when set)" + description: "Path to the rock root" required: false default: "." type: string - monorepo-path: - description: "Path to the monorepo root for rocks (relative to repository root)" - required: false - default: "" - type: string risk-track: description: "Risk track on which to release the rock" required: false @@ -48,7 +43,7 @@ jobs: id: changed-files uses: tj-actions/changed-files@v46 with: - path: rock/${{ inputs.monorepo-path || '.' }} + path: rock files: '${{ inputs.rock-path }}/**/rockcraft.yaml' - name: Sync the OCI Factory fork id: fork-sync @@ -75,42 +70,28 @@ jobs: env: ROCK_NAME: ${{ inputs.rock-name }} ROCK_PATH_INPUT: ${{ inputs.rock-path }} - MONOREPO_PATH_INPUT: ${{ inputs.monorepo-path }} # CHANGED_FILES is a space-separated list CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_and_modified_files }} RISK_TRACK: ${{ inputs.risk-track }} run: | TRACK=${RISK_TRACK:-stable} - # Normalize rock path and determine monorepo mode from monorepo-path or layout. + # Normalize the configured rock path. rock_path="${ROCK_PATH_INPUT:-.}" rock_path="${rock_path%/}" if [[ "$rock_path" == "" ]]; then rock_path="." fi - monorepo_path="${MONOREPO_PATH_INPUT:-}" - monorepo_path="${monorepo_path%/}" - if [[ -n "$monorepo_path" ]]; then - base_path="$monorepo_path" - is_monorepo="true" - else - base_path="." - if find "rock/${base_path%/}/${rock_path}" -mindepth 1 -maxdepth 1 -type d -name '[0-9]*' | grep -q .; then - is_monorepo="false" - else - is_monorepo="true" - fi - fi - # Build the full path to the rock root and move into it. - if [[ "$rock_path" == "." ]]; then - full_path="$base_path" + + # If rock-path has a justfile, it's a single-rock repo. + # Otherwise treat it as a rock folder inside a monorepo. + if [[ -f "rock/$rock_path/justfile" ]]; then + is_monorepo="false" else - full_path="$base_path/$rock_path" - fi - full_path="${full_path#./}" - if [[ "$full_path" == "" ]]; then - full_path="." + is_monorepo="true" fi - cd "rock/$full_path" + + # All version folders are located under rock_path in both modes. + cd "rock/$rock_path" # Export current time to create a unique branch name for the fork echo "now_epoch=$(date -d now +%s)" >> "$GITHUB_OUTPUT" sha="$(git rev-parse HEAD)" @@ -129,11 +110,8 @@ jobs: relative="${file#"$path_prefix"}" fi if [[ "$is_monorepo" == "true" ]]; then - if [[ "$relative" == "$ROCK_NAME/"* ]]; then - remainder="${relative#*/}" - version="${remainder%%/*}" - versions="$versions $version" - fi + version="${relative%%/*}" + versions="$versions $version" else version="${relative%%/*}" versions="$versions $version" From 326f12bf362da48503d53031becd217ddd76abea Mon Sep 17 00:00:00 2001 From: Luca Bello Date: Fri, 27 Feb 2026 12:33:12 +0100 Subject: [PATCH 4/4] chore: the cake is a lie --- .github/workflows/rock-pull-request.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/rock-pull-request.yaml b/.github/workflows/rock-pull-request.yaml index c3cd4e30..dc6a20e9 100644 --- a/.github/workflows/rock-pull-request.yaml +++ b/.github/workflows/rock-pull-request.yaml @@ -57,7 +57,6 @@ jobs: id: changed-files uses: tj-actions/changed-files@v46 with: - path: . files: "${{ steps.detect-layout.outputs.rock_path }}/**/rockcraft.yaml" - name: Extract the versions id: changed-versions