-
Notifications
You must be signed in to change notification settings - Fork 77
146 lines (135 loc) · 5.2 KB
/
Copy pathmain.yml
File metadata and controls
146 lines (135 loc) · 5.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
on: [push, workflow_dispatch]
# Main prefers Mancave (self-hosted) so Dagger cache volumes stay warm.
# GitHub-hosted runs ONLY when Mancave is unavailable — never as a retry
# after a red test suite.
#
# Flow:
# 1. Pick runner — online self-hosted? (optional CI_RUNNER_STATUS_TOKEN)
# 2. Main (Mancave) XOR Main (GitHub) — one path, not failure-failover
# 3. Main — aggregator for the required status check
#
# Availability check needs a PAT that can list repo runners (GITHUB_TOKEN
# cannot). Store it as Actions secret CI_RUNNER_STATUS_TOKEN. Without that
# secret we assume Mancave is up (same as before) and will not fall back
# when tests fail.
#
# Escape hatch (force hosted, skip Mancave):
# Settings -> Secrets and variables -> Actions -> Variables
# CI_RUNNER = ["ubuntu-latest"]
#
# Only this workflow uses the self-hosted runner. Releasing/deploying stay
# on ubuntu-latest — a release must not depend on one PC being awake.
#
# SECURITY: pull_request / pull_request_target are forced onto hosted
# runners (never Mancave).
name: "Main pipeline: build, lint, test"
jobs:
pick:
name: Pick runner
runs-on: ubuntu-latest
outputs:
host: ${{ steps.pick.outputs.host }}
steps:
- id: pick
env:
GH_TOKEN: ${{ secrets.CI_RUNNER_STATUS_TOKEN }}
FORCE_RUNNER: ${{ vars.CI_RUNNER }}
EVENT_NAME: ${{ github.event_name }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "pull_request" ] || [ "$EVENT_NAME" = "pull_request_target" ]; then
echo "PR event — forcing GitHub-hosted (never run untrusted code on Mancave)"
echo "host=hosted" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "$FORCE_RUNNER" = '["ubuntu-latest"]' ]; then
echo "CI_RUNNER escape hatch — forcing GitHub-hosted"
echo "host=hosted" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ -z "${GH_TOKEN:-}" ]; then
echo "No CI_RUNNER_STATUS_TOKEN — assuming Mancave online"
echo "host=mancave" >> "$GITHUB_OUTPUT"
exit 0
fi
# Any online runner carrying the self-hosted label counts as
# available (busy is fine — the job will wait its turn).
# On API errors (bad/insufficient PAT), prefer Mancave — do NOT
# treat a 403 as "offline" or we skip the warm box forever.
set +e
body=$(gh api "repos/$REPO/actions/runners" 2>/tmp/runner-api.err)
api_status=$?
set -e
if [ "$api_status" -ne 0 ]; then
echo "Runner API failed (is CI_RUNNER_STATUS_TOKEN a fine-grained PAT with Repository Administration: Read?):"
cat /tmp/runner-api.err || true
echo "Assuming Mancave online"
echo "host=mancave" >> "$GITHUB_OUTPUT"
exit 0
fi
if printf '%s' "$body" | jq -e \
'any(.runners[]; .status == "online" and any(.labels[]; .name == "self-hosted"))' \
>/dev/null; then
echo "Self-hosted runner online — using Mancave"
echo "host=mancave" >> "$GITHUB_OUTPUT"
else
echo "No online self-hosted runner — falling back to GitHub-hosted"
echo "host=hosted" >> "$GITHUB_OUTPUT"
fi
mancave:
name: Main (Mancave)
needs: pick
if: needs.pick.outputs.host == 'mancave'
uses: ./.github/workflows/main-ci.yml
# `packages: write` lets the GITHUB_TOKEN push images to GHCR. An explicit
# permissions block replaces the defaults, so `contents: read` (checkout)
# has to come along.
permissions:
contents: read
packages: write
with:
runner: ${{ vars.CI_RUNNER || '["self-hosted", "Linux", "X64"]' }}
artifact-name: build-artifacts-mancave
host-profile: mancave
secrets:
NETLIFY_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
DAGGER_CLOUD_TOKEN: ${{ secrets.DAGGER_CLOUD_TOKEN }}
# Hosted only when pick said Mancave is unavailable (or escape/PR).
# Deliberately does NOT run when Mancave finished with test failures.
github:
name: Main (GitHub)
needs: pick
if: needs.pick.outputs.host == 'hosted'
uses: ./.github/workflows/main-ci.yml
permissions:
contents: read
packages: write
with:
runner: '["ubuntu-latest"]'
artifact-name: build-artifacts-github
host-profile: hosted
secrets:
NETLIFY_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
DAGGER_CLOUD_TOKEN: ${{ secrets.DAGGER_CLOUD_TOKEN }}
Main:
name: Main
needs: [pick, mancave, github]
if: always() && needs.pick.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Resolve runner outcome
run: |
host="${{ needs.pick.outputs.host }}"
m="${{ needs.mancave.result }}"
g="${{ needs.github.result }}"
echo "host=$host mancave=$m github=$g"
if [ "$host" = "mancave" ] && [ "$m" = "success" ]; then
exit 0
fi
if [ "$host" = "hosted" ] && [ "$g" = "success" ]; then
exit 0
fi
exit 1