Skip to content

Commit

Permalink
Initial working Merge Request code
Browse files Browse the repository at this point in the history
  • Loading branch information
justinclift committed Sep 28, 2017
1 parent 3d1070a commit dc63f98
Show file tree
Hide file tree
Showing 16 changed files with 2,901 additions and 162 deletions.
337 changes: 301 additions & 36 deletions common/postgresql.go

Large diffs are not rendered by default.

87 changes: 58 additions & 29 deletions common/types.go
Expand Up @@ -177,6 +177,7 @@ type CommitEntry struct {
CommitterName string `json:"committer_name"`
ID string `json:"id"`
Message string `json:"message"`
OtherParents []string `json:"other_parents"`
Parent string `json:"parent"`
Timestamp time.Time `json:"timestamp"`
Tree DBTree `json:"tree"`
Expand Down Expand Up @@ -210,12 +211,12 @@ type DBTree struct {
Entries []DBTreeEntry `json:"entries"`
}
type DBTreeEntry struct {
EntryType DBTreeEntryType `json:"entry_type"`
Last_Modified time.Time `json:"last_modified"`
LicenceSHA string `json:"licence"`
Name string `json:"name"`
Sha256 string `json:"sha256"`
Size int `json:"size"`
EntryType DBTreeEntryType `json:"entry_type"`
LastModified time.Time `json:"last_modified"`
LicenceSHA string `json:"licence"`
Name string `json:"name"`
Sha256 string `json:"sha256"`
Size int `json:"size"`
}

type DBInfo struct {
Expand Down Expand Up @@ -250,19 +251,6 @@ type DBInfo struct {
Watchers int
}

type DiscussionEntry struct {
AvatarURL string `json:"avatar_url"`
Body string `json:"body"`
BodyRendered string `json:"body_rendered"`
CommentCount int `json:"comment_count"`
Creator string `json:"creator"`
Date_created time.Time `json:"creation_date"`
ID int `json:"disc_id"`
Last_modified time.Time `json:"last_modified"`
Open bool `json:"open"`
Title string `json:"title"`
}

type DiscussionCommentType string

const (
Expand All @@ -276,21 +264,43 @@ type DiscussionCommentEntry struct {
Body string `json:"body"`
BodyRendered string `json:"body_rendered"`
Commenter string `json:"commenter"`
Date_created time.Time `json:"creation_date"`
DateCreated time.Time `json:"creation_date"`
EntryType DiscussionCommentType `json:"entry_type"`
ID int `json:"com_id"`
}

type DiscussionType int

const (
DISCUSSION DiscussionType = 0
MERGE_REQUEST = 1
)

type DiscussionEntry struct {
AvatarURL string `json:"avatar_url"`
Body string `json:"body"`
BodyRendered string `json:"body_rendered"`
CommentCount int `json:"comment_count"`
Creator string `json:"creator"`
DateCreated time.Time `json:"creation_date"`
ID int `json:"disc_id"`
LastModified time.Time `json:"last_modified"`
MRDetails MergeRequestEntry `json:"mr_details"`
Open bool `json:"open"`
Title string `json:"title"`
Type DiscussionType `json:"discussion_type"`
}

type ForkEntry struct {
DBName string
Folder string
ForkedFrom int
IconList []ForkType
ID int
Owner string
Processed bool
Public bool
Deleted bool
DBName string `json:"database_name"`
Folder string `json:"database_folder"`
ForkedFrom int `json:"forked_from"`
IconList []ForkType `json:"icon_list"`
ID int `json:"id"`
Owner string `json:"database_owner"`
Processed bool `json:"processed"`
Public bool `json:"public"`
Deleted bool `json:"deleted"`
}

type LicenceEntry struct {
Expand All @@ -301,6 +311,25 @@ type LicenceEntry struct {
URL string `json:"url"`
}

type MergeRequestState int

const (
OPEN MergeRequestState = 0
CLOSED_WITH_MERGE = 1
CLOSED_WITHOUT_MERGE = 2
)

type MergeRequestEntry struct {
Commits []CommitEntry `json:"commits"`
DestBranch string `json:"destination_branch"`
SourceBranch string `json:"source_branch"`
SourceDBID int64 `json:"source_database_id"`
SourceDBName string `json:"source_database_name"`
SourceFolder string `json:"source_folder"`
SourceOwner string `json:"source_owner"`
State MergeRequestState `json:"state"`
}

type MetaInfo struct {
AvatarURL string
Database string
Expand Down
52 changes: 32 additions & 20 deletions common/userinput.go
Expand Up @@ -14,15 +14,19 @@ import (
// Extracts a database name from GET or POST/PUT data.
func GetDatabase(r *http.Request, allowGet bool) (string, error) {
// Retrieve the variable from the GET or POST/PUT data
var dbName string
var d, dbName string
if allowGet {
dbName = r.FormValue("dbname")
d = r.FormValue("dbname")
} else {
dbName = r.PostFormValue("dbname")
d = r.PostFormValue("dbname")
}

// Validate the database name
err := ValidateDB(dbName)
// Unescape, then validate the database name
dbName, err := url.QueryUnescape(d)
if err != nil {
return "", err
}
err = ValidateDB(dbName)
if err != nil {
log.Printf("Validation failed for database name '%s': %s", dbName, err)
return "", errors.New("Invalid database name")
Expand All @@ -33,20 +37,24 @@ func GetDatabase(r *http.Request, allowGet bool) (string, error) {
// Returns the folder name (if any) present in GET or POST/PUT data.
func GetFolder(r *http.Request, allowGet bool) (string, error) {
// Retrieve the variable from the GET or POST/PUT data
var folder string
var f, folder string
if allowGet {
folder = r.FormValue("folder")
f = r.FormValue("folder")
} else {
folder = r.PostFormValue("folder")
f = r.PostFormValue("folder")
}

// If no folder given, return
if folder == "" {
if f == "" {
return "", nil
}

// Validate the folder name
err := ValidateFolder(folder)
// Unescape, then validate the folder name
folder, err := url.QueryUnescape(f)
if err != nil {
return "", err
}
err = ValidateFolder(folder)
if err != nil {
log.Printf("Validation failed for folder: '%s': %s", folder, err)
return "", err
Expand All @@ -68,7 +76,7 @@ func GetFormBranch(r *http.Request) (string, error) {
if err != nil {
return "", err
}
err = Validate.Var(b, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
err = ValidateBranchName(b)
if err != nil {
return "", errors.New(fmt.Sprintf("Invalid branch name: '%v'", b))
}
Expand Down Expand Up @@ -136,7 +144,7 @@ func GetFormRelease(r *http.Request) (release string, err error) {
if err != nil {
return "", err
}
err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
err = ValidateBranchName(c)
if err != nil {
return "", errors.New(fmt.Sprintf("Invalid release name: '%v'", c))
}
Expand All @@ -156,7 +164,7 @@ func GetFormTag(r *http.Request) (tag string, err error) {
if err != nil {
return "", err
}
err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
err = ValidateBranchName(c)
if err != nil {
return "", errors.New(fmt.Sprintf("Invalid tag name: '%v'", c))
}
Expand Down Expand Up @@ -343,20 +351,24 @@ func GetUFD(r *http.Request, allowGet bool) (string, string, string, error) {
// Return the username (if any) present in the GET or POST/PUT data.
func GetUsername(r *http.Request, allowGet bool) (string, error) {
// Retrieve the variable from the GET or POST/PUT data
var userName string
var u, userName string
if allowGet {
userName = r.FormValue("username")
u = r.FormValue("username")
} else {
userName = r.PostFormValue("username")
u = r.PostFormValue("username")
}

// If no username given, return
if userName == "" {
if u == "" {
return "", nil
}

// Validate the username
err := ValidateUser(userName)
// Unescape, then validate the user name
userName, err := url.QueryUnescape(u)
if err != nil {
return "", err
}
err = ValidateUser(userName)
if err != nil {
log.Printf("Validation failed for username: %s", err)
return "", err
Expand Down
81 changes: 79 additions & 2 deletions common/util.go
Expand Up @@ -111,7 +111,7 @@ func AddDatabase(r *http.Request, loggedInUser string, dbOwner string, dbFolder
e.EntryType = DATABASE
e.Name = dbName
e.Sha256 = sha
e.Last_Modified = lastModified
e.LastModified = lastModified
e.Size = int(numBytes)
if licenceName == "" || licenceName == "Not specified" {
// No licence was specified by the client, so check if the database is already in the system and
Expand Down Expand Up @@ -385,6 +385,9 @@ func CreateCommitID(c CommitEntry) string {
if c.Parent != "" {
b.WriteString(fmt.Sprintf("parent %s\n", c.Parent))
}
for _, j := range c.OtherParents {
b.WriteString(fmt.Sprintf("parent %s\n", j))
}
b.WriteString(fmt.Sprintf("author %s <%s> %v\n", c.AuthorName, c.AuthorEmail,
c.Timestamp.Format(time.UnixDate)))
if c.CommitterEmail != "" {
Expand All @@ -411,7 +414,7 @@ func CreateDBTreeID(entries []DBTreeEntry) string {
b.WriteByte(0)
b.WriteString(j.Name)
b.WriteByte(0)
b.WriteString(j.Last_Modified.Format(time.RFC3339))
b.WriteString(j.LastModified.Format(time.RFC3339))
b.WriteByte(0)
b.WriteString(fmt.Sprintf("%d\n", j.Size))
}
Expand Down Expand Up @@ -704,6 +707,80 @@ func DeleteBranchHistory(dbOwner string, dbFolder string, dbName string, branchN
return
}

// Determines the common ancestor commit (if any) between a source and destination branch. Returns the commit ID of
// the ancestor and a slice of the commits between them. If no common ancestor exists, the returned ancestorID will be
// an empty string. Created for use by our Merge Request functions.
func GetCommonAncestorCommits(srcOwner string, srcFolder string, srcDBName string, srcBranch string, destOwner string,
destFolder string, destName string, destBranch string) (ancestorID string, commitList []CommitEntry, err error, errType int) {

// To determine the common ancestor, we retrieve the source and destination commit lists, then starting from the
// end of the source list, step backwards looking for a matching ID in the destination list.
// * If none is found then there's nothing in common (so abort).
// * If one is found, that one is the last common commit
// * For now, we only support merging to the head commit of the destination branch, so we only check for
// that. Adding support for merging to non-head destination commits isn't yet supported.

// Get the details of the head commit for the source and destination database branches
branchList, err := GetBranches(destOwner, destFolder, destName) // Destination branch list
if err != nil {
errType = http.StatusInternalServerError
return
}
branchDetails, ok := branchList[destBranch]
if !ok {
errType = http.StatusInternalServerError
err = fmt.Errorf("Could not retrieve details for the destination branch")
return
}
destCommitID := branchDetails.Commit
srcBranchList, err := GetBranches(srcOwner, srcFolder, srcDBName)
if err != nil {
errType = http.StatusInternalServerError
return
}
srcBranchDetails, ok := srcBranchList[srcBranch]
if !ok {
errType = http.StatusInternalServerError
err = fmt.Errorf("Could not retrieve details for the source branch")
return
}
srcCommitID := srcBranchDetails.Commit
srcCommitList, err := GetCommitList(srcOwner, srcFolder, srcDBName)
if err != nil {
errType = http.StatusInternalServerError
return
}

// If the source and destination commit IDs are the same, then abort
if srcCommitID == destCommitID {
errType = http.StatusBadRequest
err = fmt.Errorf("Source and destination commits are identical, no merge needs doing")
return
}

// Look for the common ancestor
s, ok := srcCommitList[srcCommitID]
if !ok {
errType = http.StatusInternalServerError
err = fmt.Errorf("Could not retrieve details for the source branch commit")
return
}
for s.Parent != "" {
commitList = append(commitList, s) // Add this commit to the list
s, ok = srcCommitList[s.Parent]
if !ok {
errType = http.StatusInternalServerError
err = fmt.Errorf("Error when walking the source branch commit list")
return
}
if s.ID == destCommitID {
ancestorID = s.ID
break
}
}
return
}

// Returns the name of the function this was called from
func GetCurrentFunctionName() (FuncName string) {
stk := make([]uintptr, 1)
Expand Down

0 comments on commit dc63f98

Please sign in to comment.