Skip to content

Commit

Permalink
Merge 9f69a6b into 621ba8f
Browse files Browse the repository at this point in the history
  • Loading branch information
tamada committed Mar 7, 2019
2 parents 621ba8f + 9f69a6b commit 4aad144
Show file tree
Hide file tree
Showing 19 changed files with 386 additions and 116 deletions.
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
20 changes: 10 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ 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 -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 golang.org/x/lint/golint
go get golang.org/x/tools/cmd/goimports
go get github.com/golang/dep/cmd/dep

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)
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.
7 changes: 6 additions & 1 deletion add/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ func (add *AddCommand) isExistAndGitRepository(absPath string, path string) erro
return fmt.Errorf("%s: not directory", path)
}
fmode, err = os.Stat(filepath.Join(absPath, ".git"))
fmt.Printf(filepath.Join(absPath, ".git"))
if err != nil || !fmode.IsDir() {
return fmt.Errorf("%s: not git repository", path)
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
}
fmt.Printf("%s: not git repository (%v)", absPath, fmode.Mode())
return fmt.Errorf("%s: not git repository (%v)", path, fmode.Mode())
}
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

0 comments on commit 4aad144

Please sign in to comment.