Help us shape the future of Go! Take the 2026 Go Developer Survey

notice

package
v0.37.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package notice authors bentoo notices: one input becomes a GLEP 42 news item in the overlay and a YAML file in the site repository, sharing one ID.

The package is pure where it can be — validation and both renderers touch no disk — so every file format is pinned by tests before anything is written. It prints nothing and logs nothing: errors and warnings are returned to the command, which owns the terminal.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoEditor     = errors.New("no editor: pass --body-file, or set VISUAL or EDITOR")
	ErrEditorFailed = errors.New("the editor failed")
	ErrEmptyBody    = errors.New("the notice body is empty")
)

Errors of ReadBody.

View Source
var (
	ErrType            = errors.New("invalid notice type")
	ErrSeverity        = errors.New("invalid notice severity")
	ErrName            = errors.New("invalid notice name")
	ErrTitle           = errors.New("invalid notice title")
	ErrSummary         = errors.New("invalid notice summary")
	ErrPublished       = errors.New("invalid publication date")
	ErrFuture          = errors.New("publication date is in the future")
	ErrControlChar     = errors.New("forbidden control character")
	ErrAffectsRequired = errors.New("this notice type needs at least one --affects")
)

Sentinel errors. Every error New returns wraps one of these and names the flag or field involved, so a caller can branch with errors.Is and a person can read which input to fix.

View Source
var (
	ErrBadID          = errors.New("invalid notice ID")
	ErrNewsExists     = errors.New("the overlay already has a news item with this ID")
	ErrSiteDirMissing = errors.New("the site has no notices directory")
	ErrSiteExists     = errors.New("the site already has a notice file with this ID")
)

Errors of Publish and Revise.

View Source
var (
	ErrNotFound        = errors.New("no news item with this ID")
	ErrSiteMissing     = errors.New("the site has no notice file with this ID")
	ErrNothingToRevise = errors.New("nothing to revise: the text is unchanged and no field was given")
	ErrMalformedNews   = errors.New("malformed news item")
	ErrMalformedSite   = errors.New("malformed site notice")
)

Errors of Revise.

View Source
var ErrAffects = errors.New("invalid --affects value")

ErrAffects is wrapped by every --affects parse error.

Functions

func AffectsString

func AffectsString(a Affects) string

AffectsString renders a in the --affects syntax it was parsed from.

func EditBody

func EditBody(ctx context.Context, initial string, env func(string) string, run Runner) (body string, err error)

EditBody opens initial in the user's editor on a temporary file and returns the text saved (see editedText), with surrounding blank lines trimmed. The temporary file is removed on every path.

func NewsPath

func NewsPath(overlay, id string) string

NewsPath is the news item of id in overlay: metadata/news/<id>/<id>.en.txt.

func ReadBody

func ReadBody(ctx context.Context, bodyFile string, env func(string) string, run Runner) (string, error)

ReadBody returns the notice body: the content of bodyFile when it is given, otherwise what the user writes in $VISUAL, else $EDITOR (see editedText). env reads the environment (os.Getenv in production).

func RenderNews

func RenderNews(n Notice) (text string, warnings []string)

RenderNews renders n as a GLEP 42 news item (format 2.0): the headers in order, one Display-If-Installed per affects entry, one blank line, then the body wrapped at 72 columns with tabs expanded.

Display-If-Installed headers combine with OR, while the ranges of one feed entry combine with AND, so an entry with several ranges cannot be one header: it is written as the bare package and reported in warnings.

func RenderSiteYAML

func RenderSiteYAML(n Notice) ([]byte, error)

RenderSiteYAML renders n as the site's notice file, with the fields of the site's notice data model: id, type, severity, title, summary, body, affects, published, updated, in that order. The schema has no author and no revision — those live in the news item only.

The document is built as a yaml.Node tree rather than marshalled from a struct, because the site's YAML parser types every plain scalar: a version `1.10` written bare reads back as the float 1.1, a slot `1` as an integer, and a timestamp as a date. Every such scalar is therefore double-quoted, and the body is a literal block so its lines survive as written.

The reader is js-yaml (YAML 1.2), not yaml.v3 (YAML 1.1), and the two disagree on what a plain scalar means: js-yaml reads `2026-10-02 10:00:00Z` or `._5` as a date or a number that yaml.v3 would leave plain. Title and summary are free text, so they are always quoted too.

func SiteNoticesDir

func SiteNoticesDir(sitePath string) string

SiteNoticesDir is where the site keeps its notice files.

func SitePath

func SitePath(sitePath, id string) string

SitePath is the site notice file of id.

func TerminalRunner

func TerminalRunner(ctx context.Context, name string, args ...string) error

TerminalRunner runs the editor on the user's terminal. It never goes through a shell, and it stays in bentoo's process group on purpose: an interactive editor that is moved out of the foreground group loses the terminal's signals and its job control.

func ValidateSeverity

func ValidateSeverity(s string) error

ValidateSeverity checks a --severity value.

func ValidateSummary

func ValidateSummary(s string) error

ValidateSummary checks a --summary value: 1..300 code points, single line, no forbidden control character.

func ValidateTitle

func ValidateTitle(s string) error

ValidateTitle checks a --title value: 1..50 code points, single line, no forbidden control character.

Types

type Affects

type Affects struct {
	CP, Slot string
	Ranges   []Range
}

Affects is one affected package: a category/package, an optional slot, and zero or more ranges that combine with AND.

func ParseAffects

func ParseAffects(s string) (Affects, error)

ParseAffects parses one --affects value, `<category>/<package>[:<slot>][ <range>[,<range>…]]`, where a range is an operator from <, <=, =, >=, > immediately followed by a Gentoo version. A rejection quotes the value and the part that failed.

type BodyEditor

type BodyEditor func(ctx context.Context, current string) (string, error)

BodyEditor opens current in the user's editor and returns the edited text. Revise takes one, so the command decides how the body is edited.

func NewBodyEditor

func NewBodyEditor(env func(string) string, run Runner) BodyEditor

NewBodyEditor returns the BodyEditor `notice revise` uses: the current text, below the instructions and the scissors line, opened in $VISUAL or $EDITOR. Saved untouched, it comes back unchanged, `#` lines included.

type Changes

type Changes struct {
	Severity, Title, Summary string
	Affects                  []string
}

Changes are the fields `notice revise` replaces. An empty string or a nil slice means the flag was not given.

type Input

type Input struct {
	Type, Severity, Name, Title, Summary, Published, Author string
	Affects                                                 []string
	Body                                                    string
}

Input is the raw, unvalidated notice as the command received it: flag values verbatim, plus the body read from a file or the editor.

type Notice

type Notice struct {
	ID, Type, Severity, Title, Summary, Author, Body string
	Affects                                          []Affects
	// Published and Updated are UTC. A new notice has both at midnight of
	// its publication date; a revision moves Updated only.
	Published, Updated time.Time
	// Revision is the news item's Revision header: 1 for a new notice.
	Revision int
}

Notice is a validated notice, the single source both files are rendered from.

func New

func New(in Input, now time.Time) (Notice, error)

New validates in and returns the notice it describes, with Revision 1 and Updated equal to Published. now supplies "today" (in UTC) for the default and the future-date check. The first rule broken is returned, wrapping its sentinel and naming the flag.

type Range

type Range struct {
	Op, Ver string
}

Range is one version bound of an affects entry: an operator from <, <=, =, >=, > and a Gentoo version.

type Result

type Result struct {
	// Paths lists every file written, the news item first.
	Paths []string
	// YAML is the site document, for the command to print when no
	// notice.site_path is configured.
	YAML []byte
	// Warnings are the news renderer's.
	Warnings []string
}

Result is what a publish or a revision wrote.

func Publish

func Publish(ctx context.Context, n Notice, overlay, sitePath string) (Result, error)

Publish writes n as a news item in overlay and, when sitePath is not empty, as a site notice file. Every destination is checked before anything is written; both files are created without replacing anything; and when the site file cannot be written the news item is removed again, so the ID stays free.

func Revise

func Revise(ctx context.Context, id string, changes Changes, overlay, sitePath string,
	edit BodyEditor, now time.Time,
) (Result, error)

Revise opens the text of notice id in edit, applies changes, and rewrites the news item in overlay and — when sitePath is not empty — the site file, each replaced atomically. The news item's Revision goes up by one and the site file's updated becomes now in UTC; Posted, published and the ID stay. Nothing is written when the text comes back unchanged and no field was given, or when any check fails.

type Runner

type Runner func(ctx context.Context, name string, args ...string) error

Runner runs the editor: name and args exactly as they are exec'd, the file to edit being the last argument. Tests inject a fake; the command passes TerminalRunner.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL