Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documents #3

Merged
merged 12 commits into from
Mar 8, 2019
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "testdata/fibonacci"]
path = testdata/fibonacci
url = https://htamada@bitbucket.org/htamada/fibonacci.git
[submodule "testdata/helloworld"]
path = testdata/helloworld
url = https://htamada@bitbucket.org/htamada/helloworld.git
19 changes: 10 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@ LDFLAGS := -X 'main.version=$(VERSION)'
-X 'main.revision=$(REVISION)'

setup:
go get -u golang.org/x/lint/golint
go get -u golang.org/x/tools/cmd/goimports
go get -u github.com/golang/dep/cmd/dep
go get golang.org/x/lint/golint
go get golang.org/x/tools/cmd/goimports
go get github.com/golang/dep/cmd/dep

go get -u github.com/mitchellh/cli
go get -u gopkg.in/src-d/go-git.v4
go get -u github.com/dustin/go-humanize
go get -u github.com/posener/complete/gocomplete
go get -u golang.org/x/tools/cmd/cover
go get -u github.com/mattn/goveralls
go get github.com/mitchellh/cli
go get gopkg.in/src-d/go-git.v4
go get github.com/dustin/go-humanize
go get github.com/posener/complete/gocomplete
go get golang.org/x/tools/cmd/cover
go get github.com/mattn/goveralls

test:
go test -covermode=count -coverprofile=coverage.out $$(go list ./... | grep -v vendor)
git checkout -- testdata

update: setup
dep ensure
git submodule update --init

lint: setup
go vet $$(go list ./... | grep -v vendor)
Expand Down
104 changes: 93 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ Therefore, we built a headquarter for managing the git repositories, named RRH.
RRH manages repositories by categorizing in groups and execute git command to the groups.

I know the tool [ghq](https://github.com/motemen/ghq), manages the git repositories.
However, I cannot use it by the following reasons.
However, I cannot use it for the following reasons.

1. there are quite many repositories in my home directory.
* To start using ghq, we clone the repositories.
However, I did not accept to clone all of repositories.
However, I did not accept to clone all of the repositories.
2. The location of repositories is fixed in the config file and is accepted only one location.
* I just decide the directory layout in my home directory.
* I decide the directory layout in my home directory.

Additionally, I edit several repositories in a days, when I work hard.
Consequently, the progress of each repository are obscured, I cannot remember a lot of things.
Additionally, I edit several repositories in a day, when I work hard.
Consequently, the progress of each repository is obscured; I cannot remember a lot of things.
Therefore, it is glad to see the last modified date of branches.

RRH is now growing. Please hack RRH itself.
Expand Down Expand Up @@ -52,10 +52,12 @@ Available commands are:
status show git status of repositories.
```

## subcommands
## Subcommands

### `rrh add`

Registers the repositories which specified the given paths to the RRH database and categorize to the group (Default `no-group`, see [`RRH_DEFAULT_GROUP_NAME`](#rrh_default_group_name)).

```sh
rrh add [OPTIONS] <REPOSITORY_PATHS...>
OPTIONS
Expand All @@ -66,17 +68,28 @@ ARGUMENTS

### `rrh clone`

Runs `git clone` command and registers the cloned repository to RRH database.
The following steps identify the id of the repository.

1. If the length of `REMOTE_REPOS` is 1, and `DEST` exists, then the last entry of `REMOTE_REPOS` is repository id by eliminating the suffix `.git`.
3. If the length of `REMOTE_REPOS` is 1, and `DEST` does not exist, then the last entry of `DEST` is repository id.
2. If the length of `REMOTE_REPOS` is greater than 1, then the last entry of each `REMOTE_REPOS` is repository ids by eliminating the suffix `.git`.

```sh
rrh clone [OPTIONS] <REMOTE_REPOS...>
OPTIONS
-g, --group <GROUP> print managed repositories categoried in the group.
-d, --dest <DEST> specify the destination.
-d, --dest <DEST> specify the destination. Default is the current directory.
ARGUMENTS
REMOTE_REPOS repository urls
```

### `rrh config`

Handles the operations of configuration/environment variables.
This subcommand requires sub-sub-command.
If sub-sub-command was not specified, it runs `list` sub-sub-command.

```sh
rrh config <COMMAND> [ARGUMENTS]
COMMAND
Expand All @@ -87,6 +100,8 @@ COMMAND

### `rrh export`

Exports the data of RRH database by JSON format.

```sh
rrh export [OPTIONS]
OPTiONS
Expand All @@ -95,6 +110,8 @@ OPTiONS

### `rrh fetch`

Runs `git fetch` command in the repositories of the specified group.

```sh
rrh fetch [OPTIONS] [GROUPS...]
OPTIONS
Expand All @@ -106,6 +123,9 @@ ARGUMENTS

### `rrh fetch-all`

Runs `git fetch` command in all repositories of managing in RRH.
This command may make heavy network traffic; therefore, we do not recommend to run.

```sh
rrh fetch-all [OPTIONS]
OPTIONS
Expand All @@ -114,6 +134,10 @@ OPTIONS

### `rrh group`

Handles the operations of groups of RRH.
This subcommand requires sub-sub-command.
If sub-sub-command was not specified, it runs `list` sub-sub-command.

```sh
rrh group <SUBCOMMAND>
SUBCOMMAND
Expand All @@ -125,6 +149,8 @@ SUBCOMMAND

### `rrh list`

Prints the repositories of managing in RRH.

```sh
rrh list [OPTIONS] [GROUPS...]
OPTIONS
Expand All @@ -142,12 +168,20 @@ ARGUMENTS

### `rrh prune`

Deletes unnecessary groups and repositories.
The unnecessary groups are no repositories in them.
The unnecessary repositories are to have an invalid path.


```sh
rrh prune
```

### `rrh rm`

Removes the specified groups, repositories, and relations.
If the group has entries is removed by specifying the option `--recursive.`

```sh
rrh rm [OPTIONS] <REPO_ID|GROUP_ID|REPO_ID/GROUP_ID...>
OPTIONS
Expand All @@ -159,11 +193,13 @@ ARGUMENTS
REPOY_ID repository name for removing.
GROUP_ID group name. if the group contains repositories,
removing will fail without '-r' option.
GROUP_ID/REPO_ID remove given REPO_ID from GROUP_ID.
GROUP_ID/REPO_ID remove the relation between the given REPO_ID and GROUP_ID.
```

### `rrh status`

Prints the last modified times of each branch in the repositories of the specified group.

```sh
rrh status [OPTIONS] [GROUPS||REPOS...]
OPTIONS
Expand All @@ -177,13 +213,59 @@ ARGUMENTS
shows the result of default group.
```

# Database
## Environment variables

We can see those variables by running `rrh config` sub-command.

* `RRH_HOME`
* specifies the location of the RRH database and config file.
* default: `/Users/tamada/.rrh`
* `RRH_CONFIG_PATH`
* specifies the location of the location path.
* RRH ignores to specify `RRH_CONFIG_PATH` in the config file.
This variable availables only environment variable.
* default: `${RRH_HOME}/config.json`
* `RRH_DATABASE_PATH`
* specifies the location of the database path.
* default: `${RRH_HOME}/database.json`
* `RRH_DEFAULT_GROUP_NAME`
* specifies the default group name.
* default: `no-group`
* `RRH_ON_ERROR`
* specifies the behaviors of RRH on error.
* default: `WARN`
* Available values: `FAIL_IMMEDIATELY`, `FAIL`, `WARN`, and `IGNORE`
* `FAIL_IMMEDIATELY`
* reports error immediately and quits RRH with a non-zero status.
* `FAIL`
* runs through all targets and reports errors if needed, then quits RRH with a non-zero status.
* `WARN`
* runs through all targets and reports errors if needed, then quits RRH successfully.
* `IGNORE`
* runs all targets and no reports errors.
* `RRH_TIME_FORMAT`
* specifies the time format for `status` command.
* default: `relative`
* Available value: `relative` and the time format for Go lang.
* `relative`
* shows times by humanized format (e.g., 2 weeks ago)
* Other strings
* regard as formatting layout and give to `Format` method of the time.
* see [Time.Format](https://golang.org/pkg/time/#Time.Format), for more detail.
* `RRH_AUTO_CREATE_GROUP`
* specifies to create the group when the not existing group was specified, and it needs to create.
* default: false
* `RRH_AUTO_DELETE_GROUP`
* specifies to delete the group when some group was no more needed.
* default: false

## Database

The database for managed repositories is formatted in JSON.
The JSON format is as follows.
The JSON file is placed on `$RRH_ROOT/database.json`.
If `$RRH_ROOT` was not set, `$HOME` is used as `$RRH_ROOT`.
Also, configuration file is on `$RRH_ROOT/config.json`
Also, the configuration file is on `$RRH_ROOT/config.json`

```js
{
Expand Down Expand Up @@ -251,4 +333,4 @@ Join our Gitter channel if you have any problem or suggestions to Rrh.
[![Gitter misc_ja](https://img.shields.io/badge/Gitter-For_Japanese-red.svg)](https://gitter.im/rrh_git/misc_ja)

For Japanese user, `misc_ja` channel has discussions in Japanese.
The public language of other channels and GitHub pages is English.
The public language of other channels and GitHub pages are English.
3 changes: 2 additions & 1 deletion add/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func (add *AddCommand) isExistAndGitRepository(absPath string, path string) erro
return fmt.Errorf("%s: not directory", path)
}
fmode, err = os.Stat(filepath.Join(absPath, ".git"))
if err != nil || !fmode.IsDir() {
// If the repository of path is submodule, `.git` will be a file to indicate the `.git` directory.
if os.IsNotExist(err) {
return fmt.Errorf("%s: not git repository", path)
}
return nil
Expand Down
8 changes: 4 additions & 4 deletions add/add_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ func (add *AddCommand) Run(args []string) int {
return add.perform(db, opt.args, opt.group)
}

type addoptions struct {
type addOptions struct {
group string
args []string
}

func (add *AddCommand) parse(args []string, config *common.Config) (*addoptions, error) {
var opt = addoptions{}
flags := flag.NewFlagSet("add", flag.ExitOnError)
func (add *AddCommand) parse(args []string, config *common.Config) (*addOptions, error) {
var opt = addOptions{}
flags := flag.NewFlagSet("add", flag.ContinueOnError)
flags.Usage = func() { fmt.Println(add.Help()) }
flags.StringVar(&opt.group, "g", config.GetValue(common.RrhDefaultGroupName), "target group")
flags.StringVar(&opt.group, "group", config.GetValue(common.RrhDefaultGroupName), "target group")
Expand Down
72 changes: 72 additions & 0 deletions add/add_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package add

import (
"os"
"testing"

"github.com/tamada/rrh/common"
)

func rollback(f func()) {
var config = common.OpenConfig()
var db, _ = common.Open(config)
defer db.StoreAndClose()

f()
}

func TestHelpAndSynopsis(t *testing.T) {
var command, _ = AddCommandFactory()
if command.Synopsis() != "add repositories on the local path to RRH" {
t.Error("synopsis did not match")
}
if command.Help() != `rrh add [OPTIONS] <REPOSITORY_PATHS...>
OPTIONS
-g, --group <GROUP> add repository to RRH database.
ARGUMENTS
REPOSITORY_PATHS the local path list of the git repositories` {
t.Error("help did not match")
}
}

func TestAddToTheSpecifiedGroup(t *testing.T) {
os.Setenv(common.RrhConfigPath, "../testdata/config.json")
os.Setenv(common.RrhDatabasePath, "../testdata/tmp.json")
rollback(func() {
var command, _ = AddCommandFactory()
command.Run([]string{"--group", "group2", "../testdata/helloworld"})

var config = common.OpenConfig()
var db, _ = common.Open(config)
if !db.HasGroup("group2") {
t.Error("group2: group not found")
}
if !db.HasRepository("helloworld") {
t.Error("helloworld: repository not found")
}
if !db.HasRelation("group2", "helloworld") {
t.Error("gruop2, and helloworld: the relation not found")
}
})
}

func TestAddCommand_Run(t *testing.T) {
os.Setenv(common.RrhConfigPath, "../testdata/config.json")
os.Setenv(common.RrhDatabasePath, "../testdata/tmp.json")
rollback(func() {
var command, _ = AddCommandFactory()
command.Run([]string{"../testdata/fibonacci"})

var config = common.OpenConfig()
var db, _ = common.Open(config)
if !db.HasGroup("no-group") {
t.Error("no-group: group not found")
}
if !db.HasRepository("fibonacci") {
t.Error("fibonacci: repository not found")
}
if !db.HasRelation("no-group", "fibonacci") {
t.Error("no-group, and fibonacci: the relation not found")
}
})
}
18 changes: 16 additions & 2 deletions clone/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,27 @@ func (clone *CloneCommand) DoClone(db *common.Database, arguments []string) (int
return count, errorlist
}

func (clone *CloneCommand) relateTo(db *common.Database, groupID string, repoID string) error {
if !db.HasGroup(groupID) {
if db.Config.GetValue(common.RrhAutoCreateGroup) == "true" {
db.CreateGroup(groupID, "")
} else {
return fmt.Errorf("%s: group not found", groupID)
}
}
db.Relate(groupID, repoID)
return nil
}

func (clone *CloneCommand) DoCloneRepositories(db *common.Database, url string) (int, error) {
var count int
var id = findID(url)
var path = filepath.Join(clone.Options.dest, id)
var _, err = clone.toDir(db, url, path, id)
if err == nil {
db.Relate(clone.Options.group, id)
if err := clone.relateTo(db, clone.Options.group, id); err != nil {
return count, err
}
count++
}
return count, err
Expand All @@ -96,7 +110,7 @@ func (clone *CloneCommand) DoCloneARepository(db *common.Database, URL string) e
if err != nil {
return err
}
return db.Relate(clone.Options.group, id)
return clone.relateTo(db, clone.Options.group, id)
}

func findID(URL string) string {
Expand Down
Loading