main
yml 257 lines 8.9 KB
Raw
1 name: Build And Publish Docker Images
2
3 on:
4 push:
5 branches:
6 - "testing"
7 - "ready"
8 - "main"
9 tags:
10 - "v*"
11 workflow_dispatch:
12 inputs:
13 tag:
14 description: "Optional release tag to rebuild, for example v1.21"
15 required: false
16 type: string
17
18 env:
19 # Non-main branches publish a Docker tag with the same name as the branch.
20 ALLOWED_BRANCHES: "testing ready main"
21 MAIN_BRANCH: "main"
22 RELEASE_TAG_REGEX: "^v([0-9]+)\\.([0-9]+)$"
23 MIN_RELEASE_MAJOR: "1"
24 MIN_RELEASE_MINOR: "0"
25 DOCKERFILE_DIR: "docker/run"
26 DOCKERFILE_PATH: "docker/run/Dockerfile"
27 DOCKER_IMAGE_NAME: "agent-zero"
28 DOCKER_PLATFORMS: "linux/amd64,linux/arm64"
29
30 permissions:
31 contents: read
32
33 jobs:
34 plan:
35 if: github.repository == 'agent0ai/agent-zero'
36 runs-on: ubuntu-latest
37 outputs:
38 has_work: ${{ steps.plan.outputs.has_work }}
39 matrix: ${{ steps.plan.outputs.matrix }}
40 steps:
41 - name: Validate Docker Hub secrets
42 env:
43 DOCKERHUB_ORG: ${{ secrets.DOCKERHUB_ORG }}
44 DOCKERHUB_OAT_TOKEN: ${{ secrets.DOCKERHUB_OAT_TOKEN }}
45 run: |
46 if [[ -z "$DOCKERHUB_ORG" || -z "$DOCKERHUB_OAT_TOKEN" ]]; then
47 echo "::error::Missing DOCKERHUB_ORG or DOCKERHUB_OAT_TOKEN secret."
48 exit 1
49 fi
50
51 - name: Check out repository
52 uses: actions/checkout@v4
53 with:
54 fetch-depth: 0
55
56 - name: Fetch remote branches and tags
57 run: git fetch --force --tags origin '+refs/heads/*:refs/remotes/origin/*'
58
59 - name: Set up Docker Buildx
60 uses: docker/setup-buildx-action@v3
61
62 - name: Log in to Docker Hub
63 uses: docker/login-action@v3
64 with:
65 username: ${{ secrets.DOCKERHUB_ORG }}
66 password: ${{ secrets.DOCKERHUB_OAT_TOKEN }}
67
68 - name: Plan Docker publish targets
69 id: plan
70 env:
71 EVENT_NAME: ${{ github.event_name }}
72 SOURCE_REF_NAME: ${{ github.ref_name }}
73 SOURCE_REF_TYPE: ${{ github.ref_type }}
74 BEFORE_SHA: ${{ github.event_name == 'push' && github.event.before || '' }}
75 AFTER_SHA: ${{ github.event_name == 'push' && github.sha || '' }}
76 MANUAL_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}
77 DOCKER_IMAGE_REPO: ${{ format('{0}/{1}', secrets.DOCKERHUB_ORG, env.DOCKER_IMAGE_NAME) }}
78 run: python3 .github/scripts/docker_release_plan.py plan
79
80 build:
81 if: needs.plan.outputs.has_work == 'true'
82 needs: plan
83 runs-on: ubuntu-latest
84 permissions:
85 contents: write
86 strategy:
87 fail-fast: false
88 matrix: ${{ fromJson(needs.plan.outputs.matrix) }}
89 concurrency:
90 group: docker-publish-${{ github.repository }}-${{ matrix.branch }}
91 cancel-in-progress: false
92 steps:
93 - name: Check out repository
94 uses: actions/checkout@v4
95 with:
96 fetch-depth: 0
97
98 - name: Fetch remote branches and tags
99 run: git fetch --force --tags origin '+refs/heads/*:refs/remotes/origin/*'
100
101 - name: Validate Docker Hub secrets
102 env:
103 DOCKERHUB_ORG: ${{ secrets.DOCKERHUB_ORG }}
104 DOCKERHUB_OAT_TOKEN: ${{ secrets.DOCKERHUB_OAT_TOKEN }}
105 run: |
106 if [[ -z "$DOCKERHUB_ORG" || -z "$DOCKERHUB_OAT_TOKEN" ]]; then
107 echo "::error::Missing DOCKERHUB_ORG or DOCKERHUB_OAT_TOKEN secret."
108 exit 1
109 fi
110
111 - name: Free runner disk space
112 run: |
113 echo "Disk before cleanup:"
114 df -h /
115 docker system df || true
116
117 sudo rm -rf \
118 /opt/az \
119 /opt/ghc \
120 /opt/hostedtoolcache/CodeQL \
121 /usr/local/.ghcup \
122 /usr/local/lib/android \
123 /usr/local/share/boost \
124 /usr/share/dotnet
125 sudo apt-get clean
126 docker system prune -af --volumes || true
127
128 echo "Disk after cleanup:"
129 df -h /
130 docker system df || true
131
132 - name: Set up QEMU
133 uses: docker/setup-qemu-action@v3
134
135 - name: Set up Docker Buildx
136 uses: docker/setup-buildx-action@v3
137
138 - name: Log in to Docker Hub
139 uses: docker/login-action@v3
140 with:
141 username: ${{ secrets.DOCKERHUB_ORG }}
142 password: ${{ secrets.DOCKERHUB_OAT_TOKEN }}
143
144 - name: Re-resolve Docker tags for this build
145 id: resolve
146 env:
147 EVENT_NAME: ${{ github.event_name }}
148 SOURCE_REF_NAME: ${{ github.ref_name }}
149 SOURCE_REF_TYPE: ${{ github.ref_type }}
150 BEFORE_SHA: ${{ github.event_name == 'push' && github.event.before || '' }}
151 AFTER_SHA: ${{ github.event_name == 'push' && github.sha || '' }}
152 MANUAL_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}
153 DOCKER_IMAGE_REPO: ${{ format('{0}/{1}', secrets.DOCKERHUB_ORG, env.DOCKER_IMAGE_NAME) }}
154 TARGET_BRANCH: ${{ matrix.branch }}
155 TARGET_TAG: ${{ matrix.source_tag }}
156 TARGET_MODE: ${{ matrix.mode }}
157 TARGET_PUBLISH_VERSION: ${{ matrix.publish_version }}
158 TARGET_PUBLISH_BRANCH_TAG: ${{ matrix.publish_branch_tag }}
159 run: python3 .github/scripts/docker_release_plan.py resolve-build
160
161 - name: Skip when target is no longer eligible
162 if: steps.resolve.outputs.should_build != 'true'
163 run: echo "${{ steps.resolve.outputs.skip_reason }}"
164
165 - name: Set cache date
166 if: steps.resolve.outputs.should_build == 'true'
167 id: cache_date
168 run: echo "value=$(date -u +%Y-%m-%d:%H:%M:%S)" >> "$GITHUB_OUTPUT"
169
170 - name: Build and push Docker image
171 if: steps.resolve.outputs.should_build == 'true'
172 uses: docker/build-push-action@v6
173 with:
174 context: ${{ env.DOCKERFILE_DIR }}
175 file: ${{ env.DOCKERFILE_PATH }}
176 platforms: ${{ env.DOCKER_PLATFORMS }}
177 push: true
178 tags: ${{ steps.resolve.outputs.tags }}
179 build-args: |
180 BRANCH=${{ matrix.branch }}
181 CACHE_DATE=${{ steps.cache_date.outputs.value }}
182
183 - name: Resolve GitHub release target
184 if: steps.resolve.outputs.should_build == 'true'
185 id: release_plan
186 env:
187 EVENT_NAME: ${{ github.event_name }}
188 SOURCE_REF_NAME: ${{ github.ref_name }}
189 SOURCE_REF_TYPE: ${{ github.ref_type }}
190 BEFORE_SHA: ${{ github.event_name == 'push' && github.event.before || '' }}
191 AFTER_SHA: ${{ github.event_name == 'push' && github.sha || '' }}
192 MANUAL_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}
193 DOCKER_IMAGE_REPO: ${{ format('{0}/{1}', secrets.DOCKERHUB_ORG, env.DOCKER_IMAGE_NAME) }}
194 TARGET_BRANCH: ${{ matrix.branch }}
195 TARGET_TAG: ${{ matrix.source_tag }}
196 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
197 OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
198 OPENROUTER_MODEL_NAME: ${{ vars.OPENROUTER_MODEL_NAME }}
199 run: python3 .github/scripts/docker_release_plan.py resolve-release
200
201 - name: Skip GitHub release
202 if: steps.resolve.outputs.should_build == 'true' && steps.release_plan.outputs.should_release != 'true'
203 run: echo "${{ steps.release_plan.outputs.skip_reason }}"
204
205 - name: Create or update GitHub release
206 if: steps.resolve.outputs.should_build == 'true' && steps.release_plan.outputs.should_release == 'true'
207 uses: actions/github-script@v7
208 env:
209 RELEASE_TAG: ${{ steps.release_plan.outputs.release_tag }}
210 RELEASE_NAME: ${{ steps.release_plan.outputs.release_name }}
211 RELEASE_BODY: ${{ steps.release_plan.outputs.release_body }}
212 with:
213 script: |
214 const owner = context.repo.owner;
215 const repo = context.repo.repo;
216 const tag = process.env.RELEASE_TAG;
217 const name = process.env.RELEASE_NAME;
218 const body = process.env.RELEASE_BODY;
219
220 try {
221 const existing = await github.rest.repos.getReleaseByTag({
222 owner,
223 repo,
224 tag,
225 });
226
227 await github.rest.repos.updateRelease({
228 owner,
229 repo,
230 release_id: existing.data.id,
231 tag_name: tag,
232 name,
233 body,
234 draft: false,
235 prerelease: false,
236 make_latest: "true",
237 });
238
239 core.info(`Updated release ${tag}`);
240 } catch (error) {
241 if (error.status !== 404) {
242 throw error;
243 }
244
245 await github.rest.repos.createRelease({
246 owner,
247 repo,
248 tag_name: tag,
249 name,
250 body,
251 draft: false,
252 prerelease: false,
253 make_latest: "true",
254 });
255
256 core.info(`Created release ${tag}`);
257 }