feat(updates): per-repo platform + require-key + platform buttons #286

Merged
jmiller merged 1 commits from feat/repo-update-settings into dev 2026-05-31 03:57:01 +00:00
11 changed files with 110 additions and 5 deletions
+2
View File
@@ -24,6 +24,8 @@ type UpdateStreamConfig struct {
OwnerID int64 `xorm:"INDEX NOT NULL"` // org or user
RepoID int64 `xorm:"INDEX NOT NULL DEFAULT 0"` // 0 = org-level default
StreamMode string `xorm:"NOT NULL DEFAULT 'joomla'"` // joomla, custom
Platform string `xorm:"NOT NULL DEFAULT 'joomla'"` // joomla, dolibarr, both
RequireKey bool `xorm:"NOT NULL DEFAULT false"` // require license key for update feed
// CustomStreams is a JSON array of stream definitions.
// Each entry: {"name":"lts","suffix":"-lts","description":"Long-term support"}
CustomStreams string `xorm:"TEXT"`
+2
View File
@@ -414,6 +414,8 @@ func prepareMigrationTasks() []*migration {
newMigration(334, "Add actions user whitelist to protected branches", v1_27.AddActionsUserWhitelistToProtectedBranch),
newMigration(335, "Add license key tables for update server", v1_27.AddLicenseKeyTables),
newMigration(336, "Add update stream config table", v1_27.AddUpdateStreamConfigTable),
newMigration(337, "Add key_plain column to license_key", v1_27.AddKeyPlainToLicenseKey),
newMigration(338, "Add platform and require_key to update_stream_config", v1_27.AddPlatformAndRequireKeyToStreamConfig),
}
return preparedMigrations
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
package v1_27
import "xorm.io/xorm"
type licenseKey337 struct {
ID int64 `xorm:"pk autoincr"`
KeyPlain string `xorm:""`
}
func (licenseKey337) TableName() string {
return "license_key"
}
// AddKeyPlainToLicenseKey adds the key_plain column to license_key table.
func AddKeyPlainToLicenseKey(x *xorm.Engine) error {
return x.Sync(new(licenseKey337))
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
package v1_27
import "xorm.io/xorm"
type updateStreamConfig338 struct {
ID int64 `xorm:"pk autoincr"`
Platform string `xorm:"NOT NULL DEFAULT 'joomla'"`
RequireKey bool `xorm:"NOT NULL DEFAULT false"`
}
func (updateStreamConfig338) TableName() string {
return "update_stream_config"
}
// AddPlatformAndRequireKeyToStreamConfig adds platform and require_key
// columns to update_stream_config.
func AddPlatformAndRequireKeyToStreamConfig(x *xorm.Engine) error {
return x.Sync(new(updateStreamConfig338))
}
+4 -1
View File
@@ -2147,7 +2147,10 @@
"repo.settings.unit_visibility": "Visibility",
"repo.settings.unit_visibility_private": "Private (follow repo visibility)",
"repo.settings.unit_visibility_public": "Public (anyone can read)",
"repo.settings.unit_visibility_releases_help": "Update feeds (updates.xml, dolibarr.json) are always accessible regardless of this setting. Set to Public to also show the releases page to anonymous visitors.",
"repo.settings.unit_visibility_releases_help": "Controls whether the releases page is visible to anonymous visitors.",
"repo.settings.update_platform": "Update Server Platform",
"repo.settings.update_platform_both": "Both (Joomla + Dolibarr)",
"repo.settings.require_update_key": "Require license key for update feed access",
"repo.settings.packages_desc": "Enable Repository Packages Registry",
"repo.settings.projects_desc": "Enable Projects",
"repo.settings.projects_mode_desc": "Projects Mode (which kinds of projects to show)",
+19
View File
@@ -12,6 +12,7 @@ import (
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/organization"
licenses_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/licenses"
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/perm"
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
unit_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unit"
@@ -100,6 +101,8 @@ func SettingsCtxData(ctx *context.Context) {
// Settings show a repository's settings page
func Settings(ctx *context.Context) {
repoCfg, _ := licenses_model.GetRepoConfig(ctx, ctx.Repo.Repository.ID)
ctx.Data["RepoUpdateConfig"] = repoCfg
ctx.HTML(http.StatusOK, tplSettingsOptions)
}
@@ -672,6 +675,22 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
return
}
}
// Save update server platform and require-key settings.
updatePlatform := form.UpdatePlatform
if updatePlatform == "" {
updatePlatform = "joomla"
}
updateCfg := &licenses_model.UpdateStreamConfig{
OwnerID: repo.OwnerID,
RepoID: repo.ID,
Platform: updatePlatform,
RequireKey: form.RequireUpdateKey,
StreamMode: "joomla", // inherit org default
}
if err := licenses_model.SaveConfig(ctx, updateCfg); err != nil {
log.Error("SaveConfig: %v", err)
}
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+7 -1
View File
@@ -23,7 +23,13 @@ func validateUpdateKey(ctx *context.Context) (allowedChannels []string, ok bool)
}
if rawKey == "" {
// No key provided — allow public access (all channels).
// Check if this repo requires a key for update feed access.
repoCfg, _ := licenses.GetRepoConfig(ctx, ctx.Repo.Repository.ID)
if repoCfg != nil && repoCfg.RequireKey {
// Key required but not provided — return empty.
return nil, false
}
// No key required — allow public access (all channels).
return nil, true
}
+8
View File
@@ -614,6 +614,14 @@ func repoAssignmentPrepareTemplateData(ctx *Context, data *repoAssignmentPrepare
ctx.Data["EnableLicenses"] = numLicensePackages > 0
ctx.Data["IsRepoAdmin"] = ctx.Repo.Permission.IsAdmin()
// Load repo update config for platform-aware UI.
repoUpdateCfg, _ := licenses_model.GetRepoConfig(ctx, repo.ID)
if repoUpdateCfg != nil {
ctx.Data["RepoUpdatePlatform"] = repoUpdateCfg.Platform
} else {
ctx.Data["RepoUpdatePlatform"] = "joomla"
}
ctx.Data["Title"] = repo.Owner.Name + "/" + repo.Name
ctx.Data["PageTitleCommon"] = repo.Name + " - " + setting.AppName
ctx.Data["Repository"] = repo
+2
View File
@@ -133,6 +133,8 @@ type RepoSettingForm struct {
EnableReleases bool
ReleasesVisibility string
UpdatePlatform string
RequireUpdateKey bool
EnablePackages bool
+10 -3
View File
@@ -17,9 +17,16 @@
</a>
{{end}}
{{if not .PageIsTagList}}
<a class="ui small button" href="{{.RepoLink}}/updates.xml" target="_blank">
{{svg "octicon-download" 16}} {{ctx.Locale.Tr "repo.release.update_feed"}}
</a>
{{if or (eq .RepoUpdatePlatform "joomla") (eq .RepoUpdatePlatform "both") (eq .RepoUpdatePlatform "")}}
<a class="ui small button" href="{{.RepoLink}}/updates.xml" target="_blank">
{{svg "octicon-download" 16}} Joomla XML
</a>
{{end}}
{{if or (eq .RepoUpdatePlatform "dolibarr") (eq .RepoUpdatePlatform "both")}}
<a class="ui small button" href="{{.RepoLink}}/updates/dolibarr.json" target="_blank">
{{svg "octicon-download" 16}} Dolibarr JSON
</a>
{{end}}
{{end}}
{{if and (not .PageIsTagList) .CanCreateRelease}}
<a class="ui small primary button" href="{{$.RepoLink}}/releases/new{{if .PageIsSingleTag}}?tag={{.SingleReleaseTagName}}{{end}}">
+14
View File
@@ -514,6 +514,20 @@
</select>
<p class="help">{{ctx.Locale.Tr "repo.settings.unit_visibility_releases_help"}}</p>
</div>
<div class="inline field">
<label>{{ctx.Locale.Tr "repo.settings.update_platform"}}</label>
<select name="update_platform" class="ui dropdown">
<option value="joomla" {{if or (not .RepoUpdateConfig) (eq .RepoUpdateConfig.Platform "joomla") (eq .RepoUpdateConfig.Platform "")}}selected{{end}}>Joomla (updates.xml)</option>
<option value="dolibarr" {{if and .RepoUpdateConfig (eq .RepoUpdateConfig.Platform "dolibarr")}}selected{{end}}>Dolibarr (JSON)</option>
<option value="both" {{if and .RepoUpdateConfig (eq .RepoUpdateConfig.Platform "both")}}selected{{end}}>{{ctx.Locale.Tr "repo.settings.update_platform_both"}}</option>
</select>
</div>
<div class="inline field">
<div class="ui checkbox">
<input name="require_update_key" type="checkbox" {{if and .RepoUpdateConfig .RepoUpdateConfig.RequireKey}}checked{{end}}>
<label>{{ctx.Locale.Tr "repo.settings.require_update_key"}}</label>
</div>
</div>
</div>
{{$isPackagesEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypePackages}}