ProGroup CI
Log in to Gitea

Developer Quickstart

Your repositories are moving from GitHub to our self-hosted Gitea instance at git.progroupco.com. This guide gets you set up in under 10 minutes.

HTTPS token auth Entra ID SSO AI-powered CI Docker registry

0 What's Different

🌐

URL

From github.com to git.progroupco.com

All repos
🏢

Organization

All repos live under ProGroup CI (slug: ci)

Shared secrets
🔑

Authentication

HTTPS tokens (not SSH keys). Entra ID SSO for the web UI.

Token-based
⚡

CI / CD

Gitea Actions — same YAML syntax as GitHub Actions. AI workflows included.

Drop-in compatible
SSH is not exposed. All Git operations use HTTPS with a personal access token. This is a deliberate security decision — tokens are scope-limited and individually revocable, unlike SSH keys which grant full repo access. The .gitea/workflows/ YAML files are fully compatible with GitHub Actions syntax.

1 Web Login

  1. Go to https://git.progroupco.com
  2. Click "Sign in with entra" (Microsoft SSO)
  3. Authenticate with your ProGroup Entra credentials (MFA handled by Entra)
What happens on first login? Gitea auto-links your Entra account by email address to a pre-provisioned account. If no account exists yet, one is created automatically. Your admin privileges (if any) carry over — nothing to configure.
Entra SSO is for the web UI only. Git clone/push does not use Entra — it uses a separate Gitea access token (Step 2). Your Entra password will not work for git push.

2 Create a Personal Access Token

Git clone/push via HTTPS uses a Gitea access token (separate from your Entra credentials). Treat it like a password.

  1. Go to Settings → Applications → Access Tokens (top-right avatar → Settings)
  2. Click Generate New Token
  3. Name it (e.g., git-push)
  4. Select scope: read:repository + write:repository
  5. Copy the token immediately (shown only once)
Token permissions are scope-based, not repo-based. read:repository lets you clone/fetch from any repo you can see. write:repository lets you push to any repo where you have write access. This pair is the minimum for normal development. Never share your personal token in CI configs — use the org-level secrets described in Secrets.

3 Configure Git Credential Caching

So you only enter the token once per machine, configure Git to remember your credentials:

bash
# Option A: Store permanently (creates ~/.git-credentials):
git config --global credential.helper store

# Option B: Cache in memory for 1 hour (more secure):
git config --global credential.helper 'cache --timeout=3600'

Git for Windows includes Git Credential Manager (GCM), which stores credentials in the Windows Credential Store automatically:

powershell
# GCM is the default in Git for Windows. If it's not active, enable it:
git config --global credential.helper manager

# If you need the older wincred helper:
git config --global credential.helper wincred
Windows Credential Manager GUI: Open Control Panel → Credential Manager → Windows Credentials to view, edit, or delete stored Git credentials at any time. Look for entries starting with git:.

4 Clone Your Repo

All company repos live under the ProGroup CI organization (URL slug: ci). Replace your-repo with your actual repository name.

bash
git clone https://git.progroupco.com/ci/your-repo.git
cd your-repo
# Username: lowercase part of your email before the @ (e.g., mchildress)
# Password: paste the token from Step 2
powershell
git clone https://git.progroupco.com/ci/your-repo.git
cd your-repo
# If using Git Credential Manager, a popup appears:
#   Username: lowercase part of your email before the @
#   Password: paste the token from Step 2
Repo not on Gitea yet? If your repo is still on GitHub, ask your admin to run the migration script — it copies Git history and overlays CI workflows automatically. See Creating a New Repo below.

5 Update Existing Local Clones

If you already have a local clone pointing at GitHub, repoint it to Gitea:

bash
cd ~/projects/your-repo
git remote set-url origin https://git.progroupco.com/ci/your-repo.git
git fetch origin
git branch --set-upstream-to=origin/main main
# If your default branch is 'master':
# git branch --set-upstream-to=origin/master master
powershell
cd C:\Users\you\projects\your-repo
git remote set-url origin https://git.progroupco.com/ci/your-repo.git
git fetch origin
git branch --set-upstream-to=origin/main main
# If your default branch is 'master':
# git branch --set-upstream-to=origin/master master

Branch Naming (Critical)

Push-triggered workflows only fire on feature/** and chore/** branches. Pushing to fix-bug, wip, or any other prefix gets no CI at all — no lint fixes, no test generation, no Docker builds. PR-triggered workflows (review, coverage, pr-summary) fire on any PR regardless of branch name.
Branch patternWhat fires on pushWhat fires on PR
feature/**lint-fix, generate-tests, api-docs, build-docker, reviewAll PR workflows
chore/**lint-fix, generate-tests, api-docs, build-dockerAll PR workflows
main / masterbuild-docker (tags :latest)—
v* tagchangelog—
anything elsenothingAll PR workflows
bash
# Correct: prefix with feature/ or chore/
git checkout -b feature/add-login
git checkout -b chore/update-deps

# Wrong: no prefix — CI will NOT run on push
git checkout -b fix-bug         # no CI
git checkout -b my-experiment   # no CI

Your First Pull Request

How a typical feature goes from branch to merged PR:

  1. Branch: git checkout -b feature/your-feature from main
  2. Commit & push: git push origin feature/your-feature — this triggers lint-fix and generate-tests on the branch. If lint fixes are needed, the bot auto-commits them.
  3. Open a PR in the Gitea UI (repo → Pull Requests → New). Target main as the base.
  4. Wait ~1–2 minutes. The following fire automatically on the PR:
    • review AI posts a structured code review comment with severity tags
    • coverage Diff coverage report posted as a comment
    • pr-summary Human-readable summary of what the PR does
    • commit-message Suggested conventional commit message
    • labeler Labels applied based on changed file paths
  5. Address any high-severity findings from the review — these fail the check and block merge. Push fixes to the same branch; the review re-runs on synchronize.
  6. Merge when the check is green. On merge (push to main), build-docker fires and tags :latest if the repo has a Dockerfile.
Bot commits carry [skip ci]. The auto-generated tests and lint fixes won't re-trigger CI loops — the actor check plus the skip flag prevents infinite runs.

Troubleshooting

SymptomWhere to checkLikely fix
CI didn't run on my pushBranch nameUse feature/** or chore/** — see Branch Naming
401 on git pushToken scopeRegenerate token with write:repository scope; clear cached creds (see FAQ)
Review says high severityPR review commentFix the flagged lines, push to the same branch — review re-runs on synchronize
Bot didn't commit testsActions tab → generate-tests run logCheck scan_mode — diff only scans changed files; all scans the whole repo
Workflow not in Actions tabBranch the workflow was pushed toWorkflows only activate from the default branch (main) — push the YAML there first
Docker build failedActions tab → build-docker run logCheck Kaniko error; if AI-generated Dockerfile is wrong, edit it and re-push
PR has no review commentActions tab → review run statusIf the run failed, check the log for API key errors; review only posts on success

Creating a New Repository

Always create repos under the ProGroup CI organization (slug: ci), not under your personal account. Repos under ci automatically inherit the shared CI secrets (NEURALWATT_API_KEY, REVIEW_TOKEN, BOT_TOKEN, PACKAGES_TOKEN). Personal repos will fail silently — workflows that depend on these secrets won't find them.
  1. Go to https://git.progroupco.com/ci
  2. Click New Repository (top-right of the org page)
  3. Set the name and visibility (Private recommended)
  4. Check "Use template" → select ci/ci-template — copies the full CI workflow set (workflows, scripts, prompts) into your new repo automatically
  5. Click Create Repository
  6. Clone it as described in Step 4

Migrating an existing repo from GitHub

Ask your admin to run the migration script, which:

  1. Migrates Git history (no issues/PRs/wiki — those stay on GitHub)
  2. Overlays .gitea/ from ci/ci-template (workflows + scripts)
  3. Commits + pushes the CI template files
  4. Triggers an initial code review + test generation

Or migrate manually:

bash
# Clone from GitHub (bare — preserves all branches + tags)
git clone --mirror https://github.com/yourorg/your-repo.git
cd your-repo.git

# Push everything to Gitea
git push --mirror https://git.progroupco.com/ci/your-repo.git

# Then overlay .gitea/ from ci/ci-template (ask admin)

Secrets

Org-level secrets (managed by admin)

These are set at the ProGroup CI organization level and inherited by every repo under ci/. They're injected into workflow jobs automatically — no per-repo configuration needed.

SecretAPI ScopeUsed ByWhat It Does
NEURALWATT_API_KEY LLM provider review, generate-tests, docs, api-docs, changelog, pr-summary, commit-message, secure-scan, build-docker API key for the neuralwatt/glm-5.2 model used by all AI workflows
REVIEW_TOKEN write:issue review, coverage, pr-summary, commit-message, labeler, stale, secure-scan Posts PR comments, applies labels, manages stale issues
BOT_TOKEN write:repository generate-tests, lint-fix, docs, api-docs, build-docker, changelog, dep-update Pushes auto-generated commits (tests, docs, Dockerfiles, dep bumps)
PACKAGES_TOKEN write:package build-docker Pushes built Docker images to the Gitea container registry
You don't manage these. They're minted by the admin during stack setup and rotated centrally. Gitea masks secret values in logs — they appear as *** in action run output.

Repo-level secrets (when you need your own)

If a workflow needs a secret specific to your repo (e.g., a third-party API key, a deployment token):

  1. Go to your repo → Settings → Actions → Secrets
  2. Click Add Secret
  3. Name it (uppercase, underscores: e.g., DEPLOY_TOKEN)
  4. Paste the value, click Add Secret

Repo-level secrets override org-level secrets with the same name. Reference them in workflow YAML with ${{ secrets.YOUR_SECRET }}.

Never commit secret values to the repo — even in .env files. Gitea only injects secret values into CI job environments; they are not visible in the repo, PRs, or the web UI after creation.

Workflows

All workflows live in .gitea/workflows/ and are included automatically when your repo is created from the CI template.

On your first PR: expect a review comment, coverage report, PR summary, commit-message suggestion, and labels within ~1–2 minutes of opening. Push-triggered workflows (lint-fix, generate-tests) run on the branch before the PR is even opened. See Your First PR for a full walkthrough.

🟦 Pull Request Workflows

These fire when a PR is opened or updated:

AI Code Review
review.yaml

AI code review on the diff. Posts a structured comment with severity-tagged findings. Fails the run on high-severity issues. Also fires on pushes to feature/**.

→ PR comment

Test Generation
generate-tests.yaml

Detects source files without tests, generates pytest/jest/vitest tests via AI, runs them, and commits passing tests back to your branch.

→ New commits on the branch + Actions tab

Coverage Report
coverage.yaml

Computes diff coverage (which changed lines lack test coverage) and posts a comment with uncovered file:line ranges.

→ PR comment

PR Summary
pr-summary.yaml

Generates a human-readable summary of what the PR does (for reviewers).

→ PR comment

Commit Message Suggester
commit-message.yaml

Suggests a conventional commit message based on the PR diff.

→ PR comment

Auto-Labeler
labeler.yaml

Auto-labels PRs based on changed file paths. Configure rules in .gitea/labeler.yml.

→ PR labels

🟩 Push Workflows

These fire on pushes to feature/** or chore/** branches:

Lint & Format Fix
lint-fix.yaml

Runs ruff (Python), prettier (JS/TS), gofmt (Go) on changed files. Auto-commits formatting fixes if needed.

→ New commits on the branch

Docker Build
build-docker.yaml

Builds a Docker image and pushes it to the Gitea container registry. If no Dockerfile exists, AI generates one and opens a PR. On main/master, also tags :latest.

→ PR (if Dockerfile generated) + docker pull git.progroupco.com/ci/your-repo:<sha>

API Docs Generation
api-docs.yaml

Generates API documentation from source code analysis.

→ Commits on docs/auto-update branch + PR

Project Docs
docs.yaml

Generates/updates general project documentation (README, usage docs) from source. Manual dispatch only.

→ Commits on docs/auto-update branch + PR

🟨 Scheduled Workflows

Stale Cleanup
stale.yaml Daily 05:00 UTC

Marks PRs and issues with no activity for 30+ days as stale, closes them after 7 more days of inactivity.

→ Stale label on PRs/issues + Actions tab

Dependency Bumper
dep-update.yaml Daily 06:00 UTC

Bumps dependency versions in your manifest files (package.json, requirements.txt, go.mod, etc.) and opens a PR.

→ PR on dep/auto-update branch

Security Scan
secure-scan.yaml Weekly Mon 04:00 UTC

Scans the repo for exposed secrets, hardcoded credentials, and security anti-patterns using AI. Fails on high-severity findings.

→ Actions tab (summary with findings)

🟪 Tag-Triggered Workflows

Changelog Generator
changelog.yaml on v* tag push

Generates a CHANGELOG.md section from git log entries since the last tag. Commits to a changelog/auto-update branch and opens a PR.

→ PR on changelog/auto-update branch

Manually Triggering a Workflow

Many workflows can be triggered manually from the Gitea UI:

  1. Go to your repo → Actions tab
  2. Click the workflow name (e.g., opencode-review)
  3. Click Run Workflow (top-right of the run list)
  4. Select the branch and fill in any inputs
  5. Click Run

Dispatch Inputs Reference

WorkflowInputTypeDescription
reviewscan_modeselect: all / diffall reviews the entire repo; diff reviews changed files only
generate-testsscan_modeselect: all / diffall scans entire repo for untested files; diff scans changed files only
lint-fixscan_modeselect: all / diffall formats every tracked source file; diff formats changed files only
secure-scanfail_on_highboolean (default: true)If true, the run fails on high-severity findings
dep-updatemanifeststringSpecific manifest path to bump (default: all)
dep-updateallow_majorboolean (default: false)If true, bumps major versions (breaking changes allowed)
changelogversionstringVersion label for the changelog section (e.g., 1.2.0)
build-dockerdockerfile_pathstring (default: Dockerfile)Path to an existing Dockerfile (skip generation)
build-dockerimage_namestringCustom image name (defaults to repo name)
commit-messagepr_numberinteger (required)PR number to suggest a commit message for
coveragepr_numberinteger (required)PR number to compute coverage for
pr-summarypr_numberinteger (required)PR number to summarize
labelerpr_numberinteger (required)PR number to label
docs——No inputs (runs against the current branch)
stale——No inputs (runs a stale check sweep)
api-docs——No inputs (runs against the current branch)

Checking Workflow Results

💬

PR Comments

review, coverage, pr-summary, commit-message posts as comments

🏷️

PR Labels

labeler applies labels to the PR

📝

Auto-Commits

generate-tests, lint-fix push commits to your branch

🔀

Auto-PRs

docs, api-docs, changelog, dep-update, build-docker open PRs

FAQ

What happens on my first Entra login? ▶

When you click "Sign in with entra" for the first time, Gitea looks up your email from the Entra ID token. If an account was pre-provisioned for you (admins were created ahead of time), Gitea links your Entra identity to it — your existing permissions carry over automatically. If no account exists, Gitea creates one with default (non-admin) privileges.

After the first login, subsequent logins are instant — no re-linking needed.

Can I still use SSH? ▶

No — SSH (port 2222) is not exposed externally. All Git operations use HTTPS. Your token replaces the SSH key. This is a deliberate security decision — HTTPS tokens are scope-limited and individually revocable, unlike SSH keys which grant full repo access.

What about Git LFS? ▶

LFS is supported. Push as normal — Caddy accepts up to 512MB per request.

My push was rejected with 401 (authentication failed) ▶

Your token may have expired or lacks write:repository scope. Generate a new one (Step 2) and clear the cached credentials:

Linux / macOS

bash
# If using credential.helper store:
rm ~/.git-credentials

# Or clear the cache:
git credential reject <<EOF
protocol=https
host=git.progroupco.com
EOF

Windows

powershell
# Delete the stored credential via Credential Manager:
cmdkey /delete:git:https://git.progroupco.com

# Or open the GUI:
# Control Panel → Credential Manager → Windows Credentials
# Find "git:https://git.progroupco.com" → Remove

Next git push will prompt for username + new token.

How do I create a new repo? ▶

Go to https://git.progroupco.com/ci → New Repository. Always create repos under the ProGroup CI org (slug: ci) so they inherit the shared CI secrets. If you create a repo under your personal account, org-level secrets resolve to empty strings — workflows that depend on them will print an explicit error in the Actions tab and skip the affected step.

Tip: Check "Use template" → select ci/ci-template to copy the full CI workflow set into your new repo automatically.

Where are the CI secrets stored? ▶

At the ProGroup CI organization level (ci org → Settings → Actions → Secrets). The four org-level secrets (NEURALWATT_API_KEY, REVIEW_TOKEN, BOT_TOKEN, PACKAGES_TOKEN) are managed by the admin. They're injected into every workflow job in every repo under ci/ automatically.

For repo-specific secrets (e.g., a third-party deploy token), add them under your repo → Settings → Actions → Secrets.

Do I need to install anything locally? ▶

Linux: git (pre-installed on most distros). Optionally python3 and pytest if you want to run tests locally.

Windows: Git for Windows — includes Git, Git Bash, and Git Credential Manager. Optionally Python 3 for running tests locally.

The bot keeps committing to my branch — is that normal? ▶

Yes. Automated commits are authored by the opencode-bot user and carry [skip ci] in the commit message. Workflows also check gitea.actor != 'opencode-bot' so the bot's own pushes never re-trigger CI. You'll never see an infinite loop.

Workflows that auto-commit: generate-tests (adds test files), lint-fix (formats code), and dep-update (bumps dependencies on a PR branch).

How do I add a new CI workflow? ▶

Create a .gitea/workflows/your-workflow.yaml file in your repo. The syntax is the same as GitHub Actions. Use the existing workflows as examples. Once pushed to the default branch, the workflow is active.

Need Help?

📚

Operator Docs

.gitea/stack/README.md in the ci/ci-template repo

🆘

Admin Contact

Contact your infrastructure team