inital commit

This commit is contained in:
2026-06-08 12:50:40 -05:00
commit b012bd3e5e
7 changed files with 2477 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
# build outputs
/gitocean
/bin/
# runtime storage
/storage/
# local env
.env
+521
View File
@@ -0,0 +1,521 @@
# Gitocean Phase 2 Plan: Usability
Phase 2 focuses on making Gitocean feel usable as a day-to-day personal Git hosting environment. This phase is not about GitLab enterprise parity, CI/CD, or a web UI. It is about setup, common workflows, repository inspection, pull request ergonomics, and maintenance.
## Goals
- Make first-time setup simple.
- Make CLI output readable by humans by default.
- Support the common workflow of publishing an existing local repository.
- Provide enough CLI inspection tools to compensate for no web UI.
- Improve pull request workflows with diff and checkout commands.
- Add simple repository metadata and settings.
- Add lightweight collaboration support.
- Add comments, token management, and basic admin/backup tooling.
---
## 1. Config + `gitocean init`
### Add server config file
Create a persistent server config file, likely:
```text
storage/config.json
```
Example:
```json
{
"addr": ":8080",
"public_url": "http://localhost:8080",
"storage": "storage",
"mysql_dsn": "root:pass@tcp(127.0.0.1:3306)/gitocean?parseTime=true"
}
```
### Add command
```bash
gitocean init
```
It should:
1. Prompt for server listen address.
2. Prompt for public URL.
3. Prompt for storage directory.
4. Prompt for MySQL DSN or individual MySQL fields.
5. Create the database if missing.
6. Run migrations.
7. Create storage directories.
8. Optionally create the first user account.
9. Write config file.
10. Print next-step instructions.
### Update server command
Allow:
```bash
gitocean server
```
without requiring `--dsn` if config exists.
Still allow overrides:
```bash
gitocean server --config storage/config.json
```
```bash
gitocean server --dsn '...' --addr :8080 --storage storage
```
---
## 2. Friendly CLI output
Most commands currently print JSON. Phase 2 should make human-friendly output the default.
### Add global or per-command JSON output
Support:
```bash
gitocean repo search test --json
```
or eventually a global flag:
```bash
gitocean --json repo search test
```
### Examples
Repo creation should print:
```text
Created public repository owen/test
Clone:
git clone http://localhost:8080/owen/test.git
Add existing repo:
git remote add origin http://localhost:8080/owen/test.git
git branch -M main
git push -u origin main
```
Search should print a table:
```text
REPOSITORY VISIBILITY DESCRIPTION UPDATED
owen/test public Test repository 2m ago
alice/demo public Demo project 3h ago
```
PR list should print:
```text
#1 open Add config support bob:feature-config -> main
#2 merged Fix clone auth alice:fix-auth -> main
```
---
## 3. `repo publish`
Add a command for publishing an existing local Git repository.
```bash
gitocean repo publish NAME --public
gitocean repo publish NAME --private
```
Optional flags:
```bash
gitocean repo publish NAME --public --remote origin
gitocean repo publish NAME --public --branch main
gitocean repo publish NAME --public --description "My project"
```
### Behavior
From inside a local Git repository:
1. Verify current directory is a Git repository.
2. Create remote repository through API.
3. Add remote if missing.
4. Set or rename current branch to `main` by default.
5. Push current branch.
6. Set upstream.
7. Print success and clone URL.
Equivalent workflow:
```bash
gitocean repo create test --public
git remote add origin http://localhost:8080/owen/test.git
git branch -M main
git push -u origin main
```
---
## 4. `repo view`, branches, tags
Since there is no web UI, add basic repository inspection commands.
### Repo view
```bash
gitocean repo view OWNER/REPO
```
Output:
```text
owen/test
Visibility: public
Default branch: main
Description: My test project
Clone:
git clone http://localhost:8080/owen/test.git
Open PRs: 2
Branches: 4
Tags: 1
```
### Branch listing
```bash
gitocean repo branches OWNER/REPO
```
Output:
```text
BRANCH COMMIT UPDATED MESSAGE
main 8f31abc 2 hours ago Initial commit
feature-x 1ab22df 1 day ago Add feature
```
### Tag listing
```bash
gitocean repo tags OWNER/REPO
```
Output:
```text
TAG COMMIT DATE MESSAGE
v0.1.0 8f31abc 2026-06-08 First release
```
### API additions
```http
GET /api/repos/{owner}/{repo}/branches
GET /api/repos/{owner}/{repo}/tags
```
---
## 5. PR diff + PR checkout
Pull requests are difficult to use without seeing and checking out changes.
### PR diff
```bash
gitocean pr diff OWNER/REPO NUMBER
```
Server should generate a diff between:
```text
source_repo:source_branch
```
and:
```text
target_repo:target_branch
```
API:
```http
GET /api/repos/{owner}/{repo}/pulls/{number}/diff
```
Return `text/plain` patch/diff output.
### PR checkout
```bash
gitocean pr checkout OWNER/REPO NUMBER
```
From inside a local Git repo, it should:
1. Fetch PR source branch from source repository URL.
2. Create or update a local branch such as `pr-1`.
3. Check out that branch.
Equivalent:
```bash
git fetch http://localhost:8080/bob/test.git fix:pr-1
git checkout pr-1
```
---
## 6. Repo description/default branch/visibility update
Add basic repository settings.
### Schema additions
Add columns to `repositories`:
- `description TEXT NOT NULL DEFAULT ''`
- `default_branch VARCHAR(200) NOT NULL DEFAULT 'main'`
- `archived BOOLEAN NOT NULL DEFAULT false`
### Commands
```bash
gitocean repo set OWNER/REPO --description "My project"
gitocean repo set OWNER/REPO --visibility private
gitocean repo set OWNER/REPO --visibility public
gitocean repo set OWNER/REPO --default-branch main
gitocean repo archive OWNER/REPO
gitocean repo unarchive OWNER/REPO
```
### API additions
```http
PATCH /api/repos/{owner}/{repo}
```
Owner-only.
---
## 7. Collaborators
Owner-only permissions are too limiting for personal collaboration. Add simple collaborators.
### Roles
- `read`: can clone/fetch private repositories.
- `write`: can clone/fetch/push.
Owner remains the only user who can:
- delete repository
- update settings
- manage collaborators
- merge/close PRs, unless explicitly changed later
### Schema
Add table:
```text
repository_collaborators
id
repository_id
user_id
role: read/write
created_at
```
Unique key:
```text
(repository_id, user_id)
```
### Commands
```bash
gitocean repo collaborators OWNER/REPO
gitocean repo collaborator add OWNER/REPO USER --role read
gitocean repo collaborator add OWNER/REPO USER --role write
gitocean repo collaborator remove OWNER/REPO USER
```
### API additions
```http
GET /api/repos/{owner}/{repo}/collaborators
POST /api/repos/{owner}/{repo}/collaborators
DELETE /api/repos/{owner}/{repo}/collaborators/{username}
```
---
## 8. PR comments
Add simple general comments on pull requests. Line comments can wait.
### Schema
Add table:
```text
pull_request_comments
id
pull_request_id
author_user_id
body
created_at
updated_at
```
### Commands
```bash
gitocean pr comment OWNER/REPO NUMBER "Looks good"
gitocean pr comments OWNER/REPO NUMBER
```
Optional editor support later:
```bash
gitocean pr comment OWNER/REPO NUMBER --editor
```
### API additions
```http
GET /api/repos/{owner}/{repo}/pulls/{number}/comments
POST /api/repos/{owner}/{repo}/pulls/{number}/comments
```
---
## 9. Token management
Tokens expire after 7 days, but users need visibility and revocation.
### Commands
```bash
gitocean token list
gitocean token revoke TOKEN_ID
gitocean token prune
```
### Behavior
- `token list`: show active tokens for current user.
- `token revoke`: revoke one token.
- `token prune`: remove expired/revoked tokens from database. Owner/admin-only if global, current-user only otherwise.
### API additions
```http
GET /api/tokens
DELETE /api/tokens/{id}
POST /api/tokens/prune
```
### CLI expired-session UX
When API returns unauthorized, show:
```text
Your session may have expired. Run:
gitocean login
```
---
## 10. Backup/admin commands
Personal servers need reliable maintenance tooling.
### Admin commands
```bash
gitocean admin users list
gitocean admin users delete USER
gitocean admin repos list
gitocean admin storage check
gitocean admin tokens prune
```
For MVP, admin can be:
- the first registered user, or
- a boolean `is_admin` column on `users`.
### Backup commands
```bash
gitocean backup create backup.tar.gz
gitocean backup restore backup.tar.gz
```
Backup should include:
- server config
- `storage/repos/`
- MySQL dump of metadata
Possible implementation:
```bash
mysqldump ... > metadata.sql
tar -czf backup.tar.gz storage/config.json storage/repos metadata.sql
```
Restore should:
1. Stop or warn about running server.
2. Restore config.
3. Restore repositories.
4. Restore database from SQL dump.
5. Run migrations after restore.
---
## Recommended implementation order
1. Config file support and `gitocean init`.
2. Friendly CLI output with `--json` escape hatch.
3. `repo publish`.
4. Repository metadata fields and `repo view`.
5. Branch/tag listing.
6. PR diff.
7. PR checkout.
8. Collaborators.
9. PR comments.
10. Token management.
11. Backup/admin commands.
## Success criteria
Phase 2 is successful when a user can comfortably:
1. Initialize the server without memorizing flags.
2. Register/login from CLI.
3. Publish an existing local Git repository with one command.
4. Clone, push, search, and inspect repositories.
5. Open, inspect, checkout, and merge PRs.
6. Share private repositories with specific users.
7. Revoke tokens and back up the server.
+194
View File
@@ -0,0 +1,194 @@
# Gitocean Implementation Plan
## Product decisions
- Build a Git repository hosting platform in Go.
- Store bare Git repositories under `storage/repos/{owner}/{repo}.git`.
- Use MySQL for metadata.
- Support HTTP Smart Git only. SSH is out of scope for MVP.
- Support CLI + API only. No web UI.
- Registration is open, but registration happens through the CLI/API only.
- Users register with email, username, and password.
- Users can log in with either email + password or username + password.
- Login returns a temporary auth token that expires after 7 days.
- The CLI stores this token locally for API calls and can approve it into Git's credential helper for Git HTTP operations.
- Repository names allow lowercase letters, numbers, `.`, `_`, and `-`.
- Usernames allow lowercase letters, numbers, `_`, and `-`.
- New repositories use `main` as the default branch.
- Pull request numbers are per target repository.
## Permissions
### Repository visibility
- `public`: anyone can clone/fetch. Only the owner can push/delete/manage.
- `private`: only the owner can clone/fetch/push/delete/manage.
### Writes
- MVP is owner-only.
- There are no collaborators, organizations, teams, or fine-grained permissions yet.
- Open collaboration is supported through pull requests against public repositories.
## Storage layout
```text
storage/
repos/
alice/
demo.git/
bob/
project.git/
```
Each repository directory is a bare Git repository.
## MySQL schema
Core tables:
- `users`
- id
- email
- username
- password_hash
- created_at
- `auth_tokens`
- id
- user_id
- token_hash
- expires_at
- revoked_at
- created_at
- `repositories`
- id
- owner_user_id
- name
- visibility: `public` or `private`
- forked_from_repository_id nullable
- created_at
- updated_at
- `pull_requests`
- id
- target_repository_id
- number
- author_user_id
- source_repository_id
- source_branch
- target_branch
- title
- description
- status: `open`, `closed`, or `merged`
- closed_at nullable
- merged_at nullable
- created_at
- updated_at
## API
### Auth
```http
POST /api/register
POST /api/login
POST /api/logout
GET /api/me
```
### Repositories
```http
POST /api/repos
GET /api/repos/search?q=demo&scope=all
GET /api/repos/search?q=demo&scope=mine
GET /api/repos/{owner}/{repo}
DELETE /api/repos/{owner}/{repo}?force=false
POST /api/repos/{owner}/{repo}/fork
```
### Pull requests
```http
POST /api/repos/{owner}/{repo}/pulls
GET /api/repos/{owner}/{repo}/pulls
GET /api/repos/{owner}/{repo}/pulls/{number}
POST /api/repos/{owner}/{repo}/pulls/{number}/close
POST /api/repos/{owner}/{repo}/pulls/{number}/merge
```
### Git HTTP
```http
/{owner}/{repo}.git/info/refs
/{owner}/{repo}.git/git-upload-pack
/{owner}/{repo}.git/git-receive-pack
```
## CLI commands
```bash
gitocean server --addr :8080 --dsn 'user:pass@tcp(127.0.0.1:3306)/gitocean?parseTime=true' --storage storage
gitocean register
gitocean login
gitocean logout
gitocean whoami
gitocean repo create NAME --public
gitocean repo create NAME --private
gitocean repo delete OWNER/NAME [--force]
gitocean repo search QUERY --all
gitocean repo search QUERY --mine
gitocean repo fork OWNER/NAME [--name NEW_NAME]
gitocean clone OWNER/NAME
gitocean pr create --from OWNER/REPO:BRANCH --to OWNER/REPO:BRANCH --title TITLE --description DESC
gitocean pr create --repo OWNER/REPO --from BRANCH --to BRANCH --title TITLE --description DESC
gitocean pr list OWNER/REPO
gitocean pr view OWNER/REPO NUMBER
gitocean pr close OWNER/REPO NUMBER
gitocean pr merge OWNER/REPO NUMBER
```
## Pull request rules
### Same-repository PRs
- Source and target repository are the same.
- Only the repository owner can create same-repo PRs.
- Source and target branches must both exist.
### Cross-repository PRs
- Source repository branch points to target repository branch.
- Source repository must be owned by the PR author.
- Target repository must be public, unless the author is also the target owner.
- Source and target branches must both exist.
- Only the target repository owner can close or merge the PR.
## Merge behavior
MVP merge mode is a normal merge commit:
1. Clone target repo into a temporary worktree.
2. Checkout target branch.
3. Add/fetch source repo branch.
4. Run `git merge --no-ff FETCH_HEAD`.
5. Push the result back to the target branch.
6. Mark PR as merged.
If conflicts occur, return an error and keep the PR open.
## Implementation milestones
1. Project scaffold and build setup.
2. MySQL migrations.
3. User registration, login, logout, and token auth.
4. Repository create, delete, detail, search.
5. HTTP Smart Git integration using `git http-backend`.
6. CLI auth and repository commands.
7. Fork support.
8. Pull request create/list/view/close.
9. Pull request merge.
10. Tests, hardening, and UX polish.
+1736
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
module gitocean
go 1.23
require (
github.com/go-sql-driver/mysql v1.9.0
golang.org/x/crypto v0.31.0
)
require filippo.io/edwards25519 v1.1.0 // indirect
+6
View File
@@ -0,0 +1,6 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo=
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
Submodule
+1
Submodule test added at b00f141889