From 75c39ad79980863d0db50f7149be9f648aaa7b75 Mon Sep 17 00:00:00 2001 From: Ce Gao Date: Mon, 1 May 2017 21:34:58 +0800 Subject: [PATCH] contributing: Get owner and project from git Signed-off-by: Ce Gao --- CONTRIBUTING.md | 2 +- cmd/contributing.go | 5 ++ cmd/root.go | 12 ++++- repo/repo.go | 117 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 repo/repo.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c77c92..cc85e1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,4 +61,4 @@ For the why part, if no specific reason for the change, you can use one of some generic reasons like "Improve documentation.", "Improve performance.", "Improve robustness.", "Improve test coverage." -###### Auto generated by [gaocegege/maintainer](https://github.com/gaocegege/maintainer) on 2017-04-27 +###### Auto generated by [gaocegege/maintainer](https://github.com/gaocegege/maintainer) on 2017-05-01 diff --git a/cmd/contributing.go b/cmd/contributing.go index ad26aa1..a48ad66 100644 --- a/cmd/contributing.go +++ b/cmd/contributing.go @@ -17,6 +17,7 @@ package cmd import ( "log" + "github.com/gaocegege/maintainer/repo" "github.com/gaocegege/maintainer/util" "github.com/spf13/cobra" ) @@ -49,6 +50,10 @@ func init() { // contributingRun runs the real logic to generate CONTRIBUTING.md. func contributingRun() error { + Repo, err := repo.NewRepository() + if err != nil { + log.Panicf("Error when read the information from local repository: %s\n", err) + } // Output results to AUTHORS.md. f, err := util.OpenFile(contributingFile) if err != nil { diff --git a/cmd/root.go b/cmd/root.go index aa9276b..5f0ada9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -20,13 +20,19 @@ import ( "log" + "github.com/gaocegege/maintainer/repo" + "github.com/spf13/cobra" "github.com/spf13/viper" ) -var cfgFile string +var ( + cfgFile string + // Repo stores the information in the local repository. + Repo *repo.Repository +) -// This represents the base command when called without any subcommands +// RootCmd represents the base command when called without any subcommands var RootCmd = &cobra.Command{ Use: "maintainer", Short: "Help you to be a qualified maintainer.", @@ -61,5 +67,7 @@ func initConfig() { // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { log.Println("Using config file:", viper.ConfigFileUsed()) + } else { + log.Println("There is no config file defined.") } } diff --git a/repo/repo.go b/repo/repo.go new file mode 100644 index 0000000..27abea7 --- /dev/null +++ b/repo/repo.go @@ -0,0 +1,117 @@ +// Copyright © 2017 Maintainer Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package repo + +import ( + "errors" + "fmt" + "os/exec" + "regexp" +) + +const ( + gitCmd string = "git" + gitConfigArgs string = "config" + gitConfigGetArgs string = "--get" + gitConfigGetRemoteArgs string = "remote.origin.url" +) + +var ( + gitRemotePattern = []string{ + `.*(?:[:\/])(?P(?:-|\w|\.)*)\/(?P(?:-|\w|\.)*)(?:\.git).*`, + `.*\/(?P(?:-|\w|\.)*)\/(?P(?:-|\w|\.)*).*`, + } + + errNameOrProjectNotExists = errors.New("Couldn't get the URL of this repository") + + singleton *Repository +) + +// Repository is the type for the local repository. +type Repository struct { + Owner string + Name string +} + +// NewRepository returns a new Repository. +func NewRepository() (*Repository, error) { + if singleton != nil { + return singleton, nil + } + + name, project, err := getNameAndRepoName() + if err != nil { + return nil, err + } + + singleton = &Repository{ + Owner: name, + Name: project, + } + return singleton, nil +} + +// String returns the information of a local repository. +func (r *Repository) String() string { + return fmt.Sprintf("Local Repository Information: \n\tOwner: %s\n\tName: %s\n", r.Owner, r.Name) +} + +// See https://github.com/skywinder/github-changelog-generator/blob/master/lib/github_changelog_generator/parser.rb#L312. +func getNameAndRepoName() (string, string, error) { + cmd := exec.Command(gitCmd, gitConfigArgs, gitConfigGetArgs, gitConfigGetRemoteArgs) + output, err := cmd.Output() + if err != nil { + return "", "", err + } + outputStr := string(output) + + // get the name and project. + name, project, err := getNameAndRepoNameFromRemote(outputStr) + if err != nil { + return "", "", err + } + + return name, project, nil +} + +// getNameAndRepoName gets the name and project from local repository. +func getNameAndRepoNameFromRemote(remoteStr string) (string, string, error) { + for _, regEx := range gitRemotePattern { + paramsMap := getParams(regEx, remoteStr) + name, ok1 := paramsMap["user"] + project, ok2 := paramsMap["project"] + if ok1 != true || ok2 != true { + continue + } + return name, project, nil + } + return "", "", errNameOrProjectNotExists +} + +// getParams get the params from regexp. +// See http://stackoverflow.com/questions/30483652/how-to-get-capturing-group-functionality-in-golang-regular-expressions. +func getParams(regEx, url string) (paramsMap map[string]string) { + + var compRegEx = regexp.MustCompile(regEx) + match := compRegEx.FindStringSubmatch(url) + + paramsMap = make(map[string]string) + for i, name := range compRegEx.SubexpNames() { + if i > 0 && i <= len(match) { + paramsMap[name] = match[i] + } + } + return +}