Skip to content

Commit

Permalink
feat: Support using local directory as template (#162)
Browse files Browse the repository at this point in the history
- Deprecate `--repo` for `--source`
- Fix a bug with license when passing `repo|source` flag

---------

Closes #161
Signed-off-by: AlexNg <[email protected]>
  • Loading branch information
caffeine-addictt authored Oct 11, 2024
2 parents 024c07f + c43354e commit a0fbec2
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 28 deletions.
17 changes: 8 additions & 9 deletions cmd/commands/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,10 @@ var NewCmd = &cobra.Command{
})

// Clone repo
tmpDir, err := options.NewOpts.CloneRepo()
tmpDir, err := options.NewOpts.GetSource()
if err != nil {
return errors.NewWakuErrorf("could not clone git repo: %s", err)
return errors.ToWakuError(err)
}
cleanup.Schedule(func() error {
log.Debugf("removing tmp dir: %s\n", tmpDir)
if err := os.RemoveAll(tmpDir); err != nil {
return errors.NewWakuErrorf("failed to cleanup tmp dir: %v", err)
}
return nil
})

// Resolve dir
rootDir := tmpDir
Expand Down Expand Up @@ -248,12 +241,18 @@ func init() {

func AddNewCmdFlags(cmd *cobra.Command) {
cmd.Flags().VarP(&options.NewOpts.Repo, "repo", "r", "source repository to template from")
cmd.Flags().VarP(&options.NewOpts.Source, "source", "s", "source repository to template from")
cmd.Flags().VarP(&options.NewOpts.Branch, "branch", "b", "branch to clone from")
cmd.Flags().VarP(&options.NewOpts.Directory, "directory", "D", "directory where config is located")
cmd.Flags().VarP(&options.NewOpts.Name, "name", "n", "name of the project")
cmd.Flags().VarP(&options.NewOpts.License, "license", "l", "license to use for the project")
cmd.Flags().VarP(&options.NewOpts.Style, "style", "S", "which style to use")
cmd.Flags().BoolVarP(&options.NewOpts.NoGit, "no-git", "G", options.NewOpts.NoGit, "whether to not initialize git")

if err := cmd.Flags().MarkDeprecated("repo", "Please use --source instead."); err != nil {
panic(err)
}
cmd.MarkFlagsMutuallyExclusive("source", "repo")
}

func WriteFiles(tmpRoot, projectRoot string, paths []string, licenseText string, tmpl map[string]any, licenseTmpl map[string]string) error {
Expand Down
47 changes: 44 additions & 3 deletions cmd/options/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"errors"
"os"

"github.com/caffeine-addictt/waku/cmd/cleanup"
e "github.com/caffeine-addictt/waku/internal/errors"
"github.com/caffeine-addictt/waku/internal/git"
"github.com/caffeine-addictt/waku/internal/log"
"github.com/caffeine-addictt/waku/internal/types"
Expand All @@ -16,6 +18,7 @@ const defaultRepo = "https://github.com/caffeine-addictt/waku.git"
// The options for the new command
var NewOpts = NewOptions{
Repo: *types.NewValueGuard("", cmdOpt, types.REPO),
Source: *types.NewValueGuard("", cmdOpt, types.REPO),
Branch: *types.NewValueGuard("", cmdOpt, types.BRANCH),
Directory: *types.NewValueGuard("", cmdOpt, types.PATH),
Name: *types.NewValueGuard("", cmdOpt, types.STRING),
Expand All @@ -29,6 +32,10 @@ type NewOptions struct {
// Should be this repository by default
Repo types.ValueGuard[string]

// The repository Url or local path to use
// Should be this repository by default
Source types.ValueGuard[string]

// The branch to use
Branch types.ValueGuard[string]

Expand All @@ -54,9 +61,14 @@ func cmdOpt(v string) (string, error) {

// TO be invoked before a command is ran
func (o *NewOptions) Validate() error {
switch o.Repo.Value() {
// Since both flags are mutually exclusive
if err := o.Source.Set(o.Source.Value() + o.Repo.Value()); err != nil {
return err
}

switch o.Source.Value() {
case "":
if err := o.Repo.Set(defaultRepo); err != nil {
if err := o.Source.Set(defaultRepo); err != nil {
return err
}
if err := o.Directory.Set("template"); err != nil {
Expand All @@ -83,6 +95,35 @@ func (o *NewOptions) Validate() error {
return nil
}

// GetSource returns the source directory path
// that is either cloned with Git or is local.
//
// If it is a Git cloned path, it will be cleaned
func (o *NewOptions) GetSource() (string, error) {
switch git.CheckUrl(o.Source.Value()) {
case git.GitUrlType:
s, err := o.CloneRepo()
if err != nil {
return s, e.NewWakuErrorf("could not clone repo: %v", err)
}

cleanup.Schedule(func() error {
log.Debugf("removing tmp dir: %s\n", s)
if err := os.RemoveAll(s); err != nil {
return e.NewWakuErrorf("failed to cleanup tmp dir: %v", err)
}
return nil
})

return s, err

case git.PathUrlType:
return o.Source.Value(), nil
}

return "", e.NewWakuErrorf("invalid source URL or path: %s", o.Source.Value())
}

// To clone the repository
func (o *NewOptions) CloneRepo() (string, error) {
log.Debugln("creating tmp dir")
Expand All @@ -97,7 +138,7 @@ func (o *NewOptions) CloneRepo() (string, error) {
opts := git.CloneOptions{
Depth: 1,
Branch: o.Branch.Value(),
Url: utils.EscapeTermString(o.Repo.Value()),
Url: utils.EscapeTermString(o.Source.Value()),
ClonePath: utils.EscapeTermString(tmpDirPath),
}

Expand Down
65 changes: 65 additions & 0 deletions internal/git/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package git

import (
"net/url"
"os"

"github.com/caffeine-addictt/waku/internal/log"
)

type UrlType string

const (
GitUrlType UrlType = "git"
PathUrlType UrlType = "path"
BadUrlType UrlType = "bad"
)

var validSchemas [4]string = [4]string{"http", "https", "git", "ssh"}

// CheckUrl checks if a given string s is
// a valid git or path url
func CheckUrl(s string) UrlType {
if IsGitUrl(s) {
return GitUrlType
}

if IsPathUrl(s) {
return PathUrlType
}

return BadUrlType
}

// IsPathUrl checks if a given string s is
// a valid fs path
func IsPathUrl(s string) bool {
log.Debugf("checking if %s is a valid path\n", s)
_, err := os.Stat(s)
v := !os.IsNotExist(err)

if !v {
log.Debugf("%s is not a valid path", s)
}

return v
}

// IsGitUrl checks if a given string s is
// a valid Git url
func IsGitUrl(s string) bool {
log.Debugf("checking if %s is a valid git url\n", s)
parsedUrl, err := url.Parse(s)
if err != nil {
log.Debugf("%s is not a valid url\n", s)
return false
}

for _, schema := range validSchemas {
if parsedUrl.Scheme == schema {
return true
}
}

return false
}
14 changes: 13 additions & 1 deletion internal/license/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/caffeine-addictt/waku/cmd/options"
"github.com/caffeine-addictt/waku/internal/log"
"github.com/caffeine-addictt/waku/pkg/version"
"github.com/goccy/go-json"
)

Expand All @@ -19,14 +20,25 @@ const (
// need to hit the endpoint once per session.
var Licenses *[]License

func GetLicenseFetchUrl() string {
var url string
if options.NewOpts.Branch.Value() != "" {
url = fmt.Sprintf(BASE_URL, options.NewOpts.Branch.Value())
} else {
url = fmt.Sprintf(BASE_URL, "v"+version.Version)
}
url += LICENSE_LIST
return url
}

// GetLicenses returns the list of licenses from the GitHub API
// or returns the cached list if it exists.
func GetLicenses() (*[]License, error) {
if Licenses != nil {
return Licenses, nil
}

url := fmt.Sprintf(BASE_URL, options.NewOpts.Branch.Value()) + LICENSE_LIST
url := GetLicenseFetchUrl()
log.Infof("Fetching licenses from %s...\n", url)
req, err := http.NewRequest(http.MethodGet, url, http.NoBody)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/license/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type License struct {
}

func (license *License) GetLicenseText() (string, error) {
req, err := http.NewRequest(http.MethodGet, BASE_URL+license.Filename, http.NoBody)
req, err := http.NewRequest(http.MethodGet, GetLicenseFetchUrl()+license.Filename, http.NoBody)
if err != nil {
return "", err
}
Expand Down
11 changes: 6 additions & 5 deletions internal/types/cli.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package types

// The <typeStirng> for CLI options
// The <typeString> for CLI options
const (
PATH string = "<path>"
REPO string = "<repo>"
BRANCH string = "<branch>"
STRING string = "<string>"
PATH string = "<path>"
REPO string = "<repo>"
BRANCH string = "<branch>"
STRING string = "<string>"
REPO_OR_PATH = "<repo|path>"
)
2 changes: 1 addition & 1 deletion pkg/version/version.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package version

// The current app version
const Version = "0.6.0"
const Version = "0.7.0"
2 changes: 1 addition & 1 deletion www/docs/blog/posts/2024-10-08-waku-v0.6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Waku has a Discord server. [Join us!](https://discord.gg/NcRFkVTcaw)
## Download

You can [install](../../install.md) or upgrade Waku with your favorite package manager,
or see the full release notes [here](https://github.com/caffeine-addictt/waku/releases/tag/v0.6.0).
or see the full release notes [here](https://github.com/caffeine-addictt/waku/releases/tag/v0.7.0).

## Helping out

Expand Down
4 changes: 2 additions & 2 deletions www/docs/configuration/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ for better editor support.
https://waku.ngjx.org/static/schema.json
```

Or you can pin a specific version like `v0.6.0`:
Or you can pin a specific version like `v0.7.0`:

```text
https://raw.githubusercontent.com/caffeine-addictt/waku/v0.6.0/www/docs/static/schema.json
https://raw.githubusercontent.com/caffeine-addictt/waku/v0.7.0/www/docs/static/schema.json
```

Simply add the `$schema` property to your `configuration` file:
Expand Down
13 changes: 13 additions & 0 deletions www/docs/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

This page lists all deprecation notices in Waku.

Active deprecations will be removed in the next major version,
please update your code accordingly.

## Active notices

### waku new `--repo` flag

> since v0.7
This flag was deprecated in favor of the `--source` flag which works
like `--repo` but it also accepts local directory paths. Switching
to `--source` is __NOT BREAKING__.

## Removed in v0

Nothing so far. :partying_face:
10 changes: 5 additions & 5 deletions www/docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,17 @@ All artifacts are checksummed, and the checksum file is signed with [cosign][].
and `checksums.txt.sig` files from the [releases][] page.

```sh
curl -O 'https://github.com/caffeine-addictt/waku/releases/download/v0.6.0/checksums.txt'
curl -O 'https://github.com/caffeine-addictt/waku/releases/download/v0.7.0/checksums.txt'
```

1. Verify checksums signature:

```bash
cosign verify-blob \
--certificate-identity 'https://github.com/caffeine-addictt/waku/.github/workflows/release.yml@refs/tags/v0.6.0' \
--certificate-identity 'https://github.com/caffeine-addictt/waku/.github/workflows/release.yml@refs/tags/v0.7.0' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
--cert 'https://github.com/caffeine-addictt/waku/releases/download/v0.6.0/checksums.txt.pem' \
--signature 'https://github.com/caffeine-addictt/waku/releases/download/v0.6.0/checksums.txt.sig' \
--cert 'https://github.com/caffeine-addictt/waku/releases/download/v0.7.0/checksums.txt.pem' \
--signature 'https://github.com/caffeine-addictt/waku/releases/download/v0.7.0/checksums.txt.sig' \
./checksums.txt
```

Expand All @@ -130,7 +130,7 @@ Verify the signature:

```sh
cosign verify \
--certificate-identity 'https://github.com/caffeine-addictt/waku/.github/workflows/release.yml@refs/tags/v0.6.0' \
--certificate-identity 'https://github.com/caffeine-addictt/waku/.github/workflows/release.yml@refs/tags/v0.7.0' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
caffeinec/waku
```
Expand Down

0 comments on commit a0fbec2

Please sign in to comment.