PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/forge/v1

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v1
Namespace
moul / forge
Files
18 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/forge/v1
gno
0.9

Files (18)

  • README.mdmarkdown
  • gnomod.tomltoml
  • change.gnogno
  • errors.gnogno
  • forge.gnogno
  • issue.gnogno
  • pkg.gnogno
  • ref.gnogno
  • release.gnogno
  • validate.gnogno
  • change_test.gnogno
  • forge_test.gnogno
  • helpers_test.gnogno
  • issue_test.gnogno
  • pkg_test.gnogno
  • ref_test.gnogno
  • release_test.gnogno
  • validate_test.gnogno
  • change_test.gnogno
    1package forge23import (4	"testing"56	"gno.land/p/nt/uassert/v0"7	"gno.land/p/nt/urequire/v0"8

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    )
    9
    10// openChange sets up a repo with main at oid("a") and one open change proposing
    11// oid("b"), authored by carol (a writer).
    12func openChange(t *testing.T) (*Repo, *Change) {
    13 t.Helper()
    14 _, r := newRepo(t)
    15 _, err := r.SetRef(alice, 100, "refs/heads/main", "", oid("a"), "initial")
    16 urequire.NoError(t, err)
    17 c, err := r.OpenChange(carol, 101, "add the log", "closes #1", "", "refs/heads/feat", oid("b"), "refs/heads/main")
    18 urequire.NoError(t, err)
    19 return r, c
    20}
    21
    22func TestOpenChangeValidation(t *testing.T) {
    23 _, r := newRepo(t)
    24
    25 _, err := r.OpenChange(eve, 101, "", "", "", "", oid("b"), "refs/heads/main")
    26 uassert.ErrorIs(t, err, ErrInvalidText)
    27 _, err = r.OpenChange(eve, 101, "t", "", "", "", "beef", "refs/heads/main")
    28 uassert.ErrorIs(t, err, ErrInvalidOID)
    29 _, err = r.OpenChange(eve, 101, "t", "", "", "", oid("b"), "main")
    30 uassert.ErrorIs(t, err, ErrInvalidRefName)
    31 _, err = r.OpenChange(eve, 101, "t", "", "NOT/an/id", "", oid("b"), "refs/heads/main")
    32 uassert.ErrorIs(t, err, ErrInvalidRepoID)
    33
    34 // A fork or a plain git remote are both legal sources: the objects live
    35 // off chain either way.
    36 c, err := r.OpenChange(eve, 101, "from a fork", "", "eve/forge", "refs/heads/feat", oid("b"), "refs/heads/main")
    37 urequire.NoError(t, err)
    38 uassert.Equal(t, StateOpen, c.State)
    39 c2, err := r.OpenChange(eve, 101, "from a remote", "", "https://example.com/x.git", "refs/heads/feat", oid("b"), "refs/heads/main")
    40 urequire.NoError(t, err)
    41 uassert.Equal(t, int64(1), c2.ID)
    42 uassert.Equal(t, 2, r.OpenChangeCount())
    43}
    44
    45func TestApprovalsAreBoundToTheReviewedObject(t *testing.T) {
    46 r, c := openChange(t)
    47
    48 urequire.NoError(t, r.ReviewChange(bob, 102, 0, VerdictApprove, "lgtm"))
    49 uassert.Equal(t, 1, r.CountApprovals(c))
    50
    51 // Push a new head: the approval named an object that is no longer what
    52 // would be merged, so it stops counting. Nothing had to remember to
    53 // dismiss it.
    54 urequire.NoError(t, r.UpdateChangeHead(carol, 103, 0, oid("c")))
    55 uassert.Equal(t, 0, r.CountApprovals(c))
    56 uassert.True(t, c.Stale(c.Review(bob)))
    57
    58 urequire.NoError(t, r.ReviewChange(bob, 104, 0, VerdictApprove, "still lgtm"))
    59 uassert.Equal(t, 1, r.CountApprovals(c))
    60 uassert.Equal(t, 1, c.ReviewCount(), "one verdict per reviewer, latest wins")
    61}
    62
    63func TestApprovalWeight(t *testing.T) {
    64 r, c := openChange(t)
    65
    66 // Anyone may review; only a writer's approval counts toward policy.
    67 urequire.NoError(t, r.ReviewChange(eve, 102, 0, VerdictApprove, "as a user: works"))
    68 urequire.NoError(t, r.ReviewChange(dave, 102, 0, VerdictApprove, "reader here"))
    69 uassert.Equal(t, 2, c.ReviewCount())
    70 uassert.Equal(t, 0, r.CountApprovals(c), "unprivileged review is signal, not authority")
    71
    72 // The author cannot approve their own change, unless the repo says so.
    73 uassert.ErrorIs(t, r.ReviewChange(carol, 102, 0, VerdictApprove, "mine"), ErrSelfApproval)
    74 urequire.NoError(t, r.SetPolicy(alice, 1, true))
    75 urequire.NoError(t, r.ReviewChange(carol, 102, 0, VerdictApprove, "mine"))
    76 uassert.Equal(t, 1, r.CountApprovals(c))
    77
    78 uassert.ErrorIs(t, r.ReviewChange(bob, 102, 0, "lgtm?", ""), ErrInvalidVerdict)
    79 uassert.ErrorIs(t, r.ReviewChange(bob, 102, 9, VerdictApprove, ""), ErrChangeNotFound)
    80}
    81
    82func TestMergePolicy(t *testing.T) {
    83 r, c := openChange(t)
    84
    85 // Default policy is one approval.
    86 _, err := r.MergeChange(bob, 105, 0, oid("a"), oid("e"), "merge #0")
    87 uassert.ErrorIs(t, err, ErrNotEnoughApproval)
    88
    89 urequire.NoError(t, r.ReviewChange(bob, 106, 0, VerdictApprove, "lgtm"))
    90
    91 // A writer cannot merge, however well reviewed.
    92 _, err = r.MergeChange(carol, 107, 0, oid("a"), oid("e"), "")
    93 uassert.ErrorIs(t, err, ErrUnauthorized)
    94
    95 // A blocking review stops the merge while it stands.
    96 urequire.NoError(t, r.ReviewChange(alice, 107, 0, VerdictRequestChanges, "needs a test"))
    97 uassert.Equal(t, 1, r.CountBlocking(c))
    98 _, err = r.MergeChange(bob, 108, 0, oid("a"), oid("e"), "")
    99 uassert.ErrorIs(t, err, ErrChangesRequested)
    100 urequire.NoError(t, r.ReviewChange(alice, 109, 0, VerdictApprove, "test added"))
    101
    102 // The base moved: the change was approved against a tree that no longer
    103 // exists, so the merge is refused rather than silently rebased.
    104 _, err = r.MergeChange(bob, 110, 0, oid("9"), oid("e"), "")
    105 uassert.ErrorIs(t, err, ErrStaleRef)
    106
    107 e, err := r.MergeChange(bob, 111, 0, oid("a"), oid("e"), "merge change 0")
    108 urequire.NoError(t, err)
    109 uassert.Equal(t, KindMerge, e.Kind)
    110 uassert.Equal(t, int64(0), e.ChangeID, "the log entry names the change it came from")
    111 uassert.Equal(t, oid("a"), e.OldOID)
    112 uassert.Equal(t, oid("e"), r.Ref("refs/heads/main").OID, "the ref moved")
    113 uassert.Equal(t, StateMerged, c.State)
    114 uassert.Equal(t, bob.String(), c.MergedBy.String())
    115 uassert.Equal(t, int64(111), c.MergedAt)
    116 uassert.Equal(t, 0, r.OpenChangeCount())
    117
    118 ok, _ := r.VerifyLog()
    119 uassert.True(t, ok)
    120
    121 // A merged change is closed to everything.
    122 _, err = r.MergeChange(bob, 112, 0, oid("e"), oid("f"), "")
    123 uassert.ErrorIs(t, err, ErrChangeNotOpen)
    124 uassert.ErrorIs(t, r.UpdateChangeHead(carol, 112, 0, oid("d")), ErrChangeNotOpen)
    125 uassert.ErrorIs(t, r.ReviewChange(bob, 112, 0, VerdictApprove, ""), ErrChangeNotOpen)
    126 uassert.ErrorIs(t, r.CloseChange(carol, 112, 0), ErrChangeNotOpen)
    127}
    128
    129func TestMergeCreatesMissingRef(t *testing.T) {
    130 _, r := newRepo(t)
    131 c, err := r.OpenChange(carol, 101, "first branch", "", "", "refs/heads/feat", oid("b"), "refs/heads/main")
    132 urequire.NoError(t, err)
    133 urequire.NoError(t, r.SetPolicy(alice, 0, false))
    134
    135 _, err = r.MergeChange(bob, 102, 0, oid("a"), oid("b"), "")
    136 uassert.ErrorIs(t, err, ErrRefNotFound, "a target that does not exist takes no expectation")
    137
    138 e, err := r.MergeChange(bob, 103, 0, "", oid("b"), "first merge")
    139 urequire.NoError(t, err)
    140 uassert.Equal(t, KindMerge, e.Kind)
    141 uassert.Equal(t, "", e.OldOID)
    142 uassert.Equal(t, oid("b"), r.Ref("refs/heads/main").OID)
    143 uassert.Equal(t, StateMerged, c.State)
    144}
    145
    146func TestChangeCommentsAndClose(t *testing.T) {
    147 r, c := openChange(t)
    148
    149 cm, err := r.CommentChange(eve, 102, 0, "does this cover the force case?")
    150 urequire.NoError(t, err)
    151 uassert.Equal(t, int64(0), cm.ID)
    152 uassert.Equal(t, 1, c.CommentCount())
    153 _, err = r.CommentChange(eve, 102, 0, "")
    154 uassert.ErrorIs(t, err, ErrInvalidText)
    155
    156 uassert.ErrorIs(t, r.CloseChange(eve, 103, 0), ErrUnauthorized)
    157 urequire.NoError(t, r.CloseChange(carol, 103, 0), "the author may withdraw")
    158 uassert.Equal(t, StateClosed, c.State)
    159
    160 uassert.True(t, r.Change(42) == nil)
    161 uassert.ErrorIs(t, r.UpdateChangeHead(carol, 104, 42, oid("d")), ErrChangeNotFound)
    162}
    163
    164func TestChangeIterationIsNewestFirst(t *testing.T) {
    165 _, r := newRepo(t)
    166 for _, title := range []string{"one", "two", "three"} {
    167 _, err := r.OpenChange(carol, 101, title, "", "", "", oid("b"), "refs/heads/main")
    168 urequire.NoError(t, err)
    169 }
    170
    171 var got []string
    172 r.IterateChanges(0, 0, func(c *Change) bool {
    173 got = append(got, c.Title)
    174 return false
    175 })
    176 uassert.Equal(t, "three,two,one", join(got))
    177
    178 var reviewers []string
    179 c := r.Change(0)
    180 urequire.NoError(t, r.ReviewChange(bob, 102, 0, VerdictApprove, ""))
    181 urequire.NoError(t, r.ReviewChange(alice, 102, 0, VerdictComment, ""))
    182 c.IterateReviews(func(rv *Review) bool {
    183 reviewers = append(reviewers, rv.Verdict)
    184 return false
    185 })
    186 uassert.Equal(t, 2, len(reviewers))
    187}
    188