Skip to content

Commit 264f0c2

Browse files
authored
Merge pull request #694 from gerrod3/ci-app-versions
Make rebuilding the app images smarter
2 parents 7ba80b2 + 8b5a004 commit 264f0c2

File tree

5 files changed

+141
-3
lines changed

5 files changed

+141
-3
lines changed

.ci/scripts/check_up_to_date.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import argparse
2+
import requests
3+
from urllib.parse import urljoin
4+
from packaging.version import parse
5+
from packaging.requirements import Requirement
6+
7+
PACKAGES = [
8+
"pulp-ansible",
9+
"pulp-container",
10+
"pulp-deb",
11+
"pulp-gem",
12+
"pulp-maven",
13+
"pulp-python",
14+
"pulp-rpm",
15+
"pulp-ostree"
16+
]
17+
18+
INDEX = "https://pypi.org"
19+
20+
def check_update(branch, current_versions):
21+
"""
22+
Go through each of the image's main Pulp components and see if there is a new version available.
23+
"""
24+
new_versions = {}
25+
# Get the latest Z (or Y) pulpcore release for this branch
26+
core_pypi_response = requests.get(urljoin(INDEX, "pypi/pulpcore/json"))
27+
assert core_pypi_response.status_code == 200
28+
core_version = parse(current_versions["pulpcore"])
29+
for version, release in core_pypi_response.json()["releases"].items():
30+
cur_version = parse(version)
31+
if cur_version > core_version:
32+
if branch != "latest":
33+
if cur_version.major != core_version.major or cur_version.minor != core_version.minor:
34+
continue
35+
core_version = cur_version
36+
new_versions["pulpcore"] = core_version
37+
38+
# Now check each plugin to see if they need updates
39+
for plugin in PACKAGES:
40+
if plugin not in current_versions:
41+
continue
42+
plugin_version = parse(current_versions[plugin])
43+
plugin_pypi_response = requests.get(urljoin(INDEX, f"pypi/{plugin}/json"))
44+
assert plugin_pypi_response.status_code == 200
45+
plugin_versions = sorted((parse(v) for v in plugin_pypi_response.json()["releases"].keys()), reverse=True)
46+
for version in plugin_versions:
47+
if version <= plugin_version:
48+
break
49+
version_pypi_response = requests.get(urljoin(INDEX, f"pypi/{plugin}/{version}/json"))
50+
assert version_pypi_response.status_code == 200
51+
deps = version_pypi_response.json()["info"]["requires_dist"]
52+
core_dep = next(filter(lambda dep: dep.startswith("pulpcore"), deps))
53+
if core_version in Requirement(core_dep).specifier:
54+
new_versions[plugin] = version
55+
break
56+
57+
if new_versions:
58+
print("Updates needed for:")
59+
for plugin, version in new_versions.items():
60+
print(f"{plugin}: {current_versions[plugin]} -> {version!s}")
61+
exit(100)
62+
63+
print("No updates needed :)")
64+
65+
if __name__ == '__main__':
66+
parser = argparse.ArgumentParser()
67+
parser.add_argument("branch")
68+
parser.add_argument("versions", type=argparse.FileType("r"))
69+
opts = parser.parse_args()
70+
versions = {}
71+
for line in opts.versions:
72+
plugin, _, version = line.rstrip("\n").partition("==")
73+
versions[plugin] = version
74+
check_update(opts.branch, versions)

.github/actions/base_images/action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ outputs:
1111
base_cache_key:
1212
value: ${{ steps.hash_key.outputs.base_cache_key }}
1313
description: "The cache key the built images were uploaded to."
14+
rebuilt_images:
15+
value: ${{ env.BUILD_IMAGES }}
16+
description: "The images that were rebuilt or empty"
1417

1518
runs:
1619
using: "composite"

.github/actions/build_image/action.yml

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@ inputs:
1616
description: 'Use the latest pulp-ui when building the image'
1717
default: 'false'
1818
required: false
19+
built_base_images:
20+
description: 'A JSON list of the base-images that were freshly rebuilt prior'
21+
required: true
1922
outputs:
2023
app_version:
2124
value: ${{ steps.image_version_branch.outputs.app_version }}
2225
description: 'The full version of the app in the built image'
2326
app_branch:
2427
value: ${{ steps.image_version_branch.outputs.app_branch }}
2528
description: 'The pulpcore version branch that the built image matches'
29+
rebuilt_images:
30+
value: ${{ env.BUILD }}
31+
description: 'true/false if the app image was rebuilt'
2632

2733
runs:
2834
using: "composite"
@@ -39,7 +45,7 @@ runs:
3945
shell: bash
4046

4147
- name: Restore podman images from cache
42-
uses: actions/cache/restore@v3
48+
uses: actions/cache/restore@v4
4349
with:
4450
key: base-images=${{ inputs.image_cache_key }}
4551
path: base-images.tar.gz
@@ -62,7 +68,42 @@ runs:
6268
fi
6369
shell: bash
6470

71+
- name: Set hash key
72+
run: echo "VERSIONKEY=versions-${{ github.ref_name }}=${{ hashFiles(format('images/{0}/stable/**', inputs.image_name)) }}" >> $GITHUB_ENV
73+
shell: bash
74+
75+
- name: Restore last builds versions from cache
76+
id: cache
77+
uses: actions/cache/restore@v4
78+
with:
79+
key: ${{ env.VERSIONKEY }}
80+
path: versions.freeze
81+
82+
- name: Check if rebuild is needed
83+
run: |
84+
# Rebuilds are needed for
85+
# 1. CI is being ran in a PR or is a nightly run
86+
# 2. Base images were rebuilt
87+
# 3. New pulp versions was released
88+
if [[ "${{ github.event_name }}" == "pull_request" || "${{ inputs.image_variant }}" == "nightly" || -n "${{ inputs.built_base_images }}" ]]; then
89+
echo "BUILD=true" >> $GITHUB_ENV
90+
else
91+
if [[ "${{ steps.cache.outputs.cache-hit }}" == "false" ]]; then
92+
echo "BUILD=true" >> $GITHUB_ENV
93+
else
94+
# Script returns non-zero (100) when new versions are available
95+
if python .ci/scripts/check_up_to_date.py ${{ github.ref_name }} versions.freeze; then
96+
echo "BUILD=false" >> $GITHUB_ENV
97+
else
98+
echo "BUILD=true" >> $GITHUB_ENV
99+
fi
100+
fi
101+
fi
102+
echo "Going to rebuild: ${BUILD}"
103+
shell: bash
104+
65105
- name: Build images
106+
if: env.BUILD == 'true'
66107
run: |
67108
podman version
68109
buildah version
@@ -84,11 +125,26 @@ runs:
84125
id: image_version_branch
85126
run: |
86127
base_image=$(echo ${{ inputs.image_name }} | cut -d '-' -f1)
87-
app_version=$(podman run --pull=never pulp/${{ inputs.image_name }}:ci-amd64 bash -c "pip3 show pulpcore | sed -n -e 's/Version: //p'")
128+
podman run --pull=never pulp/${{ inputs.image_name }}:ci-amd64 bash -c "pip3 freeze | grep pulp" >> versions.freeze
129+
app_version=$(grep pulpcore versions.freeze | sed -n -e 's/pulpcore==//p')
88130
app_branch=$(echo ${app_version} | grep -oP '\d+\.\d+')
89131
90132
echo "APP_VERSION: ${app_version}"
91133
echo "APP_BRANCH: ${app_branch}"
92134
echo "app_version=${app_version}" >> "$GITHUB_OUTPUT"
93135
echo "app_branch=${app_branch}" >> "$GITHUB_OUTPUT"
94136
shell: bash
137+
138+
- name: Clear cache for next upload
139+
if: env.BUILD == 'true' && steps.cache.outputs.cache-hit == 'true' && github.event_name != 'pull_request'
140+
run: |
141+
echo "Deleting existing cache for ${{ env.VERSIONKEY }}"
142+
gh cache delete ${{ env.VERSIONKEY }} -R ${{ github.repository }}
143+
shell: bash
144+
145+
- name: Cache versions
146+
if: env.BUILD == 'true' && github.event_name != 'pull_request'
147+
uses: actions/cache/save@v4
148+
with:
149+
key: ${{ env.VERSIONKEY }}
150+
path: versions.freeze

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ jobs:
8383
image_variant: "stable"
8484
image_cache_key: ${{ needs.base-images.outputs.base_cache_key }}
8585
latest_ui: ${{ github.base_ref == 'latest' }}
86+
built_base_images: ${{ needs.base-images.outputs.rebuilt_images }}
8687

8788
- name: Test App Image
8889
uses: "./.github/actions/test_image"

.github/workflows/release.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,18 @@ jobs:
175175
image_variant: ${{ matrix.image_variant }}
176176
image_cache_key: ${{ needs.base-images.outputs.base_cache_key }}
177177
latest_ui: ${{ github.ref_name == 'latest' }}
178+
built_base_images: ${{ needs.base-images.outputs.rebuilt_images }}
179+
178180

179181
- name: Test App Image
180-
if: matrix.image_variant != 'nightly'
182+
if: ${{ matrix.image_variant != 'nightly' && steps.build_image.outputs.rebuilt_images == 'true' }}
181183
uses: "./.github/actions/test_image"
182184
with:
183185
image_name: ${{ matrix.image_name }}
184186
app_branch: ${{ steps.build_image.outputs.app_branch }}
185187

186188
- name: Set tags
189+
if: ${{ steps.build_image.outputs.rebuilt_images == 'true' }}
187190
run: |
188191
base_image=$(echo ${{ matrix.image_name }} | cut -d '-' -f1)
189192
if [[ "${{ matrix.image_name }}" == "pulp" ]]; then
@@ -211,6 +214,7 @@ jobs:
211214
echo "TAGS=${tags}" >> $GITHUB_ENV
212215
213216
- name: Publish App Image
217+
if: ${{ steps.build_image.outputs.rebuilt_images == 'true' }}
214218
uses: "./.github/actions/publish_images"
215219
with:
216220
image_names: ${{ env.IMAGES }}

0 commit comments

Comments
 (0)