|
11 | 11 | - completed |
12 | 12 | workflow_dispatch: {} |
13 | 13 |
|
14 | | -env: |
15 | | - ADDON_SLUG: hass-addon-sunsynk-multi |
16 | | - ADDON_SLUG_EDGE: hass-addon-sunsynk-edge |
17 | | - PYTHON_PKG_NAME: sunsynk |
18 | | - REGISTRY_IMAGE: ghcr.io/${{ github.repository_owner }}/hass-addon-sunsynk-multi |
19 | | - |
20 | 14 | jobs: |
21 | | - information: |
22 | | - name: Gather add-on information |
23 | | - if: |
24 | | - github.event_name != 'workflow_run' || |
25 | | - github.event.workflow_run.conclusion != 'failure' |
26 | | - runs-on: ubuntu-latest |
27 | | - outputs: |
28 | | - architectures: ${{ steps.information.outputs.architectures }} |
29 | | - build: ${{ steps.information.outputs.build }} |
30 | | - description: ${{ steps.information.outputs.description }} |
31 | | - environment: ${{ steps.release.outputs.environment }} |
32 | | - name: ${{ steps.information.outputs.name }} |
33 | | - slug: ${{ steps.information.outputs.slug }} |
34 | | - target: ${{ steps.information.outputs.target }} |
35 | | - version: ${{ steps.release.outputs.version }} |
36 | | - steps: |
37 | | - - name: ⤵️ Check out code from GitHub |
38 | | - uses: actions/checkout@v5 |
39 | | - - name: 🚀 Run add-on information |
40 | | - id: information |
41 | | - uses: frenck/action-addon-information@v1.4 |
42 | | - with: |
43 | | - path: ./${{ env.ADDON_SLUG }} |
44 | | - - name: ℹ️ Gather version and environment |
45 | | - id: release |
46 | | - run: | |
47 | | - sha="${{ github.sha }}" |
48 | | -
|
49 | | - # Default values |
50 | | - environment="edge" |
51 | | - version="${sha:0:7}" |
52 | | -
|
53 | | - # Check if it's a release event |
54 | | - if [[ "${{ github.event_name }}" == "release" ]]; then |
55 | | - version="${{ github.event.release.tag_name }}" # Lowercase the tag name |
56 | | - version="${version#v}" # Remove 'v' prefix if present |
57 | | -
|
58 | | - environment="stable" |
59 | | -
|
60 | | - # Set environment to beta if it's a prerelease |
61 | | - if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then |
62 | | - environment="beta" |
63 | | - fi |
64 | | - fi |
65 | | -
|
66 | | - # Output the environment and version |
67 | | - echo "environment=${environment}" >> "$GITHUB_OUTPUT" |
68 | | - echo "version=${version}" >> "$GITHUB_OUTPUT" |
69 | | -
|
70 | | - # Log the outputs |
71 | | - cat "$GITHUB_OUTPUT" >> $GITHUB_STEP_SUMMARY |
72 | | -
|
73 | | - build: |
74 | | - name: 👷 Build & Deploy ${{ matrix.platform }} ${{ needs.information.outputs.environment }}/${{ needs.information.outputs.version }} |
75 | | - runs-on: ubuntu-latest |
76 | | - needs: [information] |
77 | | - strategy: |
78 | | - fail-fast: false |
79 | | - matrix: |
80 | | - platform: |
81 | | - - linux/amd64 |
82 | | - - linux/arm/v6 |
83 | | - - linux/arm/v7 |
84 | | - - linux/arm64 |
85 | | - steps: |
86 | | - - name: ⤵️ Check out code from GitHub |
87 | | - uses: actions/checkout@v5 |
88 | | - |
89 | | - - name: Prepare Files for Build |
90 | | - run: | |
91 | | - mkdir -p ${{ env.ADDON_SLUG }}/${{ env.PYTHON_PKG_NAME }} |
92 | | - cp -r src ${{ env.ADDON_SLUG }}/${{ env.PYTHON_PKG_NAME }}/ |
93 | | - cp pyproject.toml MANIFEST.in LICENSE README.md uv.lock ${{ env.ADDON_SLUG }}/${{ env.PYTHON_PKG_NAME }}/ |
94 | | -
|
95 | | - - name: Set up the correct base image based on platform |
96 | | - run: | |
97 | | - case "${{ matrix.platform }}" in |
98 | | - linux/amd64) echo "BUILD_FROM=ghcr.io/home-assistant/amd64-base-python:3.12-alpine3.21" >> $GITHUB_ENV ;; |
99 | | - linux/arm/v6) echo "BUILD_FROM=ghcr.io/home-assistant/armhf-base-python:3.12-alpine3.21" >> $GITHUB_ENV ;; |
100 | | - linux/arm/v7) echo "BUILD_FROM=ghcr.io/home-assistant/armv7-base-python:3.12-alpine3.21" >> $GITHUB_ENV ;; |
101 | | - linux/arm64) echo "BUILD_FROM=ghcr.io/home-assistant/aarch64-base-python:3.12-alpine3.21" >> $GITHUB_ENV ;; |
102 | | - linux/i386) echo "BUILD_FROM=ghcr.io/home-assistant/i386-base-python:3.12-alpine3.21" >> $GITHUB_ENV ;; |
103 | | - esac |
104 | | -
|
105 | | - - name: Docker meta |
106 | | - id: meta |
107 | | - uses: docker/metadata-action@v5 |
108 | | - with: |
109 | | - images: ${{ env.REGISTRY_IMAGE }} |
110 | | - |
111 | | - - name: Set up QEMU |
112 | | - uses: docker/setup-qemu-action@v3 |
113 | | - |
114 | | - - name: Set up Docker Buildx |
115 | | - uses: docker/setup-buildx-action@v3 |
116 | | - |
117 | | - - name: Cache Docker layers |
118 | | - uses: actions/cache@v4 |
119 | | - with: |
120 | | - path: /tmp/.buildx-cache # Cache path |
121 | | - key: ${{ runner.os }}-buildx-${{ github.sha }} # Unique key for cache |
122 | | - restore-keys: | |
123 | | - ${{ runner.os }}-buildx- |
124 | | -
|
125 | | - - name: Login to GitHub Container Registry |
126 | | - uses: docker/login-action@v3 |
127 | | - with: |
128 | | - registry: ghcr.io |
129 | | - username: ${{ github.repository_owner }} |
130 | | - password: ${{ secrets.GITHUB_TOKEN }} |
131 | | - |
132 | | - - name: Prepare sanitized platform name |
133 | | - id: sanitize-platform |
134 | | - run: | |
135 | | - SANITIZED_PLATFORM=$(echo ${{ matrix.platform }} | sed 's/^linux\///; s/\///g') |
136 | | - echo "SANITIZED_PLATFORM=${SANITIZED_PLATFORM}" >> $GITHUB_ENV |
137 | | - echo "Sanitized platform name: ${SANITIZED_PLATFORM}" |
138 | | -
|
139 | | - - name: Build and push by digest |
140 | | - id: build |
141 | | - uses: docker/build-push-action@v6 |
142 | | - with: |
143 | | - context: ./${{ env.ADDON_SLUG }} # Specify the directory containing your Dockerfile |
144 | | - file: ./${{ env.ADDON_SLUG }}/Dockerfile # Specify the Dockerfile path within the context |
145 | | - platforms: ${{ matrix.platform }} |
146 | | - cache-from: type=local,src=/tmp/.buildx-cache # Use cache for build |
147 | | - cache-to: type=local,dest=/tmp/.buildx-cache,mode=max # Save cache |
148 | | - labels: ${{ steps.meta.outputs.labels }} |
149 | | - outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true |
150 | | - build-args: | |
151 | | - BUILD_FROM=${{ env.BUILD_FROM }} |
152 | | -
|
153 | | - - name: Export digest |
154 | | - run: | |
155 | | - mkdir -p /tmp/digests |
156 | | - digest="${{ steps.build.outputs.digest }}" |
157 | | - touch "/tmp/digests/${digest#sha256:}" |
158 | | -
|
159 | | - - name: Upload digest |
160 | | - uses: actions/upload-artifact@v4 |
161 | | - with: |
162 | | - name: digests-${{ env.SANITIZED_PLATFORM }} # Use the sanitized platform name |
163 | | - path: /tmp/digests/* |
164 | | - if-no-files-found: error |
165 | | - retention-days: 1 |
166 | | - |
167 | | - - name: Save platform to file |
168 | | - id: save-platform |
169 | | - run: | |
170 | | - mkdir -p outputs |
171 | | - echo ${{ env.SANITIZED_PLATFORM }} >> outputs/${{ env.SANITIZED_PLATFORM }}.txt |
172 | | -
|
173 | | - - name: Artifact platform file for later |
174 | | - uses: actions/upload-artifact@v4 |
175 | | - with: |
176 | | - name: platform-outputs-${{ env.SANITIZED_PLATFORM }} |
177 | | - path: outputs/*.txt |
178 | | - if-no-files-found: error |
179 | | - retention-days: 1 |
180 | | - |
181 | | - merge: |
182 | | - runs-on: ubuntu-latest |
183 | | - needs: [information, build] |
184 | | - steps: |
185 | | - - name: Download digests |
186 | | - uses: actions/download-artifact@v5 |
187 | | - with: |
188 | | - path: /tmp/digests |
189 | | - pattern: digests-* |
190 | | - merge-multiple: true |
191 | | - |
192 | | - - name: Set up Docker Buildx |
193 | | - uses: docker/setup-buildx-action@v3 |
194 | | - |
195 | | - - name: Docker meta |
196 | | - id: meta |
197 | | - uses: docker/metadata-action@v5 |
198 | | - with: |
199 | | - images: ${{ env.REGISTRY_IMAGE }} |
200 | | - |
201 | | - - name: Login to GitHub Container Registry |
202 | | - uses: docker/login-action@v3 |
203 | | - with: |
204 | | - registry: ghcr.io |
205 | | - username: ${{ github.repository_owner }} |
206 | | - password: ${{ secrets.GITHUB_TOKEN }} |
207 | | - |
208 | | - - name: Download platform outputs |
209 | | - uses: actions/download-artifact@v5 |
210 | | - with: |
211 | | - pattern: platform-outputs-* |
212 | | - path: outputs |
213 | | - merge-multiple: true |
214 | | - |
215 | | - - name: Load outputs to variable |
216 | | - id: platforms_raw |
217 | | - run: | |
218 | | - ls outputs |
219 | | - # Replace newlines with commas, then remove the trailing comma |
220 | | - echo "value=$(cat outputs/*.txt | tr '\n' ',' | sed 's/,$//')" >> "$GITHUB_OUTPUT" |
221 | | -
|
222 | | - - name: Generate tags for multi-platform image |
223 | | - run: | |
224 | | - # Define base tags |
225 | | - TAGS=( |
226 | | - "-t ${{ env.REGISTRY_IMAGE }}:${{ needs.information.outputs.version }}" |
227 | | - "-t ${{ env.REGISTRY_IMAGE }}:${{ needs.information.outputs.environment }}" |
228 | | - ) |
229 | | -
|
230 | | - # Get the list of platforms from the build job output |
231 | | - platforms="${{ steps.platforms_raw.outputs.value }}" |
232 | | -
|
233 | | - # Split the platforms and add platform-specific tags |
234 | | - IFS=',' read -ra PLATFORM_ARRAY <<< "$platforms" |
235 | | - for PLATFORM in "${PLATFORM_ARRAY[@]}"; do |
236 | | - TAGS+=("-t ${{ env.REGISTRY_IMAGE }}/${PLATFORM}:${{ needs.information.outputs.version }}") |
237 | | - TAGS+=("-t ${{ env.REGISTRY_IMAGE }}/${PLATFORM}:${{ needs.information.outputs.environment }}") |
238 | | - done |
239 | | -
|
240 | | - # Join tags into a string |
241 | | - TAGS_STRING=$(printf " %s" "${TAGS[@]}") |
242 | | -
|
243 | | - # Export the tags string to the environment for later use |
244 | | - echo "TAGS_STRING=${TAGS_STRING}" >> $GITHUB_ENV |
245 | | -
|
246 | | - # Log the generated tags for debugging |
247 | | - echo "Generated tags: ${TAGS_STRING}" |
248 | | -
|
249 | | - - name: Create manifest list and push |
250 | | - working-directory: /tmp/digests |
251 | | - run: | |
252 | | - # Function to retry with exponential backoff |
253 | | - function retry_with_backoff() { |
254 | | - local max_attempts=5 |
255 | | - local timeout=10 # Start with 10 seconds |
256 | | - local attempt=1 |
257 | | -
|
258 | | - while true; do |
259 | | - echo "Attempt $attempt of $max_attempts" |
260 | | - if "$@"; then |
261 | | - return 0 |
262 | | - fi |
263 | | -
|
264 | | - if [[ $attempt -ge $max_attempts ]]; then |
265 | | - echo "Failed after $attempt attempts" |
266 | | - return 1 |
267 | | - fi |
268 | | -
|
269 | | - echo "Attempt $attempt failed! Retrying in $timeout seconds..." |
270 | | - sleep $timeout |
271 | | - timeout=$((timeout * 2)) |
272 | | - attempt=$((attempt + 1)) |
273 | | - done |
274 | | - } |
275 | | -
|
276 | | - # Get all digests |
277 | | - digests=($(ls)) |
278 | | - echo "Found digests: ${digests[*]}" |
279 | | -
|
280 | | - # Create base manifest |
281 | | - echo "Creating base manifest..." |
282 | | - retry_with_backoff docker buildx imagetools create \ |
283 | | - -t ${{ env.REGISTRY_IMAGE }}:${{ needs.information.outputs.version }} \ |
284 | | - -t ${{ env.REGISTRY_IMAGE }}:${{ needs.information.outputs.environment }} \ |
285 | | - $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' "${digests[@]}") |
286 | | -
|
287 | | - - name: Inspect image |
288 | | - run: | |
289 | | - # Function to retry with exponential backoff |
290 | | - function retry_with_backoff() { |
291 | | - local max_attempts=5 |
292 | | - local timeout=10 |
293 | | - local attempt=1 |
294 | | -
|
295 | | - while true; do |
296 | | - echo "Attempt $attempt of $max_attempts" |
297 | | - if "$@"; then |
298 | | - return 0 |
299 | | - fi |
300 | | -
|
301 | | - if [[ $attempt -ge $max_attempts ]]; then |
302 | | - echo "Failed after $attempt attempts" |
303 | | - return 1 |
304 | | - fi |
305 | | -
|
306 | | - echo "Attempt $attempt failed! Retrying in $timeout seconds..." |
307 | | - sleep $timeout |
308 | | - timeout=$((timeout * 2)) |
309 | | - attempt=$((attempt + 1)) |
310 | | - done |
311 | | - } |
312 | | -
|
313 | | - echo "Waiting 20 seconds for manifests to settle before starting inspections..." |
314 | | - sleep 20 |
315 | | -
|
316 | | - # Inspect base image |
317 | | - echo "Inspecting base image..." |
318 | | - retry_with_backoff docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ needs.information.outputs.version }} |
319 | | -
|
320 | | - publish_addon: |
321 | | - name: 🆕 Update addon version to ${{ needs.information.outputs.version }} |
322 | | - needs: [information, build, merge] |
323 | | - # branches: [main] - restrict? |
324 | | - permissions: |
325 | | - contents: write |
326 | | - runs-on: ubuntu-latest |
327 | | - steps: |
328 | | - - uses: actions/checkout@v5 |
329 | | - with: |
330 | | - fetch-depth: 0 |
331 | | - ref: main |
332 | | - |
333 | | - - name: Configure Git |
334 | | - run: | |
335 | | - git config --global user.name 'github-actions[bot]' |
336 | | - git config --global user.email 'github-actions[bot]@users.noreply.github.com' |
337 | | -
|
338 | | - - name: Update versions and commit changes |
339 | | - run: | |
340 | | - # Pull latest changes with rebase strategy |
341 | | - git pull --rebase origin main |
342 | | -
|
343 | | - # Make the version updates |
344 | | - sed -i 's/version:.*/version: "${{ needs.information.outputs.version }}"/g' ${{ env.ADDON_SLUG_EDGE }}/config.yaml |
345 | | - if [[ "${{ needs.information.outputs.environment }}" == "stable" ]]; then |
346 | | - sed -i 's/version:.*/version: "${{ needs.information.outputs.version }}"/g' ${{ env.ADDON_SLUG }}/config.yaml |
347 | | - fi |
348 | | -
|
349 | | - # Stage and commit changes |
350 | | - git add ${{ env.ADDON_SLUG_EDGE }}/config.yaml ${{ env.ADDON_SLUG }}/config.yaml |
351 | | - git commit -m "Update addon version to ${{ needs.information.outputs.version }} [no ci]" || echo "No changes to commit" |
352 | | -
|
353 | | - - name: Push changes |
354 | | - run: | |
355 | | - # Try to push changes |
356 | | - for i in {1..3}; do |
357 | | - if git push origin main; then |
358 | | - echo "Successfully pushed changes" |
359 | | - exit 0 |
360 | | - else |
361 | | - echo "Push failed, attempting to rebase and retry..." |
362 | | - git pull --rebase origin main |
363 | | - fi |
364 | | - echo "Waiting 5 seconds before next push attempt..." |
365 | | - sleep 5 |
366 | | - done |
367 | | - echo "Failed to push after 3 attempts" |
368 | | - exit 1 |
| 15 | + deployer: |
| 16 | + uses: kellerza/hass-addons/.github/workflows/deployer.yml@main |
| 17 | + secrets: inherit |
| 18 | + with: |
| 19 | + addon-slug: hass-addon-sunsynk-multi |
| 20 | + addon-slug-edge: hass-addon-sunsynk-edge |
| 21 | + pkg-name: sunsynk |
| 22 | + registry-image: ghcr.io/${{ github.repository_owner }}/hass-addon-sunsynk-multi |
0 commit comments