feat(settings): repo manifest settings with auto-migration and API (#315) #504
@@ -424,6 +424,7 @@ func prepareMigrationTasks() []*migration {
|
||||
newMigration(344, "Add domain_restriction to license_package table", v1_27.AddDomainRestrictionToLicensePackage),
|
||||
newMigration(345, "Migrate custom fields to org-level with scope", v1_27.MigrateCustomFieldsToOrgLevel),
|
||||
newMigration(346, "Add issue status definitions table", v1_27.AddIssueStatusDefTable),
|
||||
newMigration(347, "Add repo manifest table", v1_27.AddRepoManifestTable),
|
||||
}
|
||||
return preparedMigrations
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package v1_27
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// AddRepoManifestTable creates the repo_manifest table for storing
|
||||
// moko-platform manifest settings per repository.
|
||||
func AddRepoManifestTable(x *xorm.Engine) error {
|
||||
type RepoManifest struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"UNIQUE INDEX NOT NULL 'repo_id'"`
|
||||
Name string `xorm:"TEXT 'name'"`
|
||||
Org string `xorm:"TEXT 'org'"`
|
||||
Description string `xorm:"TEXT 'description'"`
|
||||
Version string `xorm:"TEXT 'version'"`
|
||||
LicenseSPDX string `xorm:"VARCHAR(50) 'license_spdx'"`
|
||||
LicenseName string `xorm:"TEXT 'license_name'"`
|
||||
Platform string `xorm:"VARCHAR(50) 'platform'"`
|
||||
StandardsVersion string `xorm:"VARCHAR(20) 'standards_version'"`
|
||||
StandardsSource string `xorm:"TEXT 'standards_source'"`
|
||||
Language string `xorm:"VARCHAR(50) 'language'"`
|
||||
PackageType string `xorm:"VARCHAR(50) 'package_type'"`
|
||||
EntryPoint string `xorm:"TEXT 'entry_point'"`
|
||||
CreatedUnix int64 `xorm:"INDEX CREATED 'created_unix'"`
|
||||
UpdatedUnix int64 `xorm:"UPDATED 'updated_unix'"`
|
||||
}
|
||||
return x.Sync(new(RepoManifest))
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil"
|
||||
)
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(RepoManifest))
|
||||
}
|
||||
|
||||
// RepoManifest stores moko-platform manifest settings for a repository.
|
||||
// These fields correspond to the .mokogitea/manifest.xml schema and are
|
||||
// exposed via API for use by Actions workflows and the moko-platform CLI.
|
||||
type RepoManifest struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"UNIQUE INDEX NOT NULL 'repo_id'"`
|
||||
|
||||
// identity section
|
||||
Name string `xorm:"TEXT 'name'"` // project name
|
||||
Org string `xorm:"TEXT 'org'"` // organization name
|
||||
Description string `xorm:"TEXT 'description'"` // project description
|
||||
Version string `xorm:"TEXT 'version'"` // current version string
|
||||
LicenseSPDX string `xorm:"VARCHAR(50) 'license_spdx'"` // SPDX identifier, e.g. "GPL-3.0-or-later"
|
||||
LicenseName string `xorm:"TEXT 'license_name'"` // human-readable license name
|
||||
|
||||
// governance section
|
||||
Platform string `xorm:"VARCHAR(50) 'platform'"` // go, php, node, python, etc.
|
||||
StandardsVersion string `xorm:"VARCHAR(20) 'standards_version'"` // moko-platform standards version
|
||||
StandardsSource string `xorm:"TEXT 'standards_source'"` // URL to standards repo
|
||||
|
||||
// build section
|
||||
Language string `xorm:"VARCHAR(50) 'language'"` // Go, PHP, TypeScript, etc.
|
||||
PackageType string `xorm:"VARCHAR(50) 'package_type'"` // application, library, plugin, module, component, package
|
||||
EntryPoint string `xorm:"TEXT 'entry_point'"` // build entry point path
|
||||
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED 'created_unix'"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"UPDATED 'updated_unix'"`
|
||||
}
|
||||
|
||||
func (RepoManifest) TableName() string {
|
||||
return "repo_manifest"
|
||||
}
|
||||
|
||||
// GetRepoManifest returns the manifest for a repo, or nil if none exists.
|
||||
func GetRepoManifest(ctx context.Context, repoID int64) (*RepoManifest, error) {
|
||||
m := new(RepoManifest)
|
||||
has, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Get(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
return nil, nil
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// CreateOrUpdateRepoManifest upserts a repo manifest.
|
||||
func CreateOrUpdateRepoManifest(ctx context.Context, m *RepoManifest) error {
|
||||
existing := new(RepoManifest)
|
||||
has, err := db.GetEngine(ctx).Where("repo_id = ?", m.RepoID).Get(existing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if has {
|
||||
m.ID = existing.ID
|
||||
_, err = db.GetEngine(ctx).ID(m.ID).AllCols().Update(m)
|
||||
return err
|
||||
}
|
||||
_, err = db.GetEngine(ctx).Insert(m)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteRepoManifest deletes the manifest for a repo.
|
||||
func DeleteRepoManifest(ctx context.Context, repoID int64) error {
|
||||
_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(new(RepoManifest))
|
||||
return err
|
||||
}
|
||||
@@ -2729,6 +2729,25 @@
|
||||
"repo.settings.support_url": "Support / Product Page URL",
|
||||
"repo.settings.support_url_help": "Shown when downloads are gated. Can point to your wiki, product page, or external support site.",
|
||||
"repo.settings.custom_fields": "Custom Fields",
|
||||
"repo.settings.manifest": "Manifest",
|
||||
"repo.settings.manifest_desc": "Project identity, governance, and build settings from the moko-platform manifest. These are accessible via API for Actions workflows and the moko-platform CLI.",
|
||||
"repo.settings.manifest_identity": "Identity",
|
||||
"repo.settings.manifest_name": "Project Name",
|
||||
"repo.settings.manifest_org": "Organization",
|
||||
"repo.settings.manifest_description": "Description",
|
||||
"repo.settings.manifest_version": "Version",
|
||||
"repo.settings.manifest_license_spdx": "License (SPDX)",
|
||||
"repo.settings.manifest_license_name": "License Name",
|
||||
"repo.settings.manifest_governance": "Governance",
|
||||
"repo.settings.manifest_platform": "Platform",
|
||||
"repo.settings.manifest_standards_version": "Standards Version",
|
||||
"repo.settings.manifest_standards_source": "Standards Source",
|
||||
"repo.settings.manifest_build": "Build",
|
||||
"repo.settings.manifest_language": "Language",
|
||||
"repo.settings.manifest_package_type": "Package Type",
|
||||
"repo.settings.manifest_entry_point": "Entry Point",
|
||||
"repo.settings.manifest_save": "Save Manifest",
|
||||
"repo.settings.manifest_saved": "Manifest settings saved.",
|
||||
"repo.settings.metadata": "Metadata",
|
||||
"repo.settings.metadata_saved": "Repository metadata saved.",
|
||||
"repo.settings.metadata_empty": "No metadata fields defined. Org admins can add fields in Organization Settings > Custom Fields.",
|
||||
|
||||
@@ -1479,6 +1479,9 @@ func Routes() *web.Router {
|
||||
Delete(reqToken(), repo.DeleteTopic)
|
||||
}, reqAdmin())
|
||||
}, reqAnyRepoReader())
|
||||
m.Combo("/manifest", reqRepoReader(unit.TypeCode)).
|
||||
Get(repo.GetRepoManifest).
|
||||
Put(reqToken(), reqAdmin(), repo.UpdateRepoManifest)
|
||||
// MokoGitea badge engine
|
||||
m.Get("/badge/{type}.svg", repo.GetRepoBadge)
|
||||
m.Get("/issue_templates", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.GetIssueTemplates)
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package repo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context"
|
||||
)
|
||||
|
||||
// apiManifest is the JSON representation of a repo manifest.
|
||||
type apiManifest struct {
|
||||
Name string `json:"name"`
|
||||
Org string `json:"org"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
LicenseSPDX string `json:"license_spdx"`
|
||||
LicenseName string `json:"license_name"`
|
||||
Platform string `json:"platform"`
|
||||
StandardsVersion string `json:"standards_version"`
|
||||
StandardsSource string `json:"standards_source"`
|
||||
Language string `json:"language"`
|
||||
PackageType string `json:"package_type"`
|
||||
EntryPoint string `json:"entry_point"`
|
||||
}
|
||||
|
||||
// GetRepoManifest returns the manifest settings for a repository.
|
||||
func GetRepoManifest(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/manifest repository repoGetManifest
|
||||
// ---
|
||||
// summary: Get repo manifest settings
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/Manifest"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
m, err := repo_model.GetRepoManifest(ctx, ctx.Repo.Repository.ID)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
if m == nil {
|
||||
// Return defaults from repo metadata.
|
||||
ctx.JSON(http.StatusOK, &apiManifest{
|
||||
Name: ctx.Repo.Repository.Name,
|
||||
Org: ctx.Repo.Repository.OwnerName,
|
||||
Description: ctx.Repo.Repository.Description,
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, &apiManifest{
|
||||
Name: m.Name,
|
||||
Org: m.Org,
|
||||
Description: m.Description,
|
||||
Version: m.Version,
|
||||
LicenseSPDX: m.LicenseSPDX,
|
||||
LicenseName: m.LicenseName,
|
||||
Platform: m.Platform,
|
||||
StandardsVersion: m.StandardsVersion,
|
||||
StandardsSource: m.StandardsSource,
|
||||
Language: m.Language,
|
||||
PackageType: m.PackageType,
|
||||
EntryPoint: m.EntryPoint,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateRepoManifest updates the manifest settings for a repository.
|
||||
func UpdateRepoManifest(ctx *context.APIContext) {
|
||||
// swagger:operation PUT /repos/{owner}/{repo}/manifest repository repoUpdateManifest
|
||||
// ---
|
||||
// summary: Update repo manifest settings
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/Manifest"
|
||||
var req apiManifest
|
||||
if err := json.NewDecoder(ctx.Req.Body).Decode(&req); err != nil {
|
||||
ctx.APIError(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
m := &repo_model.RepoManifest{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: req.Name,
|
||||
Org: req.Org,
|
||||
Description: req.Description,
|
||||
Version: req.Version,
|
||||
LicenseSPDX: req.LicenseSPDX,
|
||||
LicenseName: req.LicenseName,
|
||||
Platform: req.Platform,
|
||||
StandardsVersion: req.StandardsVersion,
|
||||
StandardsSource: req.StandardsSource,
|
||||
Language: req.Language,
|
||||
PackageType: req.PackageType,
|
||||
EntryPoint: req.EntryPoint,
|
||||
}
|
||||
|
||||
if err := repo_model.CreateOrUpdateRepoManifest(ctx, m); err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, &apiManifest{
|
||||
Name: m.Name,
|
||||
Org: m.Org,
|
||||
Description: m.Description,
|
||||
Version: m.Version,
|
||||
LicenseSPDX: m.LicenseSPDX,
|
||||
LicenseName: m.LicenseName,
|
||||
Platform: m.Platform,
|
||||
StandardsVersion: m.StandardsVersion,
|
||||
StandardsSource: m.StandardsSource,
|
||||
Language: m.Language,
|
||||
PackageType: m.PackageType,
|
||||
EntryPoint: m.EntryPoint,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context"
|
||||
)
|
||||
|
||||
const tplSettingsManifest templates.TplName = "repo/settings/manifest"
|
||||
|
||||
// manifestXML mirrors the .mokogitea/manifest.xml schema for XML parsing.
|
||||
type manifestXML struct {
|
||||
XMLName xml.Name `xml:"moko-platform"`
|
||||
Identity manifestIdentity `xml:"identity"`
|
||||
Governance manifestGovernance `xml:"governance"`
|
||||
Build manifestBuild `xml:"build"`
|
||||
}
|
||||
|
||||
type manifestIdentity struct {
|
||||
Name string `xml:"name"`
|
||||
Org string `xml:"org"`
|
||||
Description string `xml:"description"`
|
||||
Version string `xml:"version"`
|
||||
License manifestLicense `xml:"license"`
|
||||
}
|
||||
|
||||
type manifestLicense struct {
|
||||
SPDX string `xml:"spdx,attr"`
|
||||
Name string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type manifestGovernance struct {
|
||||
Platform string `xml:"platform"`
|
||||
StandardsVersion string `xml:"standards-version"`
|
||||
StandardsSource string `xml:"standards-source"`
|
||||
}
|
||||
|
||||
type manifestBuild struct {
|
||||
Language string `xml:"language"`
|
||||
PackageType string `xml:"package-type"`
|
||||
EntryPoint string `xml:"entry-point"`
|
||||
}
|
||||
|
||||
// ManifestSettings displays the repo manifest settings page.
|
||||
// On first visit, if no manifest exists in DB but .mokogitea/manifest.xml
|
||||
// exists in the repo, it auto-migrates the XML values into the database.
|
||||
func ManifestSettings(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.settings.manifest")
|
||||
ctx.Data["PageIsSettingsManifest"] = true
|
||||
|
||||
repoID := ctx.Repo.Repository.ID
|
||||
manifest, err := repo_model.GetRepoManifest(ctx, repoID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRepoManifest", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Auto-detect and migrate .mokogitea/manifest.xml if no DB record exists.
|
||||
if manifest == nil {
|
||||
manifest = tryMigrateManifestXML(ctx)
|
||||
}
|
||||
|
||||
if manifest == nil {
|
||||
// No manifest found — provide empty defaults from repo metadata.
|
||||
manifest = &repo_model.RepoManifest{
|
||||
RepoID: repoID,
|
||||
Name: ctx.Repo.Repository.Name,
|
||||
Org: ctx.Repo.Repository.OwnerName,
|
||||
Description: ctx.Repo.Repository.Description,
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["Manifest"] = manifest
|
||||
ctx.HTML(http.StatusOK, tplSettingsManifest)
|
||||
}
|
||||
|
||||
// ManifestSettingsPost saves manifest settings from the form.
|
||||
func ManifestSettingsPost(ctx *context.Context) {
|
||||
manifest := &repo_model.RepoManifest{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: ctx.FormString("name"),
|
||||
Org: ctx.FormString("org"),
|
||||
Description: ctx.FormString("description"),
|
||||
Version: ctx.FormString("version"),
|
||||
LicenseSPDX: ctx.FormString("license_spdx"),
|
||||
LicenseName: ctx.FormString("license_name"),
|
||||
Platform: ctx.FormString("platform"),
|
||||
StandardsVersion: ctx.FormString("standards_version"),
|
||||
StandardsSource: ctx.FormString("standards_source"),
|
||||
Language: ctx.FormString("language"),
|
||||
PackageType: ctx.FormString("package_type"),
|
||||
EntryPoint: ctx.FormString("entry_point"),
|
||||
}
|
||||
|
||||
if err := repo_model.CreateOrUpdateRepoManifest(ctx, manifest); err != nil {
|
||||
ctx.ServerError("CreateOrUpdateRepoManifest", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.manifest_saved"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/manifest")
|
||||
}
|
||||
|
||||
// tryMigrateManifestXML reads .mokogitea/manifest.xml from the repo,
|
||||
// parses it, and stores the values in the DB. Returns nil if no file found.
|
||||
func tryMigrateManifestXML(ctx *context.Context) *repo_model.RepoManifest {
|
||||
if ctx.Repo.GitRepo == nil || ctx.Repo.Commit == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(".mokogitea/manifest.xml")
|
||||
if err != nil || entry == nil {
|
||||
return nil // no manifest.xml found — not an error
|
||||
}
|
||||
|
||||
reader, err := entry.Blob().DataAsync()
|
||||
if err != nil {
|
||||
log.Error("ManifestMigrate: read blob: %v", err)
|
||||
return nil
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
var mxml manifestXML
|
||||
if err := xml.NewDecoder(reader).Decode(&mxml); err != nil {
|
||||
log.Error("ManifestMigrate: parse XML: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
manifest := &repo_model.RepoManifest{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: mxml.Identity.Name,
|
||||
Org: mxml.Identity.Org,
|
||||
Description: mxml.Identity.Description,
|
||||
Version: mxml.Identity.Version,
|
||||
LicenseSPDX: mxml.Identity.License.SPDX,
|
||||
LicenseName: mxml.Identity.License.Name,
|
||||
Platform: mxml.Governance.Platform,
|
||||
StandardsVersion: mxml.Governance.StandardsVersion,
|
||||
StandardsSource: mxml.Governance.StandardsSource,
|
||||
Language: mxml.Build.Language,
|
||||
PackageType: mxml.Build.PackageType,
|
||||
EntryPoint: mxml.Build.EntryPoint,
|
||||
}
|
||||
|
||||
if err := repo_model.CreateOrUpdateRepoManifest(ctx, manifest); err != nil {
|
||||
log.Error("ManifestMigrate: save to DB: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Info("ManifestMigrate: migrated .mokogitea/manifest.xml for repo %s/%s",
|
||||
ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name)
|
||||
|
||||
ctx.Flash.Info(fmt.Sprintf("Manifest settings imported from .mokogitea/manifest.xml. You can now delete the file from the repository."))
|
||||
return manifest
|
||||
}
|
||||
@@ -1199,6 +1199,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
|
||||
m.Combo("/advanced").Get(repo_setting.AdvancedSettings).Post(web.Bind(forms.RepoSettingForm{}), repo_setting.SettingsPost)
|
||||
}, repo_setting.SettingsCtxData)
|
||||
m.Combo("/licensing").Get(repo_setting.LicensingSettings).Post(repo_setting.LicensingSettingsPost)
|
||||
m.Combo("/manifest").Get(repo_setting.ManifestSettings).Post(repo_setting.ManifestSettingsPost)
|
||||
m.Combo("/metadata").Get(repo_setting.Metadata).Post(repo_setting.MetadataPost)
|
||||
|
||||
m.Group("/collaboration", func() {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings manifest")}}
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "repo.settings.manifest"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p class="text grey">{{ctx.Locale.Tr "repo.settings.manifest_desc"}}</p>
|
||||
|
||||
<form class="ui form" method="post" action="{{.RepoLink}}/settings/manifest">
|
||||
{{.CsrfTokenHtml}}
|
||||
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.manifest_identity"}}</h5>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_name"}}</label>
|
||||
<input name="name" value="{{.Manifest.Name}}" placeholder="Project name">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_org"}}</label>
|
||||
<input name="org" value="{{.Manifest.Org}}" placeholder="Organization">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_description"}}</label>
|
||||
<input name="description" value="{{.Manifest.Description}}" placeholder="Project description">
|
||||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_version"}}</label>
|
||||
<input name="version" value="{{.Manifest.Version}}" placeholder="e.g. 06.00.00">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_license_spdx"}}</label>
|
||||
<input name="license_spdx" value="{{.Manifest.LicenseSPDX}}" placeholder="e.g. GPL-3.0-or-later">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_license_name"}}</label>
|
||||
<input name="license_name" value="{{.Manifest.LicenseName}}" placeholder="e.g. GNU General Public License v3">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.manifest_governance"}}</h5>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_platform"}}</label>
|
||||
<select name="platform" class="ui dropdown">
|
||||
<option value="">—</option>
|
||||
{{$platform := .Manifest.Platform}}
|
||||
{{range $val := StringUtils.Split "go,php,node,python,ruby,java,dotnet,rust" ","}}
|
||||
<option value="{{$val}}" {{if eq $val $platform}}selected{{end}}>{{$val}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_standards_version"}}</label>
|
||||
<input name="standards_version" value="{{.Manifest.StandardsVersion}}" placeholder="e.g. 05.00.00">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_standards_source"}}</label>
|
||||
<input name="standards_source" value="{{.Manifest.StandardsSource}}" placeholder="URL to standards repo">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.manifest_build"}}</h5>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_language"}}</label>
|
||||
<input name="language" value="{{.Manifest.Language}}" placeholder="e.g. Go, PHP, TypeScript">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_package_type"}}</label>
|
||||
<select name="package_type" class="ui dropdown">
|
||||
<option value="">—</option>
|
||||
{{$pkgType := .Manifest.PackageType}}
|
||||
{{range $val := StringUtils.Split "application,library,plugin,module,component,package,template" ","}}
|
||||
<option value="{{$val}}" {{if eq $val $pkgType}}selected{{end}}>{{$val}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.manifest_entry_point"}}</label>
|
||||
<input name="entry_point" value="{{.Manifest.EntryPoint}}" placeholder="e.g. ./ or src/index.ts">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="ui primary button" type="submit">{{ctx.Locale.Tr "repo.settings.manifest_save"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{template "repo/settings/layout_footer" .}}
|
||||
@@ -12,6 +12,9 @@
|
||||
{{svg "octicon-broadcast"}} {{ctx.Locale.Tr "repo.settings.licensing_section"}}
|
||||
</a>
|
||||
{{end}}
|
||||
<a class="{{if .PageIsSettingsManifest}}active {{end}}item" href="{{.RepoLink}}/settings/manifest">
|
||||
{{svg "octicon-file-code"}} {{ctx.Locale.Tr "repo.settings.manifest"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsSettingsMetadata}}active {{end}}item" href="{{.RepoLink}}/settings/metadata">
|
||||
{{svg "octicon-list-unordered"}} {{ctx.Locale.Tr "repo.settings.metadata"}}
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user