mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-26 06:16:56 +09:00
Supports migrating from Gitea-compatible forges like Forgejo and fixes many migration bugs. 1. Pre-release and `+gitea-` suffixed server versions no longer drop reviews, reactions and pagination. 2. Review states, dismissals, scoped and archived labels and merge bases are migrated. 3. Disabled units, external trackers, unavailable release assets, and GitLab confidential issues and internal notes are skipped. 4. Credentials are only sent to the source host, and `Retry-After` rate limits are waited out. 5. GitHub migrations of only issues or pull requests, basic auth clones and dismissed reviews work again. 6. The API returns 404 for releases of a disabled unit and shows migrated authors as mannequins, replacing the never populated `original_author` and `original_author_id` fields. Fixes: https://github.com/go-gitea/gitea/issues/19533 Fixes: https://github.com/go-gitea/gitea/issues/35885 Fixes: https://github.com/go-gitea/gitea/issues/18275 Fixes: https://github.com/go-gitea/gitea/issues/35069 Fixes: https://github.com/go-gitea/gitea/issues/17763 Fixes: https://github.com/go-gitea/gitea/issues/39548 Co-authored-by: bircni <bircni@icloud.com>
294 lines
8.7 KiB
Go
294 lines
8.7 KiB
Go
// Copyright 2016 The Gogs Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package structs
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
|
|
"gitea.dev/modules/optional"
|
|
|
|
"go.yaml.in/yaml/v4"
|
|
)
|
|
|
|
// StateType issue state type
|
|
//
|
|
// swagger:enum StateType
|
|
type StateType string
|
|
|
|
const (
|
|
// StateOpen pr is opened
|
|
StateOpen StateType = "open"
|
|
// StateClosed pr is closed
|
|
StateClosed StateType = "closed"
|
|
)
|
|
|
|
// StateAll is a query parameter filter value, not a valid object state.
|
|
const StateAll = "all"
|
|
|
|
// PullRequestMeta PR info if an issue is a PR
|
|
type PullRequestMeta struct {
|
|
HasMerged bool `json:"merged"`
|
|
Merged *time.Time `json:"merged_at"`
|
|
IsWorkInProgress bool `json:"draft"`
|
|
HTMLURL string `json:"html_url"`
|
|
}
|
|
|
|
// RepositoryMeta basic repository information
|
|
type RepositoryMeta struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Owner string `json:"owner"`
|
|
FullName string `json:"full_name"`
|
|
}
|
|
|
|
// Issue represents an issue in a repository
|
|
// swagger:model
|
|
type Issue struct {
|
|
ID int64 `json:"id"`
|
|
URL string `json:"url"`
|
|
HTMLURL string `json:"html_url"`
|
|
Index int64 `json:"number"`
|
|
Poster *User `json:"user"`
|
|
Title string `json:"title"`
|
|
Body string `json:"body"`
|
|
Ref string `json:"ref"`
|
|
Attachments []*Attachment `json:"assets"`
|
|
Labels []*Label `json:"labels"`
|
|
Milestone *Milestone `json:"milestone"`
|
|
Projects []*Project `json:"projects"`
|
|
// deprecated
|
|
Assignee *User `json:"assignee"`
|
|
Assignees []*User `json:"assignees"`
|
|
State StateType `json:"state"`
|
|
IsLocked bool `json:"is_locked"`
|
|
Comments int `json:"comments"`
|
|
// swagger:strfmt date-time
|
|
Created time.Time `json:"created_at"`
|
|
// swagger:strfmt date-time
|
|
Updated time.Time `json:"updated_at"`
|
|
// swagger:strfmt date-time
|
|
Closed *time.Time `json:"closed_at"`
|
|
// swagger:strfmt date-time
|
|
Deadline *time.Time `json:"due_date"`
|
|
|
|
TimeEstimate int64 `json:"time_estimate"`
|
|
|
|
PullRequest *PullRequestMeta `json:"pull_request"`
|
|
Repo *RepositoryMeta `json:"repository"`
|
|
|
|
PinOrder int `json:"pin_order"`
|
|
// The version of the issue content for optimistic locking
|
|
ContentVersion int `json:"content_version"`
|
|
}
|
|
|
|
// CreateIssueOption options to create one issue
|
|
type CreateIssueOption struct {
|
|
// required:true
|
|
Title string `json:"title" binding:"Required"`
|
|
Body string `json:"body"`
|
|
Ref string `json:"ref"`
|
|
// deprecated
|
|
Assignee string `json:"assignee"`
|
|
Assignees []string `json:"assignees"`
|
|
// swagger:strfmt date-time
|
|
Deadline optional.Option[*string] `json:"due_date,omitzero"`
|
|
// milestone id
|
|
Milestone int64 `json:"milestone"`
|
|
// list of label ids
|
|
Labels []int64 `json:"labels"`
|
|
// list of project ids
|
|
Projects []int64 `json:"projects"`
|
|
Closed bool `json:"closed"`
|
|
}
|
|
|
|
// EditIssueOption options for editing an issue
|
|
type EditIssueOption struct {
|
|
Title string `json:"title"`
|
|
Body *string `json:"body"`
|
|
Ref *string `json:"ref"`
|
|
// deprecated
|
|
Assignee *string `json:"assignee"`
|
|
Assignees []string `json:"assignees"`
|
|
Milestone *int64 `json:"milestone"`
|
|
// list of project ids to set (replaces existing projects)
|
|
Projects *[]int64 `json:"projects"`
|
|
State *string `json:"state"`
|
|
// Deadline is the updated due date for the issue, use null or empty string to remove the deadline
|
|
// swagger:strfmt date-time
|
|
Deadline optional.Option[*string] `json:"due_date,omitzero"`
|
|
RemoveDeadline *bool `json:"unset_due_date"`
|
|
// The current version of the issue content to detect conflicts during editing
|
|
ContentVersion *int `json:"content_version"`
|
|
}
|
|
|
|
// IssueAssigneesOption options for adding/removing issue assignees
|
|
type IssueAssigneesOption struct {
|
|
Assignees []string `json:"assignees"`
|
|
}
|
|
|
|
// EditDeadlineOption options for editing a deadline
|
|
type EditDeadlineOption struct {
|
|
// Deadline is the updated due date for the issue or pull request, use null or empty string to remove the deadline
|
|
// swagger:strfmt date-time
|
|
Deadline optional.Option[*string] `json:"due_date,omitzero"`
|
|
}
|
|
|
|
// IssueDeadline represents an issue deadline
|
|
// swagger:model
|
|
type IssueDeadline struct {
|
|
// swagger:strfmt date-time
|
|
Deadline *time.Time `json:"due_date"`
|
|
}
|
|
|
|
// IssueFormFieldType defines issue form field type, can be "markdown", "textarea", "input", "dropdown" or "checkboxes"
|
|
//
|
|
// swagger:enum IssueFormFieldType
|
|
type IssueFormFieldType string
|
|
|
|
const (
|
|
IssueFormFieldTypeMarkdown IssueFormFieldType = "markdown"
|
|
IssueFormFieldTypeTextarea IssueFormFieldType = "textarea"
|
|
IssueFormFieldTypeInput IssueFormFieldType = "input"
|
|
IssueFormFieldTypeDropdown IssueFormFieldType = "dropdown"
|
|
IssueFormFieldTypeCheckboxes IssueFormFieldType = "checkboxes"
|
|
)
|
|
|
|
// IssueFormField represents a form field
|
|
// swagger:model
|
|
type IssueFormField struct {
|
|
Type IssueFormFieldType `json:"type" yaml:"type"`
|
|
ID string `json:"id" yaml:"id"`
|
|
Attributes map[string]any `json:"attributes" yaml:"attributes"`
|
|
Validations map[string]any `json:"validations" yaml:"validations"`
|
|
Visible []IssueFormFieldVisible `json:"visible,omitempty"`
|
|
}
|
|
|
|
func (iff IssueFormField) VisibleOnForm() bool {
|
|
if len(iff.Visible) == 0 {
|
|
return true
|
|
}
|
|
return slices.Contains(iff.Visible, IssueFormFieldVisibleForm)
|
|
}
|
|
|
|
func (iff IssueFormField) VisibleInContent() bool {
|
|
if len(iff.Visible) == 0 {
|
|
// we have our markdown exception
|
|
return iff.Type != IssueFormFieldTypeMarkdown
|
|
}
|
|
return slices.Contains(iff.Visible, IssueFormFieldVisibleContent)
|
|
}
|
|
|
|
// IssueFormFieldVisible defines issue form field visible
|
|
//
|
|
// swagger:enum IssueFormFieldVisible
|
|
type IssueFormFieldVisible string
|
|
|
|
const (
|
|
IssueFormFieldVisibleForm IssueFormFieldVisible = "form"
|
|
IssueFormFieldVisibleContent IssueFormFieldVisible = "content"
|
|
)
|
|
|
|
// IssueTemplate represents an issue template for a repository
|
|
// swagger:model
|
|
type IssueTemplate struct {
|
|
Name string `json:"name" yaml:"name"`
|
|
Title string `json:"title" yaml:"title"`
|
|
About string `json:"about" yaml:"about"` // Using "description" in a template file is compatible
|
|
Labels IssueTemplateStringSlice `json:"labels" yaml:"labels"`
|
|
Assignees IssueTemplateStringSlice `json:"assignees" yaml:"assignees"`
|
|
Ref string `json:"ref" yaml:"ref"`
|
|
Content string `json:"content" yaml:"-"`
|
|
Fields []*IssueFormField `json:"body" yaml:"body"`
|
|
FileName string `json:"file_name" yaml:"-"`
|
|
}
|
|
|
|
type IssueTemplateStringSlice []string
|
|
|
|
func (l *IssueTemplateStringSlice) UnmarshalYAML(value *yaml.Node) error {
|
|
var labels []string
|
|
if value.IsZero() {
|
|
*l = labels
|
|
return nil
|
|
}
|
|
switch value.Kind {
|
|
case yaml.ScalarNode:
|
|
str := ""
|
|
err := value.Decode(&str)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for v := range strings.SplitSeq(str, ",") {
|
|
if v = strings.TrimSpace(v); v == "" {
|
|
continue
|
|
}
|
|
labels = append(labels, v)
|
|
}
|
|
*l = labels
|
|
return nil
|
|
case yaml.SequenceNode:
|
|
if err := value.Decode(&labels); err != nil {
|
|
return err
|
|
}
|
|
*l = labels
|
|
return nil
|
|
}
|
|
return fmt.Errorf("cannot unmarshal %s into IssueTemplateStringSlice", value.ShortTag())
|
|
}
|
|
|
|
type IssueConfigContactLink struct {
|
|
Name string `json:"name" yaml:"name"`
|
|
URL string `json:"url" yaml:"url"`
|
|
About string `json:"about" yaml:"about"`
|
|
}
|
|
|
|
type IssueConfig struct {
|
|
BlankIssuesEnabled bool `json:"blank_issues_enabled" yaml:"blank_issues_enabled"`
|
|
ContactLinks []IssueConfigContactLink `json:"contact_links" yaml:"contact_links"`
|
|
}
|
|
|
|
type IssueConfigValidation struct {
|
|
Valid bool `json:"valid"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// IssueTemplateType defines issue template type
|
|
type IssueTemplateType string
|
|
|
|
const (
|
|
IssueTemplateTypeMarkdown IssueTemplateType = "md"
|
|
IssueTemplateTypeYaml IssueTemplateType = "yaml"
|
|
)
|
|
|
|
// Type returns the type of IssueTemplate, can be "md", "yaml" or empty for known
|
|
func (it IssueTemplate) Type() IssueTemplateType {
|
|
if base := path.Base(it.FileName); base == "config.yaml" || base == "config.yml" {
|
|
// ignore config.yaml which is a special configuration file
|
|
return ""
|
|
}
|
|
if ext := path.Ext(it.FileName); ext == ".md" {
|
|
return IssueTemplateTypeMarkdown
|
|
} else if ext == ".yaml" || ext == ".yml" {
|
|
return IssueTemplateTypeYaml
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// IssueMeta basic issue information
|
|
// swagger:model
|
|
type IssueMeta struct {
|
|
Index int64 `json:"index"`
|
|
// owner of the issue's repo
|
|
Owner string `json:"owner"`
|
|
Name string `json:"repo"`
|
|
}
|
|
|
|
// LockIssueOption options to lock an issue
|
|
type LockIssueOption struct {
|
|
Reason string `json:"lock_reason"`
|
|
}
|