Skip to content

Commit

Permalink
#270 Adjust prune workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
chang-annie committed Aug 22, 2024
1 parent 4d2516d commit 88f6bee
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 10 deletions.
60 changes: 60 additions & 0 deletions .github/scripts/release_images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash

# Initialize array to store digest SHAs and all release versions
declare -a digests
declare -a all_release_versions

# Fetch all docker image names
image_names=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Token ${GITHUB_TOKEN}" \
--paginate "/orgs/boozallen/packages?package_type=container" | jq -r '.[] | select((.name | startswith("aissemble")) and (.name | endswith("-chart") | not)) | .name')

# For each docker image, find all release versions, excluding 1.7.0
for name in $image_names; do
release_versions=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Token ${GITHUB_TOKEN}" \
--paginate "/orgs/boozallen/packages/container/${name}/versions" \
| jq -r '.[] | .metadata.container.tags[] | select(test("^\\d+\\.\\d+\\.\\d+$"))' \
| jq -R -s 'split("\n") | map(select(length > 0)) | map(select(. != "1.7.0"))')

# Add release versions to all_release_versions array
all_release_versions+=("$release_versions")

# Loop through all release versions
for version in $(echo "$release_versions" | jq -r '.[]'); do
echo "Processing release image ${name}:${version}"

# Fetch the base manifest SHA
# Inspect command will output Name, MediaType, Digest in the first three lines
# so we can use a regex to pull out the SHA
manifest_base_sha=$(docker buildx imagetools inspect "ghcr.io/boozallen/${name}:${version}" | head -n 3 | sed -n 's/^Digest: *//p')

echo "Manifest index SHA: ${manifest_base_sha}"

# Add to digests array
digests+=("$manifest_base_sha")

# Query the raw inpect output to get the nested manifest list SHAs
manifest_list_shas=$(docker buildx imagetools inspect --raw "ghcr.io/boozallen/${name}:${version}" | jq -r '.manifests[].digest' | paste -s -d ' ' -)

echo "Manifest List SHAs: $manifest_list_shas"

# Add to digests array
digests+=("$manifest_list_shas")
done
done

# Pass the latest_release_version to GITHUB_OUTPUT so snapshot_images.sh can use it
latest_release_version=$(echo "$all_release_versions" | jq -r .[] | sort -uV -r | head -n 1)
echo "Latest release version is: ${latest_release_version}"
echo "latest-release-version=${latest_release_version}" >> "$GITHUB_OUTPUT"

# Join digests into a single string separated by spaces
digests_string=$(echo "${digests[*]}")

# Save the output to $GITHUB_OUTPUT
echo "multi-arch-digests=${digests_string}" >> "$GITHUB_OUTPUT"
79 changes: 79 additions & 0 deletions .github/scripts/snapshot_images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/bin/bash

# Initialize array to store digest SHAs
declare -a digests

# Fetch all docker image names
image_names=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Token ${GITHUB_TOKEN}" \
--paginate "/orgs/boozallen/packages?package_type=container" | jq -r '.[] | select((.name | startswith("aissemble")) and (.name | endswith("-chart") | not)) | .name')

# For each docker image, find their snapshot versions by grabbing any tag that ends with "-SNAPSHOT"
for name in $image_names; do
all_snapshot_versions=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Token ${GITHUB_TOKEN}" \
--paginate "/orgs/boozallen/packages/container/${name}/versions" \
| jq -r '.[] | .metadata.container.tags[] | select(endswith("-SNAPSHOT"))'| jq -R -s 'split("\n")| map(select(length > 0))')

# Find the latest snapshot version by sorting all snapshot versions, then selecting the top
latest_snapshot_version=$(echo "$all_snapshot_versions" | jq -r '.[] | select(endswith("-SNAPSHOT"))' | sort -r | head -n 1)

echo "Processing snapshot image ${name}:${latest_snapshot_version}"

# Fetch the base manifest SHA
# Inspect command will output Name, MediaType, Digest in the first three lines
# Use regex to pull out the SHA
latest_snapshot_manifest_base_sha=$(docker buildx imagetools inspect "ghcr.io/boozallen/${name}:${version}" | head -n 3 | sed -n 's/^Digest: *//p')

echo "Manifest index SHA: ${latest_snapshot_manifest_base_sha}"

# Add to digests array
digests+=("$latest_snapshot_manifest_base_sha")

# Fetch the manifest list SHAs
latest_snapshot_manifest_list_shas=$(docker buildx imagetools inspect --raw "ghcr.io/boozallen/${name}:${latest_snapshot_version}" | jq -r '.manifests[].digest' | paste -s -d ' ' -)

echo "Manifest List: $latest_snapshot_manifest_list_shas"

# Add to digests array
digests+=("$latest_snapshot_manifest_list_shas")

# Find if there are any patch versions available
# Extract the major, minor, and patch components of the latest release version using IFS (Internal Field Separator)
IFS='.' read -r major minor patch <<< "${LATEST_RELEASE_VERSION}"

# Patch pattern uses the latest release version's major and minor components
patch_pattern="${major}\.${minor}\.[1-9]+[0-9]*-SNAPSHOT?"

for version in $(echo "$all_snapshot_versions" | jq -r '.[]'); do
if [[ ${version} =~ ^${patch_pattern}$ ]]; then
echo "Patch version ${version} matches patch pattern ${patch_pattern}"

# Add to array containing all matching patch versions
matching_patch_versions+=("$version")
fi

# If matching patch versions array is not empty
if [ ${#matching_patch_versions[@]} -ne 0 ]; then
echo "Patch Versions array is not empty"
# Find the latest patch version
latest_patch_version=($(printf "%s\n" "${matching_patch_versions[@]}" | sort -V -r | head -n 1))

# Fetch the SHA
latest_patch_version_sha=$(docker buildx imagetools inspect --raw "ghcr.io/boozallen/${name}:${latest_patch_version}" | jq -r '.manifests[].digest' | paste -s -d ' ' -)

# Add to the digests array
digests+=("$latest_patch_version_sha")
fi
done
done

# Join digests into a single string separated by spaces
digests_string=$(echo "${digests[*]}")

# Save the output to $GITHUB_OUTPUT
echo "latest-snapshot-digests=${digests_string}" >> "$GITHUB_OUTPUT"
45 changes: 35 additions & 10 deletions .github/workflows/prune.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Prunes old aissemble-* untagged containers
# Prunes old aissemble-* containers, excluding those with the following tags:
# any release versions, the latest snapshot version, and the latest patch version

name: Prune ghcr.io

Expand All @@ -15,14 +16,38 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Prune
uses: snok/container-retention-policy@v2
# Required in order to access script files in this repository
- uses: actions/checkout@v4

# Prevents multi-platform release images from being pruned by identifying all manifest lists
- name: Fetch multi-platform package version SHAs
id: multi-arch-digests
env:
GITHUB_TOKEN: ${{ secrets.GHCR_IO_TOKEN }}
run: bash ${GITHUB_WORKSPACE}/.github/scripts/release_images.sh

# Prevents the latest snapshot images from being pruned
- name: Fetch latest snapshot version SHAs
id: latest-snapshot-digests
env:
GITHUB_TOKEN: ${{ secrets.GHCR_IO_TOKEN }}
LATEST_RELEASE_VERSION: ${{ steps.multi-arch-digests.outputs.latest-release-version }}
run: bash ${GITHUB_WORKSPACE}/.github/scripts/snapshot_images.sh

- name: Concatenate digests
id: concat-digests
run: |
skip-shas="${{ steps.multi-arch-digests.outputs.multi-arch-digests }} ${{ steps.latest-snapshot-digests.outputs.latest-snapshot-digests }}"
echo "skip-shas=$skip-shas" >> $GITHUB_OUTPUT
- name: Prune old release versions
uses: snok/[email protected]
with:
image-names: aissemble-*
cut-off: Two days ago UTC
account-type: org
org-name: boozallen
keep-at-least: 2
untagged-only: true
dry-run: false
skip-shas: ${{ steps.concat-digests.outputs.skip-shas }}
image-names: "aissemble-* !aissemble-*-chart"
image-tags: "!1.7.0 !1.7.0-arm64 !1.7.0-amd64"
dry-run: true
cut-off: 2d
account: boozallen
token: ${{ secrets.GHCR_IO_TOKEN }}

0 comments on commit 88f6bee

Please sign in to comment.