From 300eb24c3739581dcb9446a96b185c7c47578f9b Mon Sep 17 00:00:00 2001 From: Luca Bello Date: Fri, 6 Sep 2024 13:30:33 +0200 Subject: [PATCH 1/2] feat: use noctua --- .github/workflows/_charm-quality-checks.yaml | 17 +++-- .github/workflows/_charm-release.yaml | 65 ++++++++----------- .github/workflows/_local-promote-train.yaml | 57 +++------------- .github/workflows/charm-promote.yaml | 20 +++--- .github/workflows/charm-update-libs.yaml | 23 +------ .../workflows/rock-release-oci-factory.yaml | 50 ++------------ 6 files changed, 67 insertions(+), 165 deletions(-) diff --git a/.github/workflows/_charm-quality-checks.yaml b/.github/workflows/_charm-quality-checks.yaml index 4042136..9e78037 100644 --- a/.github/workflows/_charm-quality-checks.yaml +++ b/.github/workflows/_charm-quality-checks.yaml @@ -56,12 +56,21 @@ jobs: with: fetch-depth: 1 - name: Check charm libraries # Make sure our charm libraries are updated - uses: canonical/charming-actions/check-libraries@2.5.0-rc - with: - credentials: "${{ secrets.CHARMHUB_TOKEN }}" - github-token: "${{ secrets.GITHUB_TOKEN }}" + env: + CHARMHUB_TOKEN: "${{ secrets.CHARMHUB_TOKEN }}" + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" charm-path: "${{ inputs.charm-path }}" charmcraft-channel: "${{ inputs.charmcraft-channel }}" + run: | + pip install git+https://github.com/lucabello/noctua + outdated_libs=$(noctua charm libraries check --minor | jq 'length') + if [[ $outdated_libs != "0" ]]; then + gh pr edit ${{ github.event.number }} --remove-label="Libraries: OK" + gh pr edit ${{ github.event.number }} --add-label="Libraries: Out of sync" + else + gh pr edit ${{ github.event.number }} --remove-label="Libraries: Out of sync" + gh pr edit ${{ github.event.number }} --add-label="Libraries: OK" + fi static-analysis: name: Static Analysis uses: canonical/observability/.github/workflows/_charm-static-analysis.yaml@main diff --git a/.github/workflows/_charm-release.yaml b/.github/workflows/_charm-release.yaml index 8e1bebf..0141ee3 100644 --- a/.github/workflows/_charm-release.yaml +++ b/.github/workflows/_charm-release.yaml @@ -29,6 +29,12 @@ on: required: false description: | The snap channel from which to install Charmcraft. + release-channel: + type: string + default: latest/edge + required: false + description: | + The default channel to release charms to. secrets: CHARMHUB_TOKEN: required: true @@ -136,27 +142,22 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Select charmhub channel - uses: canonical/charming-actions/channel@2.1.1 - id: channel - name: Fetch charm artifacts uses: actions/download-artifact@v3 with: name: charms path: "${{ github.workspace }}/${{ inputs.charm-path }}" - - name: Upload charm to charmhub - uses: canonical/charming-actions/upload-charm@2.5.0-rc - with: - credentials: "${{ secrets.CHARMHUB_TOKEN }}" - github-token: "${{ secrets.GITHUB_TOKEN }}" - channel: "${{ steps.channel.outputs.name }}" - built-charm-path: "${{ matrix.path }}" - charm-path: "${{ inputs.charm-path }}" - tag-prefix: "${{ inputs.release-tag-prefix }}" - charmcraft-channel: "${{ inputs.charmcraft-channel }}" - # We set destructive mode to false, otherwise runner's OS would have to match - # charm's 'build-on' OS. - destructive-mode: false + - name: Upload charm to Charmhub + env: + CHARMHUB_TOKEN: ${{ secrets.CHARMHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + pip install git+https://github.com/lucabello/noctua + cd "${{ inputs.charm-path }}" + noctua charm release --path="${{ matrix.path }}" --channel=${{ inputs.release-channel }} + # TODO: how do I get the revision number? store it into REVISION + # TODO: push git tag; is it necessary? + gh release create "rev$REVISION" --title="Revision $REVISION" --generate-notes release-arm-to-charmhub: name: Release arm64 to CharmHub # needs to be run on arm or the oci image will resolve to the amd64 one. @@ -172,31 +173,19 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Select charmhub channel - uses: canonical/charming-actions/channel@2.1.1 - id: channel - name: Fetch charm artifacts uses: actions/download-artifact@v3 with: name: charms-arm path: "${{ github.workspace }}/${{ inputs.charm-path }}" - - name: Set up Docker + - name: Upload charm to Charmhub + env: + CHARMHUB_TOKEN: ${{ secrets.CHARMHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - sudo snap install docker - sudo addgroup --system docker - sudo adduser $USER docker - newgrp docker <<< "sudo snap disable docker" - newgrp docker <<< "sudo snap enable docker" - - name: Upload charm to charmhub - uses: canonical/charming-actions/upload-charm@2.5.0-rc - with: - credentials: "${{ secrets.CHARMHUB_TOKEN }}" - github-token: "${{ secrets.GITHUB_TOKEN }}" - channel: "${{ steps.channel.outputs.name }}" - built-charm-path: "${{ matrix.path }}" - charm-path: "${{ inputs.charm-path }}" - tag-prefix: "${{ inputs.release-tag-prefix }}" - charmcraft-channel: "${{ inputs.charmcraft-channel }}" - # We set destructive mode to false, otherwise runner's OS would have to match - # charm's 'build-on' OS. - destructive-mode: false + pip install git+https://github.com/lucabello/noctua + cd "${{ inputs.charm-path }}" + noctua charm release --path="${{ matrix.path }}" --channel=${{ inputs.release-channel }} + # TODO: how do I get the revision number? store it into REVISION + # TODO: push git tag; is it necessary? + gh release create "rev$REVISION" --title="Revision $REVISION" --generate-notes diff --git a/.github/workflows/_local-promote-train.yaml b/.github/workflows/_local-promote-train.yaml index 8b40779..7d2d5ed 100644 --- a/.github/workflows/_local-promote-train.yaml +++ b/.github/workflows/_local-promote-train.yaml @@ -8,7 +8,11 @@ on: type: boolean default: false required: true - + track: + type: choice + description: Track on which to run the promotion train + options: + - latest jobs: promote: name: Promote Charm @@ -52,52 +56,7 @@ jobs: echo "charm_path=$CHARM_PATH" >> $GITHUB_OUTPUT; fi - - name: Check which tracks already have a release - id: check-tracks - env: - CHARMCRAFT_AUTH: ${{ secrets.CHARMHUB_TOKEN }} - run: | - sudo snap install charmcraft --classic - cd ${{ steps.read-charm-path.outputs.charm_path }} - charm_name=$(yq .name metadata.yaml 2>/dev/null || yq .name charmcraft.yaml) - status=$(charmcraft status "$charm_name" --format=json) - to_stable=$(echo "$status" | jq -r '.[] | select(.track == "latest") | .mappings[].releases[] | select(.channel == "latest/stable") | .status' | head -n1) - to_candidate=$(echo "$status" | jq -r '.[] | select(.track == "latest") | .mappings[].releases[] | select(.channel == "latest/candidate") | .status' | head -n1) - to_beta=$(echo "$status" | jq -r '.[] | select(.track == "latest") | .mappings[].releases[] | select(.channel == "latest/beta") | .status' | head -n1) - echo "to_stable=$to_stable" >> $GITHUB_OUTPUT - echo "to_candidate=$to_candidate" >> $GITHUB_OUTPUT - echo "to_beta=$to_beta" >> $GITHUB_OUTPUT - - - name: (dry run) Print promotions - if: ${{ inputs.dry-run }} + - name: Run the promotion train run: | - echo "${{ matrix.charm-repo }} would promote the following channels:" - if [[ "${{ steps.check-tracks.outputs.to_stable }}" == "open" ]]; then echo "- latest/candidate --> latest/stable"; fi - if [[ "${{ steps.check-tracks.outputs.to_candidate }}" == "open" ]]; then echo "- latest/beta --> latest/candidate"; fi - if [[ "${{ steps.check-tracks.outputs.to_beta }}" == "open" ]]; then echo "- latest/edge --> latest/beta"; fi - - - name: Promote charm - latest/candidate --> latest/stable - if: ${{ !inputs.dry-run && steps.check-tracks.outputs.to_stable == 'open' }} - uses: canonical/charming-actions/promote-charm@2.6.0 - with: - charm-path: ${{ steps.read-charm-path.outputs.charm_path }} - credentials: ${{ secrets.CHARMHUB_TOKEN }} - origin-channel: latest/candidate - destination-channel: latest/stable - - - name: Promote charm - latest/beta --> latest/candidate - if: ${{ !inputs.dry-run && steps.check-tracks.outputs.to_candidate == 'open' }} - uses: canonical/charming-actions/promote-charm@2.6.0 - with: - charm-path: ${{ steps.read-charm-path.outputs.charm_path }} - credentials: ${{ secrets.CHARMHUB_TOKEN }} - origin-channel: latest/beta - destination-channel: latest/candidate - - name: Promote charm - latest/edge --> latest/beta - if: ${{ !inputs.dry-run && steps.check-tracks.outputs.to_beta == 'open' }} - uses: canonical/charming-actions/promote-charm@2.6.0 - with: - charm-path: ${{ steps.read-charm-path.outputs.charm_path }} - credentials: ${{ secrets.CHARMHUB_TOKEN }} - origin-channel: latest/edge - destination-channel: latest/beta + pip install git+https://github.com/lucabello/noctua + noctua charm promote-train --track=${{ inputs.track }} diff --git a/.github/workflows/charm-promote.yaml b/.github/workflows/charm-promote.yaml index dcf59ee..ac45261 100644 --- a/.github/workflows/charm-promote.yaml +++ b/.github/workflows/charm-promote.yaml @@ -3,7 +3,7 @@ name: Promote Charm on: workflow_call: inputs: - charm-path: + charm-name: description: "Path to the charm we want to promote. Defaults to the current working directory." type: string default: '.' @@ -27,25 +27,23 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v4 - name: Set target channel env: PROMOTE_FROM: ${{ github.event.inputs.promotion }} run: | if [ "${PROMOTE_FROM}" == "edge -> beta" ]; then echo "promote-from=edge" >> ${GITHUB_ENV} - echo "promote-to=beta" >> ${GITHUB_ENV} elif [ "${PROMOTE_FROM}" == "beta -> candidate" ]; then echo "promote-from=beta" >> ${GITHUB_ENV} - echo "promote-to=candidate" >> ${GITHUB_ENV} elif [ "${PROMOTE_FROM}" == "candidate -> stable" ]; then echo "promote-from=candidate" >> ${GITHUB_ENV} - echo "promote-to=stable" >> ${GITHUB_ENV} fi - name: Promote Charm - uses: canonical/charming-actions/promote-charm@2.6.0 - with: - charm-path: ${{ inputs.charm-path }} - credentials: ${{ secrets.CHARMHUB_TOKEN }} - destination-channel: ${{ github.event.inputs.track }}/${{ env.promote-to }} - origin-channel: ${{ github.event.inputs.track }}/${{ env.promote-from }} - charmcraft-channel: latest/stable + env: + CHARMHUB_TOKEN: ${{ secrets.CHARMHUB_TOKEN }} + run: | + pip install git+https://github.com/lucabello/noctua + cd ${{ inputs.charm-path }} + noctua charm promote --from=${{ github.event.inputs.track }}/${{ env.promote-from }} diff --git a/.github/workflows/charm-update-libs.yaml b/.github/workflows/charm-update-libs.yaml index 9b80aa9..a54ec95 100644 --- a/.github/workflows/charm-update-libs.yaml +++ b/.github/workflows/charm-update-libs.yaml @@ -63,26 +63,9 @@ jobs: - name: Check for major library updates run: | sudo snap install charmcraft --classic --channel "${{ inputs.charmcraft-channel }}" + pip install git+https://github.com/lucabello/noctua cd "$GITHUB_WORKSPACE/${{ inputs.charm-path }}" - # Get the charm name - charm_name=$((yq .name metadata.yaml 2>/dev/null || yq .name charmcraft.yaml) | tr - _) - if [[ $charm_name = "" ]]; then echo "Error: can't extract the charm name." && exit 1; fi - # Initalize the issue body content to empty string, and fill it up in the for loop - issue_body="" - # For each library not belonging to the charm, check for a major version update - # "lib" would be of the form `charms.prometheus_k8s.v0.prometheus_scrape` - for lib in $(find "lib/charms/" -type f -name "*.py" | grep -v "$charm_name" | sed 's|lib/||' | sed 's/.py//' | sed 's|/|.|g'); do - # Extract the name of the library, the current major version, and the charm that owns it - lib_name=$(cut -d. -f4 <<< "$lib") - lib_major=$(cut -d. -f3 <<< "$lib") - lib_owner=$(cut -d. -f2 <<< "$lib" | tr _ -) - # Get the latest major version of the library from Charmhub - latest_major="v$(charmcraft list-lib $lib_owner --format=json | jq -r --arg LIBNAME $lib_name '.[] | select(.library_name == $LIBNAME) | .api')" - # If there is a new major version of the library, open a new issue - if [[ $(printf "%s\n%s" "$lib_major" "$latest_major" | sort -V | tail -n1 ) != "$lib_major" ]]; then - issue_body=$(printf "%s\n%s" "$issue_body" "- update $lib to $latest_major") - fi - done + issue_body=$(noctua charm libraries check --major) # Check if there are already open issues for major library upgrades open_issues_count="$(gh issue list --search 'chore: update libraries to new major versions' --state open --json id --jq 'length')" # Complete $issue_body if it's not empty @@ -109,7 +92,7 @@ jobs: cd "$GITHUB_WORKSPACE" env: CHARMCRAFT_AUTH: "${{ secrets.CHARMHUB_TOKEN }}" - GH_TOKEN: "${{ secrets.OBSERVABILITY_NOCTUA_TOKEN }}" + GITHUB_TOKEN: "${{ secrets.OBSERVABILITY_NOCTUA_TOKEN }}" - name: Fetch charm libraries run: | diff --git a/.github/workflows/rock-release-oci-factory.yaml b/.github/workflows/rock-release-oci-factory.yaml index be80643..716a8d5 100644 --- a/.github/workflows/rock-release-oci-factory.yaml +++ b/.github/workflows/rock-release-oci-factory.yaml @@ -69,49 +69,13 @@ jobs: id: update-releases if: steps.changed-files.outputs.all_changed_and_modified_files != '' run: | - # Get the tags already in OCI Factory - existing_tags="$(jq -r 'to_entries[] | .key' $GITHUB_WORKSPACE/oci-factory/oci/${{ inputs.rock-name }}/_releases.json | sed 's/-22.04//')" - # Get the versions from the rocks that have been modified - modified_tags="$(echo ${{ steps.changed-files.outputs.all_changed_and_modified_files }} | tr ' ' '\n' | sed s@/rockcraft.yaml@@)" - # Merge the two to make a list of all the versions that will be in OCI Factory with - # the PR that is being opened in this workflow - all_tags="$existing_tags\n$modified_tags" - today="$(date)" - echo "now_epoch=$(date -d now +%s)" >> $GITHUB_OUTPUT # to create a unique branch name on the fork - end_of_life="$(date -d "$today+3 months" +%Y-%m-%d)" - yq -i ".upload = []" $GITHUB_WORKSPACE/oci-factory/oci/${{ inputs.rock-name }}/image.yaml - for file in ${{ steps.changed-files.outputs.all_changed_and_modified_files }}; do - # For each rock version, build the `upload:` element for image.yaml as a json - # Example: {"source": "canonical/prometheus-rock", "commit": "...", ...} - patch_tag=""; minor_tag=""; major_tag="" - tag_json_format='"%s-22.04": {"end-of-life": "%sT00:00:00Z", "risks":["stable"]}' - # Parse the rock version from the rockcraft.yaml - rock_version=$(yq -r '.version' $GITHUB_WORKSPACE/rock/$file) - # Always tag with patch - patch_tag=$(printf "$tag_json_format" "$rock_version" "$end_of_life") - # If rock_version is the latest tag among the ones with equal major.minor, apply major.minor - rock_major_minor=$(echo $rock_version | sed -E "s/([0-9]+\.[0-9]+).*/\1/") - same_major_minor=$(printf "%s\n%s" "$all_tags" "$rock_version" | grep "$rock_major_minor") - if [[ $(echo "$same_major_minor" | sort -V | tail -n1) == "$rock_version" ]]; then - minor_tag=$(printf ",$tag_json_format" "$rock_major_minor" "$end_of_life") - fi - # If rock_version is the latest among the ones with equal major, apply major - rock_major=$(echo $rock_version | sed -E "s/([0-9]+).*/\1/") - same_major=$(printf "%s\n%s" "$all_tags" "$rock_version" | grep "$rock_major") - if [[ $(echo "$same_major" | sort -V | tail -n1) == "$rock_version" ]]; then - major_tag=$(printf ",$tag_json_format" "$rock_major" "$end_of_life") - fi - # Build the final JSON object to update image.yaml - rock_tags=$(printf '{%s%s%s}' "$patch_tag" "$minor_tag" "$major_tag") - upload_item_format='{"source":"%s","commit":"%s","directory":"%s","release":%s}' - upload_item=$(printf "$upload_item_format" \ - "canonical/${{ inputs.rock-name }}-rock" \ - "${{ steps.commit-sha.outputs.commit_sha }}" \ - "$rock_version" \ - "$rock_tags" \ - ) - yq -i ".upload += $upload_item" $GITHUB_WORKSPACE/oci-factory/oci/${{ inputs.rock-name }}/image.yaml - done + pip install git+https://github.com/lucabello/noctua + versions="$(echo ${{ steps.changed-files.outputs.all_changed_and_modified_files }} | tr ' ' '\n' | grep rockcraft.yaml | sed 's@/rockcraft.yaml@@g')" + noctua rock manifest "${{ github.repository }}" \ + --commit="${{ steps.commit-sha.outputs.commit_sha }}" \ + --base=22.04 \ + $(echo $versions | sed -E 's/(\S+)/--version \1/g' | tr '\n' ' ') \ # build the --version flags + > $GITHUB_WORKSPACE/oci-factory/oci/${{ inputs.rock-name }}/image.yaml - name: Commit to the fork id: fork-commit From 931c55ca074663e2e1c7f7244f95f61a8fcbe229 Mon Sep 17 00:00:00 2001 From: Luca Bello Date: Fri, 6 Sep 2024 15:10:39 +0200 Subject: [PATCH 2/2] parse the revision from noctua release --- .github/workflows/_charm-release.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/_charm-release.yaml b/.github/workflows/_charm-release.yaml index 0141ee3..3e47416 100644 --- a/.github/workflows/_charm-release.yaml +++ b/.github/workflows/_charm-release.yaml @@ -154,10 +154,10 @@ jobs: run: | pip install git+https://github.com/lucabello/noctua cd "${{ inputs.charm-path }}" - noctua charm release --path="${{ matrix.path }}" --channel=${{ inputs.release-channel }} - # TODO: how do I get the revision number? store it into REVISION + release=$(noctua charm release --path="${{ matrix.path }}" --channel=${{ inputs.release-channel }} --json | tail -n1) + revision=$(echo "$release" | jq .revision) # TODO: push git tag; is it necessary? - gh release create "rev$REVISION" --title="Revision $REVISION" --generate-notes + gh release create "${{inputs.release-tag-prefix}}rev${revision}" --title="Revision ${revision}" --generate-notes release-arm-to-charmhub: name: Release arm64 to CharmHub # needs to be run on arm or the oci image will resolve to the amd64 one. @@ -185,7 +185,7 @@ jobs: run: | pip install git+https://github.com/lucabello/noctua cd "${{ inputs.charm-path }}" - noctua charm release --path="${{ matrix.path }}" --channel=${{ inputs.release-channel }} - # TODO: how do I get the revision number? store it into REVISION + release=$(noctua charm release --path="${{ matrix.path }}" --channel=${{ inputs.release-channel }} --json | tail -n1) + revision=$(echo "$release" | jq .revision) # TODO: push git tag; is it necessary? - gh release create "rev$REVISION" --title="Revision $REVISION" --generate-notes + gh release create "${{inputs.release-tag-prefix}}rev${revision}" --title="Revision ${revision}" --generate-notes