refactor: flatten into single crate
This commit is contained in:
parent
e5a5e508ff
commit
7387d7c871
194 changed files with 701 additions and 821 deletions
64
Cargo.toml
64
Cargo.toml
|
@ -1,36 +1,41 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["crates/*"]
|
||||
|
||||
[workspace.package]
|
||||
[package]
|
||||
name = "git-next"
|
||||
version = "0.14.1"
|
||||
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://git.kemitix.net/kemitix/git-next"
|
||||
description = "trunk-based development manager"
|
||||
authors = ["Paul Campbell <pcampbell@kemitix.net>"]
|
||||
rust-version = "1.76"
|
||||
description = "trunk-based development manager"
|
||||
documentation = "https://git.kemitix.net/kemitix/git-next/src/branch/main/README.md"
|
||||
keywords = ["git", "cli", "server", "tool"]
|
||||
categories = ["development-tools"]
|
||||
|
||||
# [workspace.lints.clippy]
|
||||
# pedantic = { level = "warn", priority = -1 }
|
||||
# nursery = { level = "warn", priority = -1 }
|
||||
# unwrap_used = "warn"
|
||||
# expect_used = "warn"
|
||||
[features]
|
||||
# default = ["forgejo", "github"]
|
||||
default = ["forgejo", "github", "tui"]
|
||||
forgejo = []
|
||||
github = []
|
||||
tui = [
|
||||
"ratatui",
|
||||
"directories",
|
||||
"lazy_static",
|
||||
"tui-scrollview",
|
||||
"regex",
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
[dependencies]
|
||||
|
||||
color-eyre = "0.6"
|
||||
|
||||
# TUI
|
||||
ratatui = "0.29"
|
||||
directories = "6.0"
|
||||
lazy_static = "1.5"
|
||||
color-eyre = "0.6"
|
||||
tui-scrollview = "0.5"
|
||||
regex = "1.10"
|
||||
chrono = "0.4"
|
||||
ratatui = { version = "0.29", optional = true }
|
||||
directories = { version = "6.0", optional = true }
|
||||
lazy_static = { version = "1.5", optional = true }
|
||||
tui-scrollview = { version = "0.5", optional = true }
|
||||
regex = { version = "1.10", optional = true }
|
||||
chrono = { version = "0.4", optional = true }
|
||||
|
||||
# CLI parsing
|
||||
clap = { version = "4.5", features = ["cargo", "derive"] }
|
||||
|
@ -41,7 +46,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|||
tracing-error = "0.2.0"
|
||||
|
||||
# base64 decoding
|
||||
base64 = "0.22"
|
||||
# base64 = { version = "0.22", optional = true }
|
||||
|
||||
# sha256 encoding (e.g. verify github webhooks)
|
||||
hmac = "0.12"
|
||||
|
@ -110,10 +115,21 @@ sendmail = "2.0"
|
|||
# desktop notifications
|
||||
notifica = "3.0"
|
||||
|
||||
# Testing
|
||||
mockall = "0.13"
|
||||
|
||||
[dev-dependencies]
|
||||
assert2 = "0.3"
|
||||
|
||||
pretty_assertions = "1.4"
|
||||
rand = "0.8"
|
||||
mockall = "0.13"
|
||||
test-log = "0.2"
|
||||
rstest = { version = "0.24", features = ["async-timeout"] }
|
||||
test-log = "0.2"
|
||||
|
||||
[lints.clippy]
|
||||
nursery = { level = "warn", priority = -1 }
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
unwrap_used = "warn"
|
||||
expect_used = "warn"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
|
||||
|
|
662
README.md
662
README.md
|
@ -2,11 +2,671 @@
|
|||
|
||||
## Trunk-based developement manager.
|
||||
|
||||
> A source-control branching model, where developers collaborate on code in a single branch
|
||||
> called ‘trunk’, resist any pressure to create other long-lived development branches by
|
||||
> employing documented techniques. They therefore avoid merge hell, do not break the build,
|
||||
> and live happily ever after. - [source](https://trunkbaseddevelopment.com)
|
||||
|
||||
`git-next` is a combined server and command-line tool that enables trunk-based
|
||||
development workflows where each commit must pass CI before being included in
|
||||
the main branch.
|
||||
|
||||
## Features
|
||||
|
||||
- Allows enforcing the requirement for each commit to pass the CI pipeline before being
|
||||
included in the main branch
|
||||
- Provides a server component that manages the trunk-based development process
|
||||
- Ensure a consistent, high-quality codebase by preventing untested changes
|
||||
from being added to main
|
||||
- Requires each commit uses conventional commit format.
|
||||
|
||||
See [Behaviour](#behaviour) to learn how we do this.
|
||||
|
||||
![Demo](./demo.gif)
|
||||
|
||||
## Prerequisits
|
||||
|
||||
See [README.md](https://git.kemitix.net/kemitix/git-next/src/branch/main/crates/cli/README.md) for more information.
|
||||
- Rust 1.76.0 or later - https://www.rust-lang.org
|
||||
- pgk-config
|
||||
- libssl-dev
|
||||
- libdbus-1-dev (ubuntu/debian)
|
||||
- dbus-devel (fedora)
|
||||
|
||||
See `.cargo/config.toml` for how they are configured.
|
||||
|
||||
## Installation
|
||||
|
||||
You can install `git-next` from <https://crates.io/>:
|
||||
|
||||
```shell
|
||||
cargo install git-next
|
||||
```
|
||||
|
||||
If you use [mise](https://mise.jdx.dev):
|
||||
|
||||
```shell
|
||||
mise use -g cargo:git-next
|
||||
```
|
||||
|
||||
Or you can install `git-next` from source after cloning:
|
||||
|
||||
```shell
|
||||
cargo install --path crates/cli
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] cli
|
||||
- [x] server
|
||||
- [x] notifications - notify user when intervention required (e.g. to rebase)
|
||||
- [x] tui overview
|
||||
- [ ] webui overview
|
||||
|
||||
## Branch Names
|
||||
|
||||
`git-next` uses three branches, `main`, `next` and `dev`, although they do not
|
||||
need to have those names. In the documentation we will use those names, but
|
||||
each repo must specify the names of the branches to use for each, even if they
|
||||
happen to have those same names.
|
||||
|
||||
## Configuration
|
||||
|
||||
- The branches to use for `main`, `next` and `dev` must be specified in either
|
||||
the `.git-next.toml` in the repo itself, or in the server configuration file,
|
||||
`git-next-server.toml`. See below for details.
|
||||
- CI checks should be configured to run when the `next` branch is `pushed`.
|
||||
- The `dev` branch _must_ have the `main` branch as an ancestor.
|
||||
- The `next` branch _must_ have the `main` branch as an ancestor.
|
||||
|
||||
### Server
|
||||
|
||||
The server is configured by the `git-next-server.toml` file.
|
||||
|
||||
#### listen
|
||||
|
||||
The server should listen for webhook notifications from each forge.
|
||||
|
||||
```toml
|
||||
[listen]
|
||||
http = { addr = "0.0.0.0", port = 8080 }
|
||||
url = "https://localhost:8080"
|
||||
```
|
||||
|
||||
##### http
|
||||
|
||||
The server needs to be able to receive webhook notifications from your forge,
|
||||
(e.g. github.com). You can do this via any method that suits your environment,
|
||||
e.g. ngrok or a reverse proxy from a web server that itself can route traffic
|
||||
to the machine you are running the git-next server on.
|
||||
|
||||
Specify the address and port the server should listen to for incoming webhooks.
|
||||
This is the address and port that your reverse proxy should route traffic to.
|
||||
|
||||
- **addr** - the IP address the server should bind to
|
||||
- **port** - the IP port the server should bind to
|
||||
|
||||
##### url
|
||||
|
||||
The HTTPS URL for forges to send webhooks to.
|
||||
|
||||
Your forges need to know where they should route webhooks to. This should be
|
||||
an address this is accessible to the forge. So, for github.com, it would need
|
||||
to be a publicly accessible HTTPS URL. For a self-hosted forge, e.g. ForgeJo,
|
||||
on your own network, then it only needs to be accessible from the server your
|
||||
forge is running on.
|
||||
|
||||
#### shout
|
||||
|
||||
The server should be able to notify the user when manual intervention is required.
|
||||
|
||||
```toml
|
||||
[shout]
|
||||
desktop = true
|
||||
|
||||
[shout.webhook]
|
||||
url = "https//localhost:9090"
|
||||
secret = "secret-password"
|
||||
|
||||
[shout.email]
|
||||
from = "git-next@example.com"
|
||||
to = "developer@example.com"
|
||||
|
||||
[shout.email.smtp]
|
||||
hostname = "smtp.example.com"
|
||||
username = "git-next@example.com"
|
||||
password = "MySecretEmailPassword42"
|
||||
```
|
||||
|
||||
##### desktop
|
||||
|
||||
When specified as `true`, desktop notifications will be sent for some events.
|
||||
|
||||
##### webhook
|
||||
|
||||
Will send a POST request for some events.
|
||||
|
||||
- **url** - the URL to POST the notification to and the
|
||||
- **secret** - the sync key used to sign the webhook payload
|
||||
|
||||
See [Notifications](#notifications) for more details.
|
||||
|
||||
##### email
|
||||
|
||||
Will send an email for some events.
|
||||
|
||||
- **from** - the email address to send the email from
|
||||
- **to** - the email address to send the email to
|
||||
|
||||
With just `from` and `to` specified, `git-next` will attempt to send emails
|
||||
with `sendmail` if it is configured.
|
||||
|
||||
Alternativly, you can use an SMTP relay.
|
||||
|
||||
###### smtp
|
||||
|
||||
Will send emails using an SMTP relay.
|
||||
|
||||
- **hostname** - the SMTP relay server
|
||||
- **username** - the account to authenticate as
|
||||
- **password** - the password to authenticate with
|
||||
|
||||
#### storage
|
||||
|
||||
```toml
|
||||
[storage]
|
||||
path = "./data"
|
||||
```
|
||||
|
||||
`git-next` will create a bare clone of each repo that you configure it to
|
||||
monitor. They will all be created in the directory specified here. This data
|
||||
does not need to be backed up, as any missing information will be cloned when
|
||||
the server starts up.
|
||||
|
||||
- **path** - directory to store local copies of monitored repos
|
||||
|
||||
#### forge
|
||||
|
||||
Within the forge tree, specify each forge you want to monitor repos on.
|
||||
|
||||
Give your forge an alias, e.g. `default`, `gh`, `github`.
|
||||
|
||||
e.g.
|
||||
|
||||
```toml
|
||||
[forge.github]
|
||||
forge_type = "GitHub"
|
||||
hostname = "github.com"
|
||||
user = "username"
|
||||
token = "api-key"
|
||||
max_dev_commits = 25
|
||||
```
|
||||
|
||||
- **forge_type** - one of: `ForgeJo` or `GitHub`
|
||||
- **hostname** - the hostname for the forge.
|
||||
- **user** - the user to authenticate as
|
||||
- **token** - application token for the user. See [Forges](#forges) below for the permissions required for each forge.
|
||||
- **max_dev_commits** - [optional] the maximum number of commits allowed between `dev` and `main`. Defaults to 25.
|
||||
|
||||
Generally, the `user` will need to be able to push to `main` and to _force-push_
|
||||
to `next`.
|
||||
|
||||
#### repos
|
||||
|
||||
For each forge, you need to specify which repos on the forge you want to
|
||||
monitor. They do not need to be owned by the `user`, but they `user` must have
|
||||
the `push` and `force-push` permissions as mentioned above for each of the
|
||||
repositories.
|
||||
|
||||
e.g.
|
||||
|
||||
```toml
|
||||
[forge.github.repos]
|
||||
my-repo = { repo = "owner/repo", branch = "main", gitdir = "/home/pcampbell/project/my-repo" }
|
||||
|
||||
[forge.github.repos.other-repo]
|
||||
repo = "user/other"
|
||||
branch = "master"
|
||||
main = "master"
|
||||
next = "ci-testing"
|
||||
dev = "trunk"
|
||||
```
|
||||
|
||||
Note that toml allows specifying the values on one line, or across multiple
|
||||
lines. Both are equivalent. What is not equivalent between `my-repo` and
|
||||
`other-repo`, is that one will require a configuration file within the repo
|
||||
itself. `other-repo` specifies the `main`, `next` and `dev` branches to be
|
||||
used, but `my-repo` doesn't.
|
||||
|
||||
A sample `.git-next-toml` file that would need to exist in `my-repo`'s `owner/repo`
|
||||
repo, on the `main` branch:
|
||||
|
||||
```toml
|
||||
[branches]
|
||||
main = "main"
|
||||
next = "next"
|
||||
dev = "dev"
|
||||
```
|
||||
|
||||
- **repo** - the owner and name of the repo to be monitored
|
||||
- **branch** - the branch to look for a `.git-next.toml` file if needed
|
||||
- **gitdir** - (optional) you can use a local copy of the repo
|
||||
- **main** - the branch to use as `main`
|
||||
- **next** - the branch to use as `next`
|
||||
- **dev** - the branch to use as `dev`
|
||||
|
||||
##### gitdir
|
||||
|
||||
Additional notes on using `gitdir`:
|
||||
|
||||
When you specify the `gitdir` value, the repo cloned in that directory will
|
||||
be used for perform the equivalent of `git fetch`, `git push` and `git push
|
||||
--force-with-lease`.
|
||||
|
||||
These commands will not affect the contents of your working tree, nor will
|
||||
it change any local branches. Only the details about branches on the remote
|
||||
forge will be updated.
|
||||
|
||||
Currently `git-next` can only use a `gitdir` if the forge and repo is the
|
||||
same one specified as the `origin` remote. Otherwise the behaviour is
|
||||
untested and undefined.
|
||||
|
||||
## Webhook Notifications
|
||||
|
||||
When sending a Webhook Notification to a user they are sent using the
|
||||
Standard Webhooks format. That means all POST messages have the
|
||||
following headers:
|
||||
|
||||
- `Webhook-Id`
|
||||
- `Webhook-Signature`
|
||||
- `Webhook-Timestamp`
|
||||
|
||||
### Events
|
||||
|
||||
#### Dev Not Based on Main
|
||||
|
||||
This message `type` indicates that the `dev` branch is not based on `main`.
|
||||
|
||||
**Action Required**: Rebase the `dev` branch onto the `main` branch.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"branches": {
|
||||
"dev": "dev",
|
||||
"main": "main"
|
||||
},
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio",
|
||||
"log": [
|
||||
"* 9bfce91 (origin/dev) fix: add log graph to notifications",
|
||||
"| * c37bd2c (origin/next, origin/main) feat: add log graph to notifications",
|
||||
"|/",
|
||||
"* 8c19680 refactor: macros use a more common syntax"
|
||||
]
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "branch.dev.not-on-main"
|
||||
}
|
||||
```
|
||||
|
||||
#### CI Check Failed
|
||||
|
||||
This message `type` indicates that the commit on the tip of the `next` branch has failed the
|
||||
configured CI checks.
|
||||
|
||||
**Action Required**: Either update the commit to correct the issue CI raised, or, if the issue
|
||||
is transient (e.g. a network issue), re-run/re-start the job in your CI.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"commit": {
|
||||
"sha": "c37bd2caf6825f9770d725a681e5cfc09d7fd4f2",
|
||||
"message": "feat: add log graph to notifications (1 of 2)"
|
||||
},
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio",
|
||||
"log": [
|
||||
"* 9bfce91 (origin/dev) feat: add log graph to notifications (2 of 2)",
|
||||
"* c37bd2c (origin/next) feat: add log graph to notifications (1 of 2)",
|
||||
"* 8c19680 (origin/main) refactor: macros use a more common syntax"
|
||||
]
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "cicheck.failed"
|
||||
}
|
||||
```
|
||||
|
||||
#### Repo Config Load Failed
|
||||
|
||||
This message `type` indicates that `git-next` wasn't able to load the configuration for the
|
||||
repo from the `git-next.toml` file in the repository.
|
||||
|
||||
**Action Required**: Review the `reason` provided.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"reason": "File not found: .git-next.toml",
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio"
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "config.load.failed"
|
||||
}
|
||||
```
|
||||
|
||||
#### Webhook Registration Failed
|
||||
|
||||
This message `type` indicates that `git-next` wasn't able to register it's webhook with the
|
||||
forge repository, so will not receive updates when the branches in the repo are updated.
|
||||
|
||||
**Action Required**: Review the `reason` provided.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"reason": "repo config not loaded",
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio"
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "webhook.registration.failed"
|
||||
}
|
||||
```
|
||||
|
||||
## Behaviour
|
||||
|
||||
The branch names are configurable, but we will talk about `main`, `next` and `dev`.
|
||||
|
||||
Development happens on the `dev` branch, where each commit is expected to
|
||||
be able to pass the CI checks.
|
||||
|
||||
(Note: in the diagrams, mermaid isn't capable of showing `main` and `next` on
|
||||
the same commit, so we show `next` as empty)
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
|
||||
branch dev
|
||||
commit
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
When the `git-next` server sees that the `dev` branch is ahead of the `next`
|
||||
branch, it will push the `next` branch fast-forward one commit along the `dev`
|
||||
branch.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
commit
|
||||
|
||||
branch dev
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
It will then wait for the CI checks to pass for the newly updated `next` branch.
|
||||
When the CI checks for the `next` branch pass, it will push the `main` branch
|
||||
fast-forward to the `next` branch. We return to the top and start again.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
|
||||
branch dev
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
If the CI checks should fail for the `next` branch, the developer should
|
||||
**amend** that commit **in the history of their `dev` branch**.
|
||||
They should then force-push their rebased `dev` branch.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
commit
|
||||
|
||||
checkout main
|
||||
|
||||
branch dev
|
||||
commit
|
||||
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
`git-next` will then detect that the `next` branch is no longer part of the
|
||||
`dev` branch ancestory, and will reset `next` back to `main`.
|
||||
We then return to the top, where `git-next` sees that `dev` is ahead of `next`.
|
||||
|
||||
When the `dev` branch is on the same commit as the `main` branch, then there
|
||||
are no pending commits and `git-next` will wait until it receives a webhook
|
||||
indicating that there has been a push to one of the branches. At which point
|
||||
it will start at the top again.
|
||||
|
||||
### Important
|
||||
|
||||
The `dev` branch _should_ have the `next` branch as an ancestor.
|
||||
|
||||
However, when the commit on tip of the `next` branch has failed CI and is
|
||||
amended, this will not be the case. When this happens `git-next` will
|
||||
**force-push** the `next` branch back to the same commit as the `main` branch.
|
||||
|
||||
This is the only time a force-push will happen in `git-next`.
|
||||
|
||||
In short, the `next` branch **belongs** to `git-next`. Don't try to update it
|
||||
yourself. `git-next` will update the `next` it as it sees fit.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use `git-next` for trunk-based development, follow these steps:
|
||||
|
||||
### Initialise the repo (optional)
|
||||
|
||||
You need to specify which branches you are using. You can do this in the repo,
|
||||
or in the server configuration.
|
||||
|
||||
To create a default config file for the repo, run this command in the root of
|
||||
your repo:
|
||||
|
||||
```shell
|
||||
git next init
|
||||
```
|
||||
|
||||
This will create a `.git-next.toml` file. [Default](./crates/cli/default.toml)
|
||||
|
||||
By default the expected branches are `main`, `next` and `dev`. Each of these
|
||||
three branches _must_ exist in your repo.
|
||||
|
||||
### Initialise the server
|
||||
|
||||
The server uses the file `git-next-server.toml` for configuration. It expects
|
||||
to find this file the the current directory when executed.
|
||||
|
||||
The create the default config file, run this command:
|
||||
|
||||
```shell
|
||||
git next server init
|
||||
```
|
||||
|
||||
This will create a `git-next-server.toml` file. [Default](./crates/server/server-default.toml)
|
||||
|
||||
Edit this file to your needs. See the [Configuration](#configuration) section above.
|
||||
|
||||
### Run the server
|
||||
|
||||
In the directory with your `git-next-server.toml` file, run the command:
|
||||
|
||||
```shell
|
||||
git next server start
|
||||
```
|
||||
|
||||
### Forges
|
||||
|
||||
The following forges are supported:
|
||||
|
||||
- [ForgeJo](https://forgejo.org) (probably compatible with Gitea, but not tested)
|
||||
- [GitHub](https://github.com/)
|
||||
|
||||
Note: ForgeJo is a hard fork of Gitea, but currently they are largely compatible.
|
||||
For now using a `forge_type` of `ForgeJo` with a Gitea instance will probably work
|
||||
okay. The only API calls we make are around registering and unregistering webhooks.
|
||||
So, as long as those APIs remain the same, they should be compatible.
|
||||
|
||||
#### ForgeJo
|
||||
|
||||
Configure the forge in `git-next-server.toml` like:
|
||||
|
||||
```toml
|
||||
[forge.jo]
|
||||
forge_type = "ForgeJo"
|
||||
hostname = "git.myforgejo.com"
|
||||
user = "bob"
|
||||
token = "..."
|
||||
|
||||
[forge.jo.repos]
|
||||
hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/projects/user/hello.git" } # maps to https://git.example.net/user/hello on the branch 'main'
|
||||
world = { repo = "user/world", branch = "master", main = "master", next = "upcoming", "dev" = "develop" } # maps to the 'master' branch
|
||||
```
|
||||
|
||||
The token is created on your ForgeJo instance at (for example)
|
||||
`https://git.myforgejo.com/user/settings/applications`
|
||||
and requires the `write:repository` permission.
|
||||
|
||||
#### GitHub
|
||||
|
||||
Configure the forge in `git-next-server.toml` like:
|
||||
|
||||
```toml
|
||||
[forge.gh]
|
||||
forge_type = "GitHub"
|
||||
hostname = "github.com" # required even for GitHub
|
||||
user = "bob"
|
||||
token = "..."
|
||||
|
||||
[forge.gh.repos]
|
||||
hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/projects/user/hello.git" } # maps to https://github.com/user/hello on the branch 'main'
|
||||
world = { repo = "user/world", branch = "master", main = "master", next = "upcoming", "dev" = "develop" } # maps to the 'master' branch
|
||||
```
|
||||
|
||||
The token is created [here](https://github.com/settings/tokens/new) and requires the `repo` and `admin:repo_hook` permissions.
|
||||
|
||||
## Docker
|
||||
|
||||
`git-next` is available as a [Docker image](https://git.kemitix.net/kemitix/-/packages/container/git-next/).
|
||||
|
||||
```shell
|
||||
docker pull docker pull git.kemitix.net/kemitix/git-next:latest
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Here is an example `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
server:
|
||||
image: git.kemitix.net/kemitix/git-next:latest
|
||||
container_name: git-next-server
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
RUST_LOG: "hyper=warn,info"
|
||||
ports:
|
||||
- 8080:8092
|
||||
volumes:
|
||||
- ./:/app/
|
||||
```
|
||||
|
||||
Note: this assumes the `git-next-server.toml` has a `listen.http.port` of
|
||||
`8092` and that you are using a reverse proxy to route traffic arriving at
|
||||
`listen.url` to port `8080`.
|
||||
|
||||
### Docker Run
|
||||
|
||||
This will run with the `server start` options:
|
||||
|
||||
```shell
|
||||
docker run -it -p "8080:8092" -v .:/app/ git.kemitix.net/kemitix/git-next:latest
|
||||
```
|
||||
|
||||
To perform `server init`:
|
||||
|
||||
```shell
|
||||
docker run -it -v .:/app/ git.kemitix.net/kemitix/git-next:latest server init
|
||||
```
|
||||
|
||||
To perform repo `init`:
|
||||
|
||||
```shell
|
||||
docker run -it -v .:/app/ git.kemitix.net/kemitix/git-next:latest init
|
||||
```
|
||||
|
||||
TUI support is not available in the docker container. See [kemitix/git-next#154](https://git.kemitix.net/kemitix/git-next/issues/154).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions to `git-next` are welcome! If you find a bug or have a feature
|
||||
request, please
|
||||
[create an issue](https://git.kemitix.net/kemitix/git-next/issues/new).
|
||||
If you'd like to contribute code, feel free to submit changes.
|
||||
|
||||
Before you start committing, run the `just install-hooks` command to setup the
|
||||
Git Hooks. ([Get Just](https://just.systems/man/en/chapter_3.html))
|
||||
|
||||
## Crate Dependency
|
||||
|
||||
The following diagram shows the dependency between the crates that make up `git-next`:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
|
||||
cli --> core
|
||||
cli --> forge_forgejo
|
||||
cli --> forge_github
|
||||
|
||||
forge_forgejo --> core
|
||||
|
||||
forge_github --> core
|
||||
```
|
||||
|
||||
## Actor Supervision Tree
|
||||
|
||||
```mermaid
|
||||
mindmap
|
||||
Root
|
||||
Alerts
|
||||
FileWatcher
|
||||
Server
|
||||
Repo 1
|
||||
Repo 2
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
`git-next` is released under the [MIT License](./LICENSE).
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
[package]
|
||||
name = "git-next"
|
||||
version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
description = "git-next, the trunk-based development manager"
|
||||
authors = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
keywords = { workspace = true }
|
||||
categories = { workspace = true }
|
||||
|
||||
[features]
|
||||
# default = ["forgejo", "github"]
|
||||
default = ["forgejo", "github", "tui"]
|
||||
forgejo = []
|
||||
github = []
|
||||
tui = [
|
||||
"ratatui",
|
||||
"directories",
|
||||
"lazy_static",
|
||||
"tui-scrollview",
|
||||
"regex",
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
|
||||
# TUI
|
||||
ratatui = { workspace = true, optional = true }
|
||||
directories = { workspace = true, optional = true }
|
||||
lazy_static = { workspace = true, optional = true }
|
||||
color-eyre = { workspace = true }
|
||||
tui-scrollview = { workspace = true, optional = true }
|
||||
regex = { workspace = true, optional = true }
|
||||
chrono = { workspace = true, optional = true }
|
||||
|
||||
# CLI parsing
|
||||
clap = { workspace = true }
|
||||
|
||||
# fs/network
|
||||
kxio = { workspace = true }
|
||||
|
||||
# logging
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
tracing-error.workspace = true
|
||||
|
||||
# Conventional Commit check
|
||||
git-conventional = { workspace = true }
|
||||
|
||||
# TOML parsing
|
||||
toml = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
# Actors
|
||||
kameo = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
# boilerplate
|
||||
bon = { workspace = true }
|
||||
derive_more = { workspace = true }
|
||||
derive-with = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
# Webhooks
|
||||
serde_json = { workspace = true }
|
||||
ulid = { workspace = true }
|
||||
time = { workspace = true }
|
||||
secrecy = { workspace = true }
|
||||
standardwebhooks = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
warp = { workspace = true }
|
||||
|
||||
# file watcher (linux)
|
||||
notify = { workspace = true }
|
||||
|
||||
# email
|
||||
lettre = { workspace = true }
|
||||
sendmail = { workspace = true }
|
||||
|
||||
# desktop notifications
|
||||
notifica = { workspace = true }
|
||||
|
||||
# git
|
||||
async-trait = { workspace = true }
|
||||
|
||||
# sha256 encoding (e.g. verify github webhooks)
|
||||
hmac = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
|
||||
# Git
|
||||
gix = { workspace = true }
|
||||
git-url-parse = { workspace = true }
|
||||
|
||||
# boilerplate
|
||||
pike = { workspace = true }
|
||||
|
||||
|
||||
mockall = { workspace = true }
|
||||
|
||||
#iters
|
||||
take-until = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# Testing
|
||||
assert2 = { workspace = true }
|
||||
test-log = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
mockall = { workspace = true }
|
||||
rstest = { workspace = true }
|
||||
|
||||
[lints.clippy]
|
||||
nursery = { level = "warn", priority = -1 }
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
unwrap_used = "warn"
|
||||
expect_used = "warn"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
|
|
@ -1,672 +0,0 @@
|
|||
# git-next
|
||||
|
||||
## Trunk-based developement manager.
|
||||
|
||||
> A source-control branching model, where developers collaborate on code in a single branch
|
||||
> called ‘trunk’, resist any pressure to create other long-lived development branches by
|
||||
> employing documented techniques. They therefore avoid merge hell, do not break the build,
|
||||
> and live happily ever after. - [source](https://trunkbaseddevelopment.com)
|
||||
|
||||
- Status: **BETA** - dog-fooding
|
||||
|
||||
`git-next` is a combined server and command-line tool that enables trunk-based
|
||||
development workflows where each commit must pass CI before being included in
|
||||
the main branch.
|
||||
|
||||
## Features
|
||||
|
||||
- Allows enforcing the requirement for each commit to pass the CI pipeline before being
|
||||
included in the main branch
|
||||
- Provides a server component that manages the trunk-based development process
|
||||
- Ensure a consistent, high-quality codebase by preventing untested changes
|
||||
from being added to main
|
||||
- Requires each commit uses conventional commit format.
|
||||
|
||||
See [Behaviour](#behaviour) to learn how we do this.
|
||||
|
||||
## Prerequisits
|
||||
|
||||
- Rust 1.76.0 or later - https://www.rust-lang.org
|
||||
- pgk-config
|
||||
- libssl-dev
|
||||
- libdbus-1-dev (ubuntu/debian)
|
||||
- dbus-devel (fedora)
|
||||
|
||||
See `.cargo/config.toml` for how they are configured.
|
||||
|
||||
## Installation
|
||||
|
||||
You can install `git-next` from <https://crates.io/>:
|
||||
|
||||
```shell
|
||||
cargo install git-next
|
||||
```
|
||||
|
||||
If you use [mise](https://mise.jdx.dev):
|
||||
|
||||
```shell
|
||||
mise use -g cargo:git-next
|
||||
```
|
||||
|
||||
Or you can install `git-next` from source after cloning:
|
||||
|
||||
```shell
|
||||
cargo install --path crates/cli
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] cli
|
||||
- [x] server
|
||||
- [x] notifications - notify user when intervention required (e.g. to rebase)
|
||||
- [x] tui overview
|
||||
- [ ] webui overview
|
||||
|
||||
## Branch Names
|
||||
|
||||
`git-next` uses three branches, `main`, `next` and `dev`, although they do not
|
||||
need to have those names. In the documentation we will use those names, but
|
||||
each repo must specify the names of the branches to use for each, even if they
|
||||
happen to have those same names.
|
||||
|
||||
## Configuration
|
||||
|
||||
- The branches to use for `main`, `next` and `dev` must be specified in either
|
||||
the `.git-next.toml` in the repo itself, or in the server configuration file,
|
||||
`git-next-server.toml`. See below for details.
|
||||
- CI checks should be configured to run when the `next` branch is `pushed`.
|
||||
- The `dev` branch _must_ have the `main` branch as an ancestor.
|
||||
- The `next` branch _must_ have the `main` branch as an ancestor.
|
||||
|
||||
### Server
|
||||
|
||||
The server is configured by the `git-next-server.toml` file.
|
||||
|
||||
#### listen
|
||||
|
||||
The server should listen for webhook notifications from each forge.
|
||||
|
||||
```toml
|
||||
[listen]
|
||||
http = { addr = "0.0.0.0", port = 8080 }
|
||||
url = "https://localhost:8080"
|
||||
```
|
||||
|
||||
##### http
|
||||
|
||||
The server needs to be able to receive webhook notifications from your forge,
|
||||
(e.g. github.com). You can do this via any method that suits your environment,
|
||||
e.g. ngrok or a reverse proxy from a web server that itself can route traffic
|
||||
to the machine you are running the git-next server on.
|
||||
|
||||
Specify the address and port the server should listen to for incoming webhooks.
|
||||
This is the address and port that your reverse proxy should route traffic to.
|
||||
|
||||
- **addr** - the IP address the server should bind to
|
||||
- **port** - the IP port the server should bind to
|
||||
|
||||
##### url
|
||||
|
||||
The HTTPS URL for forges to send webhooks to.
|
||||
|
||||
Your forges need to know where they should route webhooks to. This should be
|
||||
an address this is accessible to the forge. So, for github.com, it would need
|
||||
to be a publicly accessible HTTPS URL. For a self-hosted forge, e.g. ForgeJo,
|
||||
on your own network, then it only needs to be accessible from the server your
|
||||
forge is running on.
|
||||
|
||||
#### shout
|
||||
|
||||
The server should be able to notify the user when manual intervention is required.
|
||||
|
||||
```toml
|
||||
[shout]
|
||||
desktop = true
|
||||
|
||||
[shout.webhook]
|
||||
url = "https//localhost:9090"
|
||||
secret = "secret-password"
|
||||
|
||||
[shout.email]
|
||||
from = "git-next@example.com"
|
||||
to = "developer@example.com"
|
||||
|
||||
[shout.email.smtp]
|
||||
hostname = "smtp.example.com"
|
||||
username = "git-next@example.com"
|
||||
password = "MySecretEmailPassword42"
|
||||
```
|
||||
|
||||
##### desktop
|
||||
|
||||
When specified as `true`, desktop notifications will be sent for some events.
|
||||
|
||||
##### webhook
|
||||
|
||||
Will send a POST request for some events.
|
||||
|
||||
- **url** - the URL to POST the notification to and the
|
||||
- **secret** - the sync key used to sign the webhook payload
|
||||
|
||||
See [Notifications](#notifications) for more details.
|
||||
|
||||
##### email
|
||||
|
||||
Will send an email for some events.
|
||||
|
||||
- **from** - the email address to send the email from
|
||||
- **to** - the email address to send the email to
|
||||
|
||||
With just `from` and `to` specified, `git-next` will attempt to send emails
|
||||
with `sendmail` if it is configured.
|
||||
|
||||
Alternativly, you can use an SMTP relay.
|
||||
|
||||
###### smtp
|
||||
|
||||
Will send emails using an SMTP relay.
|
||||
|
||||
- **hostname** - the SMTP relay server
|
||||
- **username** - the account to authenticate as
|
||||
- **password** - the password to authenticate with
|
||||
|
||||
#### storage
|
||||
|
||||
```toml
|
||||
[storage]
|
||||
path = "./data"
|
||||
```
|
||||
|
||||
`git-next` will create a bare clone of each repo that you configure it to
|
||||
monitor. They will all be created in the directory specified here. This data
|
||||
does not need to be backed up, as any missing information will be cloned when
|
||||
the server starts up.
|
||||
|
||||
- **path** - directory to store local copies of monitored repos
|
||||
|
||||
#### forge
|
||||
|
||||
Within the forge tree, specify each forge you want to monitor repos on.
|
||||
|
||||
Give your forge an alias, e.g. `default`, `gh`, `github`.
|
||||
|
||||
e.g.
|
||||
|
||||
```toml
|
||||
[forge.github]
|
||||
forge_type = "GitHub"
|
||||
hostname = "github.com"
|
||||
user = "username"
|
||||
token = "api-key"
|
||||
max_dev_commits = 25
|
||||
```
|
||||
|
||||
- **forge_type** - one of: `ForgeJo` or `GitHub`
|
||||
- **hostname** - the hostname for the forge.
|
||||
- **user** - the user to authenticate as
|
||||
- **token** - application token for the user. See [Forges](#forges) below for the permissions required for each forge.
|
||||
- **max_dev_commits** - [optional] the maximum number of commits allowed between `dev` and `main`. Defaults to 25.
|
||||
|
||||
Generally, the `user` will need to be able to push to `main` and to _force-push_
|
||||
to `next`.
|
||||
|
||||
#### repos
|
||||
|
||||
For each forge, you need to specify which repos on the forge you want to
|
||||
monitor. They do not need to be owned by the `user`, but they `user` must have
|
||||
the `push` and `force-push` permissions as mentioned above for each of the
|
||||
repositories.
|
||||
|
||||
e.g.
|
||||
|
||||
```toml
|
||||
[forge.github.repos]
|
||||
my-repo = { repo = "owner/repo", branch = "main", gitdir = "/home/pcampbell/project/my-repo" }
|
||||
|
||||
[forge.github.repos.other-repo]
|
||||
repo = "user/other"
|
||||
branch = "master"
|
||||
main = "master"
|
||||
next = "ci-testing"
|
||||
dev = "trunk"
|
||||
```
|
||||
|
||||
Note that toml allows specifying the values on one line, or across multiple
|
||||
lines. Both are equivalent. What is not equivalent between `my-repo` and
|
||||
`other-repo`, is that one will require a configuration file within the repo
|
||||
itself. `other-repo` specifies the `main`, `next` and `dev` branches to be
|
||||
used, but `my-repo` doesn't.
|
||||
|
||||
A sample `.git-next-toml` file that would need to exist in `my-repo`'s `owner/repo`
|
||||
repo, on the `main` branch:
|
||||
|
||||
```toml
|
||||
[branches]
|
||||
main = "main"
|
||||
next = "next"
|
||||
dev = "dev"
|
||||
```
|
||||
|
||||
- **repo** - the owner and name of the repo to be monitored
|
||||
- **branch** - the branch to look for a `.git-next.toml` file if needed
|
||||
- **gitdir** - (optional) you can use a local copy of the repo
|
||||
- **main** - the branch to use as `main`
|
||||
- **next** - the branch to use as `next`
|
||||
- **dev** - the branch to use as `dev`
|
||||
|
||||
##### gitdir
|
||||
|
||||
Additional notes on using `gitdir`:
|
||||
|
||||
When you specify the `gitdir` value, the repo cloned in that directory will
|
||||
be used for perform the equivalent of `git fetch`, `git push` and `git push
|
||||
--force-with-lease`.
|
||||
|
||||
These commands will not affect the contents of your working tree, nor will
|
||||
it change any local branches. Only the details about branches on the remote
|
||||
forge will be updated.
|
||||
|
||||
Currently `git-next` can only use a `gitdir` if the forge and repo is the
|
||||
same one specified as the `origin` remote. Otherwise the behaviour is
|
||||
untested and undefined.
|
||||
|
||||
## Webhook Notifications
|
||||
|
||||
When sending a Webhook Notification to a user they are sent using the
|
||||
Standard Webhooks format. That means all POST messages have the
|
||||
following headers:
|
||||
|
||||
- `Webhook-Id`
|
||||
- `Webhook-Signature`
|
||||
- `Webhook-Timestamp`
|
||||
|
||||
### Events
|
||||
|
||||
#### Dev Not Based on Main
|
||||
|
||||
This message `type` indicates that the `dev` branch is not based on `main`.
|
||||
|
||||
**Action Required**: Rebase the `dev` branch onto the `main` branch.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"branches": {
|
||||
"dev": "dev",
|
||||
"main": "main"
|
||||
},
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio",
|
||||
"log": [
|
||||
"* 9bfce91 (origin/dev) fix: add log graph to notifications",
|
||||
"| * c37bd2c (origin/next, origin/main) feat: add log graph to notifications",
|
||||
"|/",
|
||||
"* 8c19680 refactor: macros use a more common syntax"
|
||||
]
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "branch.dev.not-on-main"
|
||||
}
|
||||
```
|
||||
|
||||
#### CI Check Failed
|
||||
|
||||
This message `type` indicates that the commit on the tip of the `next` branch has failed the
|
||||
configured CI checks.
|
||||
|
||||
**Action Required**: Either update the commit to correct the issue CI raised, or, if the issue
|
||||
is transient (e.g. a network issue), re-run/re-start the job in your CI.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"commit": {
|
||||
"sha": "c37bd2caf6825f9770d725a681e5cfc09d7fd4f2",
|
||||
"message": "feat: add log graph to notifications (1 of 2)"
|
||||
},
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio",
|
||||
"log": [
|
||||
"* 9bfce91 (origin/dev) feat: add log graph to notifications (2 of 2)",
|
||||
"* c37bd2c (origin/next) feat: add log graph to notifications (1 of 2)",
|
||||
"* 8c19680 (origin/main) refactor: macros use a more common syntax"
|
||||
]
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "cicheck.failed"
|
||||
}
|
||||
```
|
||||
|
||||
#### Repo Config Load Failed
|
||||
|
||||
This message `type` indicates that `git-next` wasn't able to load the configuration for the
|
||||
repo from the `git-next.toml` file in the repository.
|
||||
|
||||
**Action Required**: Review the `reason` provided.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"reason": "File not found: .git-next.toml",
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio"
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "config.load.failed"
|
||||
}
|
||||
```
|
||||
|
||||
#### Webhook Registration Failed
|
||||
|
||||
This message `type` indicates that `git-next` wasn't able to register it's webhook with the
|
||||
forge repository, so will not receive updates when the branches in the repo are updated.
|
||||
|
||||
**Action Required**: Review the `reason` provided.
|
||||
|
||||
Sample payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"reason": "repo config not loaded",
|
||||
"forge_alias": "jo",
|
||||
"repo_alias": "kxio"
|
||||
},
|
||||
"timestamp": "1721760933",
|
||||
"type": "webhook.registration.failed"
|
||||
}
|
||||
```
|
||||
|
||||
## Behaviour
|
||||
|
||||
The branch names are configurable, but we will talk about `main`, `next` and `dev`.
|
||||
|
||||
Development happens on the `dev` branch, where each commit is expected to
|
||||
be able to pass the CI checks.
|
||||
|
||||
(Note: in the diagrams, mermaid isn't capable of showing `main` and `next` on
|
||||
the same commit, so we show `next` as empty)
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
|
||||
branch dev
|
||||
commit
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
When the `git-next` server sees that the `dev` branch is ahead of the `next`
|
||||
branch, it will push the `next` branch fast-forward one commit along the `dev`
|
||||
branch.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
commit
|
||||
|
||||
branch dev
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
It will then wait for the CI checks to pass for the newly updated `next` branch.
|
||||
When the CI checks for the `next` branch pass, it will push the `main` branch
|
||||
fast-forward to the `next` branch. We return to the top and start again.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
|
||||
branch dev
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
If the CI checks should fail for the `next` branch, the developer should
|
||||
**amend** that commit **in the history of their `dev` branch**.
|
||||
They should then force-push their rebased `dev` branch.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
|
||||
branch next
|
||||
commit
|
||||
|
||||
checkout main
|
||||
|
||||
branch dev
|
||||
commit
|
||||
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
`git-next` will then detect that the `next` branch is no longer part of the
|
||||
`dev` branch ancestory, and will reset `next` back to `main`.
|
||||
We then return to the top, where `git-next` sees that `dev` is ahead of `next`.
|
||||
|
||||
When the `dev` branch is on the same commit as the `main` branch, then there
|
||||
are no pending commits and `git-next` will wait until it receives a webhook
|
||||
indicating that there has been a push to one of the branches. At which point
|
||||
it will start at the top again.
|
||||
|
||||
### Important
|
||||
|
||||
The `dev` branch _should_ have the `next` branch as an ancestor.
|
||||
|
||||
However, when the commit on tip of the `next` branch has failed CI and is
|
||||
amended, this will not be the case. When this happens `git-next` will
|
||||
**force-push** the `next` branch back to the same commit as the `main` branch.
|
||||
|
||||
This is the only time a force-push will happen in `git-next`.
|
||||
|
||||
In short, the `next` branch **belongs** to `git-next`. Don't try to update it
|
||||
yourself. `git-next` will update the `next` it as it sees fit.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use `git-next` for trunk-based development, follow these steps:
|
||||
|
||||
### Initialise the repo (optional)
|
||||
|
||||
You need to specify which branches you are using. You can do this in the repo,
|
||||
or in the server configuration.
|
||||
|
||||
To create a default config file for the repo, run this command in the root of
|
||||
your repo:
|
||||
|
||||
```shell
|
||||
git next init
|
||||
```
|
||||
|
||||
This will create a `.git-next.toml` file. [Default](./crates/cli/default.toml)
|
||||
|
||||
By default the expected branches are `main`, `next` and `dev`. Each of these
|
||||
three branches _must_ exist in your repo.
|
||||
|
||||
### Initialise the server
|
||||
|
||||
The server uses the file `git-next-server.toml` for configuration. It expects
|
||||
to find this file the the current directory when executed.
|
||||
|
||||
The create the default config file, run this command:
|
||||
|
||||
```shell
|
||||
git next server init
|
||||
```
|
||||
|
||||
This will create a `git-next-server.toml` file. [Default](./crates/server/server-default.toml)
|
||||
|
||||
Edit this file to your needs. See the [Configuration](#configuration) section above.
|
||||
|
||||
### Run the server
|
||||
|
||||
In the directory with your `git-next-server.toml` file, run the command:
|
||||
|
||||
```shell
|
||||
git next server start
|
||||
```
|
||||
|
||||
### Forges
|
||||
|
||||
The following forges are supported:
|
||||
|
||||
- [ForgeJo](https://forgejo.org) (probably compatible with Gitea, but not tested)
|
||||
- [GitHub](https://github.com/)
|
||||
|
||||
Note: ForgeJo is a hard fork of Gitea, but currently they are largely compatible.
|
||||
For now using a `forge_type` of `ForgeJo` with a Gitea instance will probably work
|
||||
okay. The only API calls we make are around registering and unregistering webhooks.
|
||||
So, as long as those APIs remain the same, they should be compatible.
|
||||
|
||||
#### ForgeJo
|
||||
|
||||
Configure the forge in `git-next-server.toml` like:
|
||||
|
||||
```toml
|
||||
[forge.jo]
|
||||
forge_type = "ForgeJo"
|
||||
hostname = "git.myforgejo.com"
|
||||
user = "bob"
|
||||
token = "..."
|
||||
|
||||
[forge.jo.repos]
|
||||
hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/projects/user/hello.git" } # maps to https://git.example.net/user/hello on the branch 'main'
|
||||
world = { repo = "user/world", branch = "master", main = "master", next = "upcoming", "dev" = "develop" } # maps to the 'master' branch
|
||||
```
|
||||
|
||||
The token is created on your ForgeJo instance at (for example)
|
||||
`https://git.myforgejo.com/user/settings/applications`
|
||||
and requires the `write:repository` permission.
|
||||
|
||||
#### GitHub
|
||||
|
||||
Configure the forge in `git-next-server.toml` like:
|
||||
|
||||
```toml
|
||||
[forge.gh]
|
||||
forge_type = "GitHub"
|
||||
hostname = "github.com" # required even for GitHub
|
||||
user = "bob"
|
||||
token = "..."
|
||||
|
||||
[forge.gh.repos]
|
||||
hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/projects/user/hello.git" } # maps to https://github.com/user/hello on the branch 'main'
|
||||
world = { repo = "user/world", branch = "master", main = "master", next = "upcoming", "dev" = "develop" } # maps to the 'master' branch
|
||||
```
|
||||
|
||||
The token is created [here](https://github.com/settings/tokens/new) and requires the `repo` and `admin:repo_hook` permissions.
|
||||
|
||||
## Docker
|
||||
|
||||
`git-next` is available as a [Docker image](https://git.kemitix.net/kemitix/-/packages/container/git-next/).
|
||||
|
||||
```shell
|
||||
docker pull docker pull git.kemitix.net/kemitix/git-next:latest
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Here is an example `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
server:
|
||||
image: git.kemitix.net/kemitix/git-next:latest
|
||||
container_name: git-next-server
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
RUST_LOG: "hyper=warn,info"
|
||||
ports:
|
||||
- 8080:8092
|
||||
volumes:
|
||||
- ./:/app/
|
||||
```
|
||||
|
||||
Note: this assumes the `git-next-server.toml` has a `listen.http.port` of
|
||||
`8092` and that you are using a reverse proxy to route traffic arriving at
|
||||
`listen.url` to port `8080`.
|
||||
|
||||
### Docker Run
|
||||
|
||||
This will run with the `server start` options:
|
||||
|
||||
```shell
|
||||
docker run -it -p "8080:8092" -v .:/app/ git.kemitix.net/kemitix/git-next:latest
|
||||
```
|
||||
|
||||
To perform `server init`:
|
||||
|
||||
```shell
|
||||
docker run -it -v .:/app/ git.kemitix.net/kemitix/git-next:latest server init
|
||||
```
|
||||
|
||||
To perform repo `init`:
|
||||
|
||||
```shell
|
||||
docker run -it -v .:/app/ git.kemitix.net/kemitix/git-next:latest init
|
||||
```
|
||||
|
||||
TUI support is not available in the docker container. See [kemitix/git-next#154](https://git.kemitix.net/kemitix/git-next/issues/154).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions to `git-next` are welcome! If you find a bug or have a feature
|
||||
request, please
|
||||
[create an issue](https://git.kemitix.net/kemitix/git-next/issues/new).
|
||||
If you'd like to contribute code, feel free to submit changes.
|
||||
|
||||
Before you start committing, run the `just install-hooks` command to setup the
|
||||
Git Hooks. ([Get Just](https://just.systems/man/en/chapter_3.html))
|
||||
|
||||
## Crate Dependency
|
||||
|
||||
The following diagram shows the dependency between the crates that make up `git-next`:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
|
||||
cli --> core
|
||||
cli --> forge_forgejo
|
||||
cli --> forge_github
|
||||
|
||||
forge_forgejo --> core
|
||||
|
||||
forge_github --> core
|
||||
```
|
||||
|
||||
## Actor Supervision Tree
|
||||
|
||||
```mermaid
|
||||
mindmap
|
||||
Root
|
||||
Alerts
|
||||
FileWatcher
|
||||
Server
|
||||
Repo 1
|
||||
Repo 2
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
`git-next` is released under the [MIT License](./LICENSE).
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue