ci: 按路径拆分静态检查
This commit is contained in:
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
name: ansible
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'infrastructure/**/ansible/**'
|
||||||
|
- '.ansible-lint'
|
||||||
|
- '.gitea/workflows/ansible.yml'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'infrastructure/**/ansible/**'
|
||||||
|
- '.ansible-lint'
|
||||||
|
- '.gitea/workflows/ansible.yml'
|
||||||
|
|
||||||
|
env:
|
||||||
|
ANSIBLE_COLLECTIONS_PATH: /root/.ansible/collections
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Bootstrap uv
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --user --break-system-packages \
|
||||||
|
--index-url https://pypi.org/simple --quiet uv==0.11.7
|
||||||
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
- name: Install ansible-lint and collections
|
||||||
|
run: |
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
uv tool install ansible-core --with paramiko --with pywinrm --quiet && break
|
||||||
|
echo "attempt $i failed"; sleep 10
|
||||||
|
done
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
uv tool install ansible-lint --quiet && break
|
||||||
|
echo "attempt $i failed"; sleep 10
|
||||||
|
done
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
for p in infrastructure/proxmox infrastructure/samba-ad infrastructure/openbao; do
|
||||||
|
ansible-galaxy collection install \
|
||||||
|
-r "$p/ansible/requirements.yml" -p "$ANSIBLE_COLLECTIONS_PATH"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: ansible-lint
|
||||||
|
run: |
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
rc=0
|
||||||
|
for p in infrastructure/openbao infrastructure/samba-ad infrastructure/proxmox; do
|
||||||
|
echo "::group::$p"
|
||||||
|
(cd "$p/ansible" && ansible-lint -c ../../../.ansible-lint --nocolor -f pep8 .) || rc=1
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
|
exit $rc
|
||||||
+14
-77
@@ -1,20 +1,26 @@
|
|||||||
---
|
---
|
||||||
# Stage 1 of the infra pipeline: static checks only. No cluster access, no
|
# Stage 1 of the infra pipeline: static checks only. No cluster access, no
|
||||||
# credentials, no mutation — so this is safe to run on every push from day one.
|
# credentials or mutation. It runs only when YAML-related paths change.
|
||||||
#
|
#
|
||||||
# Stages 2 (kubectl --dry-run=server) and 3 (k3d / molecule) come later and DO
|
# Stages 2 (kubectl --dry-run=server) and 3 (k3d / molecule) come later and DO
|
||||||
# need cluster access; keep them in separate workflows so a credential problem
|
# need cluster access; keep them in separate workflows so a credential problem
|
||||||
# there can never block this one.
|
# there can never block this one.
|
||||||
name: lint
|
name: yaml
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- '**/*.yaml'
|
||||||
|
- '**/*.yml'
|
||||||
|
- '.yamllint.yml'
|
||||||
|
- '.gitea/workflows/lint.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
env:
|
- '**/*.yaml'
|
||||||
# ansible-lint and ansible-core install as separate uv tools. Install Galaxy
|
- '**/*.yml'
|
||||||
# collections into this shared path so both isolated environments can see them.
|
- '.yamllint.yml'
|
||||||
ANSIBLE_COLLECTIONS_PATH: /root/.ansible/collections
|
- '.gitea/workflows/lint.yml'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
yaml:
|
yaml:
|
||||||
@@ -23,8 +29,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Bootstrap uv
|
- name: Bootstrap uv
|
||||||
# setup-uv queries api.github.com, which is unreachable from the nested
|
# Pin the tool for reproducibility; PyPI also avoids another setup action.
|
||||||
# job network. Official PyPI is reachable; pin the tool for reproducibility.
|
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install --user --break-system-packages \
|
python3 -m pip install --user --break-system-packages \
|
||||||
--index-url https://pypi.org/simple --quiet uv==0.11.7
|
--index-url https://pypi.org/simple --quiet uv==0.11.7
|
||||||
@@ -47,71 +52,3 @@ jobs:
|
|||||||
export PATH="$HOME/.local/bin:$PATH"
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
files=$(git ls-files '*.yaml' '*.yml' | grep -vE '^apps/netboot/')
|
files=$(git ls-files '*.yaml' '*.yml' | grep -vE '^apps/netboot/')
|
||||||
yamllint -c .yamllint.yml --no-warnings -f parsable $files
|
yamllint -c .yamllint.yml --no-warnings -f parsable $files
|
||||||
|
|
||||||
ansible:
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Bootstrap uv
|
|
||||||
run: |
|
|
||||||
python3 -m pip install --user --break-system-packages \
|
|
||||||
--index-url https://pypi.org/simple --quiet uv==0.11.7
|
|
||||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
||||||
|
|
||||||
- name: Install ansible-lint and collections
|
|
||||||
# pywinrm is not optional — without it every ansible.windows.* task dies
|
|
||||||
# with "No module named 'winrm'" (CLAUDE.md documents this trap).
|
|
||||||
run: |
|
|
||||||
for i in 1 2 3 4 5; do
|
|
||||||
# Do not add the `ansible` meta-package here: it bundles collections
|
|
||||||
# inside this uv venv, making Galaxy skip the shared path below while
|
|
||||||
# ansible-lint's separate venv still cannot resolve the modules.
|
|
||||||
uv tool install ansible-core --with paramiko --with pywinrm --quiet && break
|
|
||||||
echo "attempt $i failed"; sleep 10
|
|
||||||
done
|
|
||||||
for i in 1 2 3 4 5; do
|
|
||||||
uv tool install ansible-lint --quiet && break
|
|
||||||
echo "attempt $i failed"; sleep 10
|
|
||||||
done
|
|
||||||
export PATH="$HOME/.local/bin:$PATH"
|
|
||||||
for p in infrastructure/proxmox infrastructure/samba-ad infrastructure/openbao; do
|
|
||||||
ansible-galaxy collection install \
|
|
||||||
-r "$p/ansible/requirements.yml" -p "$ANSIBLE_COLLECTIONS_PATH"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: ansible-lint
|
|
||||||
# Each project has its own ansible.cfg and relative roles_path, so lint
|
|
||||||
# must run from inside each one — a single run at the repo root resolves
|
|
||||||
# roles_path incorrectly and reports spurious missing-role errors.
|
|
||||||
run: |
|
|
||||||
export PATH="$HOME/.local/bin:$PATH"
|
|
||||||
rc=0
|
|
||||||
for p in infrastructure/openbao infrastructure/samba-ad infrastructure/proxmox; do
|
|
||||||
echo "::group::$p"
|
|
||||||
(cd "$p/ansible" && ansible-lint -c ../../../.ansible-lint --nocolor -f pep8 .) || rc=1
|
|
||||||
echo "::endgroup::"
|
|
||||||
done
|
|
||||||
exit $rc
|
|
||||||
|
|
||||||
terraform:
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: hashicorp/setup-terraform@v3
|
|
||||||
|
|
||||||
- name: fmt and validate
|
|
||||||
# -backend=false so validate never touches real state or needs credentials.
|
|
||||||
# These roots deliberately use different providers AND different interactive
|
|
||||||
# auth (bao login -method=oidc, az login), which is exactly why they are not
|
|
||||||
# merged — so validate is as far as static checking can go here.
|
|
||||||
run: |
|
|
||||||
rc=0
|
|
||||||
for d in $(git ls-files '*.tf' | xargs -n1 dirname | sort -u); do
|
|
||||||
echo "::group::$d"
|
|
||||||
terraform -chdir="$d" fmt -check -diff || rc=1
|
|
||||||
terraform -chdir="$d" init -backend=false -input=false || rc=1
|
|
||||||
terraform -chdir="$d" validate || rc=1
|
|
||||||
echo "::endgroup::"
|
|
||||||
done
|
|
||||||
exit $rc
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
name: terraform
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- '**/*.tf'
|
||||||
|
- '**/.terraform.lock.hcl'
|
||||||
|
- '.gitea/workflows/terraform.yml'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '**/*.tf'
|
||||||
|
- '**/.terraform.lock.hcl'
|
||||||
|
- '.gitea/workflows/terraform.yml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
|
||||||
|
- name: fmt and validate
|
||||||
|
# -backend=false so validate never touches real state or needs credentials.
|
||||||
|
run: |
|
||||||
|
rc=0
|
||||||
|
for d in $(git ls-files '*.tf' | xargs -n1 dirname | sort -u); do
|
||||||
|
echo "::group::$d"
|
||||||
|
terraform -chdir="$d" fmt -check -diff || rc=1
|
||||||
|
terraform -chdir="$d" init -backend=false -input=false || rc=1
|
||||||
|
terraform -chdir="$d" validate || rc=1
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
|
exit $rc
|
||||||
+8
-6
@@ -1,7 +1,7 @@
|
|||||||
# CI/CD — what we are building
|
# CI/CD — what we are building
|
||||||
|
|
||||||
Status: **partly built.** Stage 1 and the Kubernetes runner are live; Flux and
|
Status: **partly built.** Stage 1、Kubernetes runner 与 Flux 已上线;credentialed
|
||||||
credentialed stages are not yet installed.
|
stages 尚未实现。
|
||||||
Started 2026-07-28.
|
Started 2026-07-28.
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
@@ -24,18 +24,20 @@ to make drift between this repo and reality visible when it happens.
|
|||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| git | `homelab-infra` is hosted on the local Gitea; an independent off-site mirror is still missing |
|
| git | `homelab-infra` is hosted on the local Gitea; an independent off-site mirror is still missing |
|
||||||
| stage 1 | Live and green on the Gitea runner — `yamllint`, `ansible-lint`, `terraform fmt`/`validate` |
|
| stage 1 | Gitea runner 上的 `yamllint`、`ansible-lint`、Terraform fmt/validate 已上线;三个 workflow 按路径触发,feature push 不再与 PR 事件重复运行 |
|
||||||
| gitea | 1.25.5, Actions enabled, `DEFAULT_ACTIONS_URL=github`; one instance-scoped Kubernetes runner is deployed with capacity four |
|
| gitea | 1.27.3,Actions 已启用;一个 instance-scoped Kubernetes runner 以 capacity 4 运行 |
|
||||||
| ansible | 33 roles across `infrastructure/proxmox/`, `infrastructure/samba-ad/`, `infrastructure/openbao/` |
|
| ansible | 33 roles across `infrastructure/proxmox/`, `infrastructure/samba-ad/`, `infrastructure/openbao/` |
|
||||||
| terraform | 4 roots, **local state**, each with **different interactive auth** (`bao login -method=oidc`, `az login`) |
|
| terraform | 4 roots, **local state**, each with **different interactive auth** (`bao login -method=oidc`, `az login`) |
|
||||||
| k8s | ~13 Helm releases, all deployed by hand |
|
| k8s | Flux 已接管 Gitea、Gitea Actions 与 http-echo canary;其余 brownfield release 逐项迁移 |
|
||||||
| secrets | 4 config files are gitignored because they embed live secrets, so their contents are **not** version controlled |
|
| secrets | 4 config files are gitignored because they embed live secrets, so their contents are **not** version controlled |
|
||||||
|
|
||||||
## The four stages
|
## The four stages
|
||||||
|
|
||||||
**Stage 1 — static. Built.**
|
**Stage 1 — static. Built.**
|
||||||
`yamllint`, `ansible-lint`, `terraform fmt -check` / `validate -backend=false`.
|
`yamllint`, `ansible-lint`, `terraform fmt -check` / `validate -backend=false`.
|
||||||
No cluster, no credentials, no mutation, so it is safe on every push. It already
|
No cluster, no credentials, no mutation. YAML、Ansible 和 Terraform 各自按相关路径
|
||||||
|
触发;feature branch 只由 `pull_request` 检查,合并后再由 `main` push 检查,避免
|
||||||
|
同一 revision 因 branch push 和 PR 各跑一遍。它已经
|
||||||
found a real defect: `infrastructure/proxmox/ansible/` had no `requirements.yml` at all, so a
|
found a real defect: `infrastructure/proxmox/ansible/` had no `requirements.yml` at all, so a
|
||||||
fresh checkout could not reproduce its collections.
|
fresh checkout could not reproduce its collections.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user