- POST /user/repos - POST /org/:org/repostags/v1.2.0-rc1
| @@ -26,6 +26,8 @@ import ( | |||
| "github.com/macaron-contrib/session" | |||
| "github.com/macaron-contrib/toolbox" | |||
| api "github.com/gogits/go-gogs-client" | |||
| "github.com/gogits/gogs/models" | |||
| "github.com/gogits/gogs/modules/auth" | |||
| "github.com/gogits/gogs/modules/auth/apiv1" | |||
| @@ -66,7 +68,7 @@ func checkVersion() { | |||
| // Check dependency version. | |||
| macaronVer := git.MustParseVersion(strings.Join(strings.Split(macaron.Version(), ".")[:3], ".")) | |||
| if macaronVer.LessThan(git.MustParseVersion("0.4.2")) { | |||
| if macaronVer.LessThan(git.MustParseVersion("0.4.7")) { | |||
| log.Fatal(4, "Package macaron version is too old, did you forget to update?(github.com/Unknwon/macaron)") | |||
| } | |||
| i18nVer := git.MustParseVersion(i18n.Version()) | |||
| @@ -200,14 +202,15 @@ func runWeb(*cli.Context) { | |||
| }) | |||
| // Repositories. | |||
| m.Get("/user/repos", middleware.ApiReqToken(), v1.ListMyRepos) | |||
| m.Combo("/user/repos", middleware.ApiReqToken()).Get(v1.ListMyRepos).Post(bind(api.CreateRepoOption{}), v1.CreateRepo) | |||
| m.Post("/org/:org/repos", middleware.ApiReqToken(), bind(api.CreateRepoOption{}), v1.CreateOrgRepo) | |||
| m.Group("/repos", func() { | |||
| m.Get("/search", v1.SearchRepos) | |||
| m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), v1.Migrate) | |||
| m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), v1.MigrateRepo) | |||
| m.Group("/:username/:reponame", func() { | |||
| m.Combo("/hooks").Get(v1.ListRepoHooks).Post(bind(v1.CreateRepoHookForm{}), v1.CreateRepoHook) | |||
| m.Patch("/hooks/:id:int", bind(v1.EditRepoHookForm{}), v1.EditRepoHook) | |||
| m.Combo("/hooks").Get(v1.ListRepoHooks).Post(bind(api.CreateHookOption{}), v1.CreateRepoHook) | |||
| m.Patch("/hooks/:id:int", bind(api.EditHookOption{}), v1.EditRepoHook) | |||
| m.Get("/raw/*", middleware.RepoRef(), v1.GetRepoRawFile) | |||
| }, middleware.ApiRepoAssignment(), middleware.ApiReqToken()) | |||
| }) | |||
| @@ -208,7 +208,7 @@ enable_custom_avatar_helper=Aktiviere dies, um deinen Avatar nicht von Gravatar | |||
| choose_new_avatar=Neuen Avatar auswählen | |||
| update_avatar=Avatar-Einstellung aktualisieren | |||
| uploaded_avatar_not_a_image=Die hochgeladene Datei ist kein Bild. | |||
| no_custom_avatar_available=No custom avatar available, cannot enable it. | |||
| no_custom_avatar_available=Kein benutzerdefinierter Avatar verfügbar, Aktivierung ist nicht möglich. | |||
| update_avatar_success=Deine Avatar-Einstellung wurde aktualisiert. | |||
| change_password=Passwort ändern | |||
| @@ -377,6 +377,30 @@ diff.stats_desc=<strong> %d geänderte Dateien</strong> mit <strong>%d neuen Zei | |||
| diff.bin=BIN | |||
| diff.view_file=Datei anzeigen | |||
| release.releases=Releases | |||
| release.new_release=Neues Release | |||
| release.draft=Entwurf | |||
| release.prerelease=Pre-Release | |||
| release.stable=Endversion | |||
| release.edit=bearbeiten | |||
| release.ahead=<strong>%d</strong> Commits zu %s seit diesem Release | |||
| release.source_code=Quelltext | |||
| release.tag_name=Tag-Name | |||
| release.target=Ziel | |||
| release.tag_helper=Wähle ein neues Tag oder erstelle ein Tag beim Veröffentlichen. | |||
| release.release_title=Release-Titel | |||
| release.content_with_md=Inhalt mit <a href="%s">Markdown</a> | |||
| release.write=Schreiben | |||
| release.preview=Vorschau | |||
| release.content_placeholder=Schreibe hier etwas | |||
| release.loading=Laden… | |||
| release.prerelease_desc=Dies ist eine Pre-Release-Version | |||
| release.prerelease_helper=Wir möchten darauf hinweisen, dass dieses Release nicht für den produktiven Einsatz gedacht ist. | |||
| release.publish=Release veröffentlichen | |||
| release.save_draft=Entwurf speichern | |||
| release.edit_release=Release bearbeiten | |||
| release.tag_name_already_exist=Ein Release mit diesem Tag existiert bereits. | |||
| [org] | |||
| org_name_holder=Name der Organisation | |||
| org_name_helper=Gute Namen von Organisationen sind kurz und einprägsam. | |||
| @@ -476,8 +500,8 @@ dashboard.delete_inactivate_accounts=inaktive Konten löschen | |||
| dashboard.delete_inactivate_accounts_success=Alle inaktiven Konten wurden erfolgreich gelöscht. | |||
| dashboard.delete_repo_archives=Alle Repository-Archive löschen | |||
| dashboard.delete_repo_archives_success=Alle Repositoriy-Archive wurden gelöscht. | |||
| dashboard.git_gc_repos=Führe Garbage Collection auf Repositorys aus | |||
| dashboard.git_gc_repos_success=Garbage Collection wurde auf allen Repositorys erfolgreich ausgeführt. | |||
| dashboard.git_gc_repos=Führe Garbage Collection auf Repositories aus | |||
| dashboard.git_gc_repos_success=Garbage Collection wurde auf allen Repositories erfolgreich ausgeführt. | |||
| dashboard.server_uptime=Server-Uptime | |||
| dashboard.current_goroutine=Aktuelle Goroutines | |||
| dashboard.current_memory_usage=Aktuelle Speichernutzung | |||
| @@ -17,7 +17,7 @@ import ( | |||
| "github.com/gogits/gogs/modules/setting" | |||
| ) | |||
| const APP_VER = "0.5.8.1211 Beta" | |||
| const APP_VER = "0.5.8.1212 Beta" | |||
| func init() { | |||
| runtime.GOMAXPROCS(runtime.NumCPU()) | |||
| @@ -25,8 +25,8 @@ var ( | |||
| ErrLastOrgOwner = errors.New("The user to remove is the last member in owner team") | |||
| ) | |||
| // IsOrgOwner returns true if given user is in the owner team. | |||
| func (org *User) IsOrgOwner(uid int64) bool { | |||
| // IsOwnedBy returns true if given user is in the owner team. | |||
| func (org *User) IsOwnedBy(uid int64) bool { | |||
| return IsOrganizationOwner(org.Id, uid) | |||
| } | |||
| @@ -170,6 +170,24 @@ func CreateOrganization(org, owner *User) (*User, error) { | |||
| return org, sess.Commit() | |||
| } | |||
| // GetOrgByName returns organization by given name. | |||
| func GetOrgByName(name string) (*User, error) { | |||
| if len(name) == 0 { | |||
| return nil, ErrOrgNotExist | |||
| } | |||
| u := &User{ | |||
| LowerName: strings.ToLower(name), | |||
| Type: ORGANIZATION, | |||
| } | |||
| has, err := x.Get(u) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, ErrOrgNotExist | |||
| } | |||
| return u, nil | |||
| } | |||
| // CountOrganizations returns number of organizations. | |||
| func CountOrganizations() int64 { | |||
| count, _ := x.Where("type=1").Count(new(User)) | |||
| @@ -21,9 +21,9 @@ type CreateRepoForm struct { | |||
| RepoName string `form:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"` | |||
| Private bool `form:"private"` | |||
| Description string `form:"desc" binding:"MaxSize(255)"` | |||
| AutoInit bool `form:"auto_init"` | |||
| Gitignore string `form:"gitignore"` | |||
| License string `form:"license"` | |||
| InitReadme bool `form:"init_readme"` | |||
| } | |||
| func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| @@ -48,7 +48,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { | |||
| ctx.Data["Org"] = org | |||
| if ctx.IsSigned { | |||
| ctx.Org.IsOwner = org.IsOrgOwner(ctx.User.Id) | |||
| ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.Id) | |||
| if ctx.Org.IsOwner { | |||
| ctx.Org.IsMember = true | |||
| ctx.Org.IsAdminTeam = true | |||
| @@ -55,7 +55,7 @@ func ApiRepoAssignment() macaron.Handler { | |||
| ctx.Repo.Owner = u | |||
| // Organization owner team members are true owners as well. | |||
| if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) { | |||
| if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Repo.IsTrueOwner = true | |||
| } | |||
| @@ -280,7 +280,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { | |||
| ctx.Repo.Owner = u | |||
| // Organization owner team members are true owners as well. | |||
| if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) { | |||
| if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Repo.IsTrueOwner = true | |||
| } | |||
| @@ -21,6 +21,26 @@ import ( | |||
| "github.com/gogits/gogs/modules/setting" | |||
| ) | |||
| // ToApiRepository converts repository to API format. | |||
| func ToApiRepository(owner *models.User, repo *models.Repository, permission api.Permission) *api.Repository { | |||
| sshUrlFmt := "%s@%s:%s/%s.git" | |||
| if setting.SshPort != 22 { | |||
| sshUrlFmt = "ssh://%s@%s:%d/%s/%s.git" | |||
| } | |||
| htmlUrl := setting.AppUrl + owner.Name + "/" + repo.Name | |||
| return &api.Repository{ | |||
| Id: repo.Id, | |||
| Owner: *ToApiUser(owner), | |||
| FullName: owner.Name + "/" + repo.Name, | |||
| Private: repo.IsPrivate, | |||
| Fork: repo.IsFork, | |||
| HtmlUrl: htmlUrl, | |||
| SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, owner.LowerName, repo.LowerName), | |||
| CloneUrl: htmlUrl + ".git", | |||
| Permissions: permission, | |||
| } | |||
| } | |||
| func SearchRepos(ctx *middleware.Context) { | |||
| opt := models.SearchOption{ | |||
| Keyword: path.Base(ctx.Query("q")), | |||
| @@ -44,7 +64,7 @@ func SearchRepos(ctx *middleware.Context) { | |||
| }) | |||
| return | |||
| } | |||
| if u.IsOrganization() && u.IsOrgOwner(ctx.User.Id) { | |||
| if u.IsOrganization() && u.IsOwnedBy(ctx.User.Id) { | |||
| opt.Private = true | |||
| } | |||
| // FIXME: how about collaborators? | |||
| @@ -75,13 +95,66 @@ func SearchRepos(ctx *middleware.Context) { | |||
| } | |||
| } | |||
| ctx.Render.JSON(200, map[string]interface{}{ | |||
| ctx.JSON(200, map[string]interface{}{ | |||
| "ok": true, | |||
| "data": results, | |||
| }) | |||
| } | |||
| func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||
| func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoOption) { | |||
| repo, err := models.CreateRepository(owner, opt.Name, opt.Description, | |||
| opt.Gitignore, opt.License, opt.Private, false, opt.AutoInit) | |||
| if err != nil { | |||
| if err == models.ErrRepoAlreadyExist || | |||
| err == models.ErrRepoNameIllegal { | |||
| ctx.JSON(422, &base.ApiJsonErr{err.Error(), base.DOC_URL}) | |||
| } else { | |||
| log.Error(4, "CreateRepository: %v", err) | |||
| if repo != nil { | |||
| if err = models.DeleteRepository(ctx.User.Id, repo.Id, ctx.User.Name); err != nil { | |||
| log.Error(4, "DeleteRepository: %v", err) | |||
| } | |||
| } | |||
| ctx.Error(500) | |||
| } | |||
| return | |||
| } | |||
| ctx.JSON(200, ToApiRepository(owner, repo, api.Permission{true, true, true})) | |||
| } | |||
| // POST /user/repos | |||
| // https://developer.github.com/v3/repos/#create | |||
| func CreateRepo(ctx *middleware.Context, opt api.CreateRepoOption) { | |||
| // Shouldn't reach this condition, but just in case. | |||
| if ctx.User.IsOrganization() { | |||
| ctx.JSON(422, "not allowed creating repository for organization") | |||
| return | |||
| } | |||
| createRepo(ctx, ctx.User, opt) | |||
| } | |||
| // POST /orgs/:org/repos | |||
| // https://developer.github.com/v3/repos/#create | |||
| func CreateOrgRepo(ctx *middleware.Context, opt api.CreateRepoOption) { | |||
| org, err := models.GetOrgByName(ctx.Params(":org")) | |||
| if err != nil { | |||
| if err == models.ErrUserNotExist { | |||
| ctx.Error(404) | |||
| } else { | |||
| ctx.Error(500) | |||
| } | |||
| return | |||
| } | |||
| if !org.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Error(403) | |||
| return | |||
| } | |||
| createRepo(ctx, org, opt) | |||
| } | |||
| func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||
| u, err := models.GetUserByName(ctx.Query("username")) | |||
| if err != nil { | |||
| ctx.JSON(500, map[string]interface{}{ | |||
| @@ -103,17 +176,15 @@ func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||
| if form.Uid != u.Id { | |||
| org, err := models.GetUserById(form.Uid) | |||
| if err != nil { | |||
| ctx.JSON(500, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": err.Error(), | |||
| }) | |||
| log.Error(4, "GetUserById: %v", err) | |||
| ctx.Error(500) | |||
| return | |||
| } | |||
| ctxUser = org | |||
| } | |||
| if ctx.HasError() { | |||
| ctx.JSON(500, map[string]interface{}{ | |||
| ctx.JSON(422, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": ctx.GetErrMsg(), | |||
| }) | |||
| @@ -122,7 +193,7 @@ func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||
| if ctxUser.IsOrganization() { | |||
| // Check ownership of organization. | |||
| if !ctxUser.IsOrgOwner(u.Id) { | |||
| if !ctxUser.IsOwnedBy(u.Id) { | |||
| ctx.JSON(403, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "given user is not owner of organization", | |||
| @@ -173,29 +244,9 @@ func ListMyRepos(ctx *middleware.Context) { | |||
| return | |||
| } | |||
| sshUrlFmt := "%s@%s:%s/%s.git" | |||
| if setting.SshPort != 22 { | |||
| sshUrlFmt = "ssh://%s@%s:%d/%s/%s.git" | |||
| } | |||
| repos := make([]*api.Repository, numOwnRepos+len(collaRepos)) | |||
| // FIXME: make only one loop | |||
| for i := range ownRepos { | |||
| repos[i] = &api.Repository{ | |||
| Id: ownRepos[i].Id, | |||
| Owner: api.User{ | |||
| Id: ctx.User.Id, | |||
| UserName: ctx.User.Name, | |||
| AvatarUrl: string(setting.Protocol) + ctx.User.AvatarLink(), | |||
| }, | |||
| FullName: ctx.User.Name + "/" + ownRepos[i].Name, | |||
| Private: ownRepos[i].IsPrivate, | |||
| Fork: ownRepos[i].IsFork, | |||
| HtmlUrl: setting.AppUrl + ctx.User.Name + "/" + ownRepos[i].Name, | |||
| SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, ctx.User.LowerName, ownRepos[i].LowerName), | |||
| Permissions: api.Permission{true, true, true}, | |||
| } | |||
| repos[i].CloneUrl = repos[i].HtmlUrl + ".git" | |||
| repos[i] = ToApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true}) | |||
| } | |||
| for i := range collaRepos { | |||
| if err = collaRepos[i].GetOwner(); err != nil { | |||
| @@ -203,24 +254,10 @@ func ListMyRepos(ctx *middleware.Context) { | |||
| return | |||
| } | |||
| j := i + numOwnRepos | |||
| repos[j] = &api.Repository{ | |||
| Id: collaRepos[i].Id, | |||
| Owner: api.User{ | |||
| Id: collaRepos[i].Owner.Id, | |||
| UserName: collaRepos[i].Owner.Name, | |||
| AvatarUrl: string(setting.Protocol) + collaRepos[i].Owner.AvatarLink(), | |||
| }, | |||
| FullName: collaRepos[i].Owner.Name + "/" + collaRepos[i].Name, | |||
| Private: collaRepos[i].IsPrivate, | |||
| Fork: collaRepos[i].IsFork, | |||
| HtmlUrl: setting.AppUrl + collaRepos[i].Owner.Name + "/" + collaRepos[i].Name, | |||
| SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, collaRepos[i].Owner.LowerName, collaRepos[i].LowerName), | |||
| Permissions: api.Permission{false, collaRepos[i].CanPush, true}, | |||
| } | |||
| repos[j].CloneUrl = repos[j].HtmlUrl + ".git" | |||
| repos[j] = ToApiRepository(collaRepos[i].Owner, collaRepos[i].Repository, api.Permission{false, collaRepos[i].CanPush, true}) | |||
| // FIXME: cache result to reduce DB query? | |||
| if collaRepos[i].Owner.IsOrganization() && collaRepos[i].Owner.IsOrgOwner(ctx.User.Id) { | |||
| if collaRepos[i].Owner.IsOrganization() && collaRepos[i].Owner.IsOwnedBy(ctx.User.Id) { | |||
| repos[j].Permissions.Admin = true | |||
| } | |||
| } | |||
| @@ -48,15 +48,9 @@ func ListRepoHooks(ctx *middleware.Context) { | |||
| ctx.JSON(200, &apiHooks) | |||
| } | |||
| type CreateRepoHookForm struct { | |||
| Type string `json:"type" binding:"Required"` | |||
| Config map[string]string `json:"config" binding:"Required"` | |||
| Active bool `json:"active"` | |||
| } | |||
| // POST /repos/:username/:reponame/hooks | |||
| // https://developer.github.com/v3/repos/hooks/#create-a-hook | |||
| func CreateRepoHook(ctx *middleware.Context, form CreateRepoHookForm) { | |||
| func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) { | |||
| if !models.IsValidHookTaskType(form.Type) { | |||
| ctx.JSON(422, &base.ApiJsonErr{"invalid hook type", base.DOC_URL}) | |||
| return | |||
| @@ -124,14 +118,9 @@ func CreateRepoHook(ctx *middleware.Context, form CreateRepoHookForm) { | |||
| ctx.JSON(201, apiHook) | |||
| } | |||
| type EditRepoHookForm struct { | |||
| Config map[string]string `json:"config"` | |||
| Active *bool `json:"active"` | |||
| } | |||
| // PATCH /repos/:username/:reponame/hooks/:id | |||
| // https://developer.github.com/v3/repos/hooks/#edit-a-hook | |||
| func EditRepoHook(ctx *middleware.Context, form EditRepoHookForm) { | |||
| func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) { | |||
| w, err := models.GetWebhookById(ctx.ParamsInt64(":id")) | |||
| if err != nil { | |||
| ctx.JSON(500, &base.ApiJsonErr{"GetWebhookById: " + err.Error(), base.DOC_URL}) | |||
| @@ -12,8 +12,18 @@ import ( | |||
| "github.com/gogits/gogs/models" | |||
| "github.com/gogits/gogs/modules/base" | |||
| "github.com/gogits/gogs/modules/middleware" | |||
| "github.com/gogits/gogs/modules/setting" | |||
| ) | |||
| // ToApiUser converts user to API format. | |||
| func ToApiUser(u *models.User) *api.User { | |||
| return &api.User{ | |||
| Id: u.Id, | |||
| UserName: u.Name, | |||
| AvatarUrl: string(setting.Protocol) + u.AvatarLink(), | |||
| } | |||
| } | |||
| func SearchUsers(ctx *middleware.Context) { | |||
| opt := models.SearchOption{ | |||
| Keyword: ctx.Query("q"), | |||
| @@ -97,14 +97,14 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| if ctxUser.IsOrganization() { | |||
| // Check ownership of organization. | |||
| if !ctxUser.IsOrgOwner(ctx.User.Id) { | |||
| if !ctxUser.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Error(403) | |||
| return | |||
| } | |||
| } | |||
| repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description, | |||
| form.Gitignore, form.License, form.Private, false, form.InitReadme) | |||
| form.Gitignore, form.License, form.Private, false, form.AutoInit) | |||
| if err == nil { | |||
| log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name) | |||
| ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | |||
| @@ -174,7 +174,7 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||
| if ctxUser.IsOrganization() { | |||
| // Check ownership of organization. | |||
| if !ctxUser.IsOrgOwner(ctx.User.Id) { | |||
| if !ctxUser.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Error(403) | |||
| return | |||
| } | |||
| @@ -292,7 +292,7 @@ func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| if ctxUser.IsOrganization() { | |||
| // Check ownership of organization. | |||
| if !ctxUser.IsOrgOwner(ctx.User.Id) { | |||
| if !ctxUser.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Error(403) | |||
| return | |||
| } | |||
| @@ -137,7 +137,7 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) { | |||
| } | |||
| if ctx.Repo.Owner.IsOrganization() { | |||
| if !ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) { | |||
| if !ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) { | |||
| ctx.Error(404) | |||
| return | |||
| } | |||
| @@ -1 +1 @@ | |||
| 0.5.8.1211 Beta | |||
| 0.5.8.1212 Beta | |||
| @@ -69,7 +69,7 @@ | |||
| </div> | |||
| <div class="field"> | |||
| <label for="init-readme"></label> | |||
| <input class="ipt-chk" id="init-readme" name="init_readme" type="checkbox" {{if .init_readme}}checked{{end}} /> | |||
| <input class="ipt-chk" id="init-readme" name="auto_init" type="checkbox" {{if .auto_init}}checked{{end}} /> | |||
| <strong>{{.i18n.Tr "repo.init_readme"}}</strong> | |||
| </div> | |||
| <div class="field"> | |||