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
  • release.gnogno
    1package forge23import "strings"45// Size caps for a release.6const (7	MaxTagLen     = 648

    Functions

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

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

    MaxRelNameLen = 200
    9 MaxNotesLen = 8192
    10)
    11
    12// Release is a named point in a repo's history, with notes.
    13//
    14// A tag ref already says "this name points at this object". A release says why
    15// anyone should care: what changed, whether it is ready, and which deployed
    16// package paths came out of it. That last part is the one an explorer wants,
    17// and it is also the only honest bridge between a git object id and an on-chain
    18// deploy, because the chain cannot verify either against the other.
    19type Release struct {
    20 Tag string // "v1.2.0", the key; immutable once cut
    21 Name string // human title, may be empty
    22 Notes string // markdown, may be empty
    23 OID string // the object this release names
    24 Ref string // the tag ref, "" if the release does not have one
    25 Prerelease bool
    26 CreatedAt int64 // block height
    27 CreatedBy address
    28 Yanked bool // withdrawn; kept, because a version that existed cannot un-exist
    29 YankReason string
    30}
    31
    32// ValidTag reports whether s is usable as a release tag.
    33//
    34// Not semver-enforcing: gno.land's own packages version as v0, v1 with no minor
    35// or patch, and a forge that refused those would refuse its own ecosystem.
    36// Ordering is therefore lexical over a padded form, not semantic, and
    37// LatestRelease says so.
    38func ValidTag(s string) bool {
    39 if s == "" || len(s) > MaxTagLen {
    40 return false
    41 }
    42 if strings.Contains(s, "..") || strings.Contains(s, "/") {
    43 return false
    44 }
    45 for i := 0; i < len(s); i++ {
    46 c := s[i]
    47 ok := (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
    48 (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '_' || c == '+'
    49 if !ok {
    50 return false
    51 }
    52 }
    53 return true
    54}
    55
    56// CutRelease records a release. The tag is the key and cannot be re-cut: a
    57// consumer that pinned v1.2.0 and got different bytes later has been lied to,
    58// and the whole point of a tag is that it does not move. Withdrawing one is
    59// YankRelease, which leaves it visible.
    60func (r *Repo) CutRelease(actor address, height int64, tag, name, notes, oid, ref string, prerelease bool) (*Release, error) {
    61 if r.Archived {
    62 return nil, ErrRepoArchived
    63 }
    64 if !r.Can(actor, RoleWriter) {
    65 return nil, ErrUnauthorized
    66 }
    67 if !ValidTag(tag) {
    68 return nil, ErrInvalidTag
    69 }
    70 if !ValidText(name, MaxRelNameLen) || !ValidText(notes, MaxNotesLen) {
    71 return nil, ErrInvalidText
    72 }
    73 if oid != "" && !ValidOID(oid) {
    74 return nil, ErrInvalidOID
    75 }
    76 if ref != "" && !ValidRefName(ref) {
    77 return nil, ErrInvalidRefName
    78 }
    79 if r.releases.Has(tag) {
    80 return nil, ErrReleaseExists
    81 }
    82
    83 rel := &Release{
    84 Tag: tag,
    85 Name: name,
    86 Notes: notes,
    87 OID: oid,
    88 Ref: ref,
    89 Prerelease: prerelease,
    90 CreatedAt: height,
    91 CreatedBy: actor,
    92 }
    93 r.releases.Set(tag, rel)
    94 r.releaseOrder.Set(seqKey(int64(r.releases.Size())), tag)
    95 return rel, nil
    96}
    97
    98// YankRelease marks a release withdrawn without deleting it.
    99//
    100// Deleting would make a pinned version silently vanish, which reads to a
    101// consumer as "this was never published" rather than "do not use this".
    102func (r *Repo) YankRelease(actor address, tag, reason string) error {
    103 if !r.Can(actor, RoleWriter) {
    104 return ErrUnauthorized
    105 }
    106 if !ValidText(reason, MaxNoteLen) {
    107 return ErrInvalidText
    108 }
    109 v := r.releases.Get(tag)
    110 if v == nil {
    111 return ErrReleaseNotFound
    112 }
    113 rel := v.(*Release)
    114 rel.Yanked = true
    115 rel.YankReason = reason
    116 return nil
    117}
    118
    119// Release returns one release by tag, or nil.
    120func (r *Repo) Release(tag string) *Release {
    121 v := r.releases.Get(tag)
    122 if v == nil {
    123 return nil
    124 }
    125 return v.(*Release)
    126}
    127
    128// ReleaseCount is how many releases this repo has cut, yanked ones included.
    129func (r *Repo) ReleaseCount() int { return r.releases.Size() }
    130
    131// IterateReleases walks releases newest-cut first.
    132//
    133// Cut order, not tag order: tags are not required to be semver here (gno.land's
    134// own packages are v0 and v1), so there is no total order to sort by that would
    135// not be wrong for somebody. When they were cut is a fact the forge does know.
    136func (r *Repo) IterateReleases(offset, count int, cb func(*Release) bool) {
    137 if count <= 0 {
    138 count = r.releaseOrder.Size()
    139 }
    140 r.releaseOrder.ReverseIterateByOffset(offset, count, func(_ string, v any) bool {
    141 rel := r.releases.Get(v.(string))
    142 if rel == nil {
    143 return false
    144 }
    145 return cb(rel.(*Release))
    146 })
    147}
    148
    149// LatestRelease is the most recently cut release that is neither a prerelease
    150// nor yanked, or nil. "Most recently cut", never "highest version": see
    151// IterateReleases.
    152func (r *Repo) LatestRelease() *Release {
    153 var out *Release
    154 r.IterateReleases(0, 0, func(rel *Release) bool {
    155 if rel.Prerelease || rel.Yanked {
    156 return false
    157 }
    158 out = rel
    159 return true
    160 })
    161 return out
    162}
    163