Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
86fd88c
feat: Allow filtering by platform on workflow call
juanjosevazquezgil Feb 19, 2026
01189e0
fix: Add info log
juanjosevazquezgil Feb 23, 2026
ec97de0
test: Debug logs
juanjosevazquezgil Feb 23, 2026
7da00f0
fix: Removed test logs
juanjosevazquezgil Feb 23, 2026
9caed2b
fix: Tests
juanjosevazquezgil Feb 23, 2026
c4f7d6b
fix: Made it so all platforms are built by default
juanjosevazquezgil Feb 23, 2026
6830720
fix: Support platforms both with and without the linux/ prefix
juanjosevazquezgil Feb 23, 2026
5b32741
fix: Also trim platforms when checking for wildcards
juanjosevazquezgil Feb 24, 2026
41617b3
fix: Add error when no image is built
juanjosevazquezgil Feb 24, 2026
22cfed2
fix: Improved error message
juanjosevazquezgil Feb 24, 2026
0245f6e
fix: Renamed normalized platforms variable
juanjosevazquezgil Feb 24, 2026
4c766ba
fix: Added test for platform filters
juanjosevazquezgil Feb 24, 2026
c433a65
fix: Platform filter test
juanjosevazquezgil Feb 24, 2026
510e7ea
fix: Simplified tests
juanjosevazquezgil Feb 24, 2026
80af883
fix: Validate platforms var
juanjosevazquezgil Feb 24, 2026
c6f791d
Update firestarter/workflows/build_images/build_images.py
juanjosevazquezgil Feb 24, 2026
34b1143
fix: Update validation function to return trimmed platforms
juanjosevazquezgil Feb 24, 2026
ef67359
fix: Improve tests
juanjosevazquezgil Feb 24, 2026
6e4ceaf
fix: join statement
juanjosevazquezgil Feb 24, 2026
4a26bba
fix: Error matching logic
juanjosevazquezgil Feb 24, 2026
2bbff3e
fix: Add runs_on input
juanjosevazquezgil Feb 24, 2026
8e859b0
fix: Made error into warning
juanjosevazquezgil Feb 26, 2026
8ef5aca
fix: Add ::warning:: command to warning log
juanjosevazquezgil Feb 26, 2026
6ee9055
fix: Don't update check run summary or upload artifacts
juanjosevazquezgil Feb 26, 2026
518e8c1
test: info with ::warning::
juanjosevazquezgil Feb 26, 2026
42b8043
fix: Reverted changes
juanjosevazquezgil Feb 26, 2026
23ce2ec
test: Print warning
juanjosevazquezgil Feb 26, 2026
7c9989a
fix: Unset variable
juanjosevazquezgil Feb 26, 2026
ed1ff9b
fix: Restore upload artifact functionality
juanjosevazquezgil Feb 26, 2026
dc14942
fix: Duplicated error message
juanjosevazquezgil Feb 26, 2026
afeaef3
fix: Return trimmed_platforms instead of platforms
juanjosevazquezgil Feb 26, 2026
fa9a2c5
fix: Updated platforms field docs
juanjosevazquezgil Feb 26, 2026
40d4b10
fix: Updated platforms field docs
juanjosevazquezgil Feb 26, 2026
310e329
fix: Reverted changes to platforms docs
juanjosevazquezgil Feb 26, 2026
7faa23f
Update .github/workflows/build_images.yaml
juanjosevazquezgil Feb 26, 2026
457ea1b
fix: Add test for check_if_build_all_platforms function
juanjosevazquezgil Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/build_images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ on:
type: string
description: Flavor name/s | one (alone), several (separated by commas)
default: "*"
platforms:
type: string
description: Platforms to build for, formatted as os/arch (e.g. linux/amd64). Can be a single platform, a comma-separated list, or * for all
default: "*"
secrets:
type: string
description: Secrets to pass to the image
Expand All @@ -34,6 +38,10 @@ on:
type: string
description: Git reference from where to pull the workflows_repo
default: v2
runs_on:
type: string
description: Runner labels to run the job on, formatted as a JSON array (e.g. '["ubuntu-24.04"]' or '["self-hosted", "linux"]')
default: ''
secrets:
FS_CHECKS_PEM_FILE:
required: false
Expand All @@ -55,7 +63,7 @@ jobs:
build-images:
env:
GH_TOKEN: ${{ secrets.GITHUB_DOCKER_REGISTRY_CREDS || github.token }}
runs-on: ${{ fromJSON(vars.BUILD_DOCKER_IMAGES_RUNS_ON || '["ubuntu-24.04"]') }}
runs-on: ${{ fromJSON(inputs.runs_on || '["ubuntu-24.04"]') }}
steps:
- name: Configure Azure Credentials
uses: azure/login@v2
Expand Down Expand Up @@ -115,6 +123,7 @@ jobs:
vars: |
repo_name="${{ github.repository }}"
flavors="${{ inputs.flavors }}"
platforms="${{ inputs.platforms }}"
auth_strategy="${{ inputs.auth_strategy }}"
snapshots_registry="${{ vars.DOCKER_REGISTRY_SNAPSHOTS }}"
releases_registry="${{ vars.DOCKER_REGISTRY_RELEASES }}"
Expand Down
55 changes: 55 additions & 0 deletions firestarter/tests/test_build_images_functionality.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import subprocess
from mock_classes import DaggerContextMock, DaggerImageMock
import os
import re
import docker
import json
import requests
Expand All @@ -25,6 +26,7 @@
"releases_registry": "xxxx.azurecr.io",
"snapshots_registry_creds": "test_snapshots_creds",
"releases_registry_creds": "test_releases_creds",
"platforms": "linux/amd64,linux/arm64",
}
secrets = {}
config_file_path = f"{os.path.dirname(os.path.realpath(__file__))}/fixtures/build_images.yaml"
Expand Down Expand Up @@ -426,6 +428,59 @@ async def test_compile_images_for_all_flavors(mocker) -> None:
assert result[7]["repository"] == "repo3"
assert result[7]["image_tag"] == "flavor3-custom-tag"

@pytest.mark.asyncio
async def test_compile_images_filtering_by_platform(mocker) -> None:
mocker.patch("dagger.Config")
mocker.patch("dagger.Connection")
mocker.patch.object(builder, "compile_image_and_publish")

dagger_config_mock = dagger.Config
dagger_connection_mock = dagger.Connection

builder._flavors = "flavor1, flavor3"
builder._platforms = builder.validate_platforms("linux/amd64")
builder.filter_flavors()

result = await builder.compile_images_for_all_flavors()
built_flavors = set([image["flavor"] for image in result])
assert built_flavors == {"flavor1", "flavor3"}

builder._platforms = builder.validate_platforms("arm64")

result = await builder.compile_images_for_all_flavors()
built_flavors = set([image["flavor"] for image in result])
assert built_flavors == {"flavor3"}

builder._platforms = builder.validate_platforms("*")

result = await builder.compile_images_for_all_flavors()
built_flavors = set([image["flavor"] for image in result])
assert built_flavors == {"flavor1", "flavor3"}

def test_validate_platforms() -> None:
all_valid_platforms = "linux/amd64 , linux/arm64,arm64 , amd64"
returned_platforms = builder.validate_platforms(all_valid_platforms)
assert returned_platforms == all_valid_platforms.replace(" ", "")

some_valid_platforms = " linux/amd64, arm64 "
returned_platforms = builder.validate_platforms(some_valid_platforms)
assert returned_platforms == some_valid_platforms.replace(" ", "")

invalid_platforms = "platform_doesnt_exist, test"
with pytest.raises(ValueError, match=re.escape("Invalid platform(s): platform_doesnt_exist, test.")):
builder.validate_platforms(invalid_platforms)

no_platforms = ",,,,"
with pytest.raises(ValueError, match=re.escape("Invalid platform(s):")):
builder.validate_platforms(no_platforms)

def test_check_if_build_all_platforms():
builder._platforms = '*'
assert builder.check_if_build_all_platforms() == True

builder._platforms = 'linux/amd64'
assert builder.check_if_build_all_platforms() == False

# The object correctly returns the flavor data of a chosen flavor,
# as written in fixtures/build_images.yaml
def test_get_flavor_data() -> None:
Expand Down
68 changes: 66 additions & 2 deletions firestarter/workflows/build_images/build_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def __init__(self, **kwargs) -> None:
self._workflow_run_url = self.vars.get('workflow_run_url', None)
self._service_path = self.vars.get('service_path', '')
self._flavors = self.vars.get('flavors', 'default')
self._platforms = self.validate_platforms(
self.vars.get('platforms', '*')
)
self._container_structure_filename = self.vars.get(
'container_structure_filename', None
)
Expand Down Expand Up @@ -123,6 +126,10 @@ def workflow_run_url(self):
def flavors(self):
return self._flavors

@property
def platforms(self):
return self._platforms

@property
def service_path(self):
return self._service_path
Expand Down Expand Up @@ -251,7 +258,6 @@ def filter_flavors(self):

self._flavors = final_flavors_list


def filter_auto_build(self):
logger.info(
'Publishing all flavors with auto build enabled:',
Expand Down Expand Up @@ -359,6 +365,33 @@ async def compile_images_for_all_flavors(self):
dockerfile, extra_registries,\
extra_tags, platforms = self.get_flavor_data(flavor)

platforms_to_build = []
if self.check_if_build_all_platforms():
platforms_to_build = platforms
else:
allowed_platforms = self.platforms.replace(' ', '').split(',')
normalized_allowed_platforms = {
p.replace('linux/', '') for p in allowed_platforms
}

# Get the platforms to build for this flavor by checking the intersection
platforms_to_build = [
platform for platform in platforms
if platform.replace('linux/', '') in normalized_allowed_platforms
]

logger.info(
f"Building flavor {flavor} for platforms: {platforms_to_build}"
)

if len(platforms_to_build) == 0:
print(
f"::warning title=BuildImages Warning::"
f"No matching platforms to build for flavor {flavor}. "
f"Skipping..."
)
continue

# Set the build arguments for the current flavor
build_args_list = [
dagger.BuildArg(name=key, value=value)
Expand Down Expand Up @@ -424,7 +457,7 @@ async def compile_images_for_all_flavors(self):
secrets,
dockerfile,
image,
platforms
platforms_to_build
)

image_tag = image.split(":")[1]
Expand All @@ -444,12 +477,43 @@ async def compile_images_for_all_flavors(self):
"workflow_run_url": self.workflow_run_url
})

if len(results_list) == 0:
print(
f"::warning title=BuildImages Warning::"
f"No images were built. "
f"Please check the workflow filters are correct."
)

yaml.default_flow_style = False
with open(os.path.join("/tmp", self.output_results), "w") as f:
yaml.dump(results_list, f)

return results_list

def check_if_build_all_platforms(self):
return self.platforms.replace(' ', '') == '*'

Comment on lines +493 to +495
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test for the wildcard platform '' is missing. While test_validate_platforms tests that '' is accepted as valid input, and test_compile_images_filtering_by_platform tests the filtering behavior with '', neither test explicitly verifies that validate_platforms('') returns '' correctly or that check_if_build_all_platforms() returns True when platforms is ''.

Consider adding a specific test case:

def test_check_if_build_all_platforms():
    builder._platforms = '*'
    assert builder.check_if_build_all_platforms() == True
    
    builder._platforms = 'linux/amd64'
    assert builder.check_if_build_all_platforms() == False

This would ensure the wildcard logic is explicitly tested, though the current indirect coverage through the integration test is sufficient for basic functionality.

Copilot uses AI. Check for mistakes.
def validate_platforms(self, platforms):
trimmed_platforms = platforms.replace(' ', '')
if trimmed_platforms == '*':
return trimmed_platforms

platform_list = trimmed_platforms.split(',')

invalid_platforms = []
for platform in platform_list:
if not re.match(r'^(linux/)?(amd64|arm64)$', platform):
invalid_platforms.append(platform)

if invalid_platforms:
raise ValueError(
f"Invalid platform(s): {', '.join(invalid_platforms)}. "
"Valid platforms are: linux/amd64, linux/arm64, amd64, arm64, "
"or '*'. Whitespace around comma-separated entries is ignored."
)

return trimmed_platforms

def get_flavor_data(self, flavor):
flavor_data = self.config.images[flavor]

Expand Down