652 lines
21 KiB
Markdown
652 lines
21 KiB
Markdown
---
|
|
name: gitea-transfer
|
|
description: Guide for transferring repositories from GitHub to self-hosted Gitea, including remotes, branches, PR migration, Gitea Actions porting, runner images, and cutover verification.
|
|
---
|
|
|
|
# Gitea Transfer
|
|
|
|
## When To Use
|
|
|
|
Use this skill when moving a repository from GitHub to self-hosted Gitea, converting a Gitea mirror into the canonical source repo, migrating active branches and pull requests, porting GitHub Actions to Gitea Actions, or designing runner job images for CI.
|
|
|
|
## Operating Principles
|
|
|
|
- Treat Gitea as canonical only after confirming the repo is no longer a mirror and the default branch is pushed.
|
|
- Keep the GitHub remote as a recovery/reference remote unless the user explicitly asks to remove it.
|
|
- Prefer `tea` or the Gitea API for Gitea repository, pull request, Actions, and runner operations.
|
|
- Do not use `gh` for Gitea work.
|
|
- Do not paste, log, commit, or store registration tokens, API tokens, deploy keys, or package credentials.
|
|
- Avoid Gitea Actions secret names beginning with `GITEA_` or `GITHUB_`; those prefixes are reserved or confusing in Gitea/GitHub-compatible runners.
|
|
- Do not modify ignored local config files such as `bunfig.toml` unless the user explicitly requests it.
|
|
- Do not merge pull requests unless the user explicitly approves the merge.
|
|
- Do not force-push or rewrite shared branches unless the user explicitly approves it.
|
|
- Verify every cutover step with API or git status output before moving on.
|
|
|
|
## Preflight Checks
|
|
|
|
Confirm local state and remotes:
|
|
|
|
```bash
|
|
git status --short --branch
|
|
git remote -v
|
|
git branch --show-current
|
|
```
|
|
|
|
Confirm the Gitea CLI is authenticated and targeting the expected instance:
|
|
|
|
```bash
|
|
tea login list
|
|
tea repo ls
|
|
```
|
|
|
|
Confirm the Gitea repository exists and inspect settings:
|
|
|
|
```bash
|
|
tea api repos/{owner}/{repo}
|
|
```
|
|
|
|
If Gitea is behind Nginx or another reverse proxy, verify dot directories are reachable. A common Forge/Nginx rule blocks paths such as `.github`, `.gitea`, `.codex`, and `.well-known`:
|
|
|
|
```nginx
|
|
location ~ /\.(?!well-known).* {
|
|
deny all;
|
|
}
|
|
```
|
|
|
|
For Gitea, that rule can break UI/API access to workflow files and agent config paths. Update the reverse proxy deliberately rather than working around it in git.
|
|
|
|
## Convert Mirror To Source
|
|
|
|
If the Gitea repository was imported as a mirror, convert it to a normal source repository before cutover. Use the Gitea UI or API, then verify:
|
|
|
|
```bash
|
|
tea api repos/{owner}/{repo}
|
|
```
|
|
|
|
Check that `mirror` is `false` and the expected default branch is set.
|
|
|
|
Enable repository features as needed:
|
|
|
|
```bash
|
|
tea api --method PATCH repos/{owner}/{repo} \
|
|
--field has_pull_requests=true \
|
|
--field has_actions=true
|
|
```
|
|
|
|
Use the actual supported fields for the installed Gitea version. Re-read the repository after patching.
|
|
|
|
## Remote Cutover
|
|
|
|
Keep GitHub as a named fallback remote and make Gitea `origin`:
|
|
|
|
```bash
|
|
git remote rename origin github
|
|
git remote add origin ssh://git@git.example.com:30009/{owner}/{repo}.git
|
|
git remote -v
|
|
```
|
|
|
|
If `origin` already points elsewhere, adjust non-destructively:
|
|
|
|
```bash
|
|
git remote set-url origin ssh://git@git.example.com:30009/{owner}/{repo}.git
|
|
git remote add github git@github.com:{owner-or-org}/{repo}.git
|
|
```
|
|
|
|
Push the default branch first:
|
|
|
|
```bash
|
|
git fetch github --prune
|
|
git push origin {default-branch}:{default-branch}
|
|
```
|
|
|
|
Verify Gitea sees the branch:
|
|
|
|
```bash
|
|
tea api repos/{owner}/{repo}/branches/{default-branch}
|
|
```
|
|
|
|
## Branch Migration
|
|
|
|
List active GitHub branches that need to move:
|
|
|
|
```bash
|
|
git branch -r
|
|
```
|
|
|
|
Push only active work branches, not every stale remote branch by default:
|
|
|
|
```bash
|
|
git push origin github/{branch-name}:refs/heads/{branch-name}
|
|
```
|
|
|
|
For multiple open PR heads, script carefully from reviewed data. Avoid pushing deleted/stale branches blindly.
|
|
|
|
Verify pushed branches:
|
|
|
|
```bash
|
|
tea api repos/{owner}/{repo}/branches
|
|
```
|
|
|
|
## Pull Request Migration
|
|
|
|
Gitea does not automatically migrate all GitHub PR review history during a basic repo transfer. Recreate open PRs with enough context to continue work:
|
|
|
|
- title
|
|
- body
|
|
- base branch
|
|
- head branch
|
|
- draft/WIP state in title or body if Gitea draft support is not available
|
|
- link back to the original GitHub PR
|
|
|
|
Use the Gitea API or `tea`:
|
|
|
|
```bash
|
|
tea pr create \
|
|
--repo {owner}/{repo} \
|
|
--base {base-branch} \
|
|
--head {head-branch} \
|
|
--title "{title}" \
|
|
--description "{body}"
|
|
```
|
|
|
|
After creating each PR, verify it is open, conflict status is correct, and the branch is correct:
|
|
|
|
```bash
|
|
tea pr {index} --repo {owner}/{repo}
|
|
```
|
|
|
|
If comments/reviews matter, add a short migration note to the PR body linking to the original GitHub PR rather than attempting to recreate every review event.
|
|
|
|
## CI Workflow Porting
|
|
|
|
Gitea Actions workflows live in `.gitea/workflows/`. GitHub workflows can remain temporarily in `.github/workflows/` during transition, but do not assume they run on Gitea.
|
|
|
|
Port workflows incrementally:
|
|
|
|
- Start with tests.
|
|
- Then add build/deploy workflows.
|
|
- Keep workflow syntax close to GitHub Actions where Gitea supports it.
|
|
- Validate YAML before pushing.
|
|
- Prefer small commits so each Actions failure identifies one change.
|
|
|
|
Example validation:
|
|
|
|
```bash
|
|
ruby -e "require 'yaml'; YAML.load_file('.gitea/workflows/tests.yml'); puts 'ok'"
|
|
git diff --check
|
|
```
|
|
|
|
Common changes when porting:
|
|
|
|
- Replace GitHub-only secrets with Gitea Actions secrets.
|
|
- Use neutral secret names such as `REGISTRY_USERNAME`, `REGISTRY_TOKEN`, `REVIEW_BOT_TOKEN`, and `OPENCODE_GO_TOKEN`.
|
|
- Remove GitHub Packages auth if the private package dependency is removed or mirrored elsewhere.
|
|
- Replace GitHub-hosted assumptions with Gitea runner/job container assumptions.
|
|
- Ensure `actions/checkout` version works with the installed Gitea Actions runner.
|
|
- Use service hostnames for service containers instead of `127.0.0.1`.
|
|
- Add explicit service readiness checks for databases.
|
|
- Do not rely on `permissions:` for security-sensitive sandboxing in Gitea Actions; some Gitea versions ignore it.
|
|
|
|
For Postgres services, use the service name as the host:
|
|
|
|
```yaml
|
|
services:
|
|
postgres:
|
|
image: postgres:16
|
|
env:
|
|
POSTGRES_DB: app_test
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: password
|
|
|
|
env:
|
|
DB_HOST: postgres
|
|
```
|
|
|
|
Add a readiness loop before running tests:
|
|
|
|
```bash
|
|
until PGPASSWORD=password pg_isready -h postgres -U postgres; do
|
|
sleep 1
|
|
done
|
|
```
|
|
|
|
## Package Registry Cutover
|
|
|
|
Identify GitHub-specific package auth before enabling Gitea CI:
|
|
|
|
- npm/Bun scopes using `npm.pkg.github.com`
|
|
- Composer auth for GitHub-hosted private packages
|
|
- workflow steps writing `.npmrc` or package auth
|
|
- lockfiles referencing private GitHub package tarballs
|
|
|
|
Options:
|
|
|
|
- Remove the dependency if it can be replaced locally.
|
|
- Mirror the package to Gitea Packages.
|
|
- Keep GitHub Packages temporarily and configure Gitea secrets deliberately.
|
|
|
|
Do not leave workflows requiring secrets that no longer exist. If deploy secrets are absent during cutover, prefer a clear skip for deploy-only workflows so the default branch is not red while secrets are being configured.
|
|
|
|
## Runner Image Strategy
|
|
|
|
Prefer job containers over custom runner labels for language/runtime selection.
|
|
|
|
Use shared CI job images when several repositories need the same runtime stack. The current shared image family is:
|
|
|
|
- `git.bayliss.cloud/harry/gitea-ci-runner:php8.2`
|
|
- `git.bayliss.cloud/harry/gitea-ci-runner:php8.3`
|
|
- `git.bayliss.cloud/harry/gitea-ci-runner:php8.4`
|
|
- `git.bayliss.cloud/harry/gitea-ci-runner:php8.5`
|
|
- `git.bayliss.cloud/harry/gitea-ci-runner:latest`
|
|
|
|
`latest` points to PHP `8.5`. Repositories should usually hardcode the PHP tag they require instead of using `latest`, so runtime upgrades are explicit per repository.
|
|
|
|
Good pattern:
|
|
|
|
```yaml
|
|
jobs:
|
|
tests:
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: git.bayliss.cloud/harry/gitea-ci-runner:php8.2
|
|
```
|
|
|
|
Avoid creating labels such as `stratbase-php82` just to pick an image. Labels select eligible runners; job containers select the runtime image. This keeps the runner reusable across repositories.
|
|
|
|
Use an instance-level or organization-level runner with generic labels such as:
|
|
|
|
- `ubuntu-latest`
|
|
- `ubuntu-24.04`
|
|
- `ubuntu-22.04`
|
|
|
|
If runner labels change, the runner usually needs re-registration because `.runner` pins registration details. App UI fields called "Labels Configuration" may refer to Docker metadata, not Gitea runner labels. Verify actual labels through the API:
|
|
|
|
```bash
|
|
tea api admin/actions/runners
|
|
```
|
|
|
|
## Building A CI Job Image
|
|
|
|
Create or update a shared image when workflows need system dependencies that are expensive or brittle to install per run. Prefer a central image repository over per-application image repositories unless the runtime is truly application-specific.
|
|
|
|
Current shared image repository:
|
|
|
|
```text
|
|
ssh://git@git.bayliss.cloud:30009/harry/gitea-ci-runner.git
|
|
https://git.bayliss.cloud/harry/gitea-ci-runner
|
|
```
|
|
|
|
Current shared PHP/Laravel CI image contents:
|
|
|
|
- base Gitea runner job image
|
|
- PHP CLI for `8.2`, `8.3`, `8.4`, and `8.5`, selected with `ARG PHP_VERSION`
|
|
- Composer 2
|
|
- Bun
|
|
- Node.js, `npm`, and `npx`
|
|
- Go
|
|
- Python 3, `pip`, and `venv`
|
|
- `jq`
|
|
- database and cache client tools such as `postgresql-client` and `redis-tools`
|
|
- common PHP extensions including `rdkafka`, `redis`, `pcov`, `xdebug`, `imagick`, `imap`, `pgsql`, `mysql`, `sqlite3`, `gmp`, and `gd`
|
|
|
|
Do not add MongoDB to the shared image unless a repository has a real runtime or CI need for it.
|
|
|
|
Shared Dockerfile pattern:
|
|
|
|
```dockerfile
|
|
FROM docker.gitea.com/runner-images:ubuntu-latest
|
|
|
|
ARG PHP_VERSION=8.5
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
ENV BUN_INSTALL=/root/.bun
|
|
ENV PATH="/root/.bun/bin:${PATH}"
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
ca-certificates \
|
|
curl \
|
|
git \
|
|
golang-go \
|
|
gnupg \
|
|
jq \
|
|
lsb-release \
|
|
postgresql-client \
|
|
python3 \
|
|
python3-pip \
|
|
python3-venv \
|
|
redis-tools \
|
|
software-properties-common \
|
|
unzip \
|
|
&& install -d -m 0755 /etc/apt/keyrings \
|
|
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
|
|
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \
|
|
&& add-apt-repository ppa:ondrej/php -y \
|
|
&& apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
nodejs \
|
|
php${PHP_VERSION} \
|
|
php${PHP_VERSION}-bcmath \
|
|
php${PHP_VERSION}-curl \
|
|
php${PHP_VERSION}-gd \
|
|
php${PHP_VERSION}-imagick \
|
|
php${PHP_VERSION}-imap \
|
|
php${PHP_VERSION}-intl \
|
|
php${PHP_VERSION}-mbstring \
|
|
php${PHP_VERSION}-mysql \
|
|
php${PHP_VERSION}-pcov \
|
|
php${PHP_VERSION}-pgsql \
|
|
php${PHP_VERSION}-redis \
|
|
php${PHP_VERSION}-rdkafka \
|
|
php${PHP_VERSION}-sqlite3 \
|
|
php${PHP_VERSION}-xdebug \
|
|
php${PHP_VERSION}-xml \
|
|
php${PHP_VERSION}-zip \
|
|
&& update-alternatives --set php /usr/bin/php${PHP_VERSION} \
|
|
&& curl -fsSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
|
|
&& curl -fsSL https://bun.sh/install | bash \
|
|
&& ln -sf /root/.bun/bin/bun /usr/local/bin/bun \
|
|
&& ln -sf /root/.bun/bin/bunx /usr/local/bin/bunx \
|
|
&& apt-get clean \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
RUN php -v \
|
|
&& php -m \
|
|
&& composer --version \
|
|
&& go version \
|
|
&& bun --version \
|
|
&& node --version \
|
|
&& python3 --version \
|
|
&& pg_isready --version
|
|
```
|
|
|
|
Build and push manually only when necessary:
|
|
|
|
```bash
|
|
docker build --build-arg PHP_VERSION=8.2 -t git.bayliss.cloud/harry/gitea-ci-runner:php8.2 -f docker/Dockerfile .
|
|
docker push git.bayliss.cloud/harry/gitea-ci-runner:php8.2
|
|
```
|
|
|
|
Prefer the image repository workflow for normal updates. Use a matrix over the supported PHP versions and push `latest` only from PHP `8.5`:
|
|
|
|
```yaml
|
|
env:
|
|
REGISTRY: git.bayliss.cloud
|
|
IMAGE_NAME: harry/gitea-ci-runner
|
|
|
|
jobs:
|
|
build:
|
|
strategy:
|
|
matrix:
|
|
php-version:
|
|
- '8.2'
|
|
- '8.3'
|
|
- '8.4'
|
|
- '8.5'
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Check registry credentials
|
|
env:
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
run: |
|
|
if [ -z "$REGISTRY_USERNAME" ] || [ -z "$REGISTRY_TOKEN" ]; then
|
|
echo "Skipping image publish because REGISTRY_USERNAME or REGISTRY_TOKEN is missing."
|
|
echo "SKIP_IMAGE_PUBLISH=true" >> "$GITHUB_ENV"
|
|
fi
|
|
|
|
- name: Login to Gitea registry
|
|
if: env.SKIP_IMAGE_PUBLISH != 'true'
|
|
env:
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
run: echo "$REGISTRY_TOKEN" | docker login "$REGISTRY" --username "$REGISTRY_USERNAME" --password-stdin
|
|
|
|
- name: Build and push version tag
|
|
if: env.SKIP_IMAGE_PUBLISH != 'true'
|
|
run: |
|
|
docker build \
|
|
--build-arg PHP_VERSION="${{ matrix.php-version }}" \
|
|
--tag "$REGISTRY/$IMAGE_NAME:php${{ matrix.php-version }}" \
|
|
--file docker/Dockerfile \
|
|
.
|
|
docker push "$REGISTRY/$IMAGE_NAME:php${{ matrix.php-version }}"
|
|
|
|
- name: Push latest tag
|
|
if: env.SKIP_IMAGE_PUBLISH != 'true' && matrix.php-version == '8.5'
|
|
run: |
|
|
docker tag "$REGISTRY/$IMAGE_NAME:php${{ matrix.php-version }}" "$REGISTRY/$IMAGE_NAME:latest"
|
|
docker push "$REGISTRY/$IMAGE_NAME:latest"
|
|
```
|
|
|
|
If the runner host exposes the Gitea registry locally, prefer the runner-local endpoint in workflow job containers for faster pulls:
|
|
|
|
```yaml
|
|
container:
|
|
image: localhost:30008/harry/gitea-ci-runner:php8.2
|
|
```
|
|
|
|
Do not include `http://` in Docker image references. Configure insecure/local registry trust at the Docker daemon level if needed.
|
|
|
|
## OpenCode PR Review Workflow
|
|
|
|
Use this pattern when adding a repo-scoped OpenCode reviewer to Gitea Actions.
|
|
|
|
Core behavior:
|
|
|
|
- Trigger only from PR comments containing `/review`.
|
|
- Do not auto-review on PR open or synchronize events for the first version.
|
|
- Run OpenCode read-only.
|
|
- Post or update one aggregate PR comment instead of line comments.
|
|
- Use the PR head checkout for repository context, but keep checkout shallow.
|
|
- Do not expose Gitea API tokens to OpenCode.
|
|
|
|
Required secrets:
|
|
|
|
- `REVIEW_BOT_TOKEN`: Gitea token for reading the repository/PR and writing issue comments.
|
|
- `OPENCODE_GO_TOKEN`: OpenCode Go API token.
|
|
|
|
Recommended token permissions for `REVIEW_BOT_TOKEN`:
|
|
|
|
- `read:repository`
|
|
- `read:issue`
|
|
- `write:issue`
|
|
|
|
Recommended workflow shape:
|
|
|
|
```yaml
|
|
on:
|
|
issue_comment:
|
|
types:
|
|
- created
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
review:
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: git.bayliss.cloud/harry/gitea-ci-runner:php8.2
|
|
```
|
|
|
|
In a preparation step:
|
|
|
|
- Read `$GITHUB_EVENT_PATH` with `jq`.
|
|
- Skip unless the event action is `created`.
|
|
- Skip unless the issue is a pull request.
|
|
- Skip unless the comment contains `/review`.
|
|
- Fetch pull request metadata from `GET /repos/{owner}/{repo}/pulls/{number}`.
|
|
- Fetch the diff from `GET /repos/{owner}/{repo}/pulls/{number}.diff`.
|
|
- Export `PR_NUMBER`, `REPO`, `BASE_BRANCH`, `HEAD_BRANCH`, and `HEAD_SHA` to `$GITHUB_ENV`.
|
|
|
|
Checkout the PR head after preparation:
|
|
|
|
```yaml
|
|
- name: Checkout PR head
|
|
if: env.SKIP_OPENCODE_REVIEW != 'true'
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ env.HEAD_SHA }}
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
```
|
|
|
|
Avoid `fetch-depth: 0` unless full history is required; full-history checkout can make review runs slow on Gitea runners.
|
|
|
|
Generate OpenCode auth at runtime from `OPENCODE_GO_TOKEN`:
|
|
|
|
```bash
|
|
mkdir -p "$HOME/.local/share/opencode"
|
|
jq -n --arg token "$OPENCODE_GO_TOKEN" '{"opencode-go": {"type": "api", "key": $token}}' > "$HOME/.local/share/opencode/auth.json"
|
|
```
|
|
|
|
Disable mutation tools and unset repository tokens before invoking OpenCode:
|
|
|
|
```bash
|
|
export OPENCODE_CONFIG_CONTENT='{"tools":{"write":false,"edit":false,"bash":false},"permission":{"edit":"deny","bash":"deny"},"share":"disabled","autoupdate":false}'
|
|
unset OPENCODE_GO_TOKEN REVIEW_BOT_TOKEN GITEA_TOKEN GITHUB_TOKEN
|
|
|
|
opencode run \
|
|
--model "${REVIEW_MODEL:-opencode-go/glm-5.1}" \
|
|
--file /tmp/opencode-pr.diff \
|
|
--title "PR #$PR_NUMBER review" \
|
|
"Review this pull request diff for bugs, security issues, behavior regressions, and missing tests. Use the checked-out PR head tree for repository context. Focus on actionable findings. If there are no findings, say so clearly. Do not suggest style-only changes. Output Markdown with concise sections." \
|
|
> /tmp/opencode-review.md
|
|
```
|
|
|
|
Use a stable marker in the review comment body so later `/review` runs update the same comment:
|
|
|
|
```text
|
|
<!-- opencode-review -->
|
|
```
|
|
|
|
Gitea Actions logs can be awkward to fetch on versions before `1.26`; if `tea actions runs logs` is unavailable or incomplete, inspect run/task state through the Gitea API.
|
|
|
|
## Deploy Workflow Porting
|
|
|
|
Deploy workflows often need secrets and remote side effects. Port them after tests pass.
|
|
|
|
Guard required secrets explicitly:
|
|
|
|
```bash
|
|
missing=()
|
|
|
|
for required_var in SPARK_EMAIL SPARK_KEY TIPTAP_PRO_KEY DO_SPACES_KEY DO_SPACES_SECRET DO_SPACES_ENDPOINT DO_SPACES_REGION; do
|
|
if [ -z "${!required_var}" ]; then
|
|
missing+=("$required_var")
|
|
fi
|
|
done
|
|
|
|
if [ "${#missing[@]}" -gt 0 ]; then
|
|
echo "Skipping deploy because required secrets are missing: ${missing[*]}"
|
|
echo "SKIP_DEPLOY=true" >> "$GITHUB_ENV"
|
|
fi
|
|
```
|
|
|
|
Gate deploy steps:
|
|
|
|
```yaml
|
|
if: env.SKIP_DEPLOY != 'true'
|
|
```
|
|
|
|
This keeps the default branch green while still making the missing configuration obvious in logs. File follow-up work for the missing secrets.
|
|
|
|
Do not manually dispatch deploy workflows that upload assets or mutate production unless the user explicitly approves it.
|
|
|
|
## Verification Checklist
|
|
|
|
Before declaring cutover complete:
|
|
|
|
- Gitea repo is not a mirror.
|
|
- `origin` points to Gitea.
|
|
- `github` remote exists for recovery/reference if desired.
|
|
- Default branch is pushed to Gitea.
|
|
- Active PR branches are pushed to Gitea.
|
|
- Open PRs are recreated in Gitea.
|
|
- Repository PRs and Actions are enabled.
|
|
- Test workflow passes on PR.
|
|
- Test workflow passes on default branch after merge.
|
|
- Deploy workflow either succeeds or skips cleanly with a clear missing-secrets message.
|
|
- Optional `/review` workflow posts or updates the aggregate OpenCode review comment.
|
|
- Runner is online with generic labels.
|
|
- Job containers pull the expected image.
|
|
- Local branch is synchronized with Gitea:
|
|
|
|
```bash
|
|
git pull --rebase origin {default-branch}
|
|
git push origin {default-branch}
|
|
git rev-list --left-right --count origin/{default-branch}...{default-branch}
|
|
git status --short --branch
|
|
```
|
|
|
|
Expected commit comparison after sync:
|
|
|
|
```text
|
|
0 0
|
|
```
|
|
|
|
## Common Failure Modes
|
|
|
|
### Dot Paths 403 In Gitea UI
|
|
|
|
Cause: reverse proxy blocks dot directories.
|
|
|
|
Fix: adjust the proxy rule for Gitea. Do not rename workflow directories.
|
|
|
|
### Postgres Connection Refused
|
|
|
|
Cause: CI app connects to `127.0.0.1` while Postgres runs as a service container.
|
|
|
|
Fix: use service hostname such as `postgres` and add readiness checks.
|
|
|
|
### Runner Job Never Starts
|
|
|
|
Cause: workflow `runs-on` label does not match registered runner labels.
|
|
|
|
Fix: use generic labels and verify with `tea api admin/actions/runners`.
|
|
|
|
### Image Pull Fails
|
|
|
|
Cause: wrong registry hostname, missing Docker daemon trust, or private package auth issue.
|
|
|
|
Fix: verify image reference by pulling on the runner host, then use the same host/port in the workflow.
|
|
|
|
### Deploy Fails For Missing Secrets
|
|
|
|
Cause: Gitea Actions secrets not configured yet.
|
|
|
|
Fix: add a preflight skip or configure secrets. File follow-up work instead of leaving the default branch red.
|
|
|
|
### OpenCode Review Has No Context
|
|
|
|
Cause: the workflow passed only a diff to OpenCode and did not checkout the PR head tree.
|
|
|
|
Fix: fetch the PR diff through the Gitea API, then shallow-checkout the PR head SHA with `fetch-depth: 1` and `persist-credentials: false`.
|
|
|
|
### OpenCode Review Checkout Is Slow
|
|
|
|
Cause: `actions/checkout` fetched full history with `fetch-depth: 0`.
|
|
|
|
Fix: checkout the PR head SHA with `fetch-depth: 1` unless full git history is required.
|
|
|
|
### Branch Tracks Old GitHub Remote
|
|
|
|
Cause: local branch upstream still points to `github/{branch}` after remote cutover.
|
|
|
|
Fix only if requested or useful:
|
|
|
|
```bash
|
|
git branch --set-upstream-to=origin/{branch} {branch}
|
|
```
|
|
|
|
## Follow-Up Issues
|
|
|
|
File explicit follow-up issues for work intentionally deferred during cutover, such as:
|
|
|
|
- configuring deploy secrets in Gitea
|
|
- moving remaining Composer VCS repositories from GitHub to Gitea
|
|
- removing obsolete GitHub workflows after Gitea Actions are trusted
|
|
- deleting or archiving the GitHub repository after a retention period
|
|
- rotating any tokens that were exposed during setup
|