first commit

This commit is contained in:
bcharest 2023-06-12 22:40:22 -04:00
commit 8bb6c99d39
11 changed files with 816 additions and 0 deletions

105
config/config.go Normal file
View File

@ -0,0 +1,105 @@
package config
import (
"kode-starter/utils"
"github.com/spf13/cobra"
)
var version string = "0.0.1"
var author string = "Bruno Charest"
var modifDate string = "2023-06-12"
var tokenEnv string = utils.GetGitToken()
var verboseFlag bool = false
var jsonFlag bool = false
var urlBase string = "https://git.bcmaison.cf"
var urlApiBase string = urlBase + "/api/v1"
var urlApiOrgs string = urlApiBase + "/orgs"
func GetVersion() string {
return version
}
func GetAuthor() string {
return author
}
func GetBuildDate() string {
return modifDate
}
func GetToken() string {
return tokenEnv
}
func SetToken(token string) {
tokenEnv = token
}
func GetJsonFlag() bool {
return jsonFlag
}
func SetJsonFlag(flag bool) {
jsonFlag = flag
}
func GetUrlBase() string {
return urlBase
}
func GetUrlApiBase() string {
return urlApiBase
}
func GetUrlApiOrgs() string {
return urlApiOrgs
}
func GetVerboseFlag() bool {
return verboseFlag
}
func SetVerboseFlag(flag bool) {
verboseFlag = flag
}
func SetInformations(cmd *cobra.Command, args []string, userToken string) {
// Check if the verbose flag is set
if cmd.Flags().Changed("verbose") || cmd.Flags().Changed("v") {
SetVerboseFlag(true)
} else {
SetVerboseFlag(false)
}
// Check if the json flag is set
if cmd.Flags().Changed("json") || cmd.Flags().Changed("j") {
SetJsonFlag(true)
} else {
SetJsonFlag(false)
}
// Check if token come from flag or env
if cmd.Flags().Changed("token") || cmd.Flags().Changed("t") {
if utils.IsValidToken(userToken) {
SetToken(userToken)
} else {
utils.ExitWithError(10, "Invalid token, format must be 40 characters UUID.")
}
} else {
if utils.IsValidToken(utils.GetGitToken()) {
SetToken(utils.GetGitToken())
} else {
utils.ExitWithError(10, "Invalid token, format must be 40 characters UUID.")
}
}
}

2
create/create.go Normal file
View File

@ -0,0 +1,2 @@
package create

13
go.mod Normal file
View File

@ -0,0 +1,13 @@
module kode-starter
go 1.20
require (
github.com/joho/godotenv v1.5.1
github.com/spf13/cobra v1.7.0
)
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)

12
go.sum Normal file
View File

@ -0,0 +1,12 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

219
kode-starter.go Normal file
View File

@ -0,0 +1,219 @@
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"kode-starter/config"
"kode-starter/lists"
"kode-starter/structures"
"kode-starter/utils"
"log"
"net/http"
"os"
"os/exec"
"strings"
"github.com/joho/godotenv"
"github.com/spf13/cobra"
)
func createReadme(projectName, description, author, url string) bool {
file, err := os.Open("../readme.template")
if err != nil {
log.Fatal(err)
}
defer file.Close()
template := ""
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
line = strings.Replace(line, "<project_name>", projectName, -1)
line = strings.Replace(line, "<description>", description, -1)
line = strings.Replace(line, "<author>", author, -1)
line = strings.Replace(line, "<gitea_project_url>", url, -1)
template += line + "\n"
}
readmeFile, err := os.Create("README.md")
if err != nil {
log.Fatal(err)
}
defer readmeFile.Close()
_, err = readmeFile.WriteString(template)
if err != nil {
log.Fatal(err)
}
return true
}
var rootCmd = &cobra.Command{
Use: "prj-creator.exe",
Short: "Simple cli app create startup project",
Long: `A simple CLI app to work with Github, Gitea`,
Run: func(cmd *cobra.Command, args []string) {
config.SetInformations(cmd, args, token)
mainProgram(cmd, args)
},
}
var createCmd = &cobra.Command{
Use: "create",
Short: "Create Github project",
Long: `A simple CLI app to create a startup project on Github`,
Run: func(cmd *cobra.Command, args []string) {
config.SetInformations(cmd, args, token)
createProject()
},
}
var token, org, name, private, description string
var verbose, createFlag bool
func init() {
rootCmd.Flags().BoolP("help", "h", false, "Show help for create command")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "mode verbose")
rootCmd.PersistentFlags().BoolVarP(&createFlag, "json", "j", false, "Print output as json format")
lists.ListCmd.Flags().StringVarP(&token, "token", "t", "", "Github token")
lists.ListCmd.Flags().StringVarP(&org, "org", "o", "", "Github organization")
createCmd.Flags().StringVarP(&token, "token", "t", "", "Github token")
createCmd.Flags().StringVarP(&org, "org", "o", "", "Github organization")
createCmd.Flags().StringVarP(&name, "name", "n", "", "Project name")
createCmd.Flags().StringVarP(&description, "desc", "d", "", "Description")
createCmd.Flags().StringVarP(&private, "private", "p", "", "true/false")
rootCmd.AddCommand(lists.ListCmd)
rootCmd.AddCommand(createCmd)
}
func mainProgram(cmd *cobra.Command, args []string) {
// Check if the help flag is set
if cmd.Flags().Changed("help") || cmd.Flags().Changed("h") {
printHelpFormated(cmd)
return
} else {
// If no flag is set, show help
printHelpFormated(cmd)
return
}
}
func createProject() {
godotenv.Load()
fmt.Printf("Token: %s\n", config.GetToken())
// Construct POST data
data := structures.Project{
Name: name,
Description: description,
Private: private == "true",
}
// Make API request to create Github project
jsonData, _ := json.Marshal(data)
req, err := http.NewRequest("POST",
fmt.Sprintf("%s/%s/repos", config.GetUrlApiOrgs(), org),
bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "token "+config.GetToken())
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
var dataReceived structures.GitOrgsRepoResponse
err = json.NewDecoder(res.Body).Decode(&dataReceived)
if err != nil {
log.Fatal(err)
}
fmt.Printf("==> Created project '%s' URL: '%s'\n", name, dataReceived.CloneURL)
defer res.Body.Close()
// Create directory of the project
fmt.Println("==> Creating directory...")
utils.CreateDir(name)
fmt.Println("==> Created directory")
// Change to project directory
err = os.Chdir(name)
if err != nil {
log.Fatal(err)
}
isCreated := createReadme(name, description, "BC", "")
if isCreated {
fmt.Println("==> Created README.md")
}
// Git commands
gitCmd := exec.Command("git", "init")
err = gitCmd.Run()
if err != nil {
log.Fatal(err)
} else {
fmt.Printf("==> Initialized empty Git repository in %s\n", name)
}
gitCmd = exec.Command("git", "checkout", "-b", "main")
err = gitCmd.Run()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("==> Switched to a new branch 'main'")
}
gitCmd = exec.Command("git", "add", "-A")
err = gitCmd.Run()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("==> Switched to a new branch 'main'")
}
gitCmd = exec.Command("git", "commit", "-m", "first commit from project creator !")
err = gitCmd.Run()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("==> first commit from project creator !")
}
// Get project info from API response
var project structures.Project
json.NewDecoder(res.Body).Decode(&project)
fmt.Println(project)
}
func printHelpFormated(cmd *cobra.Command) {
var line string = "--- --- --- --- --- --- --- --- --- --- --- --- ---"
fmt.Println("")
cmd.Help()
fmt.Println("")
fmt.Println(line)
fmt.Println("| Version: " + config.GetVersion() + " || Author: " + config.GetAuthor() + " || Build date: " + config.GetBuildDate() + " |")
fmt.Println(line)
fmt.Println("")
}
func main() {
rootCmd.Execute()
}

94
lists/lists.go Normal file
View File

@ -0,0 +1,94 @@
package lists
import (
"kode-starter/config"
"kode-starter/utils"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/joho/godotenv"
"github.com/spf13/cobra"
)
var token string
var ListCmd = &cobra.Command{
Use: "list",
Short: "List Github, Gitea orgs, project",
Long: `A simple CLI app to list Github, Gitea orgs, project`,
Run: func(cmd *cobra.Command, args []string) {
config.SetInformations(cmd, args, token)
orgs, err := ListItems()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("List of ")
for _, org := range orgs {
fmt.Print(org)
}
},
}
func ListItems() ([]string, error) {
godotenv.Load()
if config.GetVerboseFlag() {
fmt.Println("execute list items...")
fmt.Println("URL: " + config.GetUrlApiOrgs())
fmt.Println("Token: " + config.GetToken())
}
body := UrlGetGithub(config.GetUrlApiOrgs(), config.GetToken())
if config.GetJsonFlag() {
return utils.BytesToStrings(body), nil
} else {
var orgs []map[string]interface{}
err := json.Unmarshal(body, &orgs)
if err != nil {
return nil, err
} else {
var orgNames []string
for i, org := range orgs {
orgNames = append(orgNames, fmt.Sprintf("%d. %s\n", i+1, org["username"]))
}
return orgNames, nil
}
}
}
func UrlGetGithub(url string, token string) []byte {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println("Error creating request:", err)
}
req.Header.Set("Authorization", "token "+config.GetToken())
req.Header.Set("Content-Type", "application/json")
// req.Header.Add("Accept", "application/vnd.github.v3+json")
fmt.Println(req.Header.Get("Authorization"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("Error making request:", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
}
return body
}

72
readme.md Normal file
View File

@ -0,0 +1,72 @@
# Project Creator
This is a simple CLI app to create Github project.
## Description
The Project Creator GO app allows you to:
- Create a Github project (repo)
- Initialize a Git repository
- Create an initial commit
- Generate a README.md file
It uses the Github API to create projects.
## Usage
To build and run the app:
```bash
go build
./prj-creator.exe
```
This will show the help menu. The main commands are:
- `create` - Create a Github project
- `list` - List Github orgs and repos
To create a project:
```bash
./prj-creator.exe create -t <github_token> -o <org_name> -n <project_name> -d <description> -p <private|false>
```
For example:
```bash
./prj-creator.exe create -t abc123 -o myorg -n myproject -d "A test project" -p false
```
This will:
- Create a public Github repo named `myproject` in the `myorg` org
- Create a directory named `myproject`
- Initialize a Git repo
- Make an initial commit
- Generate a README.md
To list Github orgs and repos:
```bash
./prj-creator.exe list -t <github_token> -o <org_name>
```
For example:
```bash
./prj-creator.exe list -t abc123 -o myorg
```
This will list the repos in the `myorg` organization.
## Environment Variables
You can set the following environment variables:
- `GIT_TOKEN` - Your Github personal access token. This will be used instead of passing the `-t` flag.
##License
MIT License.

48
readme.template Normal file
View File

@ -0,0 +1,48 @@
# <project_name>
## Description
<description>
## Getting Started
### Dependencies
### Installing
### Executing program
#### Show Help
#### Show Version
## Help
Any advise for common problems or issues.
N / A
## Authors
Contributors names and contact info
ex. <author>
ex. [@<author> - Gitea](<gitea_project_url>)
## Version History
* 0.1
* Initial Release
## License
This project is licensed under the GPL License - see the [LICENSE.md](./LICENSE.md) file for details
## Acknowledgments
Inspiration, code snippets, etc.
* [README-Template.md](https://gist.github.com/DomPizzie/7a5ff55ffa9081f2de27c315f5018afc)

View File

@ -0,0 +1,161 @@
package structures
// The GitOrgsRepoResponse type contains various fields related to a Git repository, including
// information about the owner, name, description, permissions, and more.
// @property {int} ID - The unique identifier for the repository.
// @property Owner - An object containing information about the owner of the repository, including
// their ID, login, full name, email, avatar URL, language, admin status, last login time, creation
// time, and various other details.
// @property {string} Name - The name of the repository.
// @property {string} FullName - The full name of the repository, including the owner's username or
// organization name.
// @property {string} Description - A struct that represents the response from the GitHub API when
// retrieving information about a repository belonging to an organization. It contains various
// properties such as the repository ID, owner information, name, description, size, language, number
// of stars, forks, watchers, open issues, and more.
// @property {bool} Empty - a boolean value indicating whether the repository is empty or not.
// @property {bool} Private - A boolean value indicating whether the repository is private or not.
// @property {bool} Fork - A boolean value indicating whether the repository is a fork of another
// repository.
// @property {bool} Template - A boolean value indicating whether the repository is a template
// repository or not. If it is a template repository, it can be used as a starting point for creating
// new repositories with the same structure and content.
// @property Parent - This property represents the parent repository of a forked repository. If the
// repository is not a fork, this property will be null.
// @property {bool} Mirror - A boolean value indicating whether the repository is a mirror or not. A
// mirror repository is a read-only copy of another repository that is automatically kept in sync with
// the original repository.
// @property {int} Size - The size of the repository in bytes.
// @property {string} Language - The primary programming language used in the repository.
// @property {string} LanguagesURL - The URL to retrieve the languages used in the repository.
// @property {string} HTMLURL - The URL of the repository on the web.
// @property {string} SSHURL - The SSH URL of the repository. This is the URL that can be used to clone
// the repository using the SSH protocol.
// @property {string} CloneURL - The URL that can be used to clone the repository.
// @property {string} OriginalURL - The original URL of the repository before it was mirrored.
// @property {string} Website - The website associated with the repository.
// @property {int} StarsCount - The number of stars (or likes) that the repository has received on
// GitHub.
// @property {int} ForksCount - The number of times this repository has been forked.
// @property {int} WatchersCount - The number of users who have starred or are watching the repository.
// @property {int} OpenIssuesCount - The number of open issues in the repository.
// @property {int} OpenPrCounter - The number of open pull requests for the repository.
// @property {int} ReleaseCounter - The number of releases for the repository.
// @property {string} DefaultBranch - The default branch of the repository.
// @property {bool} Archived - A boolean value indicating whether the repository has been archived or
// not.
// @property {string} CreatedAt - The date and time when the repository was created.
// @property {string} UpdatedAt - The date and time when the repository was last updated.
// @property Permissions - This property contains information about the permissions granted to users or
// teams for the repository. It includes three boolean values: admin, push, and pull. Admin grants full
// control over the repository, push allows users to push changes to the repository, and pull allows
// users to pull changes from the repository.
// @property {bool} HasIssues - a boolean value indicating whether the repository has issues enabled
// @property InternalTracker - This property contains information about the internal issue tracker for
// the repository, including whether the time tracker is enabled, whether only contributors can track
// time, and whether issue dependencies are enabled.
// @property {bool} HasWiki - A boolean value indicating whether the repository has a wiki.
// @property {bool} HasPullRequests - A boolean value indicating whether the repository has pull
// requests enabled or not.
// @property {bool} HasProjects - A boolean value indicating whether the repository has GitHub Projects
// enabled.
// @property {bool} IgnoreWhitespaceConflicts - A boolean value indicating whether or not whitespace
// conflicts should be ignored in the repository. This can be useful when merging code that has
// differences in whitespace formatting.
// @property {bool} AllowMergeCommits - A boolean value indicating whether merge commits are allowed in
// the repository.
// @property {bool} AllowRebase - A boolean value indicating whether or not rebase is allowed for this
// repository.
// @property {bool} AllowRebaseExplicit - A boolean value indicating whether explicit rebasing is
// allowed in the repository.
// @property {bool} AllowSquashMerge - A boolean value indicating whether or not squash merging is
// allowed for pull requests in the repository. Squash merging is a way to merge changes from a branch
// into another branch by condensing all the commits into a single commit.
// @property {string} DefaultMergeStyle - The default merge style for pull requests in the repository.
// It can be one of three values: "merge", "rebase", or "squash".
// @property {string} AvatarURL - The URL of the avatar for the owner of the repository.
// @property {bool} Internal - A boolean value indicating whether the repository is internal or not. An
// internal repository is only visible to members of the organization that owns it.
// @property {string} MirrorInterval - The interval at which the repository is mirrored (if it is a
// mirror).
// @property {string} MirrorUpdated - The date and time when the repository was last updated as a
// mirrored repository.
// @property RepoTransfer - This property is of type interface{} and represents the transfer of
// ownership of the repository. It can be null if there is no transfer in progress.
type GitOrgsRepoResponse struct {
ID int `json:"id"`
Owner struct {
ID int `json:"id"`
Login string `json:"login"`
FullName string `json:"full_name"`
Email string `json:"email"`
AvatarURL string `json:"avatar_url"`
Language string `json:"language"`
IsAdmin bool `json:"is_admin"`
LastLogin string `json:"last_login"`
Created string `json:"created"`
Restricted bool `json:"restricted"`
Active bool `json:"active"`
ProhibitLogin bool `json:"prohibit_login"`
Location string `json:"location"`
Website string `json:"website"`
Description string `json:"description"`
Visibility string `json:"visibility"`
FollowersCount int `json:"followers_count"`
FollowingCount int `json:"following_count"`
StarredReposCount int `json:"starred_repos_count"`
Username string `json:"username"`
} `json:"owner"`
Name string `json:"name"`
FullName string `json:"full_name"`
Description string `json:"description"`
Empty bool `json:"empty"`
Private bool `json:"private"`
Fork bool `json:"fork"`
Template bool `json:"template"`
Parent interface{} `json:"parent"`
Mirror bool `json:"mirror"`
Size int `json:"size"`
Language string `json:"language"`
LanguagesURL string `json:"languages_url"`
HTMLURL string `json:"html_url"`
SSHURL string `json:"ssh_url"`
CloneURL string `json:"clone_url"`
OriginalURL string `json:"original_url"`
Website string `json:"website"`
StarsCount int `json:"stars_count"`
ForksCount int `json:"forks_count"`
WatchersCount int `json:"watchers_count"`
OpenIssuesCount int `json:"open_issues_count"`
OpenPrCounter int `json:"open_pr_counter"`
ReleaseCounter int `json:"release_counter"`
DefaultBranch string `json:"default_branch"`
Archived bool `json:"archived"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
Permissions struct {
Admin bool `json:"admin"`
Push bool `json:"push"`
Pull bool `json:"pull"`
} `json:"permissions"`
HasIssues bool `json:"has_issues"`
InternalTracker struct {
EnableTimeTracker bool `json:"enable_time_tracker"`
AllowOnlyContributorsToTrackTime bool `json:"allow_only_contributors_to_track_time"`
EnableIssueDependencies bool `json:"enable_issue_dependencies"`
} `json:"internal_tracker"`
HasWiki bool `json:"has_wiki"`
HasPullRequests bool `json:"has_pull_requests"`
HasProjects bool `json:"has_projects"`
IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"`
AllowMergeCommits bool `json:"allow_merge_commits"`
AllowRebase bool `json:"allow_rebase"`
AllowRebaseExplicit bool `json:"allow_rebase_explicit"`
AllowSquashMerge bool `json:"allow_squash_merge"`
DefaultMergeStyle string `json:"default_merge_style"`
AvatarURL string `json:"avatar_url"`
Internal bool `json:"internal"`
MirrorInterval string `json:"mirror_interval"`
MirrorUpdated string `json:"mirror_updated"`
RepoTransfer interface{} `json:"repo_transfer"`
}

18
structures/Project.go Normal file
View File

@ -0,0 +1,18 @@
package structures
// The "Project" type represents a project with a name, privacy status, and description.
// @property {string} Name - Name is a property of a struct type called Project. It is a string type
// field that represents the name of the project. The `json:"name"` tag is used to specify the name of
// the field when encoding or decoding JSON data.
// @property {bool} Private - Private is a boolean property that indicates whether the project is
// private or not. If it is set to true, only authorized users can access the project. If it is set to
// false, the project is public and can be accessed by anyone.
// @property {string} Description - The "Description" property is a string that represents the
// description of a project. It provides additional information about the project, such as its purpose,
// features, or functionality. This property is used in the "Project" struct, which is a data structure
// used to represent a project in a programming language.
type Project struct {
Name string `json:"name"`
Private bool `json:"private"`
Description string `json:"description"`
}

72
utils/utils.go Normal file
View File

@ -0,0 +1,72 @@
package utils
import (
"fmt"
"os"
"path/filepath"
)
func BytesToStrings(bytes []byte) []string {
var strings []string
for _, b := range bytes {
strings = append(strings, string(b))
}
return strings
}
func GetGitToken() string {
token := os.Getenv("GIT_TOKEN")
return token
}
func IsValidToken(token string) bool {
if len(token) != 40 {
return false
}
// Check if token contains only hexadecimal characters (0-9 and a-f)
for _, c := range token {
if !(('0' <= c && c <= '9') || ('a' <= c && c <= 'f')) {
return false
}
}
return true
}
func IsValidOrg(org string) bool {
// Check if organization is valid
// ...
return true
}
func IsValidProjectName(name string) bool {
// Check if project name is valid
// ...
return true
}
// function that print error message and exit program with specific error code
func ExitWithError(code int, msg string) {
// Print error message
fmt.Println(msg)
// Exit program with specific error code
os.Exit(code)
}
func CreateDir(dirName string) {
path, err := os.Getwd()
if err != nil {
panic(err)
}
fmt.Println("Current working directory: ", path)
dirPath := filepath.Join(path, dirName)
err = os.Mkdir(dirPath, 0755)
if err != nil {
panic(err)
}
fmt.Printf("Created directory '%s' \n", dirName)
}