feat: add admin-web Docker build & push workflow with semantic-release #11
41
.github/workflows/admin-web-docker.yml
vendored
41
.github/workflows/admin-web-docker.yml
vendored
@@ -3,6 +3,10 @@ name: Admin Web Docker
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
paths:
|
||||
- 'admin-web/**'
|
||||
- '.github/workflows/admin-web-docker.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
@@ -13,15 +17,46 @@ env:
|
||||
NODE_VERSION: "22"
|
||||
|
||||
jobs:
|
||||
build-validation:
|
||||
name: Docker Build Validation
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
|
||||
- name: Install Docker CLI
|
||||
run: sudo apt-get update -qq && sudo apt-get install -y -qq docker.io
|
||||
|
||||
- name: Build admin-web image (no push)
|
||||
env:
|
||||
NEXT_PUBLIC_SUPABASE_URL: ${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ vars.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
|
||||
run: |
|
||||
set -e
|
||||
docker build \
|
||||
--file admin-web/Dockerfile \
|
||||
--build-arg "NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL}" \
|
||||
--build-arg "NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY}" \
|
||||
--tag "tabatago-admin-web:pr-validation" \
|
||||
admin-web
|
||||
|
||||
semantic-release:
|
||||
name: Semantic Release
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
if: |
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name != 'pull_request' &&
|
||||
(
|
||||
!contains(github.event.head_commit.message, '[skip ci]') &&
|
||||
!contains(github.event.head_commit.message, '[ci skip]')
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(
|
||||
!contains(github.event.head_commit.message, '[skip ci]') &&
|
||||
!contains(github.event.head_commit.message, '[ci skip]')
|
||||
)
|
||||
)
|
||||
outputs:
|
||||
released: ${{ steps.release.outputs.released }}
|
||||
|
||||
@@ -263,9 +263,9 @@ check_workflow_valid() {
|
||||
yaml_valid ".github/workflows/admin-web-docker.yml" "admin-web-docker.yml is valid YAML"
|
||||
}
|
||||
|
||||
# --- workflow: exactly 2 jobs --------------------------------------- #
|
||||
# --- workflow: exactly 3 jobs --------------------------------------- #
|
||||
check_workflow_jobs() {
|
||||
local label="workflow has exactly 2 jobs: semantic-release + build-and-push"
|
||||
local label="workflow has exactly 3 jobs: build-validation + semantic-release + build-and-push"
|
||||
local f=".github/workflows/admin-web-docker.yml"
|
||||
if [[ ! -f "$f" ]]; then
|
||||
fail "$label" "file missing"
|
||||
@@ -281,7 +281,7 @@ print(','.join(sorted(jobs)))
|
||||
fail "$label" "could not parse jobs"
|
||||
return
|
||||
fi
|
||||
if [[ "$out" == "build-and-push,semantic-release" ]]; then
|
||||
if [[ "$out" == "build-and-push,build-validation,semantic-release" ]]; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label" "jobs=[$out]"
|
||||
@@ -495,6 +495,126 @@ check_git_commit_prefix() {
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================== #
|
||||
# PR BUILD-VALIDATION FEATURE CHECKS
|
||||
# (trigger pull_request + job build-validation build-only/no-secret)
|
||||
# =================================================================== #
|
||||
|
||||
# --- workflow: pull_request trigger with admin-web/** path filter --- #
|
||||
check_pr_trigger() {
|
||||
local f=".github/workflows/admin-web-docker.yml"
|
||||
local label="workflow triggers on pull_request with admin-web/** path filter"
|
||||
if [[ ! -f "$f" ]]; then
|
||||
fail "$label" "file missing"
|
||||
return
|
||||
fi
|
||||
local out
|
||||
out=$(python3 -c "
|
||||
import yaml,sys
|
||||
d=yaml.safe_load(open(sys.argv[1]))
|
||||
on=d.get(True) or d.get('on') or {}
|
||||
if not isinstance(on,dict): print('NO-PR: on not a dict'); sys.exit()
|
||||
pr=on.get('pull_request')
|
||||
if pr is None: print('NO-PR: no pull_request key'); sys.exit()
|
||||
paths=(pr.get('paths') if isinstance(pr,dict) else None) or []
|
||||
print('|'.join(str(p) for p in paths))
|
||||
" "$f" 2>/dev/null || echo "ERR")
|
||||
if echo "$out" | grep -Eq 'admin-web/\*\*'; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label" "pull_request.paths=[$out]"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- build-validation job: exists + if: pull_request ---------------- #
|
||||
check_build_validation_if() {
|
||||
local f=".github/workflows/admin-web-docker.yml"
|
||||
local label="build-validation job if: github.event_name == 'pull_request'"
|
||||
if [[ ! -f "$f" ]]; then
|
||||
fail "$label" "file missing"
|
||||
return
|
||||
fi
|
||||
local cond
|
||||
cond=$(python3 -c "
|
||||
import yaml,sys
|
||||
d=yaml.safe_load(open(sys.argv[1]))
|
||||
bv=d.get('jobs',{}).get('build-validation',{})
|
||||
print(bv.get('if','') or '')
|
||||
" "$f" 2>/dev/null || true)
|
||||
if echo "$cond" | grep -Eq "github\.event_name\s*==\s*'pull_request'"; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label" "if='$cond'"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- build-validation job: NO docker push (build-only) -------------- #
|
||||
check_build_validation_no_push() {
|
||||
local f=".github/workflows/admin-web-docker.yml"
|
||||
local label="build-validation does NOT docker push (build-only)"
|
||||
if [[ ! -f "$f" ]]; then
|
||||
fail "$label" "file missing"
|
||||
return
|
||||
fi
|
||||
local out
|
||||
out=$(python3 -c "
|
||||
import yaml,sys,json
|
||||
d=yaml.safe_load(open(sys.argv[1]))
|
||||
bv=d.get('jobs',{}).get('build-validation',{})
|
||||
blob=json.dumps(bv)
|
||||
print('PUSH' if 'docker push' in blob else 'NO-PUSH')
|
||||
" "$f" 2>/dev/null || echo "ERR")
|
||||
if [[ "$out" == "NO-PUSH" ]]; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label" "docker push found in build-validation job"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- build-validation job: NO secrets (public vars only) ------------ #
|
||||
check_build_validation_no_secrets() {
|
||||
local f=".github/workflows/admin-web-docker.yml"
|
||||
local label="build-validation references no secrets (build-only, public vars only)"
|
||||
if [[ ! -f "$f" ]]; then
|
||||
fail "$label" "file missing"
|
||||
return
|
||||
fi
|
||||
local out
|
||||
out=$(python3 -c "
|
||||
import yaml,sys,json
|
||||
d=yaml.safe_load(open(sys.argv[1]))
|
||||
bv=d.get('jobs',{}).get('build-validation',{})
|
||||
blob=json.dumps(bv)
|
||||
print('SECRET' if 'secrets.' in blob else 'NO-SECRET')
|
||||
" "$f" 2>/dev/null || echo "ERR")
|
||||
if [[ "$out" == "NO-SECRET" ]]; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label" "secrets.* referenced in build-validation job"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- semantic-release if excludes pull_request ---------------------- #
|
||||
check_sr_excludes_pr() {
|
||||
local f=".github/workflows/admin-web-docker.yml"
|
||||
local label="semantic-release if excludes pull_request"
|
||||
if [[ ! -f "$f" ]]; then
|
||||
fail "$label" "file missing"
|
||||
return
|
||||
fi
|
||||
local cond
|
||||
cond=$(python3 -c "
|
||||
import yaml,sys
|
||||
d=yaml.safe_load(open(sys.argv[1]))
|
||||
print(d.get('jobs',{}).get('semantic-release',{}).get('if','') or '')
|
||||
" "$f" 2>/dev/null || true)
|
||||
if echo "$cond" | grep -Eq "github\.event_name\s*!=\s*'pull_request'"; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label" "if missing pull_request exclusion (if='$cond')"
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================== #
|
||||
# RUN ALL
|
||||
# =================================================================== #
|
||||
@@ -525,6 +645,12 @@ check_buildargs_source
|
||||
check_actions_pinned
|
||||
check_git_branch
|
||||
check_git_commit_prefix
|
||||
# PR build-validation feature checks
|
||||
check_pr_trigger
|
||||
check_build_validation_if
|
||||
check_build_validation_no_push
|
||||
check_build_validation_no_secrets
|
||||
check_sr_excludes_pr
|
||||
|
||||
echo ""
|
||||
echo "# Summary: $PASS_COUNT passed, $FAIL_COUNT failed"
|
||||
|
||||
Reference in New Issue
Block a user