Skip to content
Merged
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
85 changes: 75 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,9 @@ jobs:
- deployment-script-syntax
runs-on: ubuntu-22.04
timeout-minutes: 60
# Keep testing and publishing the same local image. Serialize main jobs
# through the latest push, including reruns, without replacing queued jobs.
concurrency:
group: ci-standalone-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: false
queue: max
outputs:
image-id: ${{ steps.export-image.outputs.image-id }}
artifact-id: ${{ steps.upload-image.outputs.artifact-id }}

steps:
- name: Check out repository
Expand Down Expand Up @@ -290,19 +287,87 @@ jobs:
docker rm -f akernel-traefik akernel-node >/dev/null 2>&1 || true
fi

- name: Log in to Docker Hub
- name: Export tested all-in-one image
id: export-image
if: >-
github.repository == 'inclusionAI/AKernel' &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
shell: bash
run: |
source_image="akernel-ci/all-in-one:${GITHUB_SHA}"
image_id="$(docker image inspect "${source_image}" --format '{{.Id}}')"
echo "image-id=${image_id}" >> "${GITHUB_OUTPUT}"
docker save "${source_image}" | gzip -1 > "${RUNNER_TEMP}/all-in-one.tar.gz"

- name: Upload tested image for publication
id: upload-image
if: >-
github.repository == 'inclusionAI/AKernel' &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tested-all-in-one-${{ github.run_attempt }}
path: ${{ runner.temp }}/all-in-one.tar.gz
if-no-files-found: error
compression-level: 0
retention-days: 1

publish-dockerhub:
name: Publish to Docker Hub
needs: standalone-e2e
if: >-
github.repository == 'inclusionAI/AKernel' &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-22.04
timeout-minutes: 30
concurrency:
# Retain the previous workflow's lock key while older runs finish.
group: ci-standalone-${{ github.ref }}
cancel-in-progress: false
queue: max

steps:
- name: Check whether main still needs this image
id: current-main
env:
GH_TOKEN: ${{ github.token }}
run: |
main_sha="$(gh api "repos/${GITHUB_REPOSITORY}/commits/main" --jq .sha)"
if [[ "${main_sha}" == "${GITHUB_SHA}" ]]; then
echo "publish=true" >> "${GITHUB_OUTPUT}"
else
echo "Skipped latest: main has advanced to ${main_sha}." \
>> "${GITHUB_STEP_SUMMARY}"
fi

- name: Download tested image
if: steps.current-main.outputs.publish == 'true'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.standalone-e2e.outputs.artifact-id }}
path: ${{ runner.temp }}
merge-multiple: true

- name: Load and verify tested image
if: steps.current-main.outputs.publish == 'true'
env:
EXPECTED_IMAGE_ID: ${{ needs.standalone-e2e.outputs.image-id }}
run: |
docker load --input "${RUNNER_TEMP}/all-in-one.tar.gz"
actual_image_id="$(docker image inspect "akernel-ci/all-in-one:${GITHUB_SHA}" \
--format '{{.Id}}')"
test -n "${EXPECTED_IMAGE_ID}"
test "${actual_image_id}" = "${EXPECTED_IMAGE_ID}"

- name: Log in to Docker Hub
if: steps.current-main.outputs.publish == 'true'
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Publish tested all-in-one image
if: >-
github.repository == 'inclusionAI/AKernel' &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
if: steps.current-main.outputs.publish == 'true'
env:
GH_TOKEN: ${{ github.token }}
IMAGE_REPOSITORY: akerneldev/all-in-one
Expand Down
20 changes: 15 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -543,11 +543,21 @@ independent of external package mirrors.
Configure the repository Actions variable `DOCKERHUB_USERNAME` and secret
`DOCKERHUB_TOKEN` with Docker Hub credentials that can push to
`akerneldev/all-in-one`. Keep credentials out of source and logs. Main CI runs
are not canceled by subsequent pushes. The standalone job serializes builds,
tests, and publication using `queue: max` (up to 100 pending jobs), so a slow
or rerun job cannot overwrite a newer published `latest`. Do not remove the
main-head check or the publication lock. A failed check or push leaves the
run failed and can be retried using GitHub Actions' rerun controls.
are not canceled by subsequent pushes. After E2E and teardown succeed on
upstream main, the standalone job exports the tested image as a compressed
Actions artifact retained for one day. The separate `publish-dockerhub` job
downloads that exact artifact by ID, loads it, and verifies its image ID
against the E2E job output before publishing. PRs and forks skip image
transfer and publication. Do not rebuild the image in the publishing job.

The publishing job serializes publication using `queue: max` (up to 100
pending jobs), so a slow or rerun job cannot overwrite a newer published
`latest`. Keep its existing lock key to coordinate with older workflow runs.
Check main before downloading and again immediately before pushing while
holding this lock. Do not remove the main-head check or the publication lock.
A failed check or push leaves the run failed. Rerun the failed publishing job
while the artifact is available; after it expires, rerun all jobs to rebuild
and retest the image.

Python SDK releases use stable `vX.Y.Z` tags or release-candidate
`vX.Y.ZrcN` tags. The tag version must match the version in
Expand Down