Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 28 additions & 24 deletions .github/actions/slack-build-notify/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,32 +54,36 @@ runs:
.filter(r => r.id !== context.runId && r.conclusion !== 'cancelled')
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));

if (previousRuns.length === 0) {
core.info('No previous completed runs found, skipping notification');
return;
}

const previousRun = previousRuns[0];
const currentFailed = currentResult !== 'success';

// Compare against the previous run's CI job conclusion (not the workflow
// conclusion) so that clean-job flaps don't trigger false notifications.
// Falls back to workflow conclusion if the CI job isn't found.
const { data: { jobs: prevJobs } } = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: previousRun.id,
per_page: 100,
});
const prevCiJob = prevJobs.find(j => j.name === 'CI');
const previousConclusion = prevCiJob
? prevCiJob.conclusion
: previousRun.conclusion;
const previousFailed = previousConclusion !== 'success';

if (currentFailed === previousFailed) {
core.info(`No state transition (current: ${currentResult}, previous: ${previousConclusion}), skipping`);
return;
if (previousRuns.length === 0) {
if (!currentFailed) {
core.info('No previous completed runs found and build passed, skipping notification');
return;
}
// No history — notify on failure directly (e.g. merge queue runs on ephemeral refs)
} else {
const previousRun = previousRuns[0];

// Compare against the previous run's CI job conclusion (not the workflow
// conclusion) so that clean-job flaps don't trigger false notifications.
// Falls back to workflow conclusion if the CI job isn't found.
const { data: { jobs: prevJobs } } = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: previousRun.id,
per_page: 100,
});
const prevCiJob = prevJobs.find(j => j.name === 'CI');
const previousConclusion = prevCiJob
? prevCiJob.conclusion
: previousRun.conclusion;
const previousFailed = previousConclusion !== 'success';

if (currentFailed === previousFailed) {
core.info(`No state transition (current: ${currentResult}, previous: ${previousConclusion}), skipping`);
return;
}
}

const runUrl = currentRun.html_url;
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/bakery-build-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ on:
default: "exclude"
required: false
type: string
latest-only:
description: "Build only the latest version of each image (faster PR checks)"
default: false
required: false
type: boolean
retry:
description: "Number of times to retry a failed build"
default: 1
Expand Down Expand Up @@ -102,9 +107,12 @@ jobs:
IS_FORK: ${{ needs.detect.outputs.is-fork }}
DEV_VERSIONS: ${{ inputs.dev-versions }}
MATRIX_VERSIONS: ${{ inputs.matrix-versions }}
LATEST_ONLY: ${{ inputs.latest-only }}
BAKERY_CONTEXT: ${{ inputs.context }}
run: |
FULL_MATRIX=$(bakery ci matrix --quiet --dev-versions "$DEV_VERSIONS" --matrix-versions "$MATRIX_VERSIONS" --context "$BAKERY_CONTEXT" | jq --compact-output .)
LATEST_FLAGS=()
if [ "$LATEST_ONLY" = "true" ]; then LATEST_FLAGS=(--latest); fi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I want to be able to run only the latest version of every image for each PR.

This allows us to enable merge queues in all the repos. Then when ready to merge it runs the full suite without passing --latest.

FULL_MATRIX=$(bakery ci matrix --quiet --dev-versions "$DEV_VERSIONS" --matrix-versions "$MATRIX_VERSIONS" "${LATEST_FLAGS[@]}" --context "$BAKERY_CONTEXT" | jq --compact-output .)
if [ "$IS_FORK" = "true" ]; then
# Skip arm64 for fork PRs — paid runners may not be available
FULL_MATRIX=$(echo "$FULL_MATRIX" | jq --compact-output '[.[] | select(.platform != "linux/arm64")]')
Expand All @@ -116,9 +124,12 @@ jobs:
env:
DEV_VERSIONS: ${{ inputs.dev-versions }}
MATRIX_VERSIONS: ${{ inputs.matrix-versions }}
LATEST_ONLY: ${{ inputs.latest-only }}
BAKERY_CONTEXT: ${{ inputs.context }}
run: |
result=$(bakery ci matrix --quiet --dev-versions "$DEV_VERSIONS" --matrix-versions "$MATRIX_VERSIONS" --exclude platform --context "$BAKERY_CONTEXT")
LATEST_FLAGS=()
if [ "$LATEST_ONLY" = "true" ]; then LATEST_FLAGS=(--latest); fi
result=$(bakery ci matrix --quiet --dev-versions "$DEV_VERSIONS" --matrix-versions "$MATRIX_VERSIONS" "${LATEST_FLAGS[@]}" --exclude platform --context "$BAKERY_CONTEXT")
echo "versions_matrix=$(echo "$result" | jq --compact-output .)" >> "$GITHUB_OUTPUT"

build-test:
Expand Down
10 changes: 10 additions & 0 deletions posit-bakery/posit_bakery/cli/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ def matrix(
rich_help_panel=RichHelpPanelEnum.FILTERS,
),
] = None,
latest: Annotated[
Optional[bool],
typer.Option(
"--latest",
help="Include only the latest version of each image. For matrix images, includes only the highest-version combination.",
rich_help_panel=RichHelpPanelEnum.FILTERS,
),
] = False,
exclude: Annotated[
Optional[list[BakeryCIMatrixFieldEnum]],
typer.Option(help="Fields to exclude splitting the matrix by."),
Expand Down Expand Up @@ -152,6 +160,8 @@ def matrix(
continue
if image_version is not None and not version_matches(ver.name, image_version):
continue
if latest and not ver.latest:
continue

if BakeryCIMatrixFieldEnum.VERSION not in exclude:
entry["version"] = ver.name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"image": "test-image", "version": "2.0.0", "dev": false, "platform": "linux/amd64"}, {"image": "test-image", "version": "1.0.0", "dev": false, "platform": "linux/amd64"}]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"image": "test-image", "version": "2.0.0", "dev": false, "platform": "linux/amd64"}]
16 changes: 16 additions & 0 deletions posit-bakery/test/features/cli/ci/matrix.feature
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,19 @@ Feature: matrix
| --image-version | 9.9.9 |
When I execute the command
Then The command fails

Scenario: Generating a full CI matrix for the multiversion suite
Given I call bakery ci matrix
* in the multiversion context
When I execute the command
Then The command succeeds
* the matrix matches testdata ci/matrix/multiversion/default.json

Scenario: Filtering the CI matrix to latest versions only
Given I call bakery ci matrix
* in the multiversion context
* with the arguments:
| --latest | |
When I execute the command
Then The command succeeds
* the matrix matches testdata ci/matrix/multiversion/latest_only.json
23 changes: 23 additions & 0 deletions posit-bakery/test/resources/multiversion/bakery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
repository:
url: "github.com/posit-dev/images-shared"
vendor: "Posit Software, PBC"
maintainer:
name: "Posit Docker Team"
email: "docker@posit.co"

registries:
- host: "ghcr.io"
namespace: "posit-dev"

images:
- name: "test-image"
versions:
- name: "2.0.0"
latest: true
os:
- name: Ubuntu 22.04
primary: true
- name: "1.0.0"
os:
- name: Ubuntu 22.04
primary: true
Loading