fail("Key permission denied", "Cannot push with deployment key: %d", key.ID) | fail("Key permission denied", "Cannot push with deployment key: %d", key.ID) | ||||
} | } | ||||
// Check if this deploy key belongs to current repository. | // Check if this deploy key belongs to current repository. | ||||
if !models.HasDeployKey(key.ID, repo.Id) { | |||||
fail("Key access denied", "Key access denied: %d-%d", key.ID, repo.Id) | |||||
if !models.HasDeployKey(key.ID, repo.ID) { | |||||
fail("Key access denied", "Key access denied: %d-%d", key.ID, repo.ID) | |||||
} | } | ||||
// Update deploy key activity. | // Update deploy key activity. | ||||
deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.Id) | |||||
deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID) | |||||
if err != nil { | if err != nil { | ||||
fail("Internal error", "GetDeployKey: %v", err) | fail("Internal error", "GetDeployKey: %v", err) | ||||
} | } |
m.Get("/edit/:tagname", repo.EditRelease) | m.Get("/edit/:tagname", repo.EditRelease) | ||||
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost) | m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost) | ||||
}, reqRepoAdmin, middleware.RepoRef()) | }, reqRepoAdmin, middleware.RepoRef()) | ||||
m.Combo("/compare/*").Get(repo.CompareAndPullRequest) | |||||
}, reqSignIn, middleware.RepoAssignment(true)) | }, reqSignIn, middleware.RepoAssignment(true)) | ||||
m.Group("/:username/:reponame", func() { | m.Group("/:username/:reponame", func() { | ||||
m.Get("/commit/*", repo.Diff) | m.Get("/commit/*", repo.Diff) | ||||
}, middleware.RepoRef()) | }, middleware.RepoRef()) | ||||
m.Get("/compare/:before([a-z0-9]+)...:after([a-z0-9]+)", repo.CompareDiff) | |||||
m.Get("/compare/:before([a-z0-9]{40})...:after([a-z0-9]{40})", repo.CompareDiff) | |||||
}, ignSignIn, middleware.RepoAssignment(true)) | }, ignSignIn, middleware.RepoAssignment(true)) | ||||
m.Group("/:username", func() { | m.Group("/:username", func() { |
issues.label_deletion_desc = Delete this label will remove its information in all related issues. Do you want to continue? | issues.label_deletion_desc = Delete this label will remove its information in all related issues. Do you want to continue? | ||||
issues.label_deletion_success = Label has been deleted successfully! | issues.label_deletion_success = Label has been deleted successfully! | ||||
pulls.compare_changes = Compare Changes | |||||
pulls.compare_changes_desc = Compare two branches and make a pull request for changes. | |||||
milestones.new = New Milestone | milestones.new = New Milestone | ||||
milestones.open_tab = %d Open | milestones.open_tab = %d Open | ||||
milestones.close_tab = %d Closed | milestones.close_tab = %d Closed |
} | } | ||||
if u != nil { | if u != nil { | ||||
if u.Id == repo.OwnerId { | |||||
if u.Id == repo.OwnerID { | |||||
return ACCESS_MODE_OWNER, nil | return ACCESS_MODE_OWNER, nil | ||||
} | } | ||||
a := &Access{UserID: u.Id, RepoID: repo.Id} | |||||
a := &Access{UserID: u.Id, RepoID: repo.ID} | |||||
if has, err := e.Get(a); !has || err != nil { | if has, err := e.Get(a); !has || err != nil { | ||||
return mode, err | return mode, err | ||||
} | } | ||||
repos := make(map[*Repository]AccessMode, len(accesses)) | repos := make(map[*Repository]AccessMode, len(accesses)) | ||||
for _, access := range accesses { | for _, access := range accesses { | ||||
repo, err := GetRepositoryById(access.RepoID) | |||||
repo, err := GetRepositoryByID(access.RepoID) | |||||
if err != nil { | if err != nil { | ||||
if IsErrRepoNotExist(err) { | if IsErrRepoNotExist(err) { | ||||
log.Error(4, "%v", err) | log.Error(4, "%v", err) | ||||
} | } | ||||
if err = repo.GetOwner(); err != nil { | if err = repo.GetOwner(); err != nil { | ||||
return nil, err | return nil, err | ||||
} else if repo.OwnerId == u.Id { | |||||
} else if repo.OwnerID == u.Id { | |||||
continue | continue | ||||
} | } | ||||
repos[repo] = access.Mode | repos[repo] = access.Mode | ||||
} | } | ||||
newAccesses = append(newAccesses, Access{ | newAccesses = append(newAccesses, Access{ | ||||
UserID: userID, | UserID: userID, | ||||
RepoID: repo.Id, | |||||
RepoID: repo.ID, | |||||
Mode: mode, | Mode: mode, | ||||
}) | }) | ||||
} | } | ||||
// Delete old accesses and insert new ones for repository. | // Delete old accesses and insert new ones for repository. | ||||
if _, err = e.Delete(&Access{RepoID: repo.Id}); err != nil { | |||||
if _, err = e.Delete(&Access{RepoID: repo.ID}); err != nil { | |||||
return fmt.Errorf("delete old accesses: %v", err) | return fmt.Errorf("delete old accesses: %v", err) | ||||
} else if _, err = e.Insert(newAccesses); err != nil { | } else if _, err = e.Insert(newAccesses); err != nil { | ||||
return fmt.Errorf("insert new accesses: %v", err) | return fmt.Errorf("insert new accesses: %v", err) | ||||
// have relations with repository. | // have relations with repository. | ||||
if t.IsOwnerTeam() { | if t.IsOwnerTeam() { | ||||
t.Authorize = ACCESS_MODE_OWNER | t.Authorize = ACCESS_MODE_OWNER | ||||
} else if !t.hasRepository(e, repo.Id) { | |||||
} else if !t.hasRepository(e, repo.ID) { | |||||
continue | continue | ||||
} | } | ||||
// check if repo belongs to org and append additional webhooks | // check if repo belongs to org and append additional webhooks | ||||
if repo.Owner.IsOrganization() { | if repo.Owner.IsOrganization() { | ||||
// get hooks for org | // get hooks for org | ||||
orgws, err := GetActiveWebhooksByOrgId(repo.OwnerId) | |||||
orgws, err := GetActiveWebhooksByOrgId(repo.OwnerID) | |||||
if err != nil { | if err != nil { | ||||
return errors.New("GetActiveWebhooksByOrgId: " + err.Error()) | return errors.New("GetActiveWebhooksByOrgId: " + err.Error()) | ||||
} | } | ||||
Ref: refFullName, | Ref: refFullName, | ||||
Commits: commits, | Commits: commits, | ||||
Repo: &PayloadRepo{ | Repo: &PayloadRepo{ | ||||
Id: repo.Id, | |||||
Id: repo.ID, | |||||
Name: repo.LowerName, | Name: repo.LowerName, | ||||
Url: repoLink, | Url: repoLink, | ||||
Description: repo.Description, | Description: repo.Description, | ||||
} | } | ||||
if err = CreateHookTask(&HookTask{ | if err = CreateHookTask(&HookTask{ | ||||
RepoID: repo.Id, | |||||
RepoID: repo.ID, | |||||
HookID: w.Id, | HookID: w.Id, | ||||
Type: w.HookTaskType, | Type: w.HookTaskType, | ||||
Url: w.Url, | Url: w.Url, | ||||
ActUserName: u.Name, | ActUserName: u.Name, | ||||
ActEmail: u.Email, | ActEmail: u.Email, | ||||
OpType: CREATE_REPO, | OpType: CREATE_REPO, | ||||
RepoID: repo.Id, | |||||
RepoID: repo.ID, | |||||
RepoUserName: repo.Owner.Name, | RepoUserName: repo.Owner.Name, | ||||
RepoName: repo.Name, | RepoName: repo.Name, | ||||
IsPrivate: repo.IsPrivate, | IsPrivate: repo.IsPrivate, | ||||
}); err != nil { | }); err != nil { | ||||
return fmt.Errorf("notify watchers '%d/%s'", u.Id, repo.Id) | |||||
return fmt.Errorf("notify watchers '%d/%s'", u.Id, repo.ID) | |||||
} | } | ||||
log.Trace("action.NewRepoAction: %s/%s", u.Name, repo.Name) | log.Trace("action.NewRepoAction: %s/%s", u.Name, repo.Name) | ||||
ActUserName: actUser.Name, | ActUserName: actUser.Name, | ||||
ActEmail: actUser.Email, | ActEmail: actUser.Email, | ||||
OpType: TRANSFER_REPO, | OpType: TRANSFER_REPO, | ||||
RepoID: repo.Id, | |||||
RepoID: repo.ID, | |||||
RepoUserName: newOwner.Name, | RepoUserName: newOwner.Name, | ||||
RepoName: repo.Name, | RepoName: repo.Name, | ||||
IsPrivate: repo.IsPrivate, | IsPrivate: repo.IsPrivate, | ||||
Content: path.Join(oldOwner.LowerName, repo.LowerName), | Content: path.Join(oldOwner.LowerName, repo.LowerName), | ||||
} | } | ||||
if err = notifyWatchers(e, action); err != nil { | if err = notifyWatchers(e, action); err != nil { | ||||
return fmt.Errorf("notify watchers '%d/%s'", actUser.Id, repo.Id) | |||||
return fmt.Errorf("notify watchers '%d/%s'", actUser.Id, repo.ID) | |||||
} | } | ||||
// Remove watch for organization. | // Remove watch for organization. | ||||
if repo.Owner.IsOrganization() { | if repo.Owner.IsOrganization() { | ||||
if err = watchRepo(e, repo.Owner.Id, repo.Id, false); err != nil { | |||||
if err = watchRepo(e, repo.Owner.Id, repo.ID, false); err != nil { | |||||
return fmt.Errorf("watch repository: %v", err) | return fmt.Errorf("watch repository: %v", err) | ||||
} | } | ||||
} | } |
} | } | ||||
func (i *Issue) GetPoster() (err error) { | func (i *Issue) GetPoster() (err error) { | ||||
i.Poster, err = GetUserById(i.PosterID) | |||||
i.Poster, err = GetUserByID(i.PosterID) | |||||
if IsErrUserNotExist(err) { | if IsErrUserNotExist(err) { | ||||
i.Poster = &User{Name: "FakeUser"} | i.Poster = &User{Name: "FakeUser"} | ||||
return nil | return nil | ||||
return nil | return nil | ||||
} | } | ||||
i.Assignee, err = GetUserById(i.AssigneeID) | |||||
i.Assignee, err = GetUserByID(i.AssigneeID) | |||||
if IsErrUserNotExist(err) { | if IsErrUserNotExist(err) { | ||||
return nil | return nil | ||||
} | } | ||||
return | return | ||||
} | } | ||||
return GetIssueByIndex(repo.Id, issueNumber) | |||||
return GetIssueByIndex(repo.ID, issueNumber) | |||||
} | } | ||||
// GetIssueByIndex returns issue by given index in repository. | // GetIssueByIndex returns issue by given index in repository. | ||||
iu := &IssueUser{ | iu := &IssueUser{ | ||||
IssueId: issueID, | IssueId: issueID, | ||||
RepoId: repo.Id, | |||||
RepoId: repo.ID, | |||||
} | } | ||||
isNeedAddPoster := true | isNeedAddPoster := true | ||||
} | } | ||||
// Add owner's as well. | // Add owner's as well. | ||||
if repo.OwnerId != posterID { | |||||
if repo.OwnerID != posterID { | |||||
iu.Id = 0 | iu.Id = 0 | ||||
iu.Uid = repo.OwnerId | |||||
iu.Uid = repo.OwnerID | |||||
iu.IsAssigned = iu.Uid == assigneeID | iu.IsAssigned = iu.Uid == assigneeID | ||||
if _, err = x.Insert(iu); err != nil { | if _, err = x.Insert(iu); err != nil { | ||||
return err | return err | ||||
// ChangeMilestoneStatus changes the milestone open/closed status. | // ChangeMilestoneStatus changes the milestone open/closed status. | ||||
func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { | func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { | ||||
repo, err := GetRepositoryById(m.RepoID) | |||||
repo, err := GetRepositoryByID(m.RepoID) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
return err | return err | ||||
} | } | ||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.Id)) | |||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.Id)) | |||||
if _, err = sess.Id(repo.Id).AllCols().Update(repo); err != nil { | |||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID)) | |||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID)) | |||||
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil { | |||||
return err | return err | ||||
} | } | ||||
return sess.Commit() | return sess.Commit() | ||||
return err | return err | ||||
} | } | ||||
repo, err := GetRepositoryById(m.RepoID) | |||||
repo, err := GetRepositoryByID(m.RepoID) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
return err | return err | ||||
} | } | ||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.Id)) | |||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.Id)) | |||||
if _, err = sess.Id(repo.Id).AllCols().Update(repo); err != nil { | |||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID)) | |||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID)) | |||||
if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil { | |||||
return err | return err | ||||
} | } | ||||
} else if oa.Uid == -1 { | } else if oa.Uid == -1 { | ||||
return oa, ErrOauth2NotAssociated | return oa, ErrOauth2NotAssociated | ||||
} | } | ||||
oa.User, err = GetUserById(oa.Uid) | |||||
oa.User, err = GetUserByID(oa.Uid) | |||||
return oa, err | return oa, err | ||||
} | } | ||||
org.Members = make([]*User, len(ous)) | org.Members = make([]*User, len(ous)) | ||||
for i, ou := range ous { | for i, ou := range ous { | ||||
org.Members[i], err = GetUserById(ou.Uid) | |||||
org.Members[i], err = GetUserByID(ou.Uid) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
return nil | return nil | ||||
} | } | ||||
u, err := GetUserById(uid) | |||||
u, err := GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("GetUserById: %v", err) | return fmt.Errorf("GetUserById: %v", err) | ||||
} | } | ||||
org, err := GetUserById(orgId) | |||||
org, err := GetUserByID(orgId) | |||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("get organization: %v", err) | return fmt.Errorf("get organization: %v", err) | ||||
} else if err = org.GetRepositories(); err != nil { | } else if err = org.GetRepositories(); err != nil { | ||||
// Delete all repository accesses. | // Delete all repository accesses. | ||||
access := &Access{UserID: u.Id} | access := &Access{UserID: u.Id} | ||||
for _, repo := range org.Repos { | for _, repo := range org.Repos { | ||||
access.RepoID = repo.Id | |||||
access.RepoID = repo.ID | |||||
if _, err = sess.Delete(access); err != nil { | if _, err = sess.Delete(access); err != nil { | ||||
return err | return err | ||||
} else if err = watchRepo(sess, u.Id, repo.Id, false); err != nil { | |||||
} else if err = watchRepo(sess, u.Id, repo.ID, false); err != nil { | |||||
return err | return err | ||||
} | } | ||||
} | } | ||||
t.Repos = make([]*Repository, 0, len(teamRepos)) | t.Repos = make([]*Repository, 0, len(teamRepos)) | ||||
for i := range teamRepos { | for i := range teamRepos { | ||||
repo, err := getRepositoryById(e, teamRepos[i].RepoID) | |||||
repo, err := getRepositoryByID(e, teamRepos[i].RepoID) | |||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err) | return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err) | ||||
} | } | ||||
} | } | ||||
func (t *Team) addRepository(e Engine, repo *Repository) (err error) { | func (t *Team) addRepository(e Engine, repo *Repository) (err error) { | ||||
if err = addTeamRepo(e, t.OrgID, t.ID, repo.Id); err != nil { | |||||
if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil { | |||||
return err | return err | ||||
} | } | ||||
return fmt.Errorf("getMembers: %v", err) | return fmt.Errorf("getMembers: %v", err) | ||||
} | } | ||||
for _, u := range t.Members { | for _, u := range t.Members { | ||||
if err = watchRepo(e, u.Id, repo.Id, true); err != nil { | |||||
if err = watchRepo(e, u.Id, repo.ID, true); err != nil { | |||||
return fmt.Errorf("watchRepo: %v", err) | return fmt.Errorf("watchRepo: %v", err) | ||||
} | } | ||||
} | } | ||||
// AddRepository adds new repository to team of organization. | // AddRepository adds new repository to team of organization. | ||||
func (t *Team) AddRepository(repo *Repository) (err error) { | func (t *Team) AddRepository(repo *Repository) (err error) { | ||||
if repo.OwnerId != t.OrgID { | |||||
if repo.OwnerID != t.OrgID { | |||||
return errors.New("Repository does not belong to organization") | return errors.New("Repository does not belong to organization") | ||||
} else if t.HasRepository(repo.Id) { | |||||
} else if t.HasRepository(repo.ID) { | |||||
return nil | return nil | ||||
} | } | ||||
} | } | ||||
func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) { | func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) { | ||||
if err = removeTeamRepo(e, t.ID, repo.Id); err != nil { | |||||
if err = removeTeamRepo(e, t.ID, repo.ID); err != nil { | |||||
return err | return err | ||||
} | } | ||||
continue | continue | ||||
} | } | ||||
if err = watchRepo(e, u.Id, repo.Id, false); err != nil { | |||||
if err = watchRepo(e, u.Id, repo.ID, false); err != nil { | |||||
return err | return err | ||||
} | } | ||||
} | } | ||||
return nil | return nil | ||||
} | } | ||||
repo, err := GetRepositoryById(repoID) | |||||
repo, err := GetRepositoryByID(repoID) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
} | } | ||||
// Get organization. | // Get organization. | ||||
org, err := GetUserById(t.OrgID) | |||||
org, err := GetUserByID(t.OrgID) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
} | } | ||||
// Get organization. | // Get organization. | ||||
org, err := getUserById(e, orgId) | |||||
org, err := getUserByID(e, orgId) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } |
// Repository represents a git repository. | // Repository represents a git repository. | ||||
type Repository struct { | type Repository struct { | ||||
Id int64 | |||||
OwnerId int64 `xorm:"UNIQUE(s)"` | |||||
ID int64 `xorm:"pk autoincr"` | |||||
OwnerID int64 `xorm:"UNIQUE(s)"` | |||||
Owner *User `xorm:"-"` | Owner *User `xorm:"-"` | ||||
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` | LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` | ||||
Name string `xorm:"INDEX NOT NULL"` | Name string `xorm:"INDEX NOT NULL"` | ||||
*Mirror `xorm:"-"` | *Mirror `xorm:"-"` | ||||
IsFork bool `xorm:"NOT NULL DEFAULT false"` | IsFork bool `xorm:"NOT NULL DEFAULT false"` | ||||
ForkId int64 | |||||
ForkRepo *Repository `xorm:"-"` | |||||
ForkID int64 | |||||
BaseRepo *Repository `xorm:"-"` | |||||
Created time.Time `xorm:"CREATED"` | Created time.Time `xorm:"CREATED"` | ||||
Updated time.Time `xorm:"UPDATED"` | Updated time.Time `xorm:"UPDATED"` | ||||
func (repo *Repository) getOwner(e Engine) (err error) { | func (repo *Repository) getOwner(e Engine) (err error) { | ||||
if repo.Owner == nil { | if repo.Owner == nil { | ||||
repo.Owner, err = getUserById(e, repo.OwnerId) | |||||
repo.Owner, err = getUserByID(e, repo.OwnerID) | |||||
} | } | ||||
return err | return err | ||||
} | } | ||||
} | } | ||||
func (repo *Repository) GetMirror() (err error) { | func (repo *Repository) GetMirror() (err error) { | ||||
repo.Mirror, err = GetMirror(repo.Id) | |||||
repo.Mirror, err = GetMirror(repo.ID) | |||||
return err | return err | ||||
} | } | ||||
func (repo *Repository) GetForkRepo() (err error) { | |||||
func (repo *Repository) GetBaseRepo() (err error) { | |||||
if !repo.IsFork { | if !repo.IsFork { | ||||
return nil | return nil | ||||
} | } | ||||
repo.ForkRepo, err = GetRepositoryById(repo.ForkId) | |||||
repo.BaseRepo, err = GetRepositoryByID(repo.ForkID) | |||||
return err | return err | ||||
} | } | ||||
} | } | ||||
func (repo *Repository) IsOwnedBy(u *User) bool { | func (repo *Repository) IsOwnedBy(u *User) bool { | ||||
return repo.OwnerId == u.Id | |||||
return repo.OwnerID == u.Id | |||||
} | } | ||||
// DescriptionHtml does special handles to description and return HTML string. | // DescriptionHtml does special handles to description and return HTML string. | ||||
func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) { | func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) { | ||||
has, err := e.Get(&Repository{ | has, err := e.Get(&Repository{ | ||||
OwnerId: u.Id, | |||||
OwnerID: u.Id, | |||||
LowerName: strings.ToLower(repoName), | LowerName: strings.ToLower(repoName), | ||||
}) | }) | ||||
return has && com.IsDir(RepoPath(u.Name, repoName)), err | return has && com.IsDir(RepoPath(u.Name, repoName)), err | ||||
// Mirror represents a mirror information of repository. | // Mirror represents a mirror information of repository. | ||||
type Mirror struct { | type Mirror struct { | ||||
Id int64 | |||||
RepoId int64 | |||||
ID int64 `xorm:"pk autoincr"` | |||||
RepoID int64 | |||||
RepoName string // <user name>/<repo name> | RepoName string // <user name>/<repo name> | ||||
Interval int // Hour. | Interval int // Hour. | ||||
Updated time.Time `xorm:"UPDATED"` | Updated time.Time `xorm:"UPDATED"` | ||||
} | } | ||||
func getMirror(e Engine, repoId int64) (*Mirror, error) { | func getMirror(e Engine, repoId int64) (*Mirror, error) { | ||||
m := &Mirror{RepoId: repoId} | |||||
m := &Mirror{RepoID: repoId} | |||||
has, err := e.Get(m) | has, err := e.Get(m) | ||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
func updateMirror(e Engine, m *Mirror) error { | func updateMirror(e Engine, m *Mirror) error { | ||||
_, err := e.Id(m.Id).Update(m) | |||||
_, err := e.Id(m.ID).Update(m) | |||||
return err | return err | ||||
} | } | ||||
} | } | ||||
if _, err = x.InsertOne(&Mirror{ | if _, err = x.InsertOne(&Mirror{ | ||||
RepoId: repoId, | |||||
RepoID: repoId, | |||||
RepoName: strings.ToLower(userName + "/" + repoName), | RepoName: strings.ToLower(userName + "/" + repoName), | ||||
Interval: 24, | Interval: 24, | ||||
NextUpdate: time.Now().Add(24 * time.Hour), | NextUpdate: time.Now().Add(24 * time.Hour), | ||||
repo.IsBare = false | repo.IsBare = false | ||||
if mirror { | if mirror { | ||||
if err = MirrorRepository(repo.Id, u.Name, repo.Name, repoPath, url); err != nil { | |||||
if err = MirrorRepository(repo.ID, u.Name, repo.Name, repoPath, url); err != nil { | |||||
return repo, err | return repo, err | ||||
} | } | ||||
repo.IsMirror = true | repo.IsMirror = true | ||||
if len(fileName) == 0 { | if len(fileName) == 0 { | ||||
// Re-fetch the repository from database before updating it (else it would | // Re-fetch the repository from database before updating it (else it would | ||||
// override changes that were done earlier with sql) | // override changes that were done earlier with sql) | ||||
if repo, err = getRepositoryById(e, repo.Id); err != nil { | |||||
if repo, err = getRepositoryByID(e, repo.ID); err != nil { | |||||
return err | return err | ||||
} | } | ||||
repo.IsBare = true | repo.IsBare = true | ||||
} | } | ||||
} | } | ||||
if err = watchRepo(e, u.Id, repo.Id, true); err != nil { | |||||
if err = watchRepo(e, u.Id, repo.ID, true); err != nil { | |||||
return fmt.Errorf("watchRepo: %v", err) | return fmt.Errorf("watchRepo: %v", err) | ||||
} else if err = newRepoAction(e, u, repo); err != nil { | } else if err = newRepoAction(e, u, repo); err != nil { | ||||
return fmt.Errorf("newRepoAction: %v", err) | return fmt.Errorf("newRepoAction: %v", err) | ||||
// CreateRepository creates a repository for given user or organization. | // CreateRepository creates a repository for given user or organization. | ||||
func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMirror, initReadme bool) (_ *Repository, err error) { | func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMirror, initReadme bool) (_ *Repository, err error) { | ||||
repo := &Repository{ | repo := &Repository{ | ||||
OwnerId: u.Id, | |||||
OwnerID: u.Id, | |||||
Owner: u, | Owner: u, | ||||
Name: name, | Name: name, | ||||
LowerName: strings.ToLower(name), | LowerName: strings.ToLower(name), | ||||
} | } | ||||
for _, repo := range repos { | for _, repo := range repos { | ||||
repo.Owner = &User{Id: repo.OwnerId} | |||||
repo.Owner = &User{Id: repo.OwnerID} | |||||
has, err := x.Get(repo.Owner) | has, err := x.Get(repo.Owner) | ||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} else if !has { | } else if !has { | ||||
return nil, ErrUserNotExist{repo.OwnerId, ""} | |||||
return nil, ErrUserNotExist{repo.OwnerID, ""} | |||||
} | } | ||||
} | } | ||||
// Note: we have to set value here to make sure recalculate accesses is based on | // Note: we have to set value here to make sure recalculate accesses is based on | ||||
// new owner. | // new owner. | ||||
repo.OwnerId = newOwner.Id | |||||
repo.OwnerID = newOwner.Id | |||||
repo.Owner = newOwner | repo.Owner = newOwner | ||||
// Update repository. | // Update repository. | ||||
if _, err := sess.Id(repo.Id).Update(repo); err != nil { | |||||
if _, err := sess.Id(repo.ID).Update(repo); err != nil { | |||||
return fmt.Errorf("update owner: %v", err) | return fmt.Errorf("update owner: %v", err) | ||||
} | } | ||||
} | } | ||||
// Dummy object. | // Dummy object. | ||||
collaboration := &Collaboration{RepoID: repo.Id} | |||||
collaboration := &Collaboration{RepoID: repo.ID} | |||||
for _, c := range collaborators { | for _, c := range collaborators { | ||||
collaboration.UserID = c.Id | collaboration.UserID = c.Id | ||||
if c.Id == newOwner.Id || newOwner.IsOrgMember(c.Id) { | if c.Id == newOwner.Id || newOwner.IsOrgMember(c.Id) { | ||||
return fmt.Errorf("getTeams: %v", err) | return fmt.Errorf("getTeams: %v", err) | ||||
} | } | ||||
for _, t := range owner.Teams { | for _, t := range owner.Teams { | ||||
if !t.hasRepository(sess, repo.Id) { | |||||
if !t.hasRepository(sess, repo.ID) { | |||||
continue | continue | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if err = owner.removeOrgRepo(sess, repo.Id); err != nil { | |||||
if err = owner.removeOrgRepo(sess, repo.ID); err != nil { | |||||
return fmt.Errorf("removeOrgRepo: %v", err) | return fmt.Errorf("removeOrgRepo: %v", err) | ||||
} | } | ||||
} | } | ||||
return fmt.Errorf("decrease old owner repository count: %v", err) | return fmt.Errorf("decrease old owner repository count: %v", err) | ||||
} | } | ||||
if err = watchRepo(sess, newOwner.Id, repo.Id, true); err != nil { | |||||
if err = watchRepo(sess, newOwner.Id, repo.ID, true); err != nil { | |||||
return fmt.Errorf("watchRepo: %v", err) | return fmt.Errorf("watchRepo: %v", err) | ||||
} else if err = transferRepoAction(sess, u, owner, newOwner, repo); err != nil { | } else if err = transferRepoAction(sess, u, owner, newOwner, repo); err != nil { | ||||
return fmt.Errorf("transferRepoAction: %v", err) | return fmt.Errorf("transferRepoAction: %v", err) | ||||
// Update mirror information. | // Update mirror information. | ||||
if repo.IsMirror { | if repo.IsMirror { | ||||
mirror, err := getMirror(sess, repo.Id) | |||||
mirror, err := getMirror(sess, repo.ID) | |||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("getMirror: %v", err) | return fmt.Errorf("getMirror: %v", err) | ||||
} | } | ||||
repo.Website = repo.Website[:255] | repo.Website = repo.Website[:255] | ||||
} | } | ||||
if _, err = e.Id(repo.Id).AllCols().Update(repo); err != nil { | |||||
if _, err = e.Id(repo.ID).AllCols().Update(repo); err != nil { | |||||
return fmt.Errorf("update: %v", err) | return fmt.Errorf("update: %v", err) | ||||
} | } | ||||
// DeleteRepository deletes a repository for a user or organization. | // DeleteRepository deletes a repository for a user or organization. | ||||
func DeleteRepository(uid, repoID int64, userName string) error { | func DeleteRepository(uid, repoID int64, userName string) error { | ||||
repo := &Repository{Id: repoID, OwnerId: uid} | |||||
repo := &Repository{ID: repoID, OwnerID: uid} | |||||
has, err := x.Get(repo) | has, err := x.Get(repo) | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
// In case is a organization. | // In case is a organization. | ||||
org, err := GetUserById(uid) | |||||
org, err := GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if _, err = sess.Delete(&Repository{Id: repoID}); err != nil { | |||||
if _, err = sess.Delete(&Repository{ID: repoID}); err != nil { | |||||
return err | return err | ||||
} else if _, err = sess.Delete(&Access{RepoID: repo.Id}); err != nil { | |||||
} else if _, err = sess.Delete(&Access{RepoID: repo.ID}); err != nil { | |||||
return err | return err | ||||
} else if _, err = sess.Delete(&Action{RepoID: repo.Id}); err != nil { | |||||
} else if _, err = sess.Delete(&Action{RepoID: repo.ID}); err != nil { | |||||
return err | return err | ||||
} else if _, err = sess.Delete(&Watch{RepoID: repoID}); err != nil { | } else if _, err = sess.Delete(&Watch{RepoID: repoID}); err != nil { | ||||
return err | return err | ||||
} else if _, err = sess.Delete(&Mirror{RepoId: repoID}); err != nil { | |||||
} else if _, err = sess.Delete(&Mirror{RepoID: repoID}); err != nil { | |||||
return err | return err | ||||
} else if _, err = sess.Delete(&IssueUser{RepoId: repoID}); err != nil { | } else if _, err = sess.Delete(&IssueUser{RepoId: repoID}); err != nil { | ||||
return err | return err | ||||
} | } | ||||
if repo.IsFork { | if repo.IsFork { | ||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkId); err != nil { | |||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil { | |||||
return err | return err | ||||
} | } | ||||
} | } | ||||
// GetRepositoryByName returns the repository by given name under user if exists. | // GetRepositoryByName returns the repository by given name under user if exists. | ||||
func GetRepositoryByName(uid int64, repoName string) (*Repository, error) { | func GetRepositoryByName(uid int64, repoName string) (*Repository, error) { | ||||
repo := &Repository{ | repo := &Repository{ | ||||
OwnerId: uid, | |||||
OwnerID: uid, | |||||
LowerName: strings.ToLower(repoName), | LowerName: strings.ToLower(repoName), | ||||
} | } | ||||
has, err := x.Get(repo) | has, err := x.Get(repo) | ||||
return repo, err | return repo, err | ||||
} | } | ||||
func getRepositoryById(e Engine, id int64) (*Repository, error) { | |||||
func getRepositoryByID(e Engine, id int64) (*Repository, error) { | |||||
repo := new(Repository) | repo := new(Repository) | ||||
has, err := e.Id(id).Get(repo) | has, err := e.Id(id).Get(repo) | ||||
if err != nil { | if err != nil { | ||||
return repo, nil | return repo, nil | ||||
} | } | ||||
// GetRepositoryById returns the repository by given id if exists. | |||||
func GetRepositoryById(id int64) (*Repository, error) { | |||||
return getRepositoryById(x, id) | |||||
// GetRepositoryByID returns the repository by given id if exists. | |||||
func GetRepositoryByID(id int64) (*Repository, error) { | |||||
return getRepositoryByID(x, id) | |||||
} | } | ||||
// GetRepositories returns a list of repositories of given user. | // GetRepositories returns a list of repositories of given user. | ||||
sess.Where("is_private=?", false) | sess.Where("is_private=?", false) | ||||
} | } | ||||
err := sess.Find(&repos, &Repository{OwnerId: uid}) | |||||
return repos, err | |||||
return repos, sess.Find(&repos, &Repository{OwnerID: uid}) | |||||
} | } | ||||
// GetRecentUpdatedRepositories returns the list of repositories that are recently updated. | // GetRecentUpdatedRepositories returns the list of repositories that are recently updated. | ||||
} | } | ||||
// GetRepositoryCount returns the total number of repositories of user. | // GetRepositoryCount returns the total number of repositories of user. | ||||
func GetRepositoryCount(user *User) (int64, error) { | |||||
return x.Count(&Repository{OwnerId: user.Id}) | |||||
func GetRepositoryCount(u *User) (int64, error) { | |||||
return x.Count(&Repository{OwnerID: u.Id}) | |||||
} | } | ||||
type SearchOption struct { | type SearchOption struct { | ||||
// Add collaborator and accompanying access | // Add collaborator and accompanying access | ||||
func (repo *Repository) AddCollaborator(u *User) error { | func (repo *Repository) AddCollaborator(u *User) error { | ||||
collaboration := &Collaboration{ | collaboration := &Collaboration{ | ||||
RepoID: repo.Id, | |||||
RepoID: repo.ID, | |||||
UserID: u.Id, | UserID: u.Id, | ||||
} | } | ||||
func (repo *Repository) getCollaborators(e Engine) ([]*User, error) { | func (repo *Repository) getCollaborators(e Engine) ([]*User, error) { | ||||
collaborations := make([]*Collaboration, 0) | collaborations := make([]*Collaboration, 0) | ||||
if err := e.Find(&collaborations, &Collaboration{RepoID: repo.Id}); err != nil { | |||||
if err := e.Find(&collaborations, &Collaboration{RepoID: repo.ID}); err != nil { | |||||
return nil, err | return nil, err | ||||
} | } | ||||
users := make([]*User, len(collaborations)) | users := make([]*User, len(collaborations)) | ||||
for i, c := range collaborations { | for i, c := range collaborations { | ||||
user, err := getUserById(e, c.UserID) | |||||
user, err := getUserByID(e, c.UserID) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
// Delete collaborator and accompanying access | // Delete collaborator and accompanying access | ||||
func (repo *Repository) DeleteCollaborator(u *User) (err error) { | func (repo *Repository) DeleteCollaborator(u *User) (err error) { | ||||
collaboration := &Collaboration{ | collaboration := &Collaboration{ | ||||
RepoID: repo.Id, | |||||
RepoID: repo.ID, | |||||
UserID: u.Id, | UserID: u.Id, | ||||
} | } | ||||
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) { | func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) { | ||||
repo := &Repository{ | repo := &Repository{ | ||||
OwnerId: u.Id, | |||||
OwnerID: u.Id, | |||||
Owner: u, | Owner: u, | ||||
Name: name, | Name: name, | ||||
LowerName: strings.ToLower(name), | LowerName: strings.ToLower(name), | ||||
Description: desc, | Description: desc, | ||||
IsPrivate: oldRepo.IsPrivate, | IsPrivate: oldRepo.IsPrivate, | ||||
IsFork: true, | IsFork: true, | ||||
ForkId: oldRepo.Id, | |||||
ForkID: oldRepo.ID, | |||||
} | } | ||||
sess := x.NewSession() | sess := x.NewSession() | ||||
return nil, err | return nil, err | ||||
} | } | ||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.Id); err != nil { | |||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.ID); err != nil { | |||||
return nil, err | return nil, err | ||||
} | } | ||||
commit := &base.PushCommits{} | commit := &base.PushCommits{} | ||||
if err = CommitRepoAction(userId, ru.Id, userName, actEmail, | if err = CommitRepoAction(userId, ru.Id, userName, actEmail, | ||||
repos.Id, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil { | |||||
repos.ID, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil { | |||||
log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) | log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) | ||||
} | } | ||||
return err | return err | ||||
} | } | ||||
if err = CommitRepoAction(userId, ru.Id, userName, actEmail, | if err = CommitRepoAction(userId, ru.Id, userName, actEmail, | ||||
repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitId, newCommitId); err != nil { | |||||
repos.ID, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitId, newCommitId); err != nil { | |||||
return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) | return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) | ||||
} | } | ||||
return nil | return nil |
u.Orgs = make([]*User, len(ous)) | u.Orgs = make([]*User, len(ous)) | ||||
for i, ou := range ous { | for i, ou := range ous { | ||||
u.Orgs[i], err = GetUserById(ou.OrgID) | |||||
u.Orgs[i], err = GetUserByID(ou.OrgID) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
return user, nil | return user, nil | ||||
} | } | ||||
func getUserById(e Engine, id int64) (*User, error) { | |||||
func getUserByID(e Engine, id int64) (*User, error) { | |||||
u := new(User) | u := new(User) | ||||
has, err := e.Id(id).Get(u) | has, err := e.Id(id).Get(u) | ||||
if err != nil { | if err != nil { | ||||
return u, nil | return u, nil | ||||
} | } | ||||
// GetUserById returns the user object by given ID if exists. | |||||
func GetUserById(id int64) (*User, error) { | |||||
return getUserById(x, id) | |||||
// GetUserByID returns the user object by given ID if exists. | |||||
func GetUserByID(id int64) (*User, error) { | |||||
return getUserByID(x, id) | |||||
} | } | ||||
// GetUserByName returns user by given name. | // GetUserByName returns user by given name. | ||||
return nil, err | return nil, err | ||||
} | } | ||||
u, err := GetUserById(uid) | |||||
u, err := GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
return err | return err | ||||
} | } | ||||
if user, err := GetUserById(email.Uid); err != nil { | |||||
if user, err := GetUserByID(email.Uid); err != nil { | |||||
return err | return err | ||||
} else { | } else { | ||||
user.Rands = GetUserSalt() | user.Rands = GetUserSalt() | ||||
return nil, err | return nil, err | ||||
} | } | ||||
if has { | if has { | ||||
return GetUserById(emailAddress.Uid) | |||||
return GetUserByID(emailAddress.Uid) | |||||
} | } | ||||
return nil, ErrUserNotExist{0, "email"} | return nil, ErrUserNotExist{0, "email"} |
return 0 | return 0 | ||||
} | } | ||||
if id, ok := uid.(int64); ok { | if id, ok := uid.(int64); ok { | ||||
if _, err := models.GetUserById(id); err != nil { | |||||
if _, err := models.GetUserByID(id); err != nil { | |||||
if !models.IsErrUserNotExist(err) { | if !models.IsErrUserNotExist(err) { | ||||
log.Error(4, "GetUserById: %v", err) | log.Error(4, "GetUserById: %v", err) | ||||
} | } | ||||
return nil, false | return nil, false | ||||
} | } | ||||
u, err := models.GetUserById(uid) | |||||
u, err := models.GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
log.Error(4, "GetUserById: %v", err) | log.Error(4, "GetUserById: %v", err) | ||||
return nil, false | return nil, false |
// SendIssueNotifyMail sends mail notification of all watchers of repository. | // SendIssueNotifyMail sends mail notification of all watchers of repository. | ||||
func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *models.Issue) ([]string, error) { | func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *models.Issue) ([]string, error) { | ||||
ws, err := models.GetWatchers(repo.Id) | |||||
ws, err := models.GetWatchers(repo.ID) | |||||
if err != nil { | if err != nil { | ||||
return nil, errors.New("mail.NotifyWatchers(GetWatchers): " + err.Error()) | return nil, errors.New("mail.NotifyWatchers(GetWatchers): " + err.Error()) | ||||
} | } | ||||
if u.Id == uid { | if u.Id == uid { | ||||
continue | continue | ||||
} | } | ||||
u, err := models.GetUserById(uid) | |||||
u, err := models.GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
return nil, errors.New("mail.NotifyWatchers(GetUserById): " + err.Error()) | return nil, errors.New("mail.NotifyWatchers(GetUserById): " + err.Error()) | ||||
} | } |
ctx.Data["HasAccess"] = true | ctx.Data["HasAccess"] = true | ||||
if repo.IsMirror { | if repo.IsMirror { | ||||
ctx.Repo.Mirror, err = models.GetMirror(repo.Id) | |||||
ctx.Repo.Mirror, err = models.GetMirror(repo.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetMirror", err) | ctx.Handle(500, "GetMirror", err) | ||||
return | return | ||||
ctx.Data["Tags"] = tags | ctx.Data["Tags"] = tags | ||||
ctx.Repo.Repository.NumTags = len(tags) | ctx.Repo.Repository.NumTags = len(tags) | ||||
// Non-fork repository will not return error in this method. | |||||
if err = repo.GetForkRepo(); err != nil { | |||||
ctx.Handle(500, "GetForkRepo", err) | |||||
return | |||||
if repo.IsFork { | |||||
// Non-fork repository will not return error in this method. | |||||
if err = repo.GetBaseRepo(); err != nil { | |||||
ctx.Handle(500, "GetBaseRepo", err) | |||||
return | |||||
} else if repo.BaseRepo.GetOwner(); err != nil { | |||||
ctx.Handle(500, "BaseRepo.GetOwner", err) | |||||
return | |||||
} | |||||
bsaeRepo := repo.BaseRepo | |||||
baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name)) | |||||
if err != nil { | |||||
ctx.Handle(500, "OpenRepository", err) | |||||
return | |||||
} | |||||
if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) { | |||||
ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch | |||||
} else { | |||||
baseBranches, err := baseGitRepo.GetBranches() | |||||
if err != nil { | |||||
ctx.Handle(500, "GetBranches", err) | |||||
return | |||||
} | |||||
if len(baseBranches) > 0 { | |||||
ctx.Data["BaseDefaultBranch"] = baseBranches[0] | |||||
} | |||||
} | |||||
} | } | ||||
ctx.Data["Title"] = u.Name + "/" + repo.Name | ctx.Data["Title"] = u.Name + "/" + repo.Name | ||||
} | } | ||||
if ctx.IsSigned { | if ctx.IsSigned { | ||||
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id) | |||||
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id) | |||||
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID) | |||||
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID) | |||||
} | } | ||||
ctx.Data["TagName"] = ctx.Repo.TagName | ctx.Data["TagName"] = ctx.Repo.TagName | ||||
// If not branch selected, try default one. | // If not branch selected, try default one. | ||||
// If default branch doesn't exists, fall back to some other branch. | // If default branch doesn't exists, fall back to some other branch. | ||||
if ctx.Repo.BranchName == "" { | |||||
if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { | |||||
if len(ctx.Repo.BranchName) == 0 { | |||||
if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { | |||||
ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch | ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch | ||||
} else if len(brs) > 0 { | } else if len(brs) > 0 { | ||||
ctx.Repo.BranchName = brs[0] | ctx.Repo.BranchName = brs[0] |
$('#add-deploy-key-panel').show(); | $('#add-deploy-key-panel').show(); | ||||
}); | }); | ||||
} | } | ||||
// Pull request | |||||
if ($('.repository.compare.pull').length > 0) { | |||||
$('.choose.branch .dropdown').dropdown({ | |||||
action: 'hide', | |||||
fullTextSearch: true, | |||||
onNoResults: function () { | |||||
$('.choose.branch .dropdown .active').addClass('selected'); | |||||
} | |||||
}); | |||||
} | |||||
}; | }; | ||||
$(document).ready(function () { | $(document).ready(function () { |
padding-left: 20px!important; | padding-left: 20px!important; | ||||
} | } | ||||
} | } | ||||
&.compare.pull { | |||||
.choose.branch { | |||||
.octicon { | |||||
padding-right: 10px; | |||||
} | |||||
} | |||||
} | |||||
.filter.dropdown .menu { | |||||
margin-top: 1px!important; | |||||
.items { | |||||
max-height: 300px; | |||||
overflow-y: auto; | |||||
.item { | |||||
position: relative; | |||||
cursor: pointer; | |||||
display: block; | |||||
border: none; | |||||
height: auto; | |||||
border-top: none; | |||||
line-height: 1em; | |||||
color: rgba(0,0,0,.8); | |||||
padding: .71428571em 1.14285714em!important; | |||||
font-size: 1rem; | |||||
text-transform: none; | |||||
font-weight: 400; | |||||
box-shadow: none; | |||||
-webkit-touch-callout: none; | |||||
&.active { | |||||
font-weight: 700; | |||||
} | |||||
&:hover { | |||||
background: rgba(0,0,0,.05); | |||||
color: rgba(0,0,0,.8); | |||||
z-index: 13; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
.settings .key.list { | .settings .key.list { |
return | return | ||||
} | } | ||||
u, err := models.GetUserById(uid) | |||||
u, err := models.GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById", err) | |||||
ctx.Handle(500, "GetUserByID", err) | |||||
return | return | ||||
} | } | ||||
return | return | ||||
} | } | ||||
u, err := models.GetUserById(uid) | |||||
u, err := models.GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById", err) | ctx.Handle(500, "GetUserById", err) | ||||
return | return | ||||
return | return | ||||
} | } | ||||
u, err := models.GetUserById(uid) | |||||
u, err := models.GetUserByID(uid) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById", err) | |||||
ctx.Handle(500, "GetUserByID", err) | |||||
return | return | ||||
} | } | ||||
log.Error(4, "CloneLink: %v", err) | log.Error(4, "CloneLink: %v", err) | ||||
} | } | ||||
return &api.Repository{ | return &api.Repository{ | ||||
Id: repo.Id, | |||||
Id: repo.ID, | |||||
Owner: *ToApiUser(owner), | Owner: *ToApiUser(owner), | ||||
FullName: owner.Name + "/" + repo.Name, | FullName: owner.Name + "/" + repo.Name, | ||||
Private: repo.IsPrivate, | Private: repo.IsPrivate, | ||||
if ctx.User.Id == opt.Uid { | if ctx.User.Id == opt.Uid { | ||||
opt.Private = true | opt.Private = true | ||||
} else { | } else { | ||||
u, err := models.GetUserById(opt.Uid) | |||||
u, err := models.GetUserByID(opt.Uid) | |||||
if err != nil { | if err != nil { | ||||
ctx.JSON(500, map[string]interface{}{ | ctx.JSON(500, map[string]interface{}{ | ||||
"ok": false, | "ok": false, | ||||
return | return | ||||
} | } | ||||
results[i] = &api.Repository{ | results[i] = &api.Repository{ | ||||
Id: repos[i].Id, | |||||
Id: repos[i].ID, | |||||
FullName: path.Join(repos[i].Owner.Name, repos[i].Name), | FullName: path.Join(repos[i].Owner.Name, repos[i].Name), | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
log.Error(4, "CreateRepository: %v", err) | log.Error(4, "CreateRepository: %v", err) | ||||
if repo != nil { | if repo != nil { | ||||
if err = models.DeleteRepository(ctx.User.Id, repo.Id, ctx.User.Name); err != nil { | |||||
if err = models.DeleteRepository(ctx.User.Id, repo.ID, ctx.User.Name); err != nil { | |||||
log.Error(4, "DeleteRepository: %v", err) | log.Error(4, "DeleteRepository: %v", err) | ||||
} | } | ||||
} | } | ||||
ctxUser := u | ctxUser := u | ||||
// Not equal means current user is an organization. | // Not equal means current user is an organization. | ||||
if form.Uid != u.Id { | if form.Uid != u.Id { | ||||
org, err := models.GetUserById(form.Uid) | |||||
org, err := models.GetUserByID(form.Uid) | |||||
if err != nil { | if err != nil { | ||||
if models.IsErrUserNotExist(err) { | if models.IsErrUserNotExist(err) { | ||||
ctx.HandleAPI(422, err) | ctx.HandleAPI(422, err) | ||||
repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) | repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) | ||||
if err != nil { | if err != nil { | ||||
if repo != nil { | if repo != nil { | ||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil { | |||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID, ctxUser.Name); errDelete != nil { | |||||
log.Error(4, "DeleteRepository: %v", errDelete) | log.Error(4, "DeleteRepository: %v", errDelete) | ||||
} | } | ||||
} | } |
// GET /repos/:username/:reponame/hooks | // GET /repos/:username/:reponame/hooks | ||||
// https://developer.github.com/v3/repos/hooks/#list-hooks | // https://developer.github.com/v3/repos/hooks/#list-hooks | ||||
func ListRepoHooks(ctx *middleware.Context) { | func ListRepoHooks(ctx *middleware.Context) { | ||||
hooks, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.Id) | |||||
hooks, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.JSON(500, &base.ApiJsonErr{"GetWebhooksByRepoId: " + err.Error(), base.DOC_URL}) | ctx.JSON(500, &base.ApiJsonErr{"GetWebhooksByRepoId: " + err.Error(), base.DOC_URL}) | ||||
return | return | ||||
} | } | ||||
w := &models.Webhook{ | w := &models.Webhook{ | ||||
RepoId: ctx.Repo.Repository.Id, | |||||
RepoId: ctx.Repo.Repository.ID, | |||||
Url: form.Config["url"], | Url: form.Config["url"], | ||||
ContentType: models.ToHookContentType(form.Config["content_type"]), | ContentType: models.ToHookContentType(form.Config["content_type"]), | ||||
Secret: form.Config["secret"], | Secret: form.Config["secret"], |
} | } | ||||
for _, repo := range repos { | for _, repo := range repos { | ||||
if err = repo.GetOwner(); err != nil { | if err = repo.GetOwner(); err != nil { | ||||
ctx.Handle(500, "GetOwner", fmt.Errorf("%d: %v", repo.Id, err)) | |||||
ctx.Handle(500, "GetOwner", fmt.Errorf("%d: %v", repo.ID, err)) | |||||
return | return | ||||
} | } | ||||
} | } |
} | } | ||||
return | return | ||||
} | } | ||||
authUser, err = models.GetUserById(token.Uid) | |||||
authUser, err = models.GetUserByID(token.Uid) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById", err) | ctx.Handle(500, "GetUserById", err) | ||||
return | return | ||||
// FIXME: handle error. | // FIXME: handle error. | ||||
if err = models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id); err == nil { | if err = models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id); err == nil { | ||||
models.HookQueue.AddRepoID(repo.Id) | |||||
models.HookQueue.AddRepoID(repo.ID) | |||||
} | } | ||||
} | } |
) | ) | ||||
func RetrieveLabels(ctx *middleware.Context) { | func RetrieveLabels(ctx *middleware.Context) { | ||||
labels, err := models.GetLabels(ctx.Repo.Repository.Id) | |||||
labels, err := models.GetLabels(ctx.Repo.Repository.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "RetrieveLabels.GetLabels: %v", err) | ctx.Handle(500, "RetrieveLabels.GetLabels: %v", err) | ||||
return | return | ||||
selectLabels := ctx.Query("labels") | selectLabels := ctx.Query("labels") | ||||
milestoneID := ctx.QueryInt64("milestone") | milestoneID := ctx.QueryInt64("milestone") | ||||
isShowClosed := ctx.Query("state") == "closed" | isShowClosed := ctx.Query("state") == "closed" | ||||
issueStats := models.GetIssueStats(repo.Id, uid, com.StrTo(selectLabels).MustInt64(), milestoneID, isShowClosed, filterMode) | |||||
issueStats := models.GetIssueStats(repo.ID, uid, com.StrTo(selectLabels).MustInt64(), milestoneID, isShowClosed, filterMode) | |||||
page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
if page <= 1 { | if page <= 1 { | ||||
ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5) | ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5) | ||||
// Get issues. | // Get issues. | ||||
issues, err := models.Issues(uid, assigneeID, repo.Id, posterID, milestoneID, | |||||
issues, err := models.Issues(uid, assigneeID, repo.ID, posterID, milestoneID, | |||||
page, isShowClosed, filterMode == models.FM_MENTION, selectLabels, ctx.Query("sortType")) | page, isShowClosed, filterMode == models.FM_MENTION, selectLabels, ctx.Query("sortType")) | ||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetIssues: %v", err) | ctx.Handle(500, "GetIssues: %v", err) | ||||
} | } | ||||
// Get issue-user pairs. | // Get issue-user pairs. | ||||
pairs, err := models.GetIssueUserPairs(repo.Id, posterID, isShowClosed) | |||||
pairs, err := models.GetIssueUserPairs(repo.ID, posterID, isShowClosed) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetIssueUserPairs: %v", err) | ctx.Handle(500, "GetIssueUserPairs: %v", err) | ||||
return | return | ||||
ctx.Data["Issues"] = issues | ctx.Data["Issues"] = issues | ||||
// Get milestones. | // Get milestones. | ||||
miles, err := models.GetAllRepoMilestones(repo.Id) | |||||
miles, err := models.GetAllRepoMilestones(repo.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetAllRepoMilestones: %v", err) | ctx.Handle(500, "GetAllRepoMilestones: %v", err) | ||||
return | return | ||||
err error | err error | ||||
) | ) | ||||
// Get all milestones. | // Get all milestones. | ||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.Id, -1, false) | |||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetMilestones.1: %v", err) | ctx.Handle(500, "GetMilestones.1: %v", err) | ||||
return | return | ||||
} | } | ||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.Id, -1, true) | |||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetMilestones.2: %v", err) | ctx.Handle(500, "GetMilestones.2: %v", err) | ||||
return | return | ||||
var err error | var err error | ||||
// Get all milestones. | // Get all milestones. | ||||
_, err = models.GetMilestones(ctx.Repo.Repository.Id, -1, false) | |||||
_, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, false) | |||||
if err != nil { | if err != nil { | ||||
send(500, nil, err) | send(500, nil, err) | ||||
return | return | ||||
} | } | ||||
_, err = models.GetMilestones(ctx.Repo.Repository.Id, -1, true) | |||||
_, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, true) | |||||
if err != nil { | if err != nil { | ||||
send(500, nil, err) | send(500, nil, err) | ||||
return | return | ||||
form.AssigneeId = 0 | form.AssigneeId = 0 | ||||
} | } | ||||
issue := &models.Issue{ | issue := &models.Issue{ | ||||
RepoID: ctx.Repo.Repository.Id, | |||||
RepoID: ctx.Repo.Repository.ID, | |||||
Index: int64(ctx.Repo.Repository.NumIssues) + 1, | Index: int64(ctx.Repo.Repository.NumIssues) + 1, | ||||
Name: form.IssueName, | Name: form.IssueName, | ||||
PosterID: ctx.User.Id, | PosterID: ctx.User.Id, | ||||
ActEmail: ctx.User.Email, | ActEmail: ctx.User.Email, | ||||
OpType: models.CREATE_ISSUE, | OpType: models.CREATE_ISSUE, | ||||
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), | Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), | ||||
RepoID: ctx.Repo.Repository.Id, | |||||
RepoID: ctx.Repo.Repository.ID, | |||||
RepoUserName: ctx.Repo.Owner.Name, | RepoUserName: ctx.Repo.Owner.Name, | ||||
RepoName: ctx.Repo.Repository.Name, | RepoName: ctx.Repo.Repository.Name, | ||||
RefName: ctx.Repo.BranchName, | RefName: ctx.Repo.BranchName, | ||||
return | return | ||||
} | } | ||||
} | } | ||||
log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.ID) | |||||
log.Trace("%d Issue created: %d", ctx.Repo.Repository.ID, issue.ID) | |||||
send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) | send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) | ||||
} | } | ||||
return | return | ||||
} | } | ||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx) | |||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, idx) | |||||
if err != nil { | if err != nil { | ||||
if err == models.ErrIssueNotExist { | if err == models.ErrIssueNotExist { | ||||
ctx.Handle(404, "GetIssueByIndex", err) | ctx.Handle(404, "GetIssueByIndex", err) | ||||
ctx.Handle(500, "GetLabels", err) | ctx.Handle(500, "GetLabels", err) | ||||
return | return | ||||
} | } | ||||
labels, err := models.GetLabels(ctx.Repo.Repository.Id) | |||||
labels, err := models.GetLabels(ctx.Repo.Repository.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetLabels.2", err) | ctx.Handle(500, "GetLabels.2", err) | ||||
return | return | ||||
} | } | ||||
// Get all milestones. | // Get all milestones. | ||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, -1, false) | |||||
ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.ID, -1, false) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetMilestones.1: %v", err) | ctx.Handle(500, "GetMilestones.1: %v", err) | ||||
return | return | ||||
} | } | ||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, -1, true) | |||||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.ID, -1, true) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetMilestones.2: %v", err) | ctx.Handle(500, "GetMilestones.2: %v", err) | ||||
return | return | ||||
// Get posters. | // Get posters. | ||||
for i := range comments { | for i := range comments { | ||||
u, err := models.GetUserById(comments[i].PosterId) | |||||
u, err := models.GetUserByID(comments[i].PosterId) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById.2: %v", err) | ctx.Handle(500, "GetUserById.2: %v", err) | ||||
return | return | ||||
return | return | ||||
} | } | ||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx) | |||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, idx) | |||||
if err != nil { | if err != nil { | ||||
if err == models.ErrIssueNotExist { | if err == models.ErrIssueNotExist { | ||||
ctx.Handle(404, "issue.UpdateIssue", err) | ctx.Handle(404, "issue.UpdateIssue", err) | ||||
return | return | ||||
} | } | ||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx) | |||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, idx) | |||||
if err != nil { | if err != nil { | ||||
if err == models.ErrIssueNotExist { | if err == models.ErrIssueNotExist { | ||||
ctx.Handle(404, "issue.UpdateIssueLabel(GetIssueByIndex)", err) | ctx.Handle(404, "issue.UpdateIssueLabel(GetIssueByIndex)", err) | ||||
return | return | ||||
} | } | ||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index) | |||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, index) | |||||
if err != nil { | if err != nil { | ||||
if err == models.ErrIssueNotExist { | if err == models.ErrIssueNotExist { | ||||
send(404, nil, err) | send(404, nil, err) | ||||
cmtType = models.COMMENT_TYPE_REOPEN | cmtType = models.COMMENT_TYPE_REOPEN | ||||
} | } | ||||
if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, cmtType, "", nil); err != nil { | |||||
if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.ID, issue.ID, 0, 0, cmtType, "", nil); err != nil { | |||||
send(200, nil, err) | send(200, nil, err) | ||||
return | return | ||||
} | } | ||||
if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 { | if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 { | ||||
switch ctx.Params(":action") { | switch ctx.Params(":action") { | ||||
case "new": | case "new": | ||||
if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil { | |||||
if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.ID, issue.ID, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil { | |||||
send(500, nil, err) | send(500, nil, err) | ||||
return | return | ||||
} | } | ||||
ActEmail: ctx.User.Email, | ActEmail: ctx.User.Email, | ||||
OpType: models.COMMENT_ISSUE, | OpType: models.COMMENT_ISSUE, | ||||
Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), | Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), | ||||
RepoID: ctx.Repo.Repository.Id, | |||||
RepoID: ctx.Repo.Repository.ID, | |||||
RepoUserName: ctx.Repo.Owner.LowerName, | RepoUserName: ctx.Repo.Owner.LowerName, | ||||
RepoName: ctx.Repo.Repository.LowerName, | RepoName: ctx.Repo.Repository.LowerName, | ||||
IsPrivate: ctx.Repo.Repository.IsPrivate, | IsPrivate: ctx.Repo.Repository.IsPrivate, | ||||
} | } | ||||
l := &models.Label{ | l := &models.Label{ | ||||
RepoId: ctx.Repo.Repository.Id, | |||||
RepoId: ctx.Repo.Repository.ID, | |||||
Name: form.Title, | Name: form.Title, | ||||
Color: form.Color, | Color: form.Color, | ||||
} | } | ||||
} | } | ||||
func DeleteLabel(ctx *middleware.Context) { | func DeleteLabel(ctx *middleware.Context) { | ||||
if err := models.DeleteLabel(ctx.Repo.Repository.Id, ctx.QueryInt64("id")); err != nil { | |||||
if err := models.DeleteLabel(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil { | |||||
ctx.Flash.Error("DeleteLabel: " + err.Error()) | ctx.Flash.Error("DeleteLabel: " + err.Error()) | ||||
} else { | } else { | ||||
ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success")) | ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success")) | ||||
ctx.Data["PageIsMilestones"] = true | ctx.Data["PageIsMilestones"] = true | ||||
isShowClosed := ctx.Query("state") == "closed" | isShowClosed := ctx.Query("state") == "closed" | ||||
openCount, closedCount := models.MilestoneStats(ctx.Repo.Repository.Id) | |||||
openCount, closedCount := models.MilestoneStats(ctx.Repo.Repository.ID) | |||||
ctx.Data["OpenCount"] = openCount | ctx.Data["OpenCount"] = openCount | ||||
ctx.Data["ClosedCount"] = closedCount | ctx.Data["ClosedCount"] = closedCount | ||||
} | } | ||||
ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5) | ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5) | ||||
miles, err := models.GetMilestones(ctx.Repo.Repository.Id, page, isShowClosed) | |||||
miles, err := models.GetMilestones(ctx.Repo.Repository.ID, page, isShowClosed) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetMilestones", err) | ctx.Handle(500, "GetMilestones", err) | ||||
return | return | ||||
} | } | ||||
if err = models.NewMilestone(&models.Milestone{ | if err = models.NewMilestone(&models.Milestone{ | ||||
RepoID: ctx.Repo.Repository.Id, | |||||
RepoID: ctx.Repo.Repository.ID, | |||||
Name: form.Title, | Name: form.Title, | ||||
Content: form.Content, | Content: form.Content, | ||||
Deadline: deadline, | Deadline: deadline, |
package repo | package repo | ||||
import ( | import ( | ||||
"fmt" | |||||
"strings" | |||||
"github.com/gogits/gogs/models" | "github.com/gogits/gogs/models" | ||||
"github.com/gogits/gogs/modules/auth" | "github.com/gogits/gogs/modules/auth" | ||||
"github.com/gogits/gogs/modules/base" | "github.com/gogits/gogs/modules/base" | ||||
"github.com/gogits/gogs/modules/git" | |||||
"github.com/gogits/gogs/modules/log" | "github.com/gogits/gogs/modules/log" | ||||
"github.com/gogits/gogs/modules/middleware" | "github.com/gogits/gogs/modules/middleware" | ||||
"github.com/gogits/gogs/modules/setting" | "github.com/gogits/gogs/modules/setting" | ||||
) | ) | ||||
const ( | const ( | ||||
FORK base.TplName = "repo/pulls/fork" | |||||
PULLS base.TplName = "repo/pulls" | |||||
FORK base.TplName = "repo/pulls/fork" | |||||
COMPARE_PULL base.TplName = "repo/pulls/compare" | |||||
PULLS base.TplName = "repo/pulls" | |||||
) | ) | ||||
func getForkRepository(ctx *middleware.Context) *models.Repository { | func getForkRepository(ctx *middleware.Context) *models.Repository { | ||||
forkRepo, err := models.GetRepositoryById(ctx.ParamsInt64(":repoid")) | |||||
forkRepo, err := models.GetRepositoryByID(ctx.ParamsInt64(":repoid")) | |||||
if err != nil { | if err != nil { | ||||
if models.IsErrRepoNotExist(err) { | if models.IsErrRepoNotExist(err) { | ||||
ctx.Handle(404, "GetRepositoryById", nil) | |||||
ctx.Handle(404, "GetRepositoryByID", nil) | |||||
} else { | } else { | ||||
ctx.Handle(500, "GetRepositoryById", err) | |||||
ctx.Handle(500, "GetRepositoryByID", err) | |||||
} | } | ||||
return nil | return nil | ||||
} | } | ||||
return | return | ||||
} | } | ||||
repo, has := models.HasForkedRepo(ctxUser.Id, forkRepo.Id) | |||||
repo, has := models.HasForkedRepo(ctxUser.Id, forkRepo.ID) | |||||
if has { | if has { | ||||
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | ||||
return | return | ||||
return | return | ||||
} | } | ||||
log.Trace("Repository forked[%d]: %s/%s", forkRepo.Id, ctxUser.Name, repo.Name) | |||||
log.Trace("Repository forked[%d]: %s/%s", forkRepo.ID, ctxUser.Name, repo.Name) | |||||
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) | ||||
} | } | ||||
func CompareAndPullRequest(ctx *middleware.Context) { | |||||
// Get compare information. | |||||
infos := strings.Split(ctx.Params("*"), "...") | |||||
if len(infos) != 2 { | |||||
ctx.Handle(404, "CompareAndPullRequest", nil) | |||||
return | |||||
} | |||||
baseBranch := infos[0] | |||||
ctx.Data["BaseBranch"] = baseBranch | |||||
headInfos := strings.Split(infos[1], ":") | |||||
if len(headInfos) != 2 { | |||||
ctx.Handle(404, "CompareAndPullRequest", nil) | |||||
return | |||||
} | |||||
headUser := headInfos[0] | |||||
headBranch := headInfos[1] | |||||
ctx.Data["HeadBranch"] = headBranch | |||||
// TODO: check if branches are valid. | |||||
fmt.Println(baseBranch, headUser, headBranch) | |||||
// TODO: add organization support | |||||
// Check if current user has fork of repository. | |||||
headRepo, has := models.HasForkedRepo(ctx.User.Id, ctx.Repo.Repository.ID) | |||||
if !has { | |||||
ctx.Handle(404, "HasForkedRepo", nil) | |||||
return | |||||
} | |||||
headGitRepo, err := git.OpenRepository(models.RepoPath(ctx.User.Name, headRepo.Name)) | |||||
if err != nil { | |||||
ctx.Handle(500, "OpenRepository", err) | |||||
return | |||||
} | |||||
headBranches, err := headGitRepo.GetBranches() | |||||
if err != nil { | |||||
ctx.Handle(500, "GetBranches", err) | |||||
return | |||||
} | |||||
ctx.Data["HeadBranches"] = headBranches | |||||
ctx.HTML(200, COMPARE_PULL) | |||||
} | |||||
func Pulls(ctx *middleware.Context) { | func Pulls(ctx *middleware.Context) { | ||||
ctx.Data["IsRepoToolbarPulls"] = true | ctx.Data["IsRepoToolbarPulls"] = true | ||||
ctx.HTML(200, PULLS) | ctx.HTML(200, PULLS) |
return | return | ||||
} | } | ||||
rels, err := models.GetReleasesByRepoId(ctx.Repo.Repository.Id) | |||||
rels, err := models.GetReleasesByRepoId(ctx.Repo.Repository.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetReleasesByRepoId", err) | ctx.Handle(500, "GetReleasesByRepoId", err) | ||||
return | return | ||||
continue | continue | ||||
} | } | ||||
if rel.TagName == rawTag { | if rel.TagName == rawTag { | ||||
rel.Publisher, err = models.GetUserById(rel.PublisherId) | |||||
rel.Publisher, err = models.GetUserByID(rel.PublisherId) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById", err) | ctx.Handle(500, "GetUserById", err) | ||||
return | return | ||||
continue | continue | ||||
} | } | ||||
rel.Publisher, err = models.GetUserById(rel.PublisherId) | |||||
rel.Publisher, err = models.GetUserByID(rel.PublisherId) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetUserById", err) | ctx.Handle(500, "GetUserById", err) | ||||
return | return | ||||
} | } | ||||
rel := &models.Release{ | rel := &models.Release{ | ||||
RepoId: ctx.Repo.Repository.Id, | |||||
RepoId: ctx.Repo.Repository.ID, | |||||
PublisherId: ctx.User.Id, | PublisherId: ctx.User.Id, | ||||
Title: form.Title, | Title: form.Title, | ||||
TagName: form.TagName, | TagName: form.TagName, | ||||
} | } | ||||
tagName := ctx.Params(":tagname") | tagName := ctx.Params(":tagname") | ||||
rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName) | |||||
rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName) | |||||
if err != nil { | if err != nil { | ||||
if err == models.ErrReleaseNotExist { | if err == models.ErrReleaseNotExist { | ||||
ctx.Handle(404, "GetRelease", err) | ctx.Handle(404, "GetRelease", err) | ||||
} | } | ||||
tagName := ctx.Params(":tagname") | tagName := ctx.Params(":tagname") | ||||
rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName) | |||||
rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName) | |||||
if err != nil { | if err != nil { | ||||
if err == models.ErrReleaseNotExist { | if err == models.ErrReleaseNotExist { | ||||
ctx.Handle(404, "GetRelease", err) | ctx.Handle(404, "GetRelease", err) |
return ctx.User | return ctx.User | ||||
} | } | ||||
org, err := models.GetUserById(uid) | |||||
org, err := models.GetUserByID(uid) | |||||
if models.IsErrUserNotExist(err) { | if models.IsErrUserNotExist(err) { | ||||
return ctx.User | return ctx.User | ||||
} | } | ||||
} | } | ||||
if repo != nil { | if repo != nil { | ||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil { | |||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID, ctxUser.Name); errDelete != nil { | |||||
log.Error(4, "DeleteRepository: %v", errDelete) | log.Error(4, "DeleteRepository: %v", errDelete) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if repo != nil { | if repo != nil { | ||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil { | |||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID, ctxUser.Name); errDelete != nil { | |||||
log.Error(4, "DeleteRepository: %v", errDelete) | log.Error(4, "DeleteRepository: %v", errDelete) | ||||
} | } | ||||
} | } | ||||
var err error | var err error | ||||
switch ctx.Params(":action") { | switch ctx.Params(":action") { | ||||
case "watch": | case "watch": | ||||
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true) | |||||
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.ID, true) | |||||
case "unwatch": | case "unwatch": | ||||
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false) | |||||
err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.ID, false) | |||||
case "star": | case "star": | ||||
err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, true) | |||||
err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.ID, true) | |||||
case "unstar": | case "unstar": | ||||
err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false) | |||||
err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.ID, false) | |||||
case "desc": | case "desc": | ||||
if !ctx.Repo.IsOwner() { | if !ctx.Repo.IsOwner() { | ||||
ctx.Error(404) | ctx.Error(404) |
return | return | ||||
} | } | ||||
if err := models.DeleteRepository(ctx.Repo.Owner.Id, ctx.Repo.Repository.Id, ctx.Repo.Owner.Name); err != nil { | |||||
if err := models.DeleteRepository(ctx.Repo.Owner.Id, ctx.Repo.Repository.ID, ctx.Repo.Owner.Name); err != nil { | |||||
ctx.Handle(500, "DeleteRepository", err) | ctx.Handle(500, "DeleteRepository", err) | ||||
return | return | ||||
} | } | ||||
return | return | ||||
} | } | ||||
ws, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.Id) | |||||
ws, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "GetWebhooksByRepoId", err) | ctx.Handle(500, "GetWebhooksByRepoId", err) | ||||
return | return | ||||
if _, ok := ctx.Data["RepoLink"]; ok { | if _, ok := ctx.Data["RepoLink"]; ok { | ||||
return &OrgRepoCtx{ | return &OrgRepoCtx{ | ||||
OrgId: int64(0), | OrgId: int64(0), | ||||
RepoId: ctx.Repo.Repository.Id, | |||||
RepoId: ctx.Repo.Repository.ID, | |||||
Link: ctx.Repo.RepoLink, | Link: ctx.Repo.RepoLink, | ||||
NewTemplate: HOOK_NEW, | NewTemplate: HOOK_NEW, | ||||
}, nil | }, nil | ||||
} | } | ||||
return | return | ||||
} | } | ||||
models.HookQueue.AddRepoID(repo.Id) | |||||
models.HookQueue.AddRepoID(repo.ID) | |||||
} | } | ||||
func GitHooks(ctx *middleware.Context) { | func GitHooks(ctx *middleware.Context) { | ||||
ctx.Data["Title"] = ctx.Tr("repo.settings") | ctx.Data["Title"] = ctx.Tr("repo.settings") | ||||
ctx.Data["PageIsSettingsKeys"] = true | ctx.Data["PageIsSettingsKeys"] = true | ||||
keys, err := models.ListDeployKeys(ctx.Repo.Repository.Id) | |||||
keys, err := models.ListDeployKeys(ctx.Repo.Repository.ID) | |||||
if err != nil { | if err != nil { | ||||
ctx.Handle(500, "ListDeployKeys", err) | ctx.Handle(500, "ListDeployKeys", err) | ||||
return | return | ||||
} | } | ||||
} | } | ||||
if err = models.AddDeployKey(ctx.Repo.Repository.Id, form.Title, content); err != nil { | |||||
if err = models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content); err != nil { | |||||
ctx.Data["HasError"] = true | ctx.Data["HasError"] = true | ||||
switch { | switch { | ||||
case models.IsErrKeyAlreadyExist(err): | case models.IsErrKeyAlreadyExist(err): | ||||
return | return | ||||
} | } | ||||
log.Trace("Deploy key added: %d", ctx.Repo.Repository.Id) | |||||
log.Trace("Deploy key added: %d", ctx.Repo.Repository.ID) | |||||
ctx.Flash.Success(ctx.Tr("repo.settings.add_key_success", form.Title)) | ctx.Flash.Success(ctx.Tr("repo.settings.add_key_success", form.Title)) | ||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys") | ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys") | ||||
} | } |
for _, act := range actions { | for _, act := range actions { | ||||
if act.IsPrivate { | if act.IsPrivate { | ||||
// This prevents having to retrieve the repository for each action | // This prevents having to retrieve the repository for each action | ||||
repo := &models.Repository{Id: act.RepoID, IsPrivate: true} | |||||
repo := &models.Repository{ID: act.RepoID, IsPrivate: true} | |||||
if act.RepoUserName != ctx.User.LowerName { | if act.RepoUserName != ctx.User.LowerName { | ||||
if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has { | if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has { | ||||
continue | continue | ||||
continue | continue | ||||
} | } | ||||
// This prevents having to retrieve the repository for each action | // This prevents having to retrieve the repository for each action | ||||
repo := &models.Repository{Id: act.RepoID, IsPrivate: true} | |||||
repo := &models.Repository{ID: act.RepoID, IsPrivate: true} | |||||
if act.RepoUserName != ctx.User.LowerName { | if act.RepoUserName != ctx.User.LowerName { | ||||
if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has { | if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has { | ||||
continue | continue | ||||
continue | continue | ||||
} | } | ||||
repoIds = append(repoIds, repo.Id) | |||||
repoIds = append(repoIds, repo.ID) | |||||
repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues | repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues | ||||
issueStats.AllCount += int64(repo.NumOpenIssues) | issueStats.AllCount += int64(repo.NumOpenIssues) | ||||
if isShowClosed { | if isShowClosed { | ||||
if repo.NumClosedIssues > 0 { | if repo.NumClosedIssues > 0 { | ||||
if filterMode == models.FM_CREATE { | if filterMode == models.FM_CREATE { | ||||
repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed)) | |||||
repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.ID, isShowClosed)) | |||||
} | } | ||||
showRepos = append(showRepos, repo) | showRepos = append(showRepos, repo) | ||||
} | } | ||||
} else { | } else { | ||||
if repo.NumOpenIssues > 0 { | if repo.NumOpenIssues > 0 { | ||||
if filterMode == models.FM_CREATE { | if filterMode == models.FM_CREATE { | ||||
repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed)) | |||||
repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.ID, isShowClosed)) | |||||
} | } | ||||
showRepos = append(showRepos, repo) | showRepos = append(showRepos, repo) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoID) | |||||
issues[i].Repo, err = models.GetRepositoryByID(issues[i].RepoID) | |||||
if err != nil { | if err != nil { | ||||
if models.IsErrRepoNotExist(err) { | if models.IsErrRepoNotExist(err) { | ||||
log.Warn("GetRepositoryById[%d]: repository not exist", issues[i].RepoID) | log.Warn("GetRepositoryById[%d]: repository not exist", issues[i].RepoID) |
<table class="table table-striped"> | <table class="table table-striped"> | ||||
<thead> | <thead> | ||||
<tr> | <tr> | ||||
<th>Id</th> | |||||
<th>ID</th> | |||||
<th>{{.i18n.Tr "admin.repos.owner"}}</th> | <th>{{.i18n.Tr "admin.repos.owner"}}</th> | ||||
<th>{{.i18n.Tr "admin.repos.name"}}</th> | <th>{{.i18n.Tr "admin.repos.name"}}</th> | ||||
<th>{{.i18n.Tr "admin.repos.private"}}</th> | <th>{{.i18n.Tr "admin.repos.private"}}</th> | ||||
<tbody> | <tbody> | ||||
{{range .Repos}} | {{range .Repos}} | ||||
<tr> | <tr> | ||||
<td>{{.Id}}</td> | |||||
<td>{{.ID}}</td> | |||||
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a></td> | <td><a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a></td> | ||||
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a></td> | <td><a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a></td> | ||||
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td> | <td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td> |
<div class="divider"> / </div> | <div class="divider"> / </div> | ||||
<a href="{{$.RepoLink}}">{{.Name}}</a> | <a href="{{$.RepoLink}}">{{.Name}}</a> | ||||
{{if .IsMirror}}<div class="ui label">{{$.i18n.Tr "mirror"}}</div>{{end}} | {{if .IsMirror}}<div class="ui label">{{$.i18n.Tr "mirror"}}</div>{{end}} | ||||
{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.ForkRepo.RepoLink}}">{{SubStr .ForkRepo.RepoLink 1 -1}}</a></div>{{end}} | |||||
{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.RepoLink}}">{{SubStr .BaseRepo.RepoLink 1 -1}}</a></div>{{end}} | |||||
</div> | </div> | ||||
</h2> | </h2> | ||||
<div class="ui right floated secondary menu"> | <div class="ui right floated secondary menu"> |
<span class="divider">/</span> | <span class="divider">/</span> | ||||
<a class="repo text-bold" href="{{$.RepoLink}}">{{.Name}}</a> | <a class="repo text-bold" href="{{$.RepoLink}}">{{.Name}}</a> | ||||
{{if .IsMirror}}<span class="label label-gray">{{$.i18n.Tr "mirror"}}</span>{{end}} | {{if .IsMirror}}<span class="label label-gray">{{$.i18n.Tr "mirror"}}</span>{{end}} | ||||
{{if .IsFork}}<span class="fork-flag">forked from <a href="{{.ForkRepo.RepoLink}}">{{SubStr .ForkRepo.RepoLink 1 -1}}</a></span>{{end}} | |||||
{{if .IsFork}}<span class="fork-flag">forked from <a href="{{.BaseRepo.RepoLink}}">{{SubStr .BaseRepo.RepoLink 1 -1}}</a></span>{{end}} | |||||
</h1> | </h1> | ||||
<ul id="repo-header-meta" class="right menu menu-line"> | <ul id="repo-header-meta" class="right menu menu-line"> | ||||
<li id="repo-header-download" class="drop"> | <li id="repo-header-download" class="drop"> | ||||
</a> | </a> | ||||
</li> | </li> | ||||
<li id="repo-header-fork"> | <li id="repo-header-fork"> | ||||
<a id="repo-header-fork-btn" {{if or (not $.IsRepositoryAdmin) $.Owner.IsOrganization}}href="{{AppSubUrl}}/repo/fork/{{.Id}}"{{end}}> | |||||
<a id="repo-header-fork-btn" {{if or (not $.IsRepositoryAdmin) $.Owner.IsOrganization}}href="{{AppSubUrl}}/repo/fork/{{.ID}}"{{end}}> | |||||
<button class="btn btn-gray text-bold btn-radius"> | <button class="btn btn-gray text-bold btn-radius"> | ||||
<i class="octicon octicon-repo-forked"></i>{{$.i18n.Tr "repo.fork"}} | <i class="octicon octicon-repo-forked"></i>{{$.i18n.Tr "repo.fork"}} | ||||
<span class="num">{{.NumForks}}</span> | <span class="num">{{.NumForks}}</span> |
<a class="link" href="{{.Repository.Website}}">{{.Repository.Website}}</a> | <a class="link" href="{{.Repository.Website}}">{{.Repository.Website}}</a> | ||||
</p> | </p> | ||||
<ul id="repo-file-nav" class="clear menu menu-line"> | <ul id="repo-file-nav" class="clear menu menu-line"> | ||||
<!-- <li> | |||||
<a href="#"> | |||||
{{if and .IsRepositoryAdmin .Repository.BaseRepo}} | |||||
{{ $baseRepo := .Repository.BaseRepo}} | |||||
<li> | |||||
<a href="{{AppSubUrl}}/{{$baseRepo.Owner.Name}}/{{$baseRepo.Name}}/compare/{{$.BaseDefaultBranch}}...{{$.Owner.Name}}:{{$.BranchName}}"> | |||||
<button class="btn btn-green btn-small btn-radius" id="repo-compare-btn"><i class="octicon octicon-git-compare"></i></button> | <button class="btn btn-green btn-small btn-radius" id="repo-compare-btn"><i class="octicon octicon-git-compare"></i></button> | ||||
</a> | </a> | ||||
</li> --> | |||||
</li> | |||||
{{end}} | |||||
<li id="repo-branch-switch" class="down drop"> | <li id="repo-branch-switch" class="down drop"> | ||||
<a> | <a> | ||||
<button class="btn btn-gray btn-medium btn-radius"> | <button class="btn btn-gray btn-medium btn-radius"> |
{{template "base/head" .}} | |||||
<div class="repository compare pull"> | |||||
{{template "repo/header" .}} | |||||
<div class="ui middle page grid body"> | |||||
<div class="sixteen wide column page grid"> | |||||
<h2 class="ui header"> | |||||
{{.i18n.Tr "repo.pulls.compare_changes"}} | |||||
<div class="sub header">{{.i18n.Tr "repo.pulls.compare_changes_desc"}}</div> | |||||
</h2> | |||||
<div class="ui segment choose branch"> | |||||
<span class="octicon octicon-git-compare"></span> | |||||
<div class="ui floating filter dropdown"> | |||||
<div class="ui basic small button"> | |||||
<span class="text">base: {{$.BaseBranch}}</span> | |||||
<i class="dropdown icon"></i> | |||||
</div> | |||||
<div class="menu"> | |||||
<div class="ui icon search input"> | |||||
<i class="filter icon"></i> | |||||
<input name="search" placeholder="Filter branch..."> | |||||
</div> | |||||
<div class="items"> | |||||
{{range .Branches}} | |||||
<a class="{{if eq $.BaseBranch .}}active selected{{end}} item" href="{{$.RepoLink}}/compare/{{.}}...{{$.SignedUser.Name}}:{{$.HeadBranch}}">{{.}}</a> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
... | |||||
<div class="ui floating filter dropdown"> | |||||
<div class="ui basic small button"> | |||||
<span class="text">compare: {{$.HeadBranch}}</span> | |||||
<i class="dropdown icon"></i> | |||||
</div> | |||||
<div class="menu"> | |||||
<div class="ui icon search input"> | |||||
<i class="filter icon"></i> | |||||
<input name="search" placeholder="Filter branch..."> | |||||
</div> | |||||
<div class="items"> | |||||
{{range .HeadBranches}} | |||||
<a class="{{if eq $.HeadBranch .}}active selected{{end}} item" href="{{$.RepoLink}}/compare/{{$.BaseBranch}}...{{$.SignedUser.Name}}:{{.}}">{{.}}</a> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{template "base/footer" .}} |