Files
gitea-tea/internal/app/labelfile.go
T
bircni f02245449b feat!: rebuild tea on Cobra with explicit noun/verb commands (#1126)
- **switch tea to the Cobra command tree:** `internal/app` wires the packages from parts 1–4 into explicit noun/verb commands with `--repo`, `--json` / `--jq`, `--sudo` and `--debug`; `main.go` points at it. Build, release and docs tooling (`tools/cli-docs`, Makefile, goreleaser, snap, CI) and README / CONTRIBUTING are updated.
- **remove the urfave/cli command tree:** deletes `cmd/`, `modules/`, the old integration tests, contrib completion scripts and the generated `docs/CLI.md`, and drops their dependencies. This commit only deletes.

## Breaking changes

This is a breaking release. It requires Gitea 28 or newer; configuration moves to separate `config.yml` and `hosts.yml` files and requires fresh authentication, and command names, aliases, flags and output formats change. `docs/migration-1.0.md` maps every old command, flag and environment variable to its replacement.

## Issues

fixes #1118
fixes #1116
fixes #1115
fixes #1094
fixes #1091
fixes #1073
fixes #1052
fixes #1032
fixes #1023
fixes #966
fixes #908
fixes #833
fixes #831
fixes #817
fixes #804
fixes #779
fixes #770
fixes #737
fixes #697
fixes #726
fixes #677
fixes #672
fixes #633
fixes #632
fixes #560
fixes #556
fixes #523
fixes #516
fixes #510
fixes #504
fixes #500
fixes #482
fixes #406
fixes #403
fixes #373
fixes #351
fixes #344
fixes #326
fixes #325
fixes #323
fixes #246
fixes #240
fixes #232
fixes #197
fixes #172
fixes #141
fixes #69
fixes #1110
fixes #569
fixes #480
fixes #666
fixes #670
fixes #457
fixes #643
fixes #498
fixes #490
fixes #1069
fixes #834
fixes #602
fixes #328
fixes #417
fixes #571
fixes #1029
fixes #489
fixes #1050
fixes #162
fixes #430
fixes #1087
fixes #683

Reviewed-on: https://gitea.com/gitea/tea/pulls/1126
Reviewed-by: TheFox0x7 <95654+thefox0x7@noreply.gitea.com>
2026-10-11 17:23:06 +00:00

73 lines
2.5 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package app
import (
"bufio"
"errors"
"fmt"
"io"
"regexp"
"strings"
"gitea.dev/tea/internal/clierr"
"gitea.dev/tea/internal/services"
)
var labelColor = regexp.MustCompile(`^[0-9a-fA-F]{6}$`)
// parseLabelFile reads "#color name ;description" rows, skipping blank and comment rows.
func parseLabelFile(r io.Reader) ([]services.LabelOptions, error) {
var labels []services.LabelOptions
scanner := bufio.NewScanner(r)
for line := 1; scanner.Scan(); line++ {
label, ok, err := parseLabelRow(scanner.Text(), line)
if err != nil {
return nil, err
}
if ok {
labels = append(labels, label)
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
if len(labels) == 0 {
return nil, clierr.Wrap(clierr.Usage, errors.New("label file contains no labels"))
}
return labels, nil
}
func parseLabelRow(text string, line int) (services.LabelOptions, bool, error) {
raw := strings.TrimSpace(text)
parts := strings.SplitN(raw, ";", 2)
fields := strings.Fields(parts[0])
// Rows start with an optional "#" before the color, as Gitea's label templates do.
if raw == "" || strings.HasPrefix(raw, "#") && !labelColor.MatchString(strings.TrimPrefix(fields[0], "#")) {
return services.LabelOptions{}, false, nil
}
if len(fields) < 2 {
return services.LabelOptions{}, false, clierr.Wrap(clierr.Usage, fmt.Errorf("invalid label row %d", line))
}
color, name, description := strings.TrimPrefix(fields[0], "#"), strings.Join(fields[1:], " "), ""
if len(parts) == 2 {
description = strings.TrimSpace(parts[1])
}
if !labelColor.MatchString(color) {
return services.LabelOptions{}, false, clierr.Wrap(clierr.Usage, fmt.Errorf("invalid color on row %d", line))
}
return services.LabelOptions{Name: &name, Color: &color, Description: &description}, true, nil
}
// formatLabel renders a label as a label file row, rejecting labels the row cannot reproduce.
func formatLabel(label services.Label) (string, error) {
color := strings.TrimPrefix(label.Color, "#")
row := fmt.Sprintf("#%s %s ;%s", color, label.Name, label.Description)
parsed, ok, err := parseLabelRow(row, 1)
if err != nil || !ok || strings.ContainsAny(row, "\r\n") || *parsed.Name != label.Name || *parsed.Color != color || *parsed.Description != label.Description {
return "", errors.New("label cannot be represented in the import format; use label export --json to preserve its text")
}
return row + "\n", nil
}