[PostGIS] #6087: Add repository-owned CI status checker and static dashboard generator
PostGIS
trac at osgeo.org
Thu Jun 25 22:53:50 PDT 2026
#6087: Add repository-owned CI status checker and static dashboard generator
---------------------+---------------------------
Reporter: komzpa | Owner: pramsey
Type: defect | Status: new
Priority: medium | Milestone: PostGIS 3.6.5
Component: postgis | Version: 3.6.x
Keywords: |
---------------------+---------------------------
== Background ==
PostGIS currently does not have a simple, machine-readable answer to:
{{{
Is every supported CI green?
}}}
The current CI status page is mostly a manually maintained list of badge
images. There is also `utils/ci-trac-line.sh`, which generates Trac table
markup with hard-coded badge URLs. That is useful for presentation, but
not good enough for automation or local debugging.
The common maintainer workflow is simpler:
{{{
I pushed something. Did I break anything?
}}}
We need a small repository-owned script that answers that question locally
and can also generate a static HTML page for `postgis.net/ci`.
The script should query CI provider APIs directly. It must not parse badge
images.
== Goal ==
Add a Python script that can:
* show CI status for all non-EOL PostGIS branches by default;
* print a compact terminal report with colored Unicode status markers;
* generate a static HTML status page;
* include links to the failing or relevant CI runs for debugging;
* preserve the previous known status when a CI run is currently in
progress;
* avoid making the default view too crowded.
The default experience should answer:
{{{
Did I break anything?
}}}
It should not primarily answer:
{{{
Who broke what, when, on which runner, with which dependency matrix?
}}}
Those details should be available when something is wrong, but not
dominate the normal view.
== Proposed location ==
Add a script under `utils/`, replacing the role currently served by `utils
/ci-trac-line.sh`:
{{{
utils/ci-status.py
}}}
Add a repository-owned configuration file. Exact location is flexible, but
one of these would be fine:
{{{
utils/ci-status.json
}}}
or:
{{{
ci/status-config.json
}}}
Do not commit generated HTML or JSON output files. They are build
artifacts produced by the script and published by cron or another
deployment job.
Do not add a test directory just for this service script unless
maintainers specifically want it later. The script should be simple enough
to review directly, and it should support enough local dry-run/debug
output to be useful without a test harness.
== Default command ==
Running with no arguments should show all non-EOL version statuses:
{{{
python3 utils/ci-status.py
}}}
Default behavior:
* check every configured non-EOL branch;
* show compact terminal output;
* include details only for failures, unknown states, stale results, or in-
progress jobs;
* include direct links for debugging when something is not green;
* exit with a useful status code.
Example output:
{{{
✅ master all required CI OK
✅ 3.6 all required CI OK
🔄 3.5 previous OK, new run in progress
❌ 3.4 2 failures
Failures:
3.4 / GitHub Actions / FreeBSD
status: failure
url: https://github.com/postgis/postgis/actions/runs/...
3.4 / Jenkins / bessie32
status: failure
url: https://debbie.postgis.net/...
}}}
Use colored Unicode on terminals that support it. Use plain text when
output is not a TTY or when color is disabled.
Suggested symbols:
* ✅ success
* ❌ failure
* 🔄 in progress
* ⚠️ unknown, stale, or unavailable
* ➖ not applicable / disabled
The exact glyphs are not critical, but they should be readable and not
rely on color alone.
== Outputs ==
The script should support two output modes:
{{{
terminal
html
}}}
Terminal is the default.
Examples:
{{{
python3 utils/ci-status.py
python3 utils/ci-status.py html
}}}
`html` should generate a static page and a machine-readable JSON data file
into an output directory. These generated files should not be checked into
the PostGIS source tree.
Example:
{{{
python3 utils/ci-status.py html --output-dir /var/www/postgis/ci
}}}
This should create something like:
{{{
/var/www/postgis/ci/index.html
/var/www/postgis/ci/status.json
}}}
Avoid a large argument surface. Optional flags are fine for debugging and
deployment, but the normal user should not need them.
Reasonable optional flags:
{{{
--branch BRANCH
--output-dir DIR
--json
--no-color
--verbose
}}}
Do not make users choose provider names, job names, workflow IDs, or
version lists in normal use.
== Branch selection ==
By default, check all configured non-EOL PostGIS versions.
The list of non-EOL versions should live in the repository configuration,
not in Trac.
Example configuration concept:
{{{
{
"branches": [
{ "name": "master", "label": "master", "eol": false },
{ "name": "stable-3.6", "label": "3.6", "eol": false },
{ "name": "stable-3.5", "label": "3.5", "eol": false },
{ "name": "stable-3.4", "label": "3.4", "eol": false },
{ "name": "stable-3.3", "label": "3.3", "eol": true }
]
}
}}}
EOL branches may be shown only with an explicit option later. They should
not appear in the default answer.
== In-progress behavior ==
In-progress jobs should not make the default view useless.
If a new CI run is in progress and the previous completed run was green,
show:
{{{
🔄 3.5 previous OK, new run in progress
}}}
If a new CI run is in progress and the previous completed run failed,
show:
{{{
🔄 3.5 previous failed, new run in progress
}}}
If no previous completed result is known, show:
{{{
🔄 3.5 in progress, no previous result known
}}}
This means the status model needs to keep both:
* current state;
* previous completed state, when available.
For example:
{{{
{
"current": {
"status": "in_progress",
"url": "https://..."
},
"previous_completed": {
"status": "success",
"revision": "abc123",
"url": "https://..."
}
}
}}}
The aggregate branch status should prefer current failures. But a purely
running branch should be displayed as in progress with previous known
state, not as a scary failure.
== HTML page behavior ==
The HTML page should be compact by default.
Top-level view:
{{{
PostGIS CI status
✅ master
✅ 3.6
🔄 3.5 previous OK, new run in progress
❌ 3.4 2 failures
}}}
Detailed rows should be visible for:
* failed checks;
* unknown checks;
* stale checks;
* in-progress checks;
* optionally all checks after expanding a section.
The page should not default to a huge matrix of every CI job for every
branch. That makes the common case worse.
The common case is:
{{{
Everything is fine. Go back to work.
}}}
When something is not fine, the page should immediately show where to
click.
For every failed, stale, unknown, or in-progress check, include:
* branch;
* check name;
* status;
* previous completed status if applicable;
* tested revision if known;
* target revision if known;
* age or completion time;
* direct link to the CI run or job.
The page should be static. It should not use iframes and should not make
browser-side requests to GitHub, Woodpecker, Jenkins, or badge URLs.
A cron job can regenerate the page periodically.
== Local vs published use ==
The same script should be usable locally and for publishing.
Local:
{{{
python3 utils/ci-status.py
}}}
Publish:
{{{
python3 utils/ci-status.py html --output-dir /var/www/postgis/ci
}}}
The publishing job should run from cron or an existing trusted CI host
such as debbie.
It should take a snapshot and exit. It should not wait for all CI jobs to
finish.
A failed CI status must not make page generation fail. Red CI is valid
page content.
Generation should use temporary files and atomic replacement so the
website is never left half-written.
== Providers ==
The initial implementation should support the currently relevant PostGIS
CI sources:
* GitHub Actions;
* Woodpecker;
* Jenkins.
The script should query native JSON APIs where possible.
It must not parse SVG badge images.
Existing legacy CI entries should be handled explicitly:
* supported;
* disabled with reason;
* retired with reason;
* unsupported with follow-up ticket.
Do not silently drop a current CI entry.
== GitHub Actions ==
Support configured workflows from `.github/workflows/`.
For each configured workflow and branch:
* find the current run for the branch head when possible;
* detect running, success, failure, cancelled, skipped, missing, and stale
states;
* include a link to the workflow run;
* include the tested commit SHA when available.
GitHub token use should be optional locally, but documented for cron to
avoid rate limits.
== Woodpecker ==
Support the Woodpecker API for `postgis/postgis`.
For each branch:
* find the relevant latest pipeline;
* detect success, failure, running, pending, blocked, killed, cancelled,
and unknown states;
* include a link to the pipeline;
* include the tested commit SHA when available.
== Jenkins ==
Jenkins jobs are irregular, so Jenkins job URLs and branch matching rules
should be explicit in config.
Support:
* direct job API URLs;
* branch/version substitutions;
* build parameters where needed;
* finding the newest matching build from recent builds;
* detecting building, success, failure, unstable, aborted, missing, and
unknown states.
Jenkins badge images must not be used as the status source.
== Status model ==
Each check should normalize to:
* success
* failure
* in_progress
* unknown
* stale
* disabled
* not_applicable
Each check may also have:
* previous_completed_status;
* previous_completed_url;
* previous_completed_revision;
* message;
* debug URL.
Overall branch status:
* failure if any required current check failed;
* unknown if any required check is unknown or stale;
* in_progress if no current required check failed or is unknown, but at
least one is running;
* success if all required checks are currently successful;
* disabled and informational checks do not affect aggregate status.
The terminal and HTML output should show previous completed status for in-
progress checks.
== Exit codes ==
For default terminal mode:
* 0: all required checks for all non-EOL branches are OK;
* 1: at least one required check failed;
* 2: no failure is known, but some required check is in progress, stale,
or unknown;
* another non-zero code: invalid configuration or script error.
For HTML generation:
* 0: page generated successfully;
* non-zero: page generation failed.
A failed CI run should not make HTML generation return non-zero.
== Configuration ==
Add one repository-owned JSON config file.
It should define:
* non-EOL branches;
* checks;
* providers;
* whether each check is required;
* branch applicability;
* provider URLs and workflow/job identifiers;
* disabled or retired checks with reasons.
The config should be the source of truth for CI inventory.
Do not keep a separate maintained CI matrix in Trac.
== Implementation notes ==
Keep the implementation boring.
Preferred constraints:
* Python 3 standard library only;
* no runtime dependency on requests, PyYAML, Jinja, or pytest;
* no daemon;
* no database;
* no committed generated status files;
* no browser-side API calls;
* no iframe dashboard;
* no badge image parsing.
It is fine for the script to be a single readable file.
The generated HTML can be assembled with simple string templates and
proper HTML escaping.
The generated JSON should be deterministic enough for other scripts to
consume.
== Documentation ==
Document briefly in comments or a small README section:
* how to run locally;
* how to generate HTML locally;
* how cron can publish the page;
* how to add a new CI check;
* how to retire an old CI check;
* how to mark a branch EOL.
Update README and release documentation to point to the new page.
After deployment, the Trac ContinuousIntegration page should become a
short pointer to:
{{{
https://postgis.net/ci/
}}}
It should not remain a second manually maintained CI matrix.
== Acceptance criteria ==
* `python3 utils/ci-status.py` with no arguments shows all non-EOL branch
statuses.
* The default terminal output is compact and uses colored Unicode when
possible.
* Failures include direct links to the relevant CI runs or jobs.
* In-progress checks include previous completed status when available.
* `python3 utils/ci-status.py html --output-dir DIR` generates
`index.html` and `status.json` in `DIR`.
* Generated HTML and JSON are not committed to the repository.
* The HTML page is a compact static dashboard.
* The HTML page is not a huge default matrix.
* The HTML page shows detailed rows only for failures, unknowns, stale
checks, and in-progress checks, or behind expansion.
* The script does not parse badge images.
* The script does not use iframes.
* The script does not require browser-side API calls.
* The script can be run from cron to publish `postgis.net/ci`.
* Failed CI does not prevent publishing the red status page.
* The CI inventory lives in the repository, not in Trac.
* Runtime uses Python standard library only.
== Non-goals ==
This ticket does not need to implement:
* a live web service;
* a full incident management system;
* historical uptime charts;
* time-lapse videos;
* notifications;
* automatic reruns;
* waiting for all CI to finish;
* a test suite for the helper script.
A later ticket can add history by saving periodic snapshots.
--
Ticket URL: <https://trac.osgeo.org/postgis/ticket/6087>
PostGIS <http://trac.osgeo.org/postgis/>
The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project.
More information about the postgis-tickets
mailing list