Skip to content

Latest commit

Β 

History

History
339 lines (234 loc) Β· 8.75 KB

File metadata and controls

339 lines (234 loc) Β· 8.75 KB

Markdown Progress

CI Deploy Smoke Tests

Progress bars for markdown.

Have you ever wanted to track some progress in your markdown documents? Well, I do, and I used progressed.io before but it was shut down.

So I decided to recreate it.

πŸš€ Usage

![](https://geps.dev/progress/10)

Note

I'll try to keep this domain name up as much as possible, so wish me a long life πŸ™‚

✨ Examples

Tip

Every snippet below is ready to paste into GitHub Markdown.

1) Integer percentage

Note

![](https://geps.dev/progress/10)

2) Float percentage

Note

![](https://geps.dev/progress/76.5)

3) Automatic clamping (>100)

Note

![](https://geps.dev/progress/150)

4) Automatic clamping (<0)

Note

![](https://geps.dev/progress/-10)

5) Custom threshold colors (dangerColor, warningColor, successColor)

Note

![](https://geps.dev/progress/50?dangerColor=800000&warningColor=ff9900&successColor=006600)

6) Fixed bar color (barColor)

Note

![](https://geps.dev/progress/50?barColor=4472C4)

7) Data-bar mode (min + max + label + barColor)

Note

![](https://geps.dev/progress/186?label=186&min=0&max=241&barColor=4472C4)

8) Data-bar mode with default label (raw value)

Note

![](https://geps.dev/progress/50?min=0&max=200)

9) Custom text label in percentage mode

Note

![](https://geps.dev/progress/70?label=Sprint%201)

πŸ“œ API Contract

Endpoint

  • GET /progress/{percentage}
  • HEAD /progress/{percentage}

percentage can be an integer or float and is clamped to 0..100.

Query params

  • dangerColor
  • warningColor
  • successColor
  • barColor (overrides the bar fill color)
  • label (custom text inside the bar, max 64 chars)
  • min
  • max

All color values must be 6-character hex values without # (example: ff9900). min and max must be provided together when used.

Response behavior

  • 200 OK: valid request, returns SVG.
  • 400 Bad Request: invalid numeric input, range config, label length, or color format.
  • 405 Method Not Allowed: any method different from GET or HEAD.
  • 500 Internal Server Error: template parse/render failure.

Headers for successful responses:

  • Content-Type: image/svg+xml
  • Cache-Control: public, max-age=300

Tip

percentage values outside 0..100 are accepted and clamped automatically.

πŸ› οΈ Local Development

Prerequisites

  • mise installed

Setup

mise install
mise exec -- make setup

Run locally:

mise exec -- make run

Try it in a browser:

http://localhost:8080/progress/76

Quality checks

mise exec -- make test
mise exec -- make vet
mise exec -- make check

Smoke tests against deployed URL

BASE_URL=https://geps.dev mise exec -- make smoke

The smoke test validates status codes, headers, and basic content contract.

Tip

If your BASE_URL already includes the function path (example: https://REGION-PROJECT.cloudfunctions.net/progress), keep PROGRESS_PATH empty.

If your BASE_URL already includes the function path (for example https://REGION-PROJECT.cloudfunctions.net/progress), set:

BASE_URL=https://REGION-PROJECT.cloudfunctions.net/progress PROGRESS_PATH="" mise exec -- make smoke

☁️ Deploy (Google Cloud)

Set your project first:

gcloud auth login
gcloud config set project THE_PROJECT_NAME

Deploy as an HTTP function with Progress as entrypoint:

gcloud functions deploy progress --gen2 --runtime go125 --entry-point Progress --trigger-http --allow-unauthenticated --region us-central1

After deploy, run smoke tests:

BASE_URL=https://YOUR_DOMAIN_OR_FUNCTION_URL mise exec -- make smoke

Important

This endpoint is intentionally public (allUsers invoker) so it can be used directly from markdown image links across repos.

πŸ€– Automated Deploy (GitHub Actions -> GCP)

This repo includes .github/workflows/deploy.yml to deploy automatically on push to master (and manually via workflow_dispatch).

1) πŸ” Configure GitHub repository variables

Required:

  • GCP_PROJECT_ID (example: progress-markdown)
  • GCP_WORKLOAD_IDENTITY_PROVIDER (full resource name)
  • GCP_SERVICE_ACCOUNT (deployer service account email)

Optional (defaults are already set in workflow):

  • GCP_REGION (us-central1)
  • GCP_FUNCTION_NAME (progress)
  • GCP_RUNTIME (go125)
  • GCP_ENTRY_POINT (Progress)

2) 🧩 One-time GCP setup (OIDC/WIF, no JSON keys)

Create deployer service account:

gcloud iam service-accounts create github-deployer \
  --display-name "GitHub deployer for markdown-progress"

Grant deploy permissions on project:

PROJECT_ID=progress-markdown
PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')
SA="github-deployer@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:${SA}" \
  --role="roles/cloudfunctions.developer"

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:${SA}" \
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:${SA}" \
  --role="roles/artifactregistry.writer"

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:${SA}" \
  --role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:${SA}" \
  --role="roles/iam.serviceAccountUser"

Create Workload Identity Pool + Provider:

PROJECT_ID=progress-markdown
PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')
POOL_ID=github
PROVIDER_ID=github-oidc

gcloud iam workload-identity-pools create "$POOL_ID" \
  --project="$PROJECT_ID" \
  --location="global" \
  --display-name="GitHub Actions Pool"

gcloud iam workload-identity-pools providers create-oidc "$PROVIDER_ID" \
  --project="$PROJECT_ID" \
  --location="global" \
  --workload-identity-pool="$POOL_ID" \
  --display-name="GitHub Actions Provider" \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.ref=assertion.ref"

Allow only this repository to impersonate the deployer service account:

PROJECT_ID=progress-markdown
PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')
POOL_ID=github
REPO="gepser/markdown-progress"
SA="github-deployer@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts add-iam-policy-binding "$SA" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}/attribute.repository/${REPO}"

Provider resource name to set in GitHub variable:

projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID

βœ… CI

  • CI workflow runs go test and go vet on pushes and PRs.
  • Smoke Tests workflow can be run manually (workflow_dispatch) with a base_url input.
  • Deploy workflow deploys to GCP on master using OIDC/WIF.

πŸ“¦ Dependency Policy

  • Dependabot is enabled for gomod and github-actions on a weekly schedule.
  • Merge dependency PRs only after CI is green.
  • If a dependency PR fails CI, either patch on top of that branch or close and open a follow-up PR from master.

🀝 Contributing

See CONTRIBUTING.md.