Created
August 28, 2026 17:51
-
-
Save lassebenni/9753a184333d4688fb4c4d6ac5f280aa to your computer and use it in GitHub Desktop.
Code Explainer: Week 15 data-ci-cd deploy jobs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Code Explainer: data-ci-cd deploy jobs</title> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| background: #0d1117; | |
| display: flex; | |
| justify-content: center; | |
| align-items: flex-start; | |
| min-height: 100vh; | |
| font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| padding: 12px; | |
| color: #c9d1d9; | |
| } | |
| .explainer-container { | |
| width: 100%; | |
| max-width: 860px; | |
| background: #161b22; | |
| border-radius: 10px; | |
| overflow: hidden; | |
| box-shadow: 0 16px 36px rgba(0,0,0,0.6); | |
| border: 1px solid #30363d; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .titlebar { | |
| background: #0d1117; | |
| padding: 10px 16px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| border-bottom: 1px solid #21262d; | |
| user-select: none; | |
| } | |
| .dot { width: 12px; height: 12px; border-radius: 50%; } | |
| .dot.r { background: #ff5f56; } | |
| .dot.y { background: #ffbd2e; } | |
| .dot.g { background: #27c93f; } | |
| .titlebar .title { | |
| color: #8b949e; | |
| font-size: 13px; | |
| flex: 1; | |
| text-align: center; | |
| font-family: 'SF Mono', 'Fira Code', monospace; | |
| font-weight: 500; | |
| } | |
| .code-body { | |
| padding: 14px 0; | |
| font-family: 'SF Mono', 'Fira Code', 'Menlo', monospace; | |
| font-size: 12px; | |
| line-height: 1.55; | |
| overflow-x: auto; | |
| background: #0d1117; | |
| max-height: 380px; | |
| overflow-y: auto; | |
| } | |
| .code-line { | |
| display: flex; | |
| padding: 2px 16px; | |
| cursor: pointer; | |
| border-left: 3px solid transparent; | |
| transition: background 0.15s ease; | |
| } | |
| .code-line.annotated { border-left-color: #1f6feb; background: rgba(31,111,235,0.06); } | |
| .code-line.annotated:hover { background: rgba(31,111,235,0.22); } | |
| .code-line.annotated.active { background: rgba(56,139,253,0.28); border-left-color: #58a6ff; } | |
| .line-num { width: 40px; color: #484f58; text-align: right; padding-right: 16px; flex-shrink: 0; } | |
| .line-content { white-space: pre; flex: 1; } | |
| .file-sep { | |
| padding: 8px 16px; | |
| color: #8b949e; | |
| font-size: 11px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.04em; | |
| border-top: 1px solid #21262d; | |
| border-bottom: 1px solid #21262d; | |
| background: #161b22; | |
| } | |
| .kwd { color: #ff7b72; font-weight: 600; } | |
| .fn { color: #d2a8ff; } | |
| .str { color: #a5d6ff; } | |
| .cmnt { color: #8b949e; font-style: italic; } | |
| .var { color: #ffa657; } | |
| .jja { color: #79c0ff; font-weight: 600; } | |
| .explanation-dock { | |
| background: #161b22; | |
| border-top: 1px solid #30363d; | |
| padding: 16px 20px; | |
| min-height: 120px; | |
| } | |
| .badge { | |
| font-size: 11px; | |
| text-transform: uppercase; | |
| font-weight: 700; | |
| padding: 2px 8px; | |
| border-radius: 12px; | |
| } | |
| .badge.key { background: rgba(255,166,87,0.15); color: #ffa657; border: 1px solid rgba(255,166,87,0.3); } | |
| .badge.delta { background: rgba(56,139,253,0.15); color: #58a6ff; border: 1px solid rgba(56,139,253,0.3); } | |
| .badge.dbt { background: rgba(46,160,67,0.15); color: #3fb950; border: 1px solid rgba(46,160,67,0.3); } | |
| .dock-header { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; } | |
| .dock-title { font-size: 14px; font-weight: 600; color: #f0f6fc; } | |
| .dock-body { font-size: 13px; line-height: 1.5; color: #c9d1d9; } | |
| .hint-text { font-size: 13px; color: #8b949e; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="explainer-container"> | |
| <div class="titlebar"> | |
| <span class="dot r"></span><span class="dot y"></span><span class="dot g"></span> | |
| <span class="title">.github/workflows/data-ci-cd.yaml β merge deploy</span> | |
| </div> | |
| <div class="code-body"> | |
| <div class="file-sep">top-level env (literals β edit once)</div> | |
| <div class="code-line annotated" data-key="literal" onclick="selectLine(this,'literal')" onmouseenter="selectLine(this,'literal')"><span class="line-num">52</span><span class="line-content"> <span class="var">ACA_INGEST_JOB</span>: job-fp-ingest</span></div> | |
| <div class="code-line annotated" data-key="literal" onclick="selectLine(this,'literal')" onmouseenter="selectLine(this,'literal')"><span class="line-num">57</span><span class="line-content"> <span class="var">SOURCE_API_URL</span>: https://www.arbeitnow.com/api/job-board-api</span></div> | |
| <div class="file-sep">deploy-prod (merge to main only)</div> | |
| <div class="code-line annotated" data-key="gate" onclick="selectLine(this,'gate')" onmouseenter="selectLine(this,'gate')"><span class="line-num">268</span><span class="line-content"> <span class="kwd">if</span>: github.ref == <span class="str">'refs/heads/main'</span> && github.event_name != <span class="str">'pull_request'</span></span></div> | |
| <div class="code-line annotated" data-key="image" onclick="selectLine(this,'image')" onmouseenter="selectLine(this,'image')"><span class="line-num">291</span><span class="line-content"> image=<span class="str">"$REGISTRY/pipeline:${{ github.sha }}"</span></span></div> | |
| <div class="code-line annotated" data-key="prod_env" onclick="selectLine(this,'prod_env')" onmouseenter="selectLine(this,'prod_env')"><span class="line-num">300</span><span class="line-content"> env_vars=<span class="str">"SOURCE_API_URL=${{ env.SOURCE_API_URL }} \</span></span></div> | |
| <div class="code-line annotated" data-key="prod_env" onclick="selectLine(this,'prod_env')" onmouseenter="selectLine(this,'prod_env')"><span class="line-num">302</span><span class="line-content"><span class="str"> LANDING_CONTAINER=prod \</span></span></div> | |
| <div class="code-line annotated" data-key="prod_env" onclick="selectLine(this,'prod_env')" onmouseenter="selectLine(this,'prod_env')"><span class="line-num">303</span><span class="line-content"><span class="str"> LANDING_PREFIX=raw \</span></span></div> | |
| <div class="code-line annotated" data-key="update" onclick="selectLine(this,'update')" onmouseenter="selectLine(this,'update')"><span class="line-num">309</span><span class="line-content"> az containerapp job update -g <span class="str">"$RG"</span> -n <span class="str">"$JOB"</span> \</span></div> | |
| <div class="code-line annotated" data-key="update" onclick="selectLine(this,'update')" onmouseenter="selectLine(this,'update')"><span class="line-num">310</span><span class="line-content"> --image <span class="str">"$image"</span> --set-env-vars $env_vars -o none</span></div> | |
| <div class="file-sep">deploy-dev (same SHA, different landing)</div> | |
| <div class="code-line annotated" data-key="dev_job" onclick="selectLine(this,'dev_job')" onmouseenter="selectLine(this,'dev_job')"><span class="line-num">350</span><span class="line-content"> <span class="var">JOB</span>: job-fp-ingest-dev</span></div> | |
| <div class="code-line annotated" data-key="dev_env" onclick="selectLine(this,'dev_env')" onmouseenter="selectLine(this,'dev_env')"><span class="line-num">361</span><span class="line-content"> env_vars=<span class="str">"SOURCE_API_URL=${{ env.SOURCE_API_URL }} \</span></span></div> | |
| <div class="code-line annotated" data-key="dev_env" onclick="selectLine(this,'dev_env')" onmouseenter="selectLine(this,'dev_env')"><span class="line-num">363</span><span class="line-content"><span class="str"> LANDING_CONTAINER=dev \</span></span></div> | |
| <div class="code-line annotated" data-key="dev_env" onclick="selectLine(this,'dev_env')" onmouseenter="selectLine(this,'dev_env')"><span class="line-num">364</span><span class="line-content"><span class="str"> LANDING_PREFIX=aca-dev \</span></span></div> | |
| </div> | |
| <div class="explanation-dock"> | |
| <div class="hint-text" id="hint">π‘ Hover or tap blue lines. Layer 3 owns the image tag and ACA job env β not Airflow Variables.</div> | |
| <div id="dockContent" style="display:none;"> | |
| <div class="dock-header"> | |
| <span class="badge key" id="dockBadge">key</span> | |
| <span class="dock-title" id="dockTitle"></span> | |
| </div> | |
| <div class="dock-body" id="dockBody"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| const explanations = { | |
| literal: { | |
| type: 'key', badge: 'Literals', | |
| title: 'SOURCE_API_URL lives in the workflow file', | |
| body: 'Team Azure IDs and the feed URL are top-level env literals (not GitHub repository Variables). Change the URL once here; both deploy jobs read ${{ env.SOURCE_API_URL }}. A PR can review the swap in one diff.' | |
| }, | |
| gate: { | |
| type: 'delta', badge: 'OIDC gate', | |
| title: 'Deploy only on merge to main', | |
| body: 'Azure trusts tokens minted for refs/heads/main of your repo. A PR cannot update the job β the exchange fails before az runs. Merging is the deploy.' | |
| }, | |
| image: { | |
| type: 'dbt', badge: 'ACR', | |
| title: 'Point the job at pipeline:sha', | |
| body: 'build already pushed pipeline:<commit-sha> (and latest). Deploy always pins the SHA so a bad number traces to exact code. A job on latest was pointed by hand.' | |
| }, | |
| prod_env: { | |
| type: 'key', badge: 'Prod landing', | |
| title: 'job-fp-ingest writes prod/raw', | |
| body: 'Same SOURCE_API_URL as deploy-dev. LANDING_CONTAINER=prod and LANDING_PREFIX=raw are what Mode 4 reads. Edit only these job names β do not invent a third ACA job for a new API.' | |
| }, | |
| update: { | |
| type: 'delta', badge: 'az update', | |
| title: 'Image + env in one call', | |
| body: 'az containerapp job update sets the image and --set-env-vars together. Until this step is green after your URL PR, Mode 2 and Mode 4 still hit the previous feed.' | |
| }, | |
| dev_job: { | |
| type: 'delta', badge: 'Dev job', | |
| title: 'job-fp-ingest-dev is a fixed name', | |
| body: 'Mode 2 and Mode 3 start this job. CI keeps it on the same SHA as prod; only landing differs.' | |
| }, | |
| dev_env: { | |
| type: 'key', badge: 'aca-dev', | |
| title: 'Same URL, shared staging landing', | |
| body: 'LANDING_CONTAINER=dev and LANDING_PREFIX=aca-dev. Same SOURCE_API_URL literal as prod. Your laptop .env never overrides this β only a successful deploy-dev does.' | |
| } | |
| }; | |
| function selectLine(el, key) { | |
| const exp = explanations[key]; | |
| if (!exp) return; | |
| document.querySelectorAll('.code-line').forEach(l => l.classList.remove('active')); | |
| document.querySelectorAll(`.code-line[data-key="${key}"]`).forEach(l => l.classList.add('active')); | |
| document.getElementById('hint').style.display = 'none'; | |
| document.getElementById('dockContent').style.display = 'block'; | |
| document.getElementById('dockBadge').textContent = exp.badge; | |
| document.getElementById('dockBadge').className = 'badge ' + exp.type; | |
| document.getElementById('dockTitle').textContent = exp.title; | |
| document.getElementById('dockBody').textContent = exp.body; | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment