Skip to content
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

More expansions in template repositories #10021

Merged
merged 8 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
---
date: "2019-11-28:00:00+02:00"
title: "The .gitea Directory"
slug: "gitea-directory"
weight: 40
title: "Template Repositories"
slug: "template-repositories"
weight: 14
toc: true
draft: false
menu:
sidebar:
parent: "features"
name: "The .gitea Directory"
weight: 50
identifier: "gitea-directory"
parent: "usage"
name: "Template Repositories"
weight: 14
identifier: "template-repositories"
---

# The .gitea directory
Gitea repositories can include a `.gitea` directory at their base which will store settings/configurations for certain features.

## Templates
Gitea includes template repositories, and one feature implemented with them is auto-expansion of specific variables within your template files.
## Template Repositories
Gitea `1.11.0` and above includes template repositories, and one feature implemented with them is auto-expansion of specific variables within your template files.
To tell Gitea which files to expand, you must include a `template` file inside the `.gitea` directory of the template repository.
Gitea uses [gobwas/glob](https://github.com/gobwas/glob) for its glob syntax. It closely resembles a traditional `.gitignore`, however there may be slight differences.

Expand All @@ -42,15 +39,34 @@ a/b/c/d.json
In any file matched by the above globs, certain variables will be expanded.
All variables must be of the form `$VAR` or `${VAR}`. To escape an expansion, use a double `$$`, such as `$$VAR` or `$${VAR}`

| Variable | Expands To |
|----------------------|-----------------------------------------------------|
| REPO_NAME | The name of the generated repository |
| TEMPLATE_NAME | The name of the template repository |
| REPO_DESCRIPTION | The description of the generated repository |
| TEMPLATE_DESCRIPTION | The description of the template repository |
| REPO_LINK | The URL to the generated repository |
| TEMPLATE_LINK | The URL to the template repository |
| REPO_HTTPS_URL | The HTTP(S) clone link for the generated repository |
| TEMPLATE_HTTPS_URL | The HTTP(S) clone link for the template repository |
| REPO_SSH_URL | The SSH clone link for the generated repository |
| TEMPLATE_SSH_URL | The SSH clone link for the template repository |
| Variable | Expands To | Transformable |
|----------------------|-----------------------------------------------------|---------------|
| REPO_NAME | The name of the generated repository | ✓ |
| TEMPLATE_NAME | The name of the template repository | ✓ |
| REPO_DESCRIPTION | The description of the generated repository | ✘ |
| TEMPLATE_DESCRIPTION | The description of the template repository | ✘ |
| REPO_OWNER | The owner of the generated repository | ✓ |
| TEMPLATE_OWNER | The owner of the template repository | ✓ |
| REPO_LINK | The URL to the generated repository | ✘ |
| TEMPLATE_LINK | The URL to the template repository | ✘ |
| REPO_HTTPS_URL | The HTTP(S) clone link for the generated repository | ✘ |
| TEMPLATE_HTTPS_URL | The HTTP(S) clone link for the template repository | ✘ |
| REPO_SSH_URL | The SSH clone link for the generated repository | ✘ |
| TEMPLATE_SSH_URL | The SSH clone link for the template repository | ✘ |

### Transformers :robot:
Gitea `1.12.0` adds a few transformers to some of the applicable variables above.
For example, to get `REPO_NAME` in `PASCAL`-case, your template would use `${REPO_NAME_PASCAL}`

Feeding `go-sdk` to the available transformers yields...

| Transformer | Effect |
|-------------|------------|
| SNAKE | go_sdk |
| KEBAB | go-sdk |
| CAMEL | goSdk |
| PASCAL | GoSdk |
| LOWER | go-sdk |
| UPPER | GO-SDK |
| TITLE | Go-Sdk |

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ require (
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
github.com/google/go-github/v24 v24.0.1
github.com/gorilla/context v1.1.1
github.com/huandu/xstrings v1.3.0
github.com/issue9/assert v1.3.2 // indirect
github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo=
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/issue9/assert v1.3.2 h1:IaTa37u4m1fUuTH9K9ldO5IONKVDXjLiUO1T9vj0OF0=
github.com/issue9/assert v1.3.2/go.mod h1:9Ger+iz8X7r1zMYYwEhh++2wMGWcNN2oVI+zIQXxcio=
Expand Down
138 changes: 82 additions & 56 deletions modules/repository/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,62 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"

"github.com/huandu/xstrings"
)

type transformer struct {
Name string
Transform func(string) string
}

type expansion struct {
Name string
Value string
Transformers []transformer
}

var defaultTransformers = []transformer{
{Name: "SNAKE", Transform: xstrings.ToSnakeCase},
{Name: "KEBAB", Transform: xstrings.ToKebabCase},
{Name: "CAMEL", Transform: func(str string) string {
return xstrings.FirstRuneToLower(xstrings.ToCamelCase(str))
}},
{Name: "PASCAL", Transform: xstrings.ToCamelCase},
{Name: "LOWER", Transform: strings.ToLower},
{Name: "UPPER", Transform: strings.ToUpper},
{Name: "TITLE", Transform: strings.Title},
}

func generateExpansion(src string, templateRepo, generateRepo *models.Repository) string {
expansions := []expansion{
{Name: "REPO_NAME", Value: generateRepo.Name, Transformers: defaultTransformers},
{Name: "TEMPLATE_NAME", Value: templateRepo.Name, Transformers: defaultTransformers},
{Name: "REPO_DESCRIPTION", Value: generateRepo.Description, Transformers: nil},
{Name: "TEMPLATE_DESCRIPTION", Value: templateRepo.Description, Transformers: nil},
{Name: "REPO_OWNER", Value: generateRepo.OwnerName, Transformers: defaultTransformers},
{Name: "TEMPLATE_OWNER", Value: templateRepo.OwnerName, Transformers: defaultTransformers},
{Name: "REPO_LINK", Value: generateRepo.Link(), Transformers: nil},
{Name: "TEMPLATE_LINK", Value: templateRepo.Link(), Transformers: nil},
{Name: "REPO_HTTPS_URL", Value: generateRepo.CloneLink().HTTPS, Transformers: nil},
{Name: "TEMPLATE_HTTPS_URL", Value: templateRepo.CloneLink().HTTPS, Transformers: nil},
{Name: "REPO_SSH_URL", Value: generateRepo.CloneLink().SSH, Transformers: nil},
{Name: "TEMPLATE_SSH_URL", Value: templateRepo.CloneLink().SSH, Transformers: nil},
}

var expansionMap = make(map[string]string)
for _, e := range expansions {
expansionMap[e.Name] = e.Value
for _, tr := range e.Transformers {
expansionMap[fmt.Sprintf("%s_%s", e.Name, tr.Name)] = tr.Transform(e.Value)
}
}

return os.Expand(src, func(key string) string {
switch key {
case "REPO_NAME":
return generateRepo.Name
case "TEMPLATE_NAME":
return templateRepo.Name
case "REPO_DESCRIPTION":
return generateRepo.Description
case "TEMPLATE_DESCRIPTION":
return templateRepo.Description
case "REPO_OWNER":
return generateRepo.OwnerName
case "TEMPLATE_OWNER":
return templateRepo.OwnerName
case "REPO_LINK":
return generateRepo.Link()
case "TEMPLATE_LINK":
return templateRepo.Link()
case "REPO_HTTPS_URL":
return generateRepo.CloneLink().HTTPS
case "TEMPLATE_HTTPS_URL":
return templateRepo.CloneLink().HTTPS
case "REPO_SSH_URL":
return generateRepo.CloneLink().SSH
case "TEMPLATE_SSH_URL":
return templateRepo.CloneLink().SSH
default:
return key
if expansion, ok := expansionMap[key]; ok {
return expansion
}
return key
})
}

Expand Down Expand Up @@ -104,41 +128,43 @@ func generateRepoCommit(repo, templateRepo, generateRepo *models.Repository, tmp
return fmt.Errorf("checkGiteaTemplate: %v", err)
}

if err := os.Remove(gt.Path); err != nil {
return fmt.Errorf("remove .giteatemplate: %v", err)
}

// Avoid walking tree if there are no globs
if len(gt.Globs()) > 0 {
tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/"
if err := filepath.Walk(tmpDirSlash, func(path string, info os.FileInfo, walkErr error) error {
if walkErr != nil {
return walkErr
}
if gt != nil {
if err := os.Remove(gt.Path); err != nil {
return fmt.Errorf("remove .giteatemplate: %v", err)
}

if info.IsDir() {
return nil
}
// Avoid walking tree if there are no globs
if len(gt.Globs()) > 0 {
tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/"
if err := filepath.Walk(tmpDirSlash, func(path string, info os.FileInfo, walkErr error) error {
if walkErr != nil {
return walkErr
}

base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
for _, g := range gt.Globs() {
if g.Match(base) {
content, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if info.IsDir() {
return nil
}

if err := ioutil.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
0644); err != nil {
return err
base := strings.TrimPrefix(filepath.ToSlash(path), tmpDirSlash)
for _, g := range gt.Globs() {
if g.Match(base) {
content, err := ioutil.ReadFile(path)
if err != nil {
return err
}

if err := ioutil.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
0644); err != nil {
return err
}
break
}
break
}
return nil
}); err != nil {
return err
}
return nil
}); err != nil {
return err
}
}

Expand Down
24 changes: 24 additions & 0 deletions vendor/github.com/huandu/xstrings/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions vendor/github.com/huandu/xstrings/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions vendor/github.com/huandu/xstrings/CONTRIBUTING.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions vendor/github.com/huandu/xstrings/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading