Skip to content

Commit f4cd2a0

Browse files
committed
Migrate lightweight workflow jobs to ubuntu-slim runner
Use the new 1 vCPU ubuntu-slim runner for lightweight jobs that don't need full resources: - protolint (api only) - nox-all (aggregator job) - test-installation-all (aggregator job) - create-github-release - publish-to-pypi - auto-merge (dependabot) - check-release-notes - DCO - Label The ubuntu-slim runner is more cost-effective for these simple jobs that primarily do API calls, artifact downloads, or run short scripts. Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
1 parent d022938 commit f4cd2a0

34 files changed

Lines changed: 245 additions & 54 deletions

File tree

RELEASE_NOTES.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Summary
44

5-
<!-- Here goes a general summary of what this release is about -->
5+
This release migrates lightweight GitHub Actions workflow jobs to use the new cost-effective `ubuntu-slim` runner.
66

77
## Upgrading
88

@@ -26,7 +26,14 @@ But you might still need to adapt your code:
2626

2727
### Cookiecutter template
2828

29-
<!-- Here new features for cookiecutter specifically -->
29+
- Migrated lightweight workflow jobs to use the new `ubuntu-slim` runner for cost savings.
30+
The following jobs now use `ubuntu-slim`:
31+
- `ci.yaml`: `protolint`, `nox-all`, `test-installation-all`, `create-github-release`, `publish-to-pypi`
32+
- `ci-pr.yaml`: `protolint`
33+
- `auto-dependabot.yaml`: `auto-merge`
34+
- `release-notes-check.yml`: `check-release-notes`
35+
- `dco-merge-queue.yml`: `DCO`
36+
- `labeler.yml`: `Label`
3037

3138
## Bug Fixes
3239

cookiecutter/migrate.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
""" # noqa: E501
2222

2323
import hashlib
24+
import json
2425
import os
2526
import subprocess
2627
import tempfile
@@ -32,10 +33,193 @@ def main() -> None:
3233
"""Run the migration steps."""
3334
# Add a separation line like this one after each migration step.
3435
print("=" * 72)
36+
print("Migrating workflows to use ubuntu-slim runner for lightweight jobs...")
37+
migrate_to_ubuntu_slim()
38+
print("=" * 72)
3539
print("Migration script finished. Remember to follow any manual instructions.")
3640
print("=" * 72)
3741

3842

43+
def migrate_to_ubuntu_slim() -> None:
44+
"""Migrate workflow files to use ubuntu-slim runner for lightweight jobs.
45+
46+
This updates several workflow files to use the new cost-effective ubuntu-slim
47+
runner for jobs that are lightweight (e.g., labeling, release notes checks,
48+
simple API calls).
49+
"""
50+
workflows_dir = Path(".github") / "workflows"
51+
project_type = read_project_type()
52+
include_protolint = project_type == "api"
53+
if project_type is None:
54+
include_protolint = True
55+
manual_step(
56+
"Unable to detect the cookiecutter project type from "
57+
".cookiecutter-replay.json; protolint migrations will run anyway. "
58+
"Please verify any protolint jobs and keep them only if this is an api "
59+
"project."
60+
)
61+
62+
migrations = {
63+
"ci.yaml": [
64+
{
65+
"job": "nox-all",
66+
"old": (
67+
" if: always() && needs.nox.result != 'skipped'\n"
68+
" runs-on: ubuntu-24.04"
69+
),
70+
"new": (
71+
" if: always() && needs.nox.result != 'skipped'\n"
72+
" runs-on: ubuntu-slim"
73+
),
74+
},
75+
{
76+
"job": "test-installation-all",
77+
"old": (
78+
" if: always() && needs.test-installation.result != 'skipped'\n"
79+
" runs-on: ubuntu-24.04"
80+
),
81+
"new": (
82+
" if: always() && needs.test-installation.result != 'skipped'\n"
83+
" runs-on: ubuntu-slim"
84+
),
85+
},
86+
{
87+
"job": "create-github-release",
88+
"old": " discussions: write\n runs-on: ubuntu-24.04",
89+
"new": " discussions: write\n runs-on: ubuntu-slim",
90+
},
91+
{
92+
"job": "publish-to-pypi",
93+
"old": ' needs: ["create-github-release"]\n runs-on: ubuntu-24.04',
94+
"new": ' needs: ["create-github-release"]\n runs-on: ubuntu-slim',
95+
},
96+
],
97+
"auto-dependabot.yaml": [
98+
{
99+
"job": "auto-merge",
100+
"old": (
101+
" auto-merge:\n"
102+
" if: github.actor == 'dependabot[bot]'\n"
103+
" runs-on: ubuntu-latest"
104+
),
105+
"new": (
106+
" auto-merge:\n"
107+
" if: github.actor == 'dependabot[bot]'\n"
108+
" runs-on: ubuntu-slim"
109+
),
110+
}
111+
],
112+
"release-notes-check.yml": [
113+
{
114+
"job": "check-release-notes",
115+
"old": (
116+
" check-release-notes:\n"
117+
" name: Check release notes are updated\n"
118+
" runs-on: ubuntu-latest"
119+
),
120+
"new": (
121+
" check-release-notes:\n"
122+
" name: Check release notes are updated\n"
123+
" runs-on: ubuntu-slim"
124+
),
125+
}
126+
],
127+
"dco-merge-queue.yml": [
128+
{
129+
"job": "DCO",
130+
"old": "jobs:\n DCO:\n runs-on: ubuntu-latest",
131+
"new": "jobs:\n DCO:\n runs-on: ubuntu-slim",
132+
}
133+
],
134+
"labeler.yml": [
135+
{
136+
"job": "Label",
137+
"old": (
138+
" Label:\n"
139+
" permissions:\n"
140+
" contents: read\n"
141+
" pull-requests: write\n"
142+
" runs-on: ubuntu-latest"
143+
),
144+
"new": (
145+
" Label:\n"
146+
" permissions:\n"
147+
" contents: read\n"
148+
" pull-requests: write\n"
149+
" runs-on: ubuntu-slim"
150+
),
151+
}
152+
],
153+
}
154+
if include_protolint:
155+
protolint_rule = {
156+
"job": "protolint",
157+
"old": (
158+
" protolint:\n"
159+
" name: Check proto files with protolint\n"
160+
" runs-on: ubuntu-24.04"
161+
),
162+
"new": (
163+
" protolint:\n"
164+
" name: Check proto files with protolint\n"
165+
" runs-on: ubuntu-slim"
166+
),
167+
}
168+
migrations.setdefault("ci-pr.yaml", []).append(protolint_rule)
169+
migrations.setdefault("ci.yaml", []).append(protolint_rule)
170+
171+
for filename, rules in migrations.items():
172+
filepath = workflows_dir / filename
173+
if not filepath.exists():
174+
print(f" Skipping {filepath} (file not found)")
175+
continue
176+
177+
for rule in rules:
178+
job = rule["job"]
179+
old = rule["old"]
180+
new = rule["new"]
181+
try:
182+
content = filepath.read_text(encoding="utf-8")
183+
except FileNotFoundError:
184+
continue
185+
186+
if old in content:
187+
replace_file_contents_atomically(filepath, old, new)
188+
print(f" Updated {filepath}: migrated job {job} to ubuntu-slim")
189+
continue
190+
191+
if new in content:
192+
print(f" Skipped {filepath}: already uses ubuntu-slim for job {job}")
193+
continue
194+
195+
manual_step(
196+
f" Pattern not found in {filepath}: please switch job {job} to use "
197+
"`runs-on: ubuntu-slim` where appropriate."
198+
)
199+
200+
201+
def read_project_type() -> str | None:
202+
"""Read the cookiecutter project type from the replay file."""
203+
replay_path = Path(".cookiecutter-replay.json")
204+
if not replay_path.exists():
205+
return None
206+
207+
try:
208+
data = json.loads(replay_path.read_text(encoding="utf-8"))
209+
except (json.JSONDecodeError, OSError):
210+
return None
211+
212+
cookiecutter_data = data.get("cookiecutter")
213+
if not isinstance(cookiecutter_data, dict):
214+
return None
215+
216+
project_type = cookiecutter_data.get("type")
217+
if not isinstance(project_type, str):
218+
return None
219+
220+
return project_type
221+
222+
39223
def apply_patch(patch_content: str) -> None:
40224
"""Apply a patch using the patch utility."""
41225
subprocess.run(["patch", "-p1"], input=patch_content.encode(), check=True)

cookiecutter/{{cookiecutter.github_repo_name}}/.github/workflows/auto-dependabot.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ permissions:
1010
jobs:
1111
auto-merge:
1212
if: github.actor == 'dependabot[bot]'
13-
runs-on: ubuntu-latest
13+
runs-on: ubuntu-slim
1414
steps:
1515
- name: Auto-merge Dependabot PR
1616
uses: frequenz-floss/dependabot-auto-approve@3cad5f42e79296505473325ac6636be897c8b8a1 # v1.3.2

cookiecutter/{{cookiecutter.github_repo_name}}/.github/workflows/ci-pr.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
{% endraw %}{% if cookiecutter.type == "api" %}{% raw -%}
1616
protolint:
1717
name: Check proto files with protolint
18-
runs-on: ubuntu-24.04
18+
runs-on: ubuntu-slim
1919

2020
steps:
2121
- name: Setup Git

cookiecutter/{{cookiecutter.github_repo_name}}/.github/workflows/ci.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
{% endraw %}{% if cookiecutter.type == "api" %}{% raw -%}
2828
protolint:
2929
name: Check proto files with protolint
30-
runs-on: ubuntu-24.04
30+
runs-on: ubuntu-slim
3131

3232
steps:
3333
- name: Setup Git
@@ -96,7 +96,7 @@ jobs:
9696
needs: ["nox"]
9797
# We skip this job only if nox was also skipped
9898
if: always() && needs.nox.result != 'skipped'
99-
runs-on: ubuntu-24.04
99+
runs-on: ubuntu-slim
100100
env:
101101
DEPS_RESULT: ${{ needs.nox.result }}
102102
steps:
@@ -205,7 +205,7 @@ jobs:
205205
needs: ["test-installation"]
206206
# We skip this job only if test-installation was also skipped
207207
if: always() && needs.test-installation.result != 'skipped'
208-
runs-on: ubuntu-24.04
208+
runs-on: ubuntu-slim
209209
env:
210210
DEPS_RESULT: ${{ needs.test-installation.result }}
211211
steps:
@@ -328,7 +328,7 @@ jobs:
328328
# discussions to create the release announcement in the discussion forums
329329
contents: write
330330
discussions: write
331-
runs-on: ubuntu-24.04
331+
runs-on: ubuntu-slim
332332
steps:
333333
- name: Download distribution files
334334
uses: actions/download-artifact@v4
@@ -370,7 +370,7 @@ jobs:
370370
publish-to-pypi:
371371
name: Publish packages to PyPI
372372
needs: ["create-github-release"]
373-
runs-on: ubuntu-24.04
373+
runs-on: ubuntu-slim
374374
permissions:
375375
# For trusted publishing. See:
376376
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/

cookiecutter/{{cookiecutter.github_repo_name}}/.github/workflows/dco-merge-queue.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
jobs:
88
DCO:
9-
runs-on: ubuntu-latest
9+
runs-on: ubuntu-slim
1010
if: ${{ github.actor != 'dependabot[bot]' }}
1111
steps:
1212
- run: echo "This DCO job runs on merge_queue event and doesn't check PR contents"

cookiecutter/{{cookiecutter.github_repo_name}}/.github/workflows/labeler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
permissions:
99
contents: read
1010
pull-requests: write
11-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-slim
1212
steps:
1313
- name: Labeler
1414
# XXX: !!! SECURITY WARNING !!!

cookiecutter/{{cookiecutter.github_repo_name}}/.github/workflows/release-notes-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
jobs:
1717
check-release-notes:
1818
name: Check release notes are updated
19-
runs-on: ubuntu-latest
19+
runs-on: ubuntu-slim
2020
permissions:
2121
pull-requests: read
2222
steps:

tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/.github/workflows/auto-dependabot.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ permissions:
1010
jobs:
1111
auto-merge:
1212
if: github.actor == 'dependabot[bot]'
13-
runs-on: ubuntu-latest
13+
runs-on: ubuntu-slim
1414
steps:
1515
- name: Auto-merge Dependabot PR
1616
uses: frequenz-floss/dependabot-auto-approve@3cad5f42e79296505473325ac6636be897c8b8a1 # v1.3.2

tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/.github/workflows/ci.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
needs: ["nox"]
6464
# We skip this job only if nox was also skipped
6565
if: always() && needs.nox.result != 'skipped'
66-
runs-on: ubuntu-24.04
66+
runs-on: ubuntu-slim
6767
env:
6868
DEPS_RESULT: ${{ needs.nox.result }}
6969
steps:
@@ -172,7 +172,7 @@ jobs:
172172
needs: ["test-installation"]
173173
# We skip this job only if test-installation was also skipped
174174
if: always() && needs.test-installation.result != 'skipped'
175-
runs-on: ubuntu-24.04
175+
runs-on: ubuntu-slim
176176
env:
177177
DEPS_RESULT: ${{ needs.test-installation.result }}
178178
steps:
@@ -295,7 +295,7 @@ jobs:
295295
# discussions to create the release announcement in the discussion forums
296296
contents: write
297297
discussions: write
298-
runs-on: ubuntu-24.04
298+
runs-on: ubuntu-slim
299299
steps:
300300
- name: Download distribution files
301301
uses: actions/download-artifact@v4
@@ -337,7 +337,7 @@ jobs:
337337
publish-to-pypi:
338338
name: Publish packages to PyPI
339339
needs: ["create-github-release"]
340-
runs-on: ubuntu-24.04
340+
runs-on: ubuntu-slim
341341
permissions:
342342
# For trusted publishing. See:
343343
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/

0 commit comments

Comments
 (0)