aboutsummaryrefslogtreecommitdiff
path: root/receivepack/hook.go
blob: c96911ac26e47baa505b0ffd30c1170030ae643a (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package receivepack

import (
	"context"

	"codeberg.org/lindenii/furgit/objectid"
	"codeberg.org/lindenii/furgit/objectstore"
	"codeberg.org/lindenii/furgit/receivepack/internal/service"
	"codeberg.org/lindenii/furgit/refstore"
)

// RefUpdate is one requested reference update presented to a receive-pack hook.
type RefUpdate struct {
	Name  string
	OldID objectid.ObjectID
	NewID objectid.ObjectID
}

// UpdateDecision is one hook decision for a requested reference update.
type UpdateDecision struct {
	Accept  bool
	Message string
}

// HookRequest is the input presented to a receive-pack hook before quarantine
// promotion and ref updates.
type HookRequest struct {
	Refs               refstore.ReadingStore
	ExistingObjects    objectstore.Store
	QuarantinedObjects objectstore.Store
	Updates            []RefUpdate
	PushOptions        []string
}

// Hook decides whether each requested update should proceed.
//
// The hook runs after pack ingestion into quarantine and before quarantine
// promotion or ref updates. The returned decisions must have the same length as
// HookRequest.Updates.
type Hook func(context.Context, HookRequest) ([]UpdateDecision, error)

func translateHook(hook Hook) service.Hook {
	if hook == nil {
		return nil
	}

	return func(ctx context.Context, req service.HookRequest) ([]service.UpdateDecision, error) {
		translatedUpdates := make([]RefUpdate, 0, len(req.Updates))
		for _, update := range req.Updates {
			translatedUpdates = append(translatedUpdates, RefUpdate{
				Name:  update.Name,
				OldID: update.OldID,
				NewID: update.NewID,
			})
		}

		decisions, err := hook(ctx, HookRequest{
			Refs:               req.Refs,
			ExistingObjects:    req.ExistingObjects,
			QuarantinedObjects: req.QuarantinedObjects,
			Updates:            translatedUpdates,
			PushOptions:        append([]string(nil), req.PushOptions...),
		})
		if err != nil {
			return nil, err
		}

		out := make([]service.UpdateDecision, 0, len(decisions))
		for _, decision := range decisions {
			out = append(out, service.UpdateDecision{
				Accept:  decision.Accept,
				Message: decision.Message,
			})
		}

		return out, nil
	}
}