-
Notifications
You must be signed in to change notification settings - Fork 10
feat(added): license generation #7
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,14 @@ import ( | |
| "errors" | ||
| "fmt" | ||
| "os" | ||
| "time" | ||
|
|
||
| "github.com/charmbracelet/huh" | ||
| "github.com/charmbracelet/huh/spinner" | ||
| "github.com/spf13/cobra" | ||
| app "github.com/vg006/vgo/internal" | ||
| asset "github.com/vg006/vgo/internal/assets" | ||
| "github.com/vg006/vgo/internal/license" | ||
| ) | ||
|
|
||
| var initCmd = &cobra.Command{ | ||
|
|
@@ -18,6 +20,55 @@ var initCmd = &cobra.Command{ | |
| Run: func(cmd *cobra.Command, args []string) { | ||
| var p app.Project | ||
| accessible, _ := cmd.Flags().GetBool("accessible") | ||
|
|
||
| // Fetch licenses from GitHub API | ||
| var licenses []license.GitHubLicense | ||
| var licenseOptions []huh.Option[string] | ||
|
|
||
| err := spinner. | ||
| New(). | ||
| Title("Loading licenses from GitHub..."). | ||
| Action(func() { | ||
| var fetchErr error | ||
| licenses, fetchErr = license.FetchLicenses() | ||
| if fetchErr != nil { | ||
| // If fetch fails, provide some basic options | ||
| licenses = []license.GitHubLicense{ | ||
| {Key: "mit", Name: "MIT License"}, | ||
| {Key: "apache-2.0", Name: "Apache License 2.0"}, | ||
| {Key: "gpl-3.0", Name: "GNU General Public License v3.0"}, | ||
| } | ||
| } | ||
| // Convert licenses to huh options | ||
| licenseOptions = make([]huh.Option[string], 0, len(licenses)+1) | ||
| licenseOptions = append(licenseOptions, huh.NewOption("None", "none")) | ||
| for _, lic := range licenses { | ||
| licenseOptions = append(licenseOptions, huh.NewOption(lic.Name, lic.Key)) | ||
| } | ||
| }). | ||
| Style(asset.Text). | ||
| Accessible(accessible). | ||
| Run() | ||
|
|
||
| if err != nil { | ||
| // Fallback to basic options if spinner fails | ||
| licenseOptions = []huh.Option[string]{ | ||
| huh.NewOption("None", "none"), | ||
| huh.NewOption("MIT License", "mit"), | ||
| huh.NewOption("Apache License 2.0", "apache-2.0"), | ||
| huh.NewOption("GNU General Public License v3.0", "gpl-3.0"), | ||
| } | ||
| } | ||
|
|
||
| // Get git username for default author | ||
| gitUsername := license.GetGitUsername() | ||
| if gitUsername == "" { | ||
| gitUsername = "Your Name" | ||
| } | ||
|
|
||
| // Set default year | ||
| p.Year = fmt.Sprintf("%d", time.Now().Year()) | ||
|
|
||
| form := huh.NewForm( | ||
| huh.NewGroup( | ||
| huh.NewInput(). | ||
|
|
@@ -87,13 +138,49 @@ var initCmd = &cobra.Command{ | |
| huh.NewOption("MongoDB", "mongodb"), | ||
| ), | ||
| ), | ||
| huh.NewGroup( | ||
| huh.NewSelect[string](). | ||
| Value(&p.License). | ||
| Title("License"). | ||
| Description("Select a license for the project"). | ||
| Options(licenseOptions...), | ||
| ), | ||
| huh.NewGroup( | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Conditionally can have this input group |
||
| huh.NewInput(). | ||
| Value(&p.Author). | ||
| Title("Author"). | ||
| Description("Enter the author name for the license"). | ||
| Placeholder(gitUsername). | ||
| Validate(func(s string) error { | ||
| if s == "" && p.License != "none" { | ||
| p.Author = gitUsername | ||
| } | ||
| return nil | ||
| }), | ||
| ).WithHideFunc(func() bool { | ||
| return p.License == "none" | ||
| }), | ||
| huh.NewGroup( | ||
| huh.NewInput(). | ||
| Value(&p.Year). | ||
| Title("Year"). | ||
| Description("Enter the year for the license"). | ||
| Validate(func(s string) error { | ||
| if s == "" { | ||
| p.Year = fmt.Sprintf("%d", time.Now().Year()) | ||
| } | ||
| return nil | ||
| }), | ||
| ).WithHideFunc(func() bool { | ||
| return p.License == "none" | ||
| }), | ||
| ). | ||
| WithAccessible(accessible). | ||
| WithTheme(asset.SetTheme()) | ||
|
|
||
| fmt.Println(asset.VgoLogo) | ||
|
|
||
| err := form.Run() | ||
| err = form.Run() | ||
| if err != nil { | ||
| fmt.Println(asset.Text.Foreground(asset.Red). | ||
| Render(fmt.Sprintf("%s Hey! Why stopped?", asset.EmojiConfused))) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| package license | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net/http" | ||
| "os/exec" | ||
| "strings" | ||
| "time" | ||
| ) | ||
|
|
||
| type GitHubLicense struct { | ||
| Key string `json:"key"` | ||
| Name string `json:"name"` | ||
| Body string `json:"body"` | ||
| } | ||
|
|
||
| // GetGitUsername retrieves the git user.name from global config | ||
| func GetGitUsername() string { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
| cmd := exec.Command("git", "config", "--global", "--get", "user.name") | ||
| output, err := cmd.Output() | ||
| if err != nil { | ||
| return "" | ||
| } | ||
| return strings.TrimSpace(string(output)) | ||
| } | ||
|
|
||
| // FetchLicenses retrieves the list of available licenses from GitHub API | ||
| func FetchLicenses() ([]GitHubLicense, error) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove this |
||
| client := &http.Client{ | ||
| Timeout: 10 * time.Second, | ||
| } | ||
|
|
||
| resp, err := client.Get("https://api.github.com/licenses") | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to fetch licenses: %w", err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| if resp.StatusCode != http.StatusOK { | ||
| return nil, fmt.Errorf("github API returned status: %d", resp.StatusCode) | ||
| } | ||
|
|
||
| body, err := io.ReadAll(resp.Body) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to read response: %w", err) | ||
| } | ||
|
|
||
| var licenses []GitHubLicense | ||
| err = json.Unmarshal(body, &licenses) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to parse licenses: %w", err) | ||
| } | ||
|
|
||
| return licenses, nil | ||
| } | ||
|
|
||
| // GetLicenseContent retrieves the full license content from GitHub API | ||
| func GetLicenseContent(key string) (string, error) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove this |
||
| client := &http.Client{ | ||
| Timeout: 10 * time.Second, | ||
| } | ||
|
|
||
| url := fmt.Sprintf("https://api.github.com/licenses/%s", key) | ||
| resp, err := client.Get(url) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to fetch license content: %w", err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| if resp.StatusCode != http.StatusOK { | ||
| return "", fmt.Errorf("github API returned status: %d", resp.StatusCode) | ||
| } | ||
|
|
||
| body, err := io.ReadAll(resp.Body) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to read response: %w", err) | ||
| } | ||
|
|
||
| var license GitHubLicense | ||
| err = json.Unmarshal(body, &license) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to parse license: %w", err) | ||
| } | ||
|
|
||
| return license.Body, nil | ||
| } | ||
|
|
||
| // RenderLicense replaces placeholders in license content with actual values | ||
| func RenderLicense(content, author, year string) string { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
| replacements := map[string]string{ | ||
| "[year]": year, | ||
| "[fullname]": author, | ||
| "[yyyy]": year, | ||
| "[name of copyright owner]": author, | ||
| "[NAME OF COPYRIGHT OWNER]": author, | ||
| } | ||
|
|
||
| result := content | ||
| for placeholder, value := range replacements { | ||
| result = strings.ReplaceAll(result, placeholder, value) | ||
| } | ||
|
|
||
| return result | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the keys are definite and known, we don't need a fetch call here and better skip it.