···
"tangled.sh/tangled.sh/core/api/tangled"
···
"tangled.sh/tangled.sh/core/patchutil"
"tangled.sh/tangled.sh/core/types"
25
+
"github.com/bluekeyes/go-gitdiff/gitdiff"
comatproto "github.com/bluesky-social/indigo/api/atproto"
"github.com/bluesky-social/indigo/atproto/syntax"
lexutil "github.com/bluesky-social/indigo/lex/util"
···
// can be nil if this pull is not stacked
50
-
stack := r.Context().Value("stack").(db.Stack)
52
+
stack, _ := r.Context().Value("stack").(db.Stack)
roundNumberStr := chi.URLParam(r, "round")
roundNumber, err := strconv.Atoi(roundNumberStr)
···
mergeCheckResponse := s.mergeCheck(f, pull, stack)
resubmitResult := pages.Unknown
if user.Did == pull.OwnerDid {
66
-
resubmitResult = s.resubmitCheck(f, pull)
68
+
resubmitResult = s.resubmitCheck(f, pull, stack)
s.pages.PullActionsFragment(w, pages.PullActionsParams{
···
// can be nil if this pull is not stacked
97
-
stack := r.Context().Value("stack").(db.Stack)
99
+
stack, _ := r.Context().Value("stack").(db.Stack)
for _, submission := range pull.Submissions {
···
mergeCheckResponse := s.mergeCheck(f, pull, stack)
resubmitResult := pages.Unknown
if user != nil && user.Did == pull.OwnerDid {
129
-
resubmitResult = s.resubmitCheck(f, pull)
131
+
resubmitResult = s.resubmitCheck(f, pull, stack)
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
···
for _, p := range subStack {
// stop at the first merged PR
172
-
if p.State == db.PullMerged {
174
+
if p.State == db.PullMerged || p.State == db.PullClosed {
176
-
// skip over closed PRs
178
-
// we will close PRs that are "removed" from a stack
179
-
if p.State != db.PullClosed {
178
+
// skip over deleted PRs
179
+
if p.State != db.PullDeleted {
mergeable = append(mergeable, p)
···
return mergeCheckResponse
226
-
func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull) pages.ResubmitResult {
226
+
func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull, stack db.Stack) pages.ResubmitResult {
if pull.State == db.PullMerged || pull.PullSource == nil {
···
276
-
latestSubmission := pull.Submissions[pull.LastRoundNumber()]
277
-
if latestSubmission.SourceRev != result.Branch.Hash {
278
-
fmt.Println(latestSubmission.SourceRev, result.Branch.Hash)
276
+
latestSourceRev := pull.Submissions[pull.LastRoundNumber()].SourceRev
278
+
if pull.IsStacked() && stack != nil {
280
+
latestSourceRev = top.Submissions[top.LastRoundNumber()].SourceRev
283
+
if latestSourceRev != result.Branch.Hash {
284
+
log.Println(latestSourceRev, result.Branch.Hash)
return pages.ShouldResubmit
···
RepoInfo: f.RepoInfo(s, user),
Branches: result.Branches,
title := r.FormValue("title")
body := r.FormValue("body")
···
887
-
title, body, targetBranch,
···
991
-
title, body, targetBranch string,
997
+
targetBranch string,
pullSource *db.PullSource,
995
-
recordPullSource *tangled.RepoPull_Source,
// run some necessary checks for stacked-prs first
···
formatPatches, err := patchutil.ExtractPatches(patch)
1013
+
log.Println("failed to extract patches", err)
s.pages.Notice(w, "pull", fmt.Sprintf("Failed to extract patches: %v", err))
// must have atleast 1 patch to begin with
if len(formatPatches) == 0 {
1020
+
log.Println("empty patches")
s.pages.Notice(w, "pull", "No patches found in the generated format-patch.")
1018
-
tx, err := s.db.BeginTx(r.Context(), nil)
1025
+
// build a stack out of this patch
1026
+
stackId := uuid.New()
1027
+
stack, err := newStack(f, user, targetBranch, patch, pullSource, stackId.String())
1029
+
log.Println("failed to create stack", err)
1030
+
s.pages.Notice(w, "pull", fmt.Sprintf("Failed to create stack: %v", err))
1034
+
client, err := s.oauth.AuthorizedClient(r)
1020
-
log.Println("failed to start tx")
1036
+
log.Println("failed to get authorized client", err)
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1024
-
defer tx.Rollback()
1026
-
// create a series of pull requests, and write records from them at once
1041
+
// apply all record creations at once
var writes []*comatproto.RepoApplyWrites_Input_Writes_Elem
1029
-
// the stack is identified by a UUID
1030
-
stackId := uuid.New()
1031
-
parentChangeId := ""
1032
-
for _, fp := range formatPatches {
1033
-
// all patches must have a jj change-id
1034
-
changeId, err := fp.ChangeId()
1036
-
s.pages.Notice(w, "pull", "Stacking is only supported if all patches contain a change-id commit header.")
1042
-
rkey := appview.TID()
1044
-
// TODO: can we just use a format-patch string here?
1045
-
initialSubmission := db.PullSubmission{
1047
-
SourceRev: sourceRev,
1049
-
err = db.NewPull(tx, &db.Pull{
1052
-
TargetBranch: targetBranch,
1053
-
OwnerDid: user.Did,
1056
-
Submissions: []*db.PullSubmission{
1057
-
&initialSubmission,
1059
-
PullSource: pullSource,
1061
-
StackId: stackId.String(),
1062
-
ChangeId: changeId,
1063
-
ParentChangeId: parentChangeId,
1066
-
log.Println("failed to create pull request", err)
1067
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1071
-
record := tangled.RepoPull{
1073
-
TargetRepo: string(f.RepoAt),
1074
-
TargetBranch: targetBranch,
1076
-
Source: recordPullSource,
1078
-
writes = append(writes, &comatproto.RepoApplyWrites_Input_Writes_Elem{
1043
+
for _, p := range stack {
1044
+
record := p.AsRecord()
1045
+
write := comatproto.RepoApplyWrites_Input_Writes_Elem{
RepoApplyWrites_Create: &comatproto.RepoApplyWrites_Create{
Collection: tangled.RepoPullNSID,
Value: &lexutil.LexiconTypeDecoder{
1088
-
parentChangeId = changeId
1054
+
writes = append(writes, &write)
1091
-
client, err := s.oauth.AuthorizedClient(r)
1093
-
log.Println("failed to get authorized client", err)
1094
-
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1098
-
// apply all record creations at once
_, err = client.RepoApplyWrites(r.Context(), &comatproto.RepoApplyWrites_Input{
···
// create all pulls at once
1067
+
tx, err := s.db.BeginTx(r.Context(), nil)
1069
+
log.Println("failed to start tx")
1070
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
1073
+
defer tx.Rollback()
1075
+
for _, p := range stack {
1076
+
err = db.NewPull(tx, p)
1078
+
log.Println("failed to create pull request", err)
1079
+
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
if err = tx.Commit(); err != nil {
log.Println("failed to create pull request", err)
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···
patch := r.FormValue("patch")
1374
-
if err = validateResubmittedPatch(pull, patch); err != nil {
1375
-
s.pages.Notice(w, "resubmit-error", err.Error())
1379
-
tx, err := s.db.BeginTx(r.Context(), nil)
1381
-
log.Println("failed to start tx")
1382
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1385
-
defer tx.Rollback()
1387
-
err = db.ResubmitPull(tx, pull, patch, "")
1389
-
log.Println("failed to resubmit pull request", err)
1390
-
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")
1393
-
client, err := s.oauth.AuthorizedClient(r)
1395
-
log.Println("failed to get authorized client", err)
1396
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1400
-
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1402
-
// failed to get record
1403
-
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
1407
-
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1408
-
Collection: tangled.RepoPullNSID,
1411
-
SwapRecord: ex.Cid,
1412
-
Record: &lexutil.LexiconTypeDecoder{
1413
-
Val: &tangled.RepoPull{
1414
-
Title: pull.Title,
1415
-
PullId: int64(pull.PullId),
1416
-
TargetRepo: string(f.RepoAt),
1417
-
TargetBranch: pull.TargetBranch,
1418
-
Patch: patch, // new patch
1423
-
log.Println("failed to update record", err)
1424
-
s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
1428
-
if err = tx.Commit(); err != nil {
1429
-
log.Println("failed to commit transaction", err)
1430
-
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")
1434
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
1348
+
s.resubmitPullHelper(w, r, f, user, pull, patch, "")
func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
···
sourceRev := comparison.Rev2
patch := comparison.Patch
1483
-
if err = validateResubmittedPatch(pull, patch); err != nil {
1484
-
s.pages.Notice(w, "resubmit-error", err.Error())
1488
-
if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {
1489
-
s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")
1493
-
tx, err := s.db.BeginTx(r.Context(), nil)
1495
-
log.Println("failed to start tx")
1496
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1499
-
defer tx.Rollback()
1501
-
err = db.ResubmitPull(tx, pull, patch, sourceRev)
1503
-
log.Println("failed to create pull request", err)
1504
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1507
-
client, err := s.oauth.AuthorizedClient(r)
1509
-
log.Println("failed to authorize client")
1510
-
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1514
-
ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1516
-
// failed to get record
1517
-
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
1521
-
recordPullSource := &tangled.RepoPull_Source{
1522
-
Branch: pull.PullSource.Branch,
1524
-
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1525
-
Collection: tangled.RepoPullNSID,
1528
-
SwapRecord: ex.Cid,
1529
-
Record: &lexutil.LexiconTypeDecoder{
1530
-
Val: &tangled.RepoPull{
1531
-
Title: pull.Title,
1532
-
PullId: int64(pull.PullId),
1533
-
TargetRepo: string(f.RepoAt),
1534
-
TargetBranch: pull.TargetBranch,
1535
-
Patch: patch, // new patch
1536
-
Source: recordPullSource,
1541
-
log.Println("failed to update record", err)
1542
-
s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")
1546
-
if err = tx.Commit(); err != nil {
1547
-
log.Println("failed to commit transaction", err)
1548
-
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")
1552
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
1396
+
s.resubmitPullHelper(w, r, f, user, pull, patch, sourceRev)
func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
···
sourceRev := comparison.Rev2
patch := comparison.Patch
1626
-
if err = validateResubmittedPatch(pull, patch); err != nil {
1627
-
s.pages.Notice(w, "resubmit-error", err.Error())
1469
+
s.resubmitPullHelper(w, r, f, user, pull, patch, sourceRev)
1472
+
// validate a resubmission against a pull request
1473
+
func validateResubmittedPatch(pull *db.Pull, patch string) error {
1475
+
return fmt.Errorf("Patch is empty.")
1478
+
if patch == pull.LatestPatch() {
1479
+
return fmt.Errorf("Patch is identical to previous submission.")
1482
+
if !patchutil.IsPatchValid(patch) {
1483
+
return fmt.Errorf("Invalid patch format. Please provide a valid diff.")
1489
+
func (s *State) resubmitPullHelper(
1490
+
w http.ResponseWriter,
1492
+
f *FullyResolvedRepo,
1498
+
if pull.IsStacked() {
1499
+
log.Println("resubmitting stacked PR")
1500
+
s.resubmitStackedPullHelper(w, r, f, user, pull, patch, pull.StackId)
1631
-
if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {
1632
-
s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")
1504
+
if err := validateResubmittedPatch(pull, patch); err != nil {
1505
+
s.pages.Notice(w, "resubmit-error", err.Error())
1509
+
// validate sourceRev if branch/fork based
1510
+
if pull.IsBranchBased() || pull.IsForkBased() {
1511
+
if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {
1512
+
s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")
tx, err := s.db.BeginTx(r.Context(), nil)
log.Println("failed to start tx")
···
client, err := s.oauth.AuthorizedClient(r)
1652
-
log.Println("failed to get client")
1533
+
log.Println("failed to authorize client")
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···
1664
-
repoAt := pull.PullSource.RepoAt.String()
1665
-
recordPullSource := &tangled.RepoPull_Source{
1666
-
Branch: pull.PullSource.Branch,
1545
+
var recordPullSource *tangled.RepoPull_Source
1546
+
if pull.IsBranchBased() {
1547
+
recordPullSource = &tangled.RepoPull_Source{
1548
+
Branch: pull.PullSource.Branch,
1551
+
if pull.IsForkBased() {
1552
+
repoAt := pull.PullSource.RepoAt.String()
1553
+
recordPullSource = &tangled.RepoPull_Source{
1554
+
Branch: pull.PullSource.Branch,
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
···
1701
-
// validate a resubmission against a pull request
1702
-
func validateResubmittedPatch(pull *db.Pull, patch string) error {
1704
-
return fmt.Errorf("Patch is empty.")
1591
+
func (s *State) resubmitStackedPullHelper(
1592
+
w http.ResponseWriter,
1594
+
f *FullyResolvedRepo,
1600
+
targetBranch := pull.TargetBranch
1602
+
origStack, _ := r.Context().Value("stack").(db.Stack)
1603
+
newStack, err := newStack(f, user, targetBranch, patch, pull.PullSource, stackId)
1605
+
log.Println("failed to create resubmitted stack", err)
1606
+
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1610
+
// find the diff between the stacks, first, map them by changeId
1611
+
origById := make(map[string]*db.Pull)
1612
+
newById := make(map[string]*db.Pull)
1613
+
for _, p := range origStack {
1614
+
origById[p.ChangeId] = p
1616
+
for _, p := range newStack {
1617
+
newById[p.ChangeId] = p
1620
+
// commits that got deleted: corresponding pull is closed
1621
+
// commits that got added: new pull is created
1622
+
// commits that got updated: corresponding pull is resubmitted & new round begins
1624
+
// for commits that were unchanged: no changes, parent-change-id is updated as necessary
1625
+
additions := make(map[string]*db.Pull)
1626
+
deletions := make(map[string]*db.Pull)
1627
+
unchanged := make(map[string]struct{})
1628
+
updated := make(map[string]struct{})
1630
+
// pulls in orignal stack but not in new one
1631
+
for _, op := range origStack {
1632
+
if _, ok := newById[op.ChangeId]; !ok {
1633
+
deletions[op.ChangeId] = op
1707
-
if patch == pull.LatestPatch() {
1708
-
return fmt.Errorf("Patch is identical to previous submission.")
1637
+
// pulls in new stack but not in original one
1638
+
for _, np := range newStack {
1639
+
if _, ok := origById[np.ChangeId]; !ok {
1640
+
additions[np.ChangeId] = np
1711
-
if !patchutil.IsPatchValid(patch) {
1712
-
return fmt.Errorf("Invalid patch format. Please provide a valid diff.")
1644
+
// NOTE: this loop can be written in any of above blocks,
1645
+
// but is written separately in the interest of simpler code
1646
+
for _, np := range newStack {
1647
+
if op, ok := origById[np.ChangeId]; ok {
1648
+
// pull exists in both stacks
1649
+
// TODO: can we avoid reparse?
1650
+
origFiles, _, _ := gitdiff.Parse(strings.NewReader(op.LatestPatch()))
1651
+
newFiles, _, _ := gitdiff.Parse(strings.NewReader(np.LatestPatch()))
1653
+
patchutil.SortPatch(newFiles)
1654
+
patchutil.SortPatch(origFiles)
1656
+
if patchutil.Equal(newFiles, origFiles) {
1657
+
unchanged[op.ChangeId] = struct{}{}
1659
+
updated[op.ChangeId] = struct{}{}
1664
+
tx, err := s.db.Begin()
1666
+
log.Println("failed to start transaction", err)
1667
+
s.pages.Notice(w, "pull-resubmit-error", "Failed to resubmit pull request. Try again later.")
1670
+
defer tx.Rollback()
1672
+
// pds updates to make
1673
+
var writes []*comatproto.RepoApplyWrites_Input_Writes_Elem
1675
+
// deleted pulls are marked as deleted in the DB
1676
+
for _, p := range deletions {
1677
+
err := db.DeletePull(tx, p.RepoAt, p.PullId)
1679
+
log.Println("failed to delete pull", err, p.PullId)
1680
+
s.pages.Notice(w, "pull-resubmit-error", "Failed to resubmit pull request. Try again later.")
1683
+
writes = append(writes, &comatproto.RepoApplyWrites_Input_Writes_Elem{
1684
+
RepoApplyWrites_Delete: &comatproto.RepoApplyWrites_Delete{
1685
+
Collection: tangled.RepoPullNSID,
1691
+
// new pulls are created
1692
+
for _, p := range additions {
1693
+
err := db.NewPull(tx, p)
1695
+
log.Println("failed to create pull", err, p.PullId)
1696
+
s.pages.Notice(w, "pull-resubmit-error", "Failed to resubmit pull request. Try again later.")
1700
+
record := p.AsRecord()
1701
+
writes = append(writes, &comatproto.RepoApplyWrites_Input_Writes_Elem{
1702
+
RepoApplyWrites_Create: &comatproto.RepoApplyWrites_Create{
1703
+
Collection: tangled.RepoPullNSID,
1705
+
Value: &lexutil.LexiconTypeDecoder{
1712
+
// updated pulls are, well, updated; to start a new round
1713
+
for id := range updated {
1714
+
op, _ := origById[id]
1715
+
np, _ := newById[id]
1717
+
submission := np.Submissions[np.LastRoundNumber()]
1719
+
// resubmit the old pull
1720
+
err := db.ResubmitPull(tx, op, submission.Patch, submission.SourceRev)
1723
+
log.Println("failed to update pull", err, op.PullId)
1724
+
s.pages.Notice(w, "pull-resubmit-error", "Failed to resubmit pull request. Try again later.")
1728
+
record := op.AsRecord()
1729
+
record.Patch = submission.Patch
1731
+
writes = append(writes, &comatproto.RepoApplyWrites_Input_Writes_Elem{
1732
+
RepoApplyWrites_Update: &comatproto.RepoApplyWrites_Update{
1733
+
Collection: tangled.RepoPullNSID,
1735
+
Value: &lexutil.LexiconTypeDecoder{
1742
+
// update parent-change-id relations for the entire stack
1743
+
for _, p := range newStack {
1744
+
err := db.SetPullParentChangeId(
1747
+
// these should be enough filters to be unique per-stack
1748
+
db.Filter("repo_at", p.RepoAt.String()),
1749
+
db.Filter("owner_did", p.OwnerDid),
1750
+
db.Filter("change_id", p.ChangeId),
1754
+
log.Println("failed to update pull", err, p.PullId)
1755
+
s.pages.Notice(w, "pull-resubmit-error", "Failed to resubmit pull request. Try again later.")
1762
+
log.Println("failed to resubmit pull", err)
1763
+
s.pages.Notice(w, "pull-resubmit-error", "Failed to resubmit pull request. Try again later.")
1767
+
client, err := s.oauth.AuthorizedClient(r)
1769
+
log.Println("failed to authorize client")
1770
+
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1774
+
_, err = client.RepoApplyWrites(r.Context(), &comatproto.RepoApplyWrites_Input{
1779
+
log.Println("failed to create stacked pull request", err)
1780
+
s.pages.Notice(w, "pull", "Failed to create stacked pull request. Try again later.")
1784
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
func (s *State) MergePull(w http.ResponseWriter, r *http.Request) {
···
// collect the portion of the stack that is mergeable
for _, p := range subStack {
1748
-
// stop at the first merged PR
1749
-
if p.State == db.PullMerged {
1818
+
// stop at the first merged/closed PR
1819
+
if p.State == db.PullMerged || p.State == db.PullClosed {
1753
-
// skip over closed PRs
1755
-
// TODO: we need a "deleted" state for such PRs, but without losing discussions
1756
-
// we will close PRs that are "removed" from a stack
1757
-
if p.State == db.PullClosed {
1823
+
// skip over deleted PRs
1824
+
if p.State == db.PullDeleted {
···
1809
-
log.Printf("failed to start transcation", err)
1876
+
log.Println("failed to start transcation", err)
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
1880
+
defer tx.Rollback()
for _, p := range pullsToMerge {
err := db.MergePull(tx, f.RepoAt, p.PullId)
···
s.pages.Notice(w, "pull-close", "Failed to close pull.")
1936
+
defer tx.Rollback()
var pullsToClose []*db.Pull
pullsToClose = append(pullsToClose, pull)
···
s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.")
2004
+
defer tx.Rollback()
var pullsToReopen []*db.Pull
pullsToReopen = append(pullsToReopen, pull)
···
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
2037
+
func newStack(f *FullyResolvedRepo, user *oauth.User, targetBranch, patch string, pullSource *db.PullSource, stackId string) (db.Stack, error) {
2038
+
formatPatches, err := patchutil.ExtractPatches(patch)
2040
+
return nil, fmt.Errorf("Failed to extract patches: %v", err)
2043
+
// must have atleast 1 patch to begin with
2044
+
if len(formatPatches) == 0 {
2045
+
return nil, fmt.Errorf("No patches found in the generated format-patch.")
2048
+
// the stack is identified by a UUID
2049
+
var stack db.Stack
2050
+
parentChangeId := ""
2051
+
for _, fp := range formatPatches {
2052
+
// all patches must have a jj change-id
2053
+
changeId, err := fp.ChangeId()
2055
+
return nil, fmt.Errorf("Stacking is only supported if all patches contain a change-id commit header.")
2060
+
rkey := appview.TID()
2062
+
initialSubmission := db.PullSubmission{
2064
+
SourceRev: fp.SHA,
2069
+
TargetBranch: targetBranch,
2070
+
OwnerDid: user.Did,
2073
+
Submissions: []*db.PullSubmission{
2074
+
&initialSubmission,
2076
+
PullSource: pullSource,
2077
+
Created: time.Now(),
2080
+
ChangeId: changeId,
2081
+
ParentChangeId: parentChangeId,
2084
+
stack = append(stack, &pull)
2086
+
parentChangeId = changeId