Skip to content

Commit dcbb6b1

Browse files
committed
feat: gh workflows
1 parent 3e253a2 commit dcbb6b1

File tree

4 files changed

+231
-54
lines changed

4 files changed

+231
-54
lines changed

.github/workflows/e2e.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: e2e-kind
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
kind-e2e:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Cache Helm
19+
uses: actions/cache@v4
20+
with:
21+
path: |
22+
~/.cache/helm
23+
~/.config/helm/repositories.yaml
24+
key: ${{ runner.os }}-helm-${{ hashFiles('scripts/**', 'Makefile') }}
25+
restore-keys: |
26+
${{ runner.os }}-helm-
27+
28+
- name: Setup kubectl
29+
uses: azure/setup-kubectl@v4
30+
with:
31+
version: 'v1.29.4'
32+
33+
- name: Setup Helm
34+
uses: azure/setup-helm@v4
35+
with:
36+
version: 'v3.14.4'
37+
38+
- name: Create kind cluster
39+
uses: helm/[email protected]
40+
with:
41+
cluster_name: crossplane-kind
42+
node_image: kindest/node:v1.29.4
43+
44+
- name: Tools check (sanity)
45+
run: make tools-check
46+
47+
- name: Bootstrap (idempotent)
48+
run: |
49+
scripts/bootstrap-crossplane-kind.sh --yes --skip-cluster --wait-timeout 8m
50+
51+
- name: Verify resources
52+
run: |
53+
kubectl -n crossplane-system get deploy crossplane crossplane-rbac-manager
54+
kubectl get providers.pkg.crossplane.io -o wide
55+
kubectl get functions.pkg.crossplane.io -o wide
56+
57+
- name: Idempotency run
58+
run: |
59+
scripts/bootstrap-crossplane-kind.sh --yes --skip-cluster --wait-timeout 8m
60+
61+
- name: Cleanup (keep cluster)
62+
if: always()
63+
run: |
64+
scripts/bootstrap-crossplane-kind.sh --cleanup || true
65+
kubectl get providerrevisions.pkg.crossplane.io -o wide || true
66+
kubectl get functionrevisions.pkg.crossplane.io -o wide || true
67+
kubectl -n crossplane-system get deploy -o name || true
68+
kubectl -n crossplane-system get pods -o name || true

.github/workflows/lint.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: lint
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
shell-lint:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Install ShellCheck and shfmt
17+
run: |
18+
sudo apt-get update
19+
sudo apt-get install -y shellcheck
20+
curl -sSLo /usr/local/bin/shfmt https://github.com/mvdan/sh/releases/download/v3.7.0/shfmt_v3.7.0_linux_amd64
21+
sudo chmod +x /usr/local/bin/shfmt
22+
23+
- name: Run ShellCheck
24+
run: |
25+
shellcheck -S warning scripts/*.sh || {
26+
echo "ShellCheck issues found"; exit 1; }
27+
28+
- name: Check formatting with shfmt
29+
run: |
30+
shfmt -d -i 2 -ci -s scripts || {
31+
echo "shfmt found formatting differences (run: shfmt -w -i 2 -ci -s scripts)"; exit 1; }

scripts/bootstrap-crossplane-kind.sh

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ SCRIPT_NAME="$(basename "$0")"
3535
log() { echo "[INFO ] $*"; }
3636
warn() { echo "[WARN ] $*" 2>&1; }
3737
err() { echo "[ERROR] $*" 2>&1; }
38-
die() { err "$*"; exit 1; }
38+
die() {
39+
err "$*"
40+
exit 1
41+
}
3942

4043
if [[ ${VERBOSE} == true ]]; then set -x; fi
4144

@@ -50,8 +53,8 @@ wait_pkg_healthy() {
5053
log "[dry-run] would wait for $kind/$name to become Healthy (timeout ${timeout})"
5154
return 0
5255
fi
53-
local end=$((SECONDS + ${timeout%m}*60))
54-
while (( SECONDS < end )); do
56+
local end=$((SECONDS + ${timeout%m} * 60))
57+
while ((SECONDS < end)); do
5558
if kubectl get "$kind" "$name" -o jsonpath='{.status.conditions[?(@.type=="Healthy")].status}' 2>/dev/null | grep -q True; then
5659
return 0
5760
fi
@@ -121,17 +124,18 @@ confirm() {
121124
fi
122125
read -r -p "${prompt_msg} [y/N]: " ans || true
123126
case "${ans}" in
124-
y|Y|yes|YES) return 0 ;;
127+
y | Y | yes | YES) return 0 ;;
125128
*) return 1 ;;
126129
esac
127130
}
128131

129132
require_cmd() {
130-
local cmd="$1"; shift || true
133+
local cmd="$1"
134+
shift || true
131135
local hint="$*"
132136
if ! command -v "${cmd}" >/dev/null 2>&1; then
133137
err "Missing required tool: ${cmd}"
134-
if [[ -n "${hint}" ]]; then warn "Hint: ${hint}"; fi
138+
if [[ -n ${hint} ]]; then warn "Hint: ${hint}"; fi
135139
case "${cmd}" in
136140
kind)
137141
warn "Install kind: https://kind.sigs.k8s.io/docs/user/quick-start/"
@@ -183,25 +187,85 @@ EOF
183187
parse_args() {
184188
while [[ $# -gt 0 ]]; do
185189
case "$1" in
186-
-y|--yes) YES=true; shift ;;
187-
-n|--cluster-name) CLUSTER_NAME="$2"; shift 2 ;;
188-
-k|--kind-node-image) KINDEST_NODE_IMAGE="$2"; shift 2 ;;
189-
--crossplane-version) CROSSPLANE_VERSION="$2"; shift 2 ;;
190-
--provider-azure-version) PROVIDER_AZURE_VERSION="$2"; shift 2 ;;
191-
--func-pat-version) FUNC_PAT_VERSION="$2"; shift 2 ;;
192-
--func-envcfg-version) FUNC_ENVCFG_VERSION="$2"; shift 2 ;;
193-
--wait-timeout) WAIT_TIMEOUT="$2"; shift 2 ;;
194-
--recreate) RECREATE=true; shift ;;
195-
--skip-cluster) SKIP_CLUSTER=true; shift ;;
196-
--cleanup) CLEANUP=true; shift ;;
197-
--delete-cluster) DELETE_CLUSTER=true; shift ;;
198-
--force-clean) FORCE_CLEAN=true; shift ;;
199-
-v|--verbose) VERBOSE=true; set -x; shift ;;
200-
--dry-run) DRY_RUN=true; shift ;;
201-
-h|--help) usage; exit 0 ;;
202-
--) shift; break ;;
203-
-*) err "Unknown flag: $1"; usage; exit 2 ;;
204-
*) err "Unexpected arg: $1"; usage; exit 2 ;;
190+
-y | --yes)
191+
YES=true
192+
shift
193+
;;
194+
-n | --cluster-name)
195+
CLUSTER_NAME="$2"
196+
shift 2
197+
;;
198+
-k | --kind-node-image)
199+
KINDEST_NODE_IMAGE="$2"
200+
shift 2
201+
;;
202+
--crossplane-version)
203+
CROSSPLANE_VERSION="$2"
204+
shift 2
205+
;;
206+
--provider-azure-version)
207+
PROVIDER_AZURE_VERSION="$2"
208+
shift 2
209+
;;
210+
--func-pat-version)
211+
FUNC_PAT_VERSION="$2"
212+
shift 2
213+
;;
214+
--func-envcfg-version)
215+
FUNC_ENVCFG_VERSION="$2"
216+
shift 2
217+
;;
218+
--wait-timeout)
219+
WAIT_TIMEOUT="$2"
220+
shift 2
221+
;;
222+
--recreate)
223+
RECREATE=true
224+
shift
225+
;;
226+
--skip-cluster)
227+
SKIP_CLUSTER=true
228+
shift
229+
;;
230+
--cleanup)
231+
CLEANUP=true
232+
shift
233+
;;
234+
--delete-cluster)
235+
DELETE_CLUSTER=true
236+
shift
237+
;;
238+
--force-clean)
239+
FORCE_CLEAN=true
240+
shift
241+
;;
242+
-v | --verbose)
243+
VERBOSE=true
244+
set -x
245+
shift
246+
;;
247+
--dry-run)
248+
DRY_RUN=true
249+
shift
250+
;;
251+
-h | --help)
252+
usage
253+
exit 0
254+
;;
255+
--)
256+
shift
257+
break
258+
;;
259+
-*)
260+
err "Unknown flag: $1"
261+
usage
262+
exit 2
263+
;;
264+
*)
265+
err "Unexpected arg: $1"
266+
usage
267+
exit 2
268+
;;
205269
esac
206270
done
207271
}
@@ -210,10 +274,10 @@ parse_args() {
210274
# Validations
211275
# ------------------------------
212276
validate_inputs() {
213-
[[ -n "${CLUSTER_NAME}" ]] || die "--cluster-name cannot be empty"
214-
[[ -n "${KINDEST_NODE_IMAGE}" ]] || die "--kind-node-image cannot be empty"
215-
[[ -n "${CROSSPLANE_VERSION}" ]] || die "--crossplane-version cannot be empty"
216-
[[ -n "${WAIT_TIMEOUT}" ]] || die "--wait-timeout cannot be empty"
277+
[[ -n ${CLUSTER_NAME} ]] || die "--cluster-name cannot be empty"
278+
[[ -n ${KINDEST_NODE_IMAGE} ]] || die "--kind-node-image cannot be empty"
279+
[[ -n ${CROSSPLANE_VERSION} ]] || die "--crossplane-version cannot be empty"
280+
[[ -n ${WAIT_TIMEOUT} ]] || die "--wait-timeout cannot be empty"
217281
}
218282

219283
check_tools() {
@@ -275,8 +339,7 @@ install_crossplane() {
275339
# ------------------------------
276340
# Providers and Functions (idempotent)
277341
# ------------------------------
278-
apply_providers_and_functions()
279-
{
342+
apply_providers_and_functions() {
280343
# Provider family - Azure
281344
log "Applying Provider family Azure ${PROVIDER_AZURE_VERSION}"
282345
run kubectl apply -f - <<EOF
@@ -324,9 +387,9 @@ cleanup_resources() {
324387
log "Deleting FunctionRevisions (clear finalizers if needed)"
325388
local frs
326389
frs=$(kubectl get functionrevisions.pkg.crossplane.io -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
327-
if [[ -n "${frs}" ]]; then
390+
if [[ -n ${frs} ]]; then
328391
while read -r fr; do
329-
[[ -z "$fr" ]] && continue
392+
[[ -z $fr ]] && continue
330393
run kubectl patch functionrevision.pkg.crossplane.io "$fr" --type=merge -p '{"metadata":{"finalizers":[]}}' || true
331394
run kubectl delete functionrevision.pkg.crossplane.io "$fr" --wait=false || true
332395
done <<<"$frs"
@@ -344,17 +407,17 @@ cleanup_resources() {
344407
run kubectl -n crossplane-system delete deploy -l pkg.crossplane.io/revision --ignore-not-found || true
345408
# Fallback: prefix-based cleanup; loop until nothing remains (max 60s)
346409
local end=$((SECONDS + 60))
347-
while (( SECONDS < end )); do
410+
while ((SECONDS < end)); do
348411
local dels=0
349412
local dlist
350413
dlist=$(kubectl -n crossplane-system get deploy -o name 2>/dev/null | grep -E "^deployment/(function-|provider-family-azure)" || true)
351-
if [[ -n "$dlist" ]]; then
414+
if [[ -n $dlist ]]; then
352415
run kubectl -n crossplane-system delete $dlist --ignore-not-found || true
353416
dels=1
354417
fi
355418
local plist
356419
plist=$(kubectl -n crossplane-system get pods -o name 2>/dev/null | grep -E "^pod/(function-|provider-family-azure)" || true)
357-
if [[ -n "$plist" ]]; then
420+
if [[ -n $plist ]]; then
358421
run kubectl -n crossplane-system delete $plist --ignore-not-found || true
359422
dels=1
360423
fi
@@ -406,4 +469,3 @@ main() {
406469
}
407470

408471
main "$@"
409-

0 commit comments

Comments
 (0)