Skip to content

Commit 0b5bb2c

Browse files
Sam ClementsConan-Kudo
authored andcommitted
Initial commit
0 parents  commit 0b5bb2c

21 files changed

+2808
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.env
2+
.idea/
3+
__pycache__/
4+
config.json

LICENSE

Lines changed: 373 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
git river
2+
=========
3+
4+
`git river workspace` will manage a "workspace" path you configure, cloning
5+
and managing repositories from configured GitHub and GitLab groups.
6+
7+
Repositories will be organized by the domain and path of the remote GitHub
8+
repository or GitLab project.
9+
10+
```
11+
$ tree ~/workspace
12+
~/workspace
13+
├── github.com
14+
│ └── datto
15+
│ └── example
16+
└── gitlab.com
17+
└── datto
18+
└── example
19+
```
20+
21+
Links
22+
-----
23+
24+
* [Source code](https://github.com/datto/git-river/)
25+
* [Packages](https://pypi.org/project/git-river/)
26+
27+
Installation
28+
------------
29+
30+
`git-river` requires Python 3.9 or above.
31+
32+
```
33+
pip3 install git-river
34+
```
35+
36+
Usage
37+
-----
38+
39+
Run `git-river <subcommand>`. Git's builtin aliasing also allows you to
40+
run `git river` instead.
41+
42+
```bash
43+
git-river --help
44+
```
45+
46+
- `git river config` displays the current configuration.
47+
48+
- `git river workspace` manages the workspace path.
49+
50+
Run without any subcommand, it runs all workspace subcommands except `list`
51+
and `fetch`.
52+
53+
- `git river workspace clone` clones repositories.
54+
- `git river workspace configure` sets git config options.
55+
- `git river workspace fetch` fetches each git remote.
56+
- `git river workspace list` displays remote repos that will be cloned.
57+
- `git river workspace remotes` sets `upstream` and `origin` remotes.
58+
- `git river workspace tidy` deletes merged branches.
59+
60+
- `git river repo` manages the repository in the current directory.
61+
62+
This mostly matches the features from the `workspace` subcommand.
63+
64+
- `git river repo configure` sets git config options.
65+
- `git river repo fetch` fetches each git remote.
66+
- `git river repo remotes` sets `upstream` and `origin` remotes.
67+
- `git river repo tidy` deletes merged branches.
68+
69+
Configuration
70+
-------------
71+
72+
Configuration is a JSON object read from `~/.config/git-river/config.json`.
73+
74+
- `path` - path to a directory to use as the "workspace".
75+
- `forges` - a map of forges.
76+
77+
Forges have the following options. Only `type` is required - the default
78+
configuration is to use the main public GitHub or GitLab domain without
79+
authentication.
80+
81+
- `type` (required) - The type of the instance, either `github` or `gitlab`.
82+
- `base_url` (optional) - Base url of the instance. Should not include a trailing slash.
83+
- Default for GitHub instances is `https://api.github.com`.
84+
- Default for GitLab instances is `https://gitlab.com`.
85+
- `login_or_token` (optional, GitHub only) - Authentication token.
86+
- `private_token` (optional, GitLab only) - Authentication token.
87+
- `gitconfig` (default: `{}`) - A key-value map of git config options to set on repositories.
88+
- `groups` (default: `[]`) - Include repositories from specific groups.
89+
- `users` (default: `[]`) - Include repositories from specific users.
90+
- `self` (default: `true`) - Automatically include the authenticated user's repositories.
91+
92+
93+
### Example
94+
95+
```json
96+
{
97+
"workspace": "~/Development",
98+
"forges": {
99+
"gitlab": {
100+
"type": "gitlab",
101+
"base_url": "https://gitlab.com",
102+
"private_token": "...",
103+
"groups": [],
104+
"users": [],
105+
"self": true,
106+
"gitconfig": {
107+
"user.email": "[email protected]"
108+
}
109+
},
110+
"github": {
111+
"type": "github",
112+
"login_or_token": "...",
113+
"groups": [],
114+
"users": [],
115+
"gitconfig": {
116+
"user.email": "[email protected]"
117+
}
118+
}
119+
}
120+
}
121+
```
122+
123+
Development
124+
-----------
125+
126+
[Poetry][poetry] is used to develop, build, and package git-river. Poetry's
127+
[documentation][poetry/docs] describes how to install it on your OS. Once you've
128+
installed it, create a virtual environment containing git-river and it's
129+
dependencies with `poetry install`.
130+
131+
You can then run the local version of the CLI with `poetry run git-river`.
132+
133+
Code is formatted using [black], run with `poetry run black git_river`.
134+
135+
Types are checked using [mypy], run with `poetry run mypy git_river`.
136+
137+
Tests are written using [pytest], run with `poetry run pytest`.
138+
139+
```bash
140+
# Download the project and install dependencies
141+
git clone https://github.com/datto/git-river.git
142+
cd git-river
143+
poetry install
144+
145+
# Use the local version of the CLI
146+
poetry run git-river ...
147+
148+
# Test, lint and format code
149+
poetry run black git_river
150+
poetry run mypy git_river
151+
poetry run pytest
152+
```
153+
154+
License
155+
-------
156+
157+
Licensed under the Mozilla Public License Version 2.0.
158+
159+
Copyright Datto, Inc.
160+
161+
Authored by [Sam Clements](https://github.com/borntyping).
162+
163+
[black]: https://github.com/psf/black
164+
[mypy]: https://mypy.readthedocs.io/en/stable/
165+
[poetry/docs]: https://python-poetry.org/docs/
166+
[poetry]: https://python-poetry.org/
167+
[pytest]: https://docs.pytest.org/

git_river/__init__.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# This file is part of git-river.
2+
#
3+
# Copyright Datto, Inc.
4+
# Author: Sam Clements <[email protected]>
5+
#
6+
# Licensed under the Mozilla Public License Version 2.0.
7+
# Fedora-License-Identifier: MPLv2.0
8+
# SPDX-2.0-License-Identifier: MPL-2.0
9+
# SPDX-3.0-License-Identifier: MPL-2.0
10+
#
11+
# git-river is open source software.
12+
# For more information on the license, see LICENSE.
13+
# For more information on open source software, see https://opensource.org/osd.
14+
#
15+
# This Source Code Form is subject to the terms of the Mozilla Public
16+
# License, v. 2.0. If a copy of the MPL was not distributed with this
17+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
18+
19+
__app__ = "git-river"

git_river/__main__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This file is part of git-river.
2+
#
3+
# Copyright Datto, Inc.
4+
# Author: Sam Clements <[email protected]>
5+
#
6+
# Licensed under the Mozilla Public License Version 2.0.
7+
# Fedora-License-Identifier: MPLv2.0
8+
# SPDX-2.0-License-Identifier: MPL-2.0
9+
# SPDX-3.0-License-Identifier: MPL-2.0
10+
#
11+
# git-river is open source software.
12+
# For more information on the license, see LICENSE.
13+
# For more information on open source software, see https://opensource.org/osd.
14+
#
15+
# This Source Code Form is subject to the terms of the Mozilla Public
16+
# License, v. 2.0. If a copy of the MPL was not distributed with this
17+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
18+
19+
import git_river.cli
20+
21+
git_river.cli.main()

git_river/cli.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# This file is part of git-river.
2+
#
3+
# Copyright Datto, Inc.
4+
# Author: Sam Clements <[email protected]>
5+
#
6+
# Licensed under the Mozilla Public License Version 2.0.
7+
# Fedora-License-Identifier: MPLv2.0
8+
# SPDX-2.0-License-Identifier: MPL-2.0
9+
# SPDX-3.0-License-Identifier: MPL-2.0
10+
#
11+
# git-river is open source software.
12+
# For more information on the license, see LICENSE.
13+
# For more information on open source software, see https://opensource.org/osd.
14+
#
15+
# This Source Code Form is subject to the terms of the Mozilla Public
16+
# License, v. 2.0. If a copy of the MPL was not distributed with this
17+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
18+
19+
import click
20+
import pydantic.error_wrappers
21+
22+
import git_river
23+
import git_river.commands
24+
import git_river.commands.clone
25+
import git_river.commands.forge
26+
import git_river.commands.config
27+
import git_river.commands.repo
28+
import git_river.config
29+
30+
31+
@click.group()
32+
@click.pass_context
33+
def main(ctx: click.Context) -> None:
34+
git_river.config.configure_logging()
35+
try:
36+
ctx.obj = git_river.config.Config()
37+
except pydantic.error_wrappers.ValidationError as error:
38+
raise click.UsageError(str(error)) from error
39+
40+
41+
main.add_command(git_river.commands.clone.main)
42+
main.add_command(git_river.commands.config.display_config)
43+
main.add_command(git_river.commands.config.display_workspace)
44+
main.add_command(git_river.commands.config.init_config)
45+
main.add_command(git_river.commands.forge.main)
46+
main.add_command(git_river.commands.repo.configure_options)
47+
main.add_command(git_river.commands.repo.configure_remotes)
48+
main.add_command(git_river.commands.repo.fetch_remotes)
49+
main.add_command(git_river.commands.repo.merge_feature_branches)
50+
main.add_command(git_river.commands.repo.tidy_branches)
51+
main.add_command(git_river.commands.repo.restart)
52+
main.add_command(git_river.commands.repo.end)

git_river/commands/__init__.py

Whitespace-only changes.

git_river/commands/clone.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# This file is part of git-river.
2+
#
3+
# Copyright Datto, Inc.
4+
# Author: Sam Clements <[email protected]>
5+
#
6+
# Licensed under the Mozilla Public License Version 2.0.
7+
# Fedora-License-Identifier: MPLv2.0
8+
# SPDX-2.0-License-Identifier: MPL-2.0
9+
# SPDX-3.0-License-Identifier: MPL-2.0
10+
#
11+
# git-river is open source software.
12+
# For more information on the license, see LICENSE.
13+
# For more information on open source software, see https://opensource.org/osd.
14+
#
15+
# This Source Code Form is subject to the terms of the Mozilla Public
16+
# License, v. 2.0. If a copy of the MPL was not distributed with this
17+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
18+
19+
import typing
20+
21+
import click
22+
import structlog
23+
24+
import git_river.config
25+
import git_river.ext.click
26+
27+
logger = structlog.get_logger(logger_name=__name__)
28+
29+
30+
@click.command(name="clone")
31+
@click.argument(
32+
"repositories",
33+
metavar="REPOSITORY",
34+
type=click.STRING,
35+
nargs=-1,
36+
)
37+
@click.pass_obj
38+
def main(config: git_river.config.Config, repositories: typing.Sequence[str]) -> None:
39+
"""Clone a repository to the workspace path."""
40+
for url in repositories:
41+
config.repository_from_url(url).clone(verbose=True)

git_river/commands/config.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# This file is part of git-river.
2+
#
3+
# Copyright Datto, Inc.
4+
# Author: Sam Clements <[email protected]>
5+
#
6+
# Licensed under the Mozilla Public License Version 2.0.
7+
# Fedora-License-Identifier: MPLv2.0
8+
# SPDX-2.0-License-Identifier: MPL-2.0
9+
# SPDX-3.0-License-Identifier: MPL-2.0
10+
#
11+
# git-river is open source software.
12+
# For more information on the license, see LICENSE.
13+
# For more information on open source software, see https://opensource.org/osd.
14+
#
15+
# This Source Code Form is subject to the terms of the Mozilla Public
16+
# License, v. 2.0. If a copy of the MPL was not distributed with this
17+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
18+
import pathlib
19+
20+
import click
21+
22+
import git_river
23+
import git_river.commands
24+
import git_river.commands.clone
25+
import git_river.commands.forge
26+
import git_river.commands.repo
27+
import git_river.config
28+
29+
30+
@click.command(name="config")
31+
@click.pass_obj
32+
def display_config(config: git_river.config.Config) -> None:
33+
"""Dump the current configuration as JSON."""
34+
print(config.json(indent=2, by_alias=True))
35+
36+
37+
@click.command(name="init")
38+
@click.argument(
39+
"workspace",
40+
type=click.Path(
41+
exists=False,
42+
file_okay=False,
43+
dir_okay=True,
44+
path_type=pathlib.Path,
45+
),
46+
)
47+
@click.pass_obj
48+
def init_config(config: git_river.config.Config, workspace: str) -> None:
49+
config.workspace = pathlib.Path(workspace)
50+
51+
if git_river.config.CONFIG_PATH.exists():
52+
raise click.UsageError(f"Config file {git_river.config.CONFIG_PATH} already exists")
53+
54+
if not git_river.config.CONFIG_DIRECTORY.exists():
55+
git_river.config.CONFIG_DIRECTORY.mkdir()
56+
57+
git_river.config.CONFIG_PATH.write_text(config.json(indent=2, by_alias=True))
58+
59+
60+
@click.command(name="workspace")
61+
@click.pass_obj
62+
def display_workspace(config: git_river.config.Config) -> None:
63+
"""Print the workspace path."""
64+
print(config.workspace)

0 commit comments

Comments
 (0)