Find a file
2026-07-22 15:06:35 +00:00
manifests feat: forgejo-cli with auth, repo, issue, pr and branch commands 2026-07-22 15:03:32 +00:00
src feat: add repo collaborator command 2026-07-22 15:06:35 +00:00
.gitignore feat: forgejo-cli with auth, repo, issue, pr and branch commands 2026-07-22 15:03:32 +00:00
package-lock.json feat: forgejo-cli with auth, repo, issue, pr and branch commands 2026-07-22 15:03:32 +00:00
package.json feat: forgejo-cli with auth, repo, issue, pr and branch commands 2026-07-22 15:03:32 +00:00
README.md feat: add repo collaborator command 2026-07-22 15:06:35 +00:00

forgejo-cli

A command-line interface for Forgejo, built with Commander.js. It targets the instance at https://forgejo.heavyduty.builders and is designed so that every real operation performed against Forgejo becomes a new CLI command.

Requirements

  • Node.js >= 18 (uses the global fetch API)
  • npm

Installation

cd forgejo-cli
npm install
npm link        # makes the `forgejo` binary available globally

Or run it directly without linking:

node src/cli.js <command>

Configuration

Authentication state is stored in a JSON file:

  • Default: ~/.config/forgejo-cli/config.json
  • Override with --config <path> or FORGEJO_CONFIG_FILE

The configuration directory is created with permissions 0700 and the file with 0600 so only the owner can read the token.

Example stored config:

{
  "url": "https://forgejo.heavyduty.builders",
  "login": "kimi-reviewer-andresmgsl",
  "username": "kimi-reviewer-andresmgsl",
  "email": "andres+4@heavyduty.builders",
  "token": "<sha1>",
  "tokenId": 42
}

Environment variables

Variable Purpose
FORGEJO_URL Default Forgejo base URL
FORGEJO_USERNAME Default username/email for auth login
FORGEJO_PASSWORD Default password for auth login
FORGEJO_CONFIG_FILE Path to the config file
FORGEJO_CONFIG_DIR Directory for the config file
XDG_CONFIG_HOME Followed when resolving the default config directory
GITHUB_TOKEN GitHub token used by repo import when --github-token is omitted

Commands

Global options

-c, --config <path>   path to configuration file
-h, --help            display help
-V, --version         display version

forgejo auth login

Authenticate and persist an access token.

Options:
  -u, --url <url>            Forgejo base URL (default: https://forgejo.heavyduty.builders)
  -n, --username <username>  account username or email
  -p, --password <password>  account password
  --password-file <path>     read account password from a file
  -t, --token <token>        use an existing personal access token instead of generating one
  --token-file <path>        read an existing personal access token from a file
  --token-name <name>        name for the generated token

Interactive example:

forgejo auth login
# prompts for username and password

Non-interactive example using environment variables:

export FORGEJO_USERNAME='kimi-reviewer-andresmgsl'
export FORGEJO_PASSWORD='...'
forgejo auth login

Password file example (avoids shell history and special-character issues):

chmod 600 /run/secrets/forgejo-password
forgejo auth login -n kimi-reviewer-andresmgsl --password-file /run/secrets/forgejo-password

Existing token example:

forgejo auth login -t <personal-access-token>

Flow:

  1. Calls GET /api/v1/user to verify credentials and resolve the canonical login name.
  2. Calls POST /api/v1/users/{login}/tokens to generate a personal access token.
  3. Requests the standard non-admin scopes: read/write for activitypub, issue, misc, organization, package, repository, and user.
  4. Writes the token, token id, user details and URL to the config file.

forgejo auth logout

Revoke the stored token remotely and delete the local config.

forgejo auth logout

Flow:

  1. Calls DELETE /api/v1/users/{login}/tokens/{id} using the stored token.
  2. Removes ~/.config/forgejo-cli/config.json.

forgejo auth status

Display the currently authenticated user.

forgejo auth status

Calls GET /api/v1/user with the stored token.

forgejo repo create

Create a new repository for the authenticated user.

Options:
  --name <name>                    repository name (required)
  -d, --description <description>  repository description
  --private                        make the repository private
  --public                         make the repository public
  --auto-init                      initialize with a README (default: true)
  --default-branch <branch>        default branch name (default: "main")

Example:

forgejo repo create --name forgejo-cli-test --private \
  -d "Test repository created via forgejo-cli"

Calls POST /api/v1/user/repos.

forgejo repo list

List repositories for the authenticated user.

Options:
  -l, --limit <number>   maximum repositories to display (default: 50; use 0 for all)
forgejo repo list

Calls GET /api/v1/user/repos and auto-paginates.

forgejo repo import

Import a remote repository into Forgejo, including git history, issues, pull requests, labels, milestones, releases and wiki.

Options:
  --from <clone-addr>      source clone URL (required)
  --name <name>            repository name in Forgejo (required)
  --service <service>      source service type: git, github, gitea, gitlab, ... (default: github)
  --owner <owner>          Forgejo owner for the imported repo (default: current user)
  -d, --description <description>  repository description
  --private / --public     visibility
  --issues                 migrate issues (default)
  --no-issues              skip issues
  --labels                 migrate labels (default)
  --no-labels              skip labels
  --milestones             migrate milestones (default)
  --no-milestones          skip milestones
  --pull-requests          migrate pull requests (default)
  --no-pull-requests       skip pull requests
  --releases               migrate releases (default)
  --no-releases            skip releases
  --wiki                   migrate wiki (default)
  --no-wiki                skip wiki
  --lfs                    migrate LFS objects
  --github-token <token>   GitHub token (defaults to GITHUB_TOKEN or `gh auth token`)

Example used to mirror heavy-duty/box:

forgejo repo import \
  --from https://github.com/heavy-duty/box.git \
  --name box \
  --service github \
  --public \
  --issues --labels --milestones --pull-requests --releases --wiki

Calls POST /api/v1/repos/migrate.

forgejo repo import-batch

Import multiple repositories from a JSON manifest.

Options:
  -f, --file <path>   path to JSON manifest (required)
  --dry-run           print the manifest without importing

Manifest format:

[
  {
    "name": "rig",
    "from": "https://github.com/heavy-duty/rig.git",
    "service": "github",
    "private": false,
    "issues": true,
    "labels": true,
    "milestones": true,
    "pull_requests": true,
    "releases": true,
    "wiki": true
  }
]

Example:

forgejo repo import-batch -f repos.json
forgejo repo import-batch -f repos.json --dry-run

Calls POST /api/v1/repos/migrate once per entry.

forgejo issue list

List issues in a repository.

Options:
  -o, --owner <owner>    repository owner (required)
  -r, --repo <repo>      repository name (required)
  -s, --state <state>    open, closed, all (default: open)
  -t, --type <type>      issues or pulls (default: issues)
  -l, --limit <number>   maximum issues to display (default: 50; use 0 for all)
forgejo issue list -o kimi-reviewer-andresmgsl -r box -s all -l 0

Calls GET /api/v1/repos/{owner}/{repo}/issues and auto-paginates.

forgejo pr list

List pull requests in a repository.

Options:
  -o, --owner <owner>    repository owner (required)
  -r, --repo <repo>      repository name (required)
  -s, --state <state>    open, closed, all (default: open)
  -l, --limit <number>   maximum PRs to display (default: 50; use 0 for all)
forgejo pr list -o kimi-reviewer-andresmgsl -r box -s all -l 0

Calls GET /api/v1/repos/{owner}/{repo}/pulls and auto-paginates.

forgejo branch list

List branches in a repository.

Options:
  -o, --owner <owner>    repository owner (required)
  -r, --repo <repo>      repository name (required)
  -l, --limit <number>   maximum branches to display (default: 50; use 0 for all)
forgejo branch list -o kimi-reviewer-andresmgsl -r box

Calls GET /api/v1/repos/{owner}/{repo}/branches and auto-paginates.

forgejo collaborator add

Add a collaborator to a repository.

Options:
  -o, --owner <owner>            repository owner (required)
  -r, --repo <repo>              repository name (required)
  -u, --user <username>          username of the collaborator (required)
  --permission <permission>      read, write, or admin (default: write)

Example:

forgejo collaborator add -o kimi-reviewer-andresmgsl -r infra -u andres --permission admin
forgejo collaborator add -o kimi-reviewer-andresmgsl -r infra -u dan --permission admin

Calls PUT /api/v1/repos/{owner}/{repo}/collaborators/{user}.

Architecture

src/
├── cli.js     # Commander program, commands and user I/O
├── api.js     # Forgejo API client (fetch wrapper)
└── config.js  # Secure filesystem-based config storage
  • cli.js defines commands and options, handles prompts and prints results.
  • api.js encapsulates all HTTP calls to Forgejo. It supports both Basic auth (for token generation) and token auth (for all other calls).
  • config.js reads/writes JSON config and enforces restrictive file permissions.

Security notes

  • Tokens are stored on disk with 0600 permissions.
  • Passwords are never persisted; they are only used to generate a token.
  • Prefer --password-file or FORGEJO_PASSWORD over -p to keep passwords out of shell history and avoid ! history-expansion issues.
  • The generated token name includes the hostname and a timestamp to avoid collisions.

Verification: heavy-duty repository imports

The heavy-duty repositories were imported into Forgejo under https://forgejo.heavyduty.builders/kimi-reviewer-andresmgsl.

Repository Visibility Branches Commits Open issues Total issues PRs Labels Milestones Releases
box public 1 306 11 65 92 21 0 4
rig public 1 198 10 49 59 21 0 3
cast public 1 194 7 67 75 21 0 3
infra private 1 86 2 8 22 9 0 0
handbook private 1 29 28 28 13 9 5 0
incubator private 1 1,326 1 1 23 9 0 0

Counts match GitHub for all repositories. Git history, issues, pull requests, labels, milestones and releases are included. Discussions are not enabled on any of the source repositories. The cast wiki is enabled on GitHub but contains no pages, so nothing was migrated.

Next steps

The CLI is authenticated and the first full repository import is complete. Every subsequent Forgejo task you need will be added as a new command under forgejo.