gitlab schedules sync
homelabctl2 gitlab schedules sync reconciles GitLab pipeline schedules
against an in-source declarative list. The reconciler identifies its own
schedules by the [homelab-bot] description prefix and leaves everything
else alone, so schedules created by hand in the GitLab UI are never
touched.
homelabctl2 gitlab schedules sync # dry-run (default)homelabctl2 gitlab schedules sync --apply # actually create/update| Flag | Default | Description |
|---|---|---|
--apply | false (dry-run) | Apply changes; without it, prints diff only. |
--project | joelmuehlena/homelab | GitLab project path or numeric id. |
--ref | main | Ref the schedules target. |
--gitlab-host | gitlab.com | GitLab host. |
Authentication
Section titled “Authentication”The command picks a token in this order:
$GITLAB_TOKENenv varop item get --vault HomeLab GitLab --fields api_token --reveal(reuses your signed-in 1Password desktop session)
The PAT needs the api scope.
Declarative schedule list
Section titled “Declarative schedule list”The source of truth is var schedules in
code/homelabctl2/cmd/homelabctl2/gitlab/schedules/schedules.go:
var schedules = []ScheduleSpec{ {"refresh pdns RPZs", "0 */6 * * *", "RUN_REFRESH_RPZS", "true"}, {"rebuild pdns images", "0 4 * * 0", "RUN_REBUILD_PDNS", "true"}, {"rebuild netbox image", "30 4 * * 0", "RUN_REBUILD_NETBOX", "true"}, {"rebuild vault-autoinit image", "0 5 * * 0", "RUN_REBUILD_VAULT_AUTOINIT", "true"}, {"rebuild paperless-backup image", "30 5 * * 0", "RUN_REBUILD_PAPERLESS_BACKUP","true"}, {"rebuild homelabctl2 image", "0 6 * * 0", "RUN_REBUILD_HOMELABCTL2", "true"},}Each row produces one GitLab pipeline schedule with description
[homelab-bot] <Name>, the given cron (UTC), and a single CI variable
gating the relevant pipeline file. Edit cadence/values here; commit; run
--apply.
Reconciliation behavior
Section titled “Reconciliation behavior”For each managed row:
| State in GitLab | Action |
|---|---|
| Missing | Created (cron + ref + active=true) and variable set |
| Exists, variable matches | No-op |
| Exists, variable missing | Variable added |
| Exists, variable has different value | Variable updated |
| Exists, cron/ref differs | Left untouched — edit in the UI if you want a new cadence |
Has [homelab-bot] prefix but not in source | Logged as unmanaged (no delete) |
No [homelab-bot] prefix | Logged as unmanaged (no touch) |
The reconciler intentionally never deletes — a row dropped from the source list stays in GitLab and is reported as unmanaged. Disable it via the UI when you want it actually gone.
Output
Section titled “Output”Structured slog output (text by default, JSON with --log-format json).
Example dry-run on a fresh project:
INFO syncing pipeline schedules mode=dry-run project=joelmuehlena/homelab ref=mainINFO would create schedule (dry-run) description="[homelab-bot] refresh pdns RPZs" cron="0 */6 * * *" ref=main variable=RUN_REFRESH_RPZS value=trueINFO would create schedule (dry-run) description="[homelab-bot] rebuild pdns images" cron="0 4 * * 0" ref=main variable=RUN_REBUILD_PDNS value=true...INFO dry-run only — re-run with --apply to commit changesRun with --apply to perform the changes.