Merge pull request 'release: merge integration into main' (#2) from integration into main
Some checks failed
Release / tag-and-notes (push) Has been cancelled
Some checks failed
Release / tag-and-notes (push) Has been cancelled
Reviewed-on: #2
This commit is contained in:
24
.gitea/workflows/ci.yml
Normal file
24
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: ["**"]
|
||||||
|
push:
|
||||||
|
branches: ["integration", "bootstrap", "bootstrap-cicd"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
checks:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build CI image
|
||||||
|
run: docker build -f ci.Dockerfile -t local/ci:latest .
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: docker run --rm -v ${{ github.workspace }}:/workspace local/ci:latest bash -lc "cd /workspace && IN_CI_CONTAINER=1 scripts/ci lint"
|
||||||
|
|
||||||
|
- name: Build validation
|
||||||
|
run: docker run --rm -v ${{ github.workspace }}:/workspace local/ci:latest bash -lc "cd /workspace && IN_CI_CONTAINER=1 scripts/ci build"
|
||||||
|
|
19
.gitea/workflows/nightly.yml
Normal file
19
.gitea/workflows/nightly.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
name: Nightly
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 3 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
report:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build CI image
|
||||||
|
run: docker build -f ci.Dockerfile -t local/ci:latest .
|
||||||
|
|
||||||
|
- name: Lint (nightly)
|
||||||
|
run: docker run --rm -v ${{ github.workspace }}:/workspace local/ci:latest bash -lc "cd /workspace && IN_CI_CONTAINER=1 scripts/ci lint"
|
||||||
|
|
29
.gitea/workflows/release.yml
Normal file
29
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tag-and-notes:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build CI image
|
||||||
|
run: docker build -f ci.Dockerfile -t local/ci:latest .
|
||||||
|
|
||||||
|
- name: Compute tag
|
||||||
|
id: tag
|
||||||
|
run: |
|
||||||
|
TZ=UTC date +"v%Y.%m.%d-%H%M" > tag.txt
|
||||||
|
echo "tag=$(cat tag.txt)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create annotated tag
|
||||||
|
run: |
|
||||||
|
git config user.name "ci"
|
||||||
|
git config user.email "ci@local"
|
||||||
|
git tag -a ${{ steps.tag.outputs.tag }} -m "Release ${{ steps.tag.outputs.tag }}"
|
||||||
|
git push origin ${{ steps.tag.outputs.tag }}
|
||||||
|
|
5
.githooks/commit-msg
Normal file
5
.githooks/commit-msg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
scripts/commitlint-hook "$1"
|
||||||
|
|
11
.githooks/pre-commit
Normal file
11
.githooks/pre-commit
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "> pre-commit: format + lint + commit message check"
|
||||||
|
|
||||||
|
# Run format and lint inside the CI container
|
||||||
|
scripts/ci format
|
||||||
|
scripts/ci lint
|
||||||
|
|
||||||
|
echo "pre-commit completed."
|
||||||
|
|
11
.githooks/pre-push
Normal file
11
.githooks/pre-push
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "> pre-push: build validation + placeholders for tests/security"
|
||||||
|
|
||||||
|
scripts/ci build
|
||||||
|
scripts/ci test
|
||||||
|
scripts/ci security
|
||||||
|
|
||||||
|
echo "pre-push completed."
|
||||||
|
|
33
Makefile
Normal file
33
Makefile
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
SHELL := /usr/bin/env bash
|
||||||
|
|
||||||
|
.PHONY: all check quick format lint build test security ci-image hooks-setup
|
||||||
|
|
||||||
|
all: check
|
||||||
|
|
||||||
|
check:
|
||||||
|
./scripts/ci all
|
||||||
|
|
||||||
|
quick:
|
||||||
|
./scripts/ci format && ./scripts/ci lint
|
||||||
|
|
||||||
|
format:
|
||||||
|
./scripts/ci format
|
||||||
|
|
||||||
|
lint:
|
||||||
|
./scripts/ci lint
|
||||||
|
|
||||||
|
build:
|
||||||
|
./scripts/ci build
|
||||||
|
|
||||||
|
test:
|
||||||
|
./scripts/ci test
|
||||||
|
|
||||||
|
security:
|
||||||
|
./scripts/ci security
|
||||||
|
|
||||||
|
ci-image:
|
||||||
|
docker build -f ci.Dockerfile -t local/ci:latest .
|
||||||
|
|
||||||
|
hooks-setup:
|
||||||
|
./scripts/setup-hooks
|
||||||
|
|
53
RESUME.md
Normal file
53
RESUME.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
Resume Guide
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
- Quick checklist to pick up work after restarting Codex CLI with expanded permissions.
|
||||||
|
|
||||||
|
Branches on remote
|
||||||
|
- main (default), integration, release, bootstrap, bootstrap-cicd
|
||||||
|
|
||||||
|
1) Pull latest
|
||||||
|
- git fetch --all --prune
|
||||||
|
- git switch bootstrap && git pull
|
||||||
|
- git switch bootstrap-cicd && git pull
|
||||||
|
- git switch integration && git pull
|
||||||
|
|
||||||
|
2) Ensure Docker is available
|
||||||
|
- Start Docker Desktop/daemon as needed
|
||||||
|
|
||||||
|
3) Install hooks locally
|
||||||
|
- make hooks-setup
|
||||||
|
|
||||||
|
4) Run local checks (Docker-only)
|
||||||
|
- git switch bootstrap && make quick && make build
|
||||||
|
- git switch bootstrap-cicd && make quick && make build
|
||||||
|
- Optional full pass: make check
|
||||||
|
|
||||||
|
5) Open PRs (when branches are green locally)
|
||||||
|
- bootstrap → integration: https://git.knownelement.com/KNEL/LLMScaffolding/pulls/new/bootstrap
|
||||||
|
- bootstrap-cicd → integration: https://git.knownelement.com/KNEL/LLMScaffolding/pulls/new/bootstrap-cicd
|
||||||
|
|
||||||
|
6) Merge to integration
|
||||||
|
- Use squash merge, allow auto-merge on green where configured
|
||||||
|
|
||||||
|
7) Release to main
|
||||||
|
- Open PR: integration → main (require 1 approval)
|
||||||
|
- After merge, tag manually (until CI runners are enabled):
|
||||||
|
- git switch main && git pull
|
||||||
|
- TAG=$(date -u +"v%Y.%m.%d-%H%M")
|
||||||
|
- git tag -a "$TAG" -m "Release $TAG"
|
||||||
|
- git push origin "$TAG"
|
||||||
|
- Optional: fast-forward release branch pointer:
|
||||||
|
- git branch -f release main && git push -f origin release
|
||||||
|
|
||||||
|
8) Docs & parity
|
||||||
|
- Git workflow: instructions/git-workflow.md
|
||||||
|
- Local CI parity: instructions/bootstrap-cicd.md
|
||||||
|
|
||||||
|
9) Defer CI enablement for two weeks
|
||||||
|
- Track in TODO.md: Revisit enabling runners and protected checks on 2025-09-24
|
||||||
|
|
||||||
|
10) Next tasks
|
||||||
|
- Answer any outstanding questions in questions/*
|
||||||
|
- On approval, implement further proposals and update instructions/*
|
||||||
|
|
34
TODO.md
Normal file
34
TODO.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
TODO
|
||||||
|
|
||||||
|
- Git workflow
|
||||||
|
- [x] Questions gathered and answered
|
||||||
|
- [x] Proposal iteration 2 drafted
|
||||||
|
- [x] Finalize approval and capture in instructions/git-workflow.md
|
||||||
|
|
||||||
|
- Branches
|
||||||
|
- [x] Create integration, release, bootstrap from main
|
||||||
|
- [x] Push bootstrap to origin
|
||||||
|
- [ ] Decide whether to maintain a fast-forwarded release branch to the latest tag
|
||||||
|
|
||||||
|
- CI/CD bootstrap
|
||||||
|
- [x] Create branch bootstrap-cicd from main
|
||||||
|
- [x] Add questions at questions/bootstrap-cicd.md
|
||||||
|
- [x] Draft proposal based on answers
|
||||||
|
- [x] Implement parity tooling: scripts/ci, ci.Dockerfile, docker/ci.compose.yml
|
||||||
|
- [x] Add .gitea/workflows: ci.yml, release.yml, nightly.yml
|
||||||
|
- [x] Add commitlint.config.cjs, Makefile
|
||||||
|
- [ ] Optional: add .pre-commit-config.yaml (defer for now)
|
||||||
|
- [ ] Optional: add CODEOWNERS
|
||||||
|
|
||||||
|
- Protections & settings (in Gitea UI)
|
||||||
|
- [ ] Protect main and release/* with required checks
|
||||||
|
- [ ] Leave integration unprotected; allow auto-merge on green
|
||||||
|
- [ ] Require 1 approval for integration→main
|
||||||
|
- [ ] Revisit enabling CI and protections after runners are ready (target: 2025-09-24)
|
||||||
|
|
||||||
|
- Releases
|
||||||
|
- [ ] Tag format vYYYY.MM.DD-HHMM (UTC) in release workflow
|
||||||
|
- [ ] Optional: fast-forward release branch to latest tag
|
||||||
|
|
||||||
|
- Docs
|
||||||
|
- [ ] Write docs/engineering/git-workflow.md with diagrams and examples
|
40
ci.Dockerfile
Normal file
40
ci.Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
FROM debian:12-slim
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates curl git bash coreutils findutils file python3 python3-pip \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install shfmt, hadolint, actionlint (static), shellcheck, yamllint, node tools
|
||||||
|
RUN set -eux; \
|
||||||
|
# shellcheck
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends shellcheck && rm -rf /var/lib/apt/lists/*; \
|
||||||
|
# shfmt
|
||||||
|
SHFMT_VER=3.7.0; curl -fsSL -o /usr/local/bin/shfmt https://github.com/mvdan/sh/releases/download/v${SHFMT_VER}/shfmt_v${SHFMT_VER}_linux_amd64 && chmod +x /usr/local/bin/shfmt; \
|
||||||
|
# hadolint
|
||||||
|
HADOLINT_VER=2.12.0; curl -fsSL -o /usr/local/bin/hadolint https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VER}/hadolint-Linux-x86_64 && chmod +x /usr/local/bin/hadolint;
|
||||||
|
|
||||||
|
# actionlint
|
||||||
|
RUN set -eux; \
|
||||||
|
AL_VER=1.7.1; \
|
||||||
|
curl -fsSL -o /usr/local/bin/actionlint https://github.com/rhysd/actionlint/releases/download/v${AL_VER}/actionlint_${AL_VER}_linux_amd64.tar.gz; \
|
||||||
|
tar -C /usr/local/bin -xzf /usr/local/bin/actionlint; \
|
||||||
|
rm -f /usr/local/bin/actionlint
|
||||||
|
|
||||||
|
# yamllint via pip (allow install on Debian's externally-managed Python)
|
||||||
|
RUN pip3 install --break-system-packages --no-cache-dir yamllint==1.35.1
|
||||||
|
|
||||||
|
# Node + npm for prettier, markdownlint, commitlint
|
||||||
|
RUN set -eux; \
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends nodejs && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN npm --location=global install \
|
||||||
|
prettier@3.3.3 \
|
||||||
|
markdownlint-cli@0.39.0 \
|
||||||
|
@commitlint/cli@19.5.0 @commitlint/config-conventional@19.5.0
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
ENTRYPOINT ["bash","-lc"]
|
||||||
|
CMD ["bash"]
|
4
commitlint.config.cjs
Normal file
4
commitlint.config.cjs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['@commitlint/config-conventional'],
|
||||||
|
};
|
||||||
|
|
13
docker/ci.compose.yml
Normal file
13
docker/ci.compose.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
services:
|
||||||
|
ci:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: ci.Dockerfile
|
||||||
|
working_dir: /workspace
|
||||||
|
volumes:
|
||||||
|
- "../:/workspace:Z"
|
||||||
|
environment:
|
||||||
|
- IN_CI_CONTAINER=1
|
||||||
|
entrypoint: ["bash","-lc"]
|
||||||
|
command: ["bash"]
|
||||||
|
|
36
instructions/bootstrap-cicd.md
Normal file
36
instructions/bootstrap-cicd.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
Bootstrap CI/CD – Finalized Instructions (Phase 1)
|
||||||
|
|
||||||
|
Goal
|
||||||
|
- Provide Docker‑only local checks and Git hooks with parity to future CI. CI workflows are prepared but may remain disabled until runners are ready.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
- Docker + Docker Compose v2 on the development machine. No host packages beyond Docker are required.
|
||||||
|
|
||||||
|
Local Checks
|
||||||
|
- Entry point: `scripts/ci <phase>` where phase ∈ {format, lint, build, test, security, all}.
|
||||||
|
- Always runs inside the ci container using `docker/ci.compose.yml`.
|
||||||
|
- Tools pinned in `ci.Dockerfile`: shfmt, shellcheck, hadolint, yamllint, actionlint, prettier, markdownlint, commitlint.
|
||||||
|
|
||||||
|
Hooks
|
||||||
|
- Install hooks: `make hooks-setup` (copies .githooks/* into .git/hooks).
|
||||||
|
- pre-commit: runs format + lint.
|
||||||
|
- commit-msg: runs commitlint (Conventional Commits).
|
||||||
|
- pre-push: runs build; test and security are present but currently no‑ops.
|
||||||
|
|
||||||
|
Convenience Targets
|
||||||
|
- `make quick` → format + lint.
|
||||||
|
- `make check` → all phases.
|
||||||
|
- `make build` → compose validation.
|
||||||
|
|
||||||
|
CI (Prepared, optional enablement later)
|
||||||
|
- .gitea/workflows/ci.yml: builds ci image; runs lint + build.
|
||||||
|
- .gitea/workflows/release.yml: on pushes to main, creates annotated tag vYYYY.MM.DD-HHMM (UTC).
|
||||||
|
- .gitea/workflows/nightly.yml: nightly lint run.
|
||||||
|
- All jobs run inside the ci image; no runner host package installs.
|
||||||
|
|
||||||
|
Protected Checks (when CI is enabled)
|
||||||
|
- Protect: ci / lint, ci / build, ci / commitlint. Add ci / test and ci / security when they exist.
|
||||||
|
|
||||||
|
Future Extensions
|
||||||
|
- Add tests/security phases per repo stack; enable CI branch protections once runners are ready; optionally add pre-commit framework as an alternative to native hooks.
|
||||||
|
|
36
instructions/git-workflow.md
Normal file
36
instructions/git-workflow.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
Git Workflow – Finalized Instructions
|
||||||
|
|
||||||
|
Scope
|
||||||
|
- Applies to this repo. Users typically consume tagged releases; contributors work via branches/PRs. CI/CD config is Gitea‑native; no GitHub/GitLab.
|
||||||
|
|
||||||
|
Branches
|
||||||
|
- main: production; default branch. Protected.
|
||||||
|
- integration: development (unprotected; merges auto on green).
|
||||||
|
- Working branches: `feature/<topic>`, `fix/<topic>`, `chore/<topic>` from integration.
|
||||||
|
- Hotfix: `hotfix/<date>` from main; PR back to main, then forward-merge into integration.
|
||||||
|
- Release branch: ephemeral or lightweight `release/*`. Protect when present; optionally fast‑forward to latest tag via CI.
|
||||||
|
|
||||||
|
Merges & Approvals
|
||||||
|
- Feature → integration: squash merge; auto‑merge on green (no human approval). Self‑merge allowed.
|
||||||
|
- integration → main: squash merge; require 1 approval; self‑merge not allowed.
|
||||||
|
- Force pushes disabled on protected branches (`main`, `release/*`); PRs required.
|
||||||
|
|
||||||
|
Commit Style
|
||||||
|
- Conventional Commits for PR titles and commit messages.
|
||||||
|
|
||||||
|
Versioning & Tags
|
||||||
|
- Calendar tags: vYYYY.MM.DD-HHMM (UTC). Annotated tags only on main after release.
|
||||||
|
|
||||||
|
Release Flow
|
||||||
|
1) Feature branches PR into integration; checks pass → auto‑merge.
|
||||||
|
2) PR integration → main; 1 approval required; on merge, deploy and tag release.
|
||||||
|
3) Optional: CI fast‑forwards a release branch pointer to the new tag.
|
||||||
|
|
||||||
|
Protected Checks (to enable when runners are ready)
|
||||||
|
- On protected branches (`main`, `release/*`): ci / lint, ci / build, ci / commitlint. Add ci / test and ci / security if/when introduced.
|
||||||
|
|
||||||
|
CODEOWNERS
|
||||||
|
- Keep minimal; require your review for integration → main.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
- No secrets required for this repo. Future repos should integrate Vault for secrets.
|
69
proposals/bootstrap-cicd.md
Normal file
69
proposals/bootstrap-cicd.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
**Bootstrap CI/CD Proposal (Phase 1)**
|
||||||
|
|
||||||
|
- Scope: Local developer parity via Docker-first tooling and hooks, minimal CI placeholders (no runners required yet). Applies to this repo (docs/scripts/docker-compose), with an easy path to template for others.
|
||||||
|
|
||||||
|
**Checks To Implement Now (Local via Docker)**
|
||||||
|
|
||||||
|
- Stacks: shell, Dockerfiles/Compose, Markdown/Docs, YAML; Python/Node optional later.
|
||||||
|
- Formatters/Linters:
|
||||||
|
- shell: shfmt + shellcheck
|
||||||
|
- docker: hadolint
|
||||||
|
- markdown: markdownlint + prettier
|
||||||
|
- yaml: yamllint + actionlint (for workflows)
|
||||||
|
- Tests: none for now (lint-only baseline).
|
||||||
|
- Security: skip for this repo now.
|
||||||
|
|
||||||
|
**Execution Model**
|
||||||
|
|
||||||
|
- Docker-only: all checks run inside a pinned `ci` image. Host only orchestrates Docker/Compose.
|
||||||
|
- Single entrypoint: `scripts/ci` with phases: `format`, `lint`, `build` (compose validate), `test` (no-op for now), `security` (no-op), `all`.
|
||||||
|
- Compose file: `docker/ci.compose.yml` defines `ci` service that mounts repo and executes `scripts/ci <phase>`.
|
||||||
|
|
||||||
|
**Hooks Parity**
|
||||||
|
|
||||||
|
- Provide Git hooks via pre-commit framework and native Git hooks:
|
||||||
|
- pre-commit: run `format`, `lint`, and commit message check (Conventional Commits).
|
||||||
|
- pre-push: run `build` (compose config validation) and keep `test`/`security` as no-ops for now.
|
||||||
|
- Commit message style: Conventional Commits via `commitlint` rule-set; enforce in CI later and locally via `commit-msg` hook.
|
||||||
|
|
||||||
|
**Minimal CI (Deferred Enablement)**
|
||||||
|
|
||||||
|
- Workflows will be prepared but can stay disabled until runners are available:
|
||||||
|
- `.gitea/workflows/ci.yml`: mirrors local `lint` + `build` using the same `ci` image; triggered on PRs when enabled.
|
||||||
|
- `.gitea/workflows/release.yml`: on `main` merges, tags with `vYYYY.MM.DD-HHMM` and (optionally) creates release notes; can be enabled later.
|
||||||
|
- `.gitea/workflows/nightly.yml`: scheduled dependency/lint refresh; optional for later.
|
||||||
|
- All jobs execute inside the `ci` container image; no host package installs.
|
||||||
|
|
||||||
|
**Caching & Matrix**
|
||||||
|
|
||||||
|
- Matrix: single Linux image for now.
|
||||||
|
- Caching: enable Docker layer cache when CI runners are available; no special local caching required.
|
||||||
|
|
||||||
|
**Concurrency & Timeouts (defaults for later)**
|
||||||
|
|
||||||
|
- Cancel in-progress on same ref: enabled for PRs.
|
||||||
|
- Job timeout: 30 minutes.
|
||||||
|
|
||||||
|
**Protected Check Names (for later enforcement)**
|
||||||
|
|
||||||
|
- `ci / lint`, `ci / build`, `ci / commitlint`. Tests/Security can be added when introduced.
|
||||||
|
|
||||||
|
**Files To Add (upon approval)**
|
||||||
|
|
||||||
|
- `scripts/ci` (bash) — phases and Docker/host detection (host executes Docker only).
|
||||||
|
- `ci.Dockerfile` — pinned versions: shfmt, shellcheck, hadolint, yamllint, markdownlint-cli, prettier, actionlint, commitlint.
|
||||||
|
- `docker/ci.compose.yml` — `ci` service to run checks.
|
||||||
|
- `.pre-commit-config.yaml` — wire to `scripts/ci` phases; enable `commit-msg` hook for commitlint.
|
||||||
|
- `commitlint.config.cjs` — Conventional Commits rules.
|
||||||
|
- `.gitea/workflows/ci.yml`, `release.yml`, `nightly.yml` — prepared but can be disabled until runners are ready.
|
||||||
|
- `Makefile` — `check`, `quick`, `lint`, `format`, `build` targets mapping to scripts.
|
||||||
|
|
||||||
|
**Rollout Plan**
|
||||||
|
|
||||||
|
1) Implement local tooling and hooks on `bootstrap-cicd`.
|
||||||
|
2) Document quickstart in `docs/engineering/ci-cd.md`.
|
||||||
|
3) Later: enable Gitea workflows when runners are ready; add protected checks.
|
||||||
|
4) Optionally expand with tests/security scanners and language stacks per repo.
|
||||||
|
|
||||||
|
If this matches your intent, I will scaffold the above on `bootstrap-cicd` and then capture the finalized process in `instructions/bootstrap-cicd.md`.
|
||||||
|
|
110
questions/bootstrap-cicd.md
Normal file
110
questions/bootstrap-cicd.md
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
Bootstrap CI/CD – Questions
|
||||||
|
|
||||||
|
Goal: define initial CI/CD checks and local Docker-parity hooks for this repo (docs/site, scripts, docker-compose), and a template usable by other repos.
|
||||||
|
|
||||||
|
Answer style: short codes + notes, e.g. `1:a,c 2:b 3:docker`.
|
||||||
|
|
||||||
|
1) Stacks present now (select all):
|
||||||
|
- a) Shell scripts
|
||||||
|
- b) Dockerfiles/Compose
|
||||||
|
- c) Markdown/Docs
|
||||||
|
- d) YAML (workflows/config)
|
||||||
|
- e) Python
|
||||||
|
- f) Node/JS
|
||||||
|
- g) Other (specify)
|
||||||
|
|
||||||
|
a,b,c,d potentially e.
|
||||||
|
|
||||||
|
2) Formatters/linters per stack:
|
||||||
|
- shell: a) shfmt b) shellcheck c) both
|
||||||
|
- docker: a) hadolint
|
||||||
|
- markdown: a) markdownlint b) prettier c) both
|
||||||
|
- yaml: a) yamllint b) actionlint (for workflows) c) both
|
||||||
|
- python (if used): a) black b) ruff c) pytest (tests)
|
||||||
|
- node (if used): a) eslint b) prettier c) jest (tests)
|
||||||
|
|
||||||
|
shell: c
|
||||||
|
docker: a
|
||||||
|
markdown: c
|
||||||
|
yaml: c
|
||||||
|
|
||||||
|
I will leave python/node testing up to you. It isn't needed for this repo unless you create python scripts at some point.
|
||||||
|
|
||||||
|
3) Testing scope now:
|
||||||
|
- a) none (docs/scripts only)
|
||||||
|
- b) smoke tests for scripts (bats/pytest-sh)
|
||||||
|
- c) unit tests for scripts (specify framework)
|
||||||
|
|
||||||
|
A (other then linting)
|
||||||
|
|
||||||
|
4) Security scanning:
|
||||||
|
- a) trivy fs
|
||||||
|
- b) grype
|
||||||
|
- c) bandit (python)
|
||||||
|
- d) npm audit (node)
|
||||||
|
- e) skip for this repo
|
||||||
|
|
||||||
|
e
|
||||||
|
|
||||||
|
5) Execution environment for CI:
|
||||||
|
- a) run inside repo’s `ci.Dockerfile`
|
||||||
|
- b) run on runner host with packages
|
||||||
|
- c) mix (specify)
|
||||||
|
|
||||||
|
All execution MUST be done in docker containers. Absolutely no work must be done on the host beyond git operations and docker orchestration.
|
||||||
|
|
||||||
|
6) Matrix needs (now):
|
||||||
|
- a) none (single Linux image)
|
||||||
|
- b) multiple language versions (specify)
|
||||||
|
- c) OS matrix (Linux only for now?)
|
||||||
|
|
||||||
|
Um. I don't know. I think just a simle Linux environment can be assumed?
|
||||||
|
|
||||||
|
7) Caching:
|
||||||
|
- a) enable tool caches (pip/npm) in CI
|
||||||
|
- b) enable Docker layer cache
|
||||||
|
- c) none
|
||||||
|
|
||||||
|
I guess docker layer cache? It will be two weeks before I'm working on software (and therefore setup gitea CI runners etc).
|
||||||
|
|
||||||
|
8) Check names to protect on branches (final labels):
|
||||||
|
- a) ci / lint
|
||||||
|
- b) ci / test
|
||||||
|
- c) ci / build
|
||||||
|
- d) ci / security
|
||||||
|
- e) ci / commitlint
|
||||||
|
|
||||||
|
I don't know, leave it up to you
|
||||||
|
|
||||||
|
9) Hooks parity:
|
||||||
|
- pre-commit: run format+lint+commitlint? (y/n) y
|
||||||
|
- pre-push: run test+build+security (fast profile)? (y/n) y
|
||||||
|
|
||||||
|
10) Concurrency & timeouts:
|
||||||
|
- cancel in-progress on new commits to same PR? (y/n)
|
||||||
|
- default job timeout (minutes)?
|
||||||
|
|
||||||
|
11) Release flow details:
|
||||||
|
- generate release notes from merged PRs since last tag? (y/n)
|
||||||
|
- attach built artifacts (site tarball, etc)? (y/n)
|
||||||
|
|
||||||
|
12) Coverage gates (if tests exist):
|
||||||
|
- threshold % to require? (number or skip)
|
||||||
|
|
||||||
|
13) Auto-merge bot to `integration`:
|
||||||
|
- bot account/name (or use Gitea built-in)?
|
||||||
|
- automerge conditions beyond green checks? (labels, size)
|
||||||
|
|
||||||
|
14) Notifications:
|
||||||
|
- a) none
|
||||||
|
- b) email
|
||||||
|
- c) webhook/Chat (specify)
|
||||||
|
|
||||||
|
15) Future extensibility:
|
||||||
|
- template these workflows for other repos? (y/n)
|
||||||
|
- segregate language-specific jobs behind conditions? (y/n)
|
||||||
|
|
||||||
|
Notes: add any constraints about runners, container registry, or build tools.
|
||||||
|
|
||||||
|
|
||||||
|
Lets just ignore all things CI for now? I'm brand new to CI. Use your best judgement/adopt best practices and/or ignore CI as needed. Do track that it's an outstanding item to go in depth on though. I don't want it to block moving forward with the dozen or so docs repos I need to use this LLM workflow with though.
|
115
scripts/ci
Executable file
115
scripts/ci
Executable file
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PHASE="${1:-}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: scripts/ci <format|lint|build|test|security|all>" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -z "${PHASE}" ]]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_root() {
|
||||||
|
git rev-parse --show-toplevel 2>/dev/null || pwd
|
||||||
|
}
|
||||||
|
|
||||||
|
run_outside_container() {
|
||||||
|
local phase="$1"
|
||||||
|
local root
|
||||||
|
root="$(repo_root)"
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "Docker is required to run CI tasks locally." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! command -v docker-compose >/dev/null 2>&1 && ! docker compose version >/dev/null 2>&1; then
|
||||||
|
echo "Docker Compose v2+ is required (docker compose)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Build ci image if needed and run the requested phase inside the container
|
||||||
|
(cd "$root" && docker compose -f docker/ci.compose.yml run --rm \
|
||||||
|
-e IN_CI_CONTAINER=1 \
|
||||||
|
ci bash -lc "cd /workspace && scripts/ci --inside ${phase}")
|
||||||
|
}
|
||||||
|
|
||||||
|
run_format() {
|
||||||
|
echo ">> Formatting"
|
||||||
|
# shell: format in-place
|
||||||
|
shfmt -bn -ci -i 2 -w .
|
||||||
|
# prettier for markdown/yaml/json/etc
|
||||||
|
prettier --log-level warn --write \
|
||||||
|
"**/*.md" "**/*.yaml" "**/*.yml" "**/*.json" \
|
||||||
|
"**/*.css" "**/*.html" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
run_lint() {
|
||||||
|
echo ">> Linting"
|
||||||
|
# shellcheck
|
||||||
|
mapfile -t sh_files < <(git ls-files -z | xargs -0 file --mime-type | awk -F: '/(x-shellscript|text\/x-shellscript)/{print $1}'; git ls-files "*.sh")
|
||||||
|
if [[ ${#sh_files[@]} -gt 0 ]]; then
|
||||||
|
shellcheck -x "${sh_files[@]}" || (echo "Shellcheck failed" && exit 1)
|
||||||
|
shfmt -d .
|
||||||
|
fi
|
||||||
|
# hadolint on Dockerfiles
|
||||||
|
if ls Dockerfile* docker/*Dockerfile* 1>/dev/null 2>&1; then
|
||||||
|
hadolint Dockerfile* docker/*Dockerfile* 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
# yamllint
|
||||||
|
if git ls-files "*.yml" "*.yaml" | grep -q .; then
|
||||||
|
yamllint -s $(git ls-files "*.yml" "*.yaml")
|
||||||
|
fi
|
||||||
|
# markdownlint
|
||||||
|
if git ls-files "*.md" | grep -q .; then
|
||||||
|
markdownlint $(git ls-files "*.md")
|
||||||
|
fi
|
||||||
|
# actionlint for workflow files if present
|
||||||
|
if [ -d .gitea/workflows ]; then
|
||||||
|
actionlint -color
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_build() {
|
||||||
|
echo ">> Build checks"
|
||||||
|
# Validate docker compose configs if present
|
||||||
|
if [ -f docker-compose.yml ] || [ -f docker/compose.yml ]; then
|
||||||
|
docker compose config -q
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_test() {
|
||||||
|
echo ">> Tests (none defined)"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_security() {
|
||||||
|
echo ">> Security checks (skipped for this repo)"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_inside_container() {
|
||||||
|
local phase="$1"
|
||||||
|
case "$phase" in
|
||||||
|
format) run_format ;;
|
||||||
|
lint) run_lint ;;
|
||||||
|
build) run_build ;;
|
||||||
|
test) run_test ;;
|
||||||
|
security) run_security ;;
|
||||||
|
all) run_format; run_lint; run_build; run_test; run_security ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "--inside" ]]; then
|
||||||
|
shift
|
||||||
|
PHASE="${1:-}"
|
||||||
|
[[ -z "$PHASE" ]] && usage
|
||||||
|
run_inside_container "$PHASE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${IN_CI_CONTAINER:-}" != "1" ]]; then
|
||||||
|
run_outside_container "$PHASE"
|
||||||
|
else
|
||||||
|
run_inside_container "$PHASE"
|
||||||
|
fi
|
||||||
|
|
10
scripts/commitlint-hook
Executable file
10
scripts/commitlint-hook
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MSG_FILE="${1:-.git/COMMIT_EDITMSG}"
|
||||||
|
|
||||||
|
# Run commitlint inside the CI container against the commit message file
|
||||||
|
docker compose -f docker/ci.compose.yml run --rm \
|
||||||
|
-e IN_CI_CONTAINER=1 \
|
||||||
|
ci bash -lc "commitlint --edit ${MSG_FILE}"
|
||||||
|
|
19
scripts/setup-hooks
Executable file
19
scripts/setup-hooks
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
root_dir="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||||
|
|
||||||
|
mkdir -p "$root_dir/.git/hooks"
|
||||||
|
|
||||||
|
for hook in pre-commit pre-push commit-msg; do
|
||||||
|
src="$root_dir/.githooks/$hook"
|
||||||
|
dest="$root_dir/.git/hooks/$hook"
|
||||||
|
if [[ -f "$src" ]]; then
|
||||||
|
cp "$src" "$dest"
|
||||||
|
chmod +x "$dest"
|
||||||
|
echo "Installed hook: $hook"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Git hooks installed."
|
||||||
|
|
Reference in New Issue
Block a user