diff --git a/.drone.yml b/.drone.yml index 087ddd6166f48..5096ce781fe20 100644 --- a/.drone.yml +++ b/.drone.yml @@ -773,109 +773,6 @@ steps: - name: deps path: /go ---- -kind: pipeline -name: update_translations - -platform: - os: linux - arch: arm64 - -trigger: - branch: - - main - event: - - cron - cron: - - update_translations - -steps: - - name: download - image: jonasfranz/crowdin - pull: always - settings: - download: true - export_dir: options/locale/ - ignore_branch: true - project_identifier: gitea - environment: - CROWDIN_KEY: - from_secret: crowdin_key - - - name: update - image: alpine:3.17 - pull: always - commands: - - ./build/update-locales.sh - - - name: push - image: appleboy/drone-git-push - pull: always - settings: - author_email: "teabot@gitea.io" - author_name: GiteaBot - branch: main - commit: true - commit_message: "[skip ci] Updated translations via Crowdin" - remote: "git@github.com:go-gitea/gitea.git" - environment: - DRONE_COMMIT_AUTHOR_EMAIL: "teabot@gitea.io" - DRONE_COMMIT_AUTHOR: GiteaBot - GIT_PUSH_SSH_KEY: - from_secret: git_push_ssh_key - - - name: upload_translations - image: jonasfranz/crowdin - pull: always - settings: - files: - locale_en-US.ini: options/locale/locale_en-US.ini - ignore_branch: true - project_identifier: gitea - environment: - CROWDIN_KEY: - from_secret: crowdin_key - ---- -kind: pipeline -type: docker -name: update_gitignore_and_licenses - -platform: - os: linux - arch: arm64 - -trigger: - branch: - - main - event: - - cron - cron: - - update_gitignore_and_licenses - -steps: - - name: download - image: gitea/test_env:linux-1.20-amd64 - pull: always - commands: - - timeout -s ABRT 40m make generate-license generate-gitignore - - - name: push - image: appleboy/drone-git-push - pull: always - settings: - author_email: "teabot@gitea.io" - author_name: "GiteaBot" - branch: main - commit: true - commit_message: "[skip ci] Updated licenses and gitignores" - remote: "git@github.com:go-gitea/gitea.git" - environment: - DRONE_COMMIT_AUTHOR_EMAIL: "teabot@gitea.io" - DRONE_COMMIT_AUTHOR: "GiteaBot" - GIT_PUSH_SSH_KEY: - from_secret: git_push_ssh_key - --- kind: pipeline type: docker diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml new file mode 100644 index 0000000000000..116b8dd0956f0 --- /dev/null +++ b/.github/workflows/cron-licenses.yml @@ -0,0 +1,28 @@ +on: + schedule: + # weekly on Monday at 0:07 UTC + - cron: "7 0 * * 1" + +name: Update licenses and gitignores + +jobs: + cron: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: '>=1.20.1' + - name: update licenses and gitignores + run: timeout -s ABRT 40m make generate-license generate-gitignore + - name: push translations to repo + uses: appleboy/git-push-action@v0.0.2 + with: + author_email: "teabot@gitea.io" + author_name: GiteaBot + branch: main + commit: true + commit_message: "[skip ci] Updated licenses and gitignores" + remote: "git@github.com:go-gitea/gitea.git" + ssh_key: ${{ secrets.DEPLOY_KEY }} diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml new file mode 100644 index 0000000000000..31262fd3ddecc --- /dev/null +++ b/.github/workflows/cron-translations.yml @@ -0,0 +1,47 @@ +on: + schedule: + - cron: "7 0 * * *" # every day at 0:07 UTC + +name: Pull translations from Crowdin + +jobs: + crowdin_pull: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: download from crowdin + uses: docker://jonasfranz/crowdin + env: + CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} + PLUGIN_DOWNLOAD: true + PLUGIN_EXPORT_DIR: options/locale/ + PLUGIN_IGNORE_BRANCH: true + PLUGIN_PROJECT_IDENTIFIER: gitea + - name: update locales + run: ./build/update-locales.sh + - name: push translations to repo + uses: appleboy/git-push-action@v0.0.2 + with: + author_email: "teabot@gitea.io" + author_name: GiteaBot + branch: main + commit: true + commit_message: "[skip ci] Updated translations via Crowdin" + remote: "git@github.com:go-gitea/gitea.git" + ssh_key: ${{ secrets.DEPLOY_KEY }} + crowdin_push: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: push translations to crowdin + uses: docker://jonasfranz/crowdin + env: + CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} + PLUGIN_UPLOAD: true + PLUGIN_IGNORE_BRANCH: true + PLUGIN_PROJECT_IDENTIFIER: gitea + PLUGIN_FILES: | + locale_en-US.ini: options/locale/locale_en-US.ini + PLUGIN_BRANCH: main diff --git a/cmd/web.go b/cmd/web.go index 11620c6b0063b..e451cf7dfa4fe 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -24,7 +24,6 @@ import ( "github.com/felixge/fgprof" "github.com/urfave/cli" - ini "gopkg.in/ini.v1" ) // PIDFile could be set from build tag @@ -223,9 +222,10 @@ func setPort(port string) error { defaultLocalURL += ":" + setting.HTTPPort + "/" // Save LOCAL_ROOT_URL if port changed - setting.CreateOrAppendToCustomConf("server.LOCAL_ROOT_URL", func(cfg *ini.File) { - cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL) - }) + setting.CfgProvider.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL) + if err := setting.CfgProvider.Save(); err != nil { + return fmt.Errorf("Failed to save config file: %v", err) + } } return nil } diff --git a/contrib/upgrade.sh b/contrib/upgrade.sh index 2d15f17332077..4b166a02a0dfd 100755 --- a/contrib/upgrade.sh +++ b/contrib/upgrade.sh @@ -10,6 +10,15 @@ # upgrade.sh 1.15.10 # giteahome=/opt/gitea giteaconf=$giteahome/app.ini upgrade.sh +# Check if gitea service is running +if ! pidof gitea &> /dev/null; then + echo "Error: gitea is not running." + exit 1 +fi + +# Continue with rest of the script if gitea is running +echo "Gitea is running. Continuing with rest of script..." + # apply variables from environment : "${giteabin:="/usr/local/bin/gitea"}" : "${giteahome:="/var/lib/gitea"}" diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index bf9d6d0d16418..c7c7cea90f0fb 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -16,7 +16,6 @@ import ( _ "code.gitea.io/gitea/models" "github.com/stretchr/testify/assert" - "gopkg.in/ini.v1" ) func TestMain(m *testing.M) { @@ -27,7 +26,7 @@ func TestMain(m *testing.M) { func TestBleveSearchIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - setting.CfgProvider = ini.Empty() + setting.CfgProvider = setting.NewEmptyConfigProvider() tmpIndexerDir := t.TempDir() diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index 50a5fade789a1..8d9b4e36d9b81 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -18,7 +18,6 @@ import ( _ "code.gitea.io/gitea/models" "github.com/stretchr/testify/assert" - "gopkg.in/ini.v1" ) func TestMain(m *testing.M) { @@ -29,7 +28,7 @@ func TestMain(m *testing.M) { func TestRepoStatsIndex(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - setting.CfgProvider = ini.Empty() + setting.CfgProvider = setting.NewEmptyConfigProvider() setting.LoadQueueSettings() diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 0244a8d06ed64..92c8c97fe9528 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -4,20 +4,157 @@ package setting import ( + "fmt" + "os" + "path/filepath" + "strings" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ini "gopkg.in/ini.v1" ) +type ConfigSection interface { + Name() string + MapTo(interface{}) error + HasKey(key string) bool + NewKey(name, value string) (*ini.Key, error) + Key(key string) *ini.Key + Keys() []*ini.Key + ChildSections() []*ini.Section +} + // ConfigProvider represents a config provider type ConfigProvider interface { - Section(section string) *ini.Section - NewSection(name string) (*ini.Section, error) - GetSection(name string) (*ini.Section, error) + Section(section string) ConfigSection + NewSection(name string) (ConfigSection, error) + GetSection(name string) (ConfigSection, error) + DeleteSection(name string) error + Save() error +} + +type iniFileConfigProvider struct { + *ini.File + filepath string // the ini file path + newFile bool // whether the file has not existed previously + allowEmpty bool // whether not finding configuration files is allowed (only true for the tests) +} + +// NewEmptyConfigProvider create a new empty config provider +func NewEmptyConfigProvider() ConfigProvider { + cp, _ := newConfigProviderFromData("") + return cp +} + +// newConfigProviderFromData this function is only for testing +func newConfigProviderFromData(configContent string) (ConfigProvider, error) { + var cfg *ini.File + var err error + if configContent == "" { + cfg = ini.Empty() + } else { + cfg, err = ini.Load(strings.NewReader(configContent)) + if err != nil { + return nil, err + } + } + cfg.NameMapper = ini.SnackCase + return &iniFileConfigProvider{ + File: cfg, + newFile: true, + }, nil +} + +// newConfigProviderFromFile load configuration from file. +// NOTE: do not print any log except error. +func newConfigProviderFromFile(customConf string, allowEmpty bool, extraConfig string) (*iniFileConfigProvider, error) { + cfg := ini.Empty() + newFile := true + + if customConf != "" { + isFile, err := util.IsFile(customConf) + if err != nil { + return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", customConf, err) + } + if isFile { + if err := cfg.Append(customConf); err != nil { + return nil, fmt.Errorf("failed to load custom conf '%s': %v", customConf, err) + } + newFile = false + } + } + + if newFile && !allowEmpty { + return nil, fmt.Errorf("unable to find configuration file: %q, please ensure you are running in the correct environment or set the correct configuration file with -c", CustomConf) + } + + if extraConfig != "" { + if err := cfg.Append([]byte(extraConfig)); err != nil { + return nil, fmt.Errorf("unable to append more config: %v", err) + } + } + + cfg.NameMapper = ini.SnackCase + return &iniFileConfigProvider{ + File: cfg, + filepath: customConf, + newFile: newFile, + allowEmpty: allowEmpty, + }, nil +} + +func (p *iniFileConfigProvider) Section(section string) ConfigSection { + return p.File.Section(section) +} + +func (p *iniFileConfigProvider) NewSection(name string) (ConfigSection, error) { + return p.File.NewSection(name) +} + +func (p *iniFileConfigProvider) GetSection(name string) (ConfigSection, error) { + return p.File.GetSection(name) +} + +func (p *iniFileConfigProvider) DeleteSection(name string) error { + p.File.DeleteSection(name) + return nil +} + +// Save save the content into file +func (p *iniFileConfigProvider) Save() error { + if p.filepath == "" { + if !p.allowEmpty { + return fmt.Errorf("custom config path must not be empty") + } + return nil + } + + if p.newFile { + if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil { + return fmt.Errorf("failed to create '%s': %v", CustomConf, err) + } + } + if err := p.SaveTo(p.filepath); err != nil { + return fmt.Errorf("failed to save '%s': %v", p.filepath, err) + } + + // Change permissions to be more restrictive + fi, err := os.Stat(CustomConf) + if err != nil { + return fmt.Errorf("failed to determine current conf file permissions: %v", err) + } + + if fi.Mode().Perm() > 0o600 { + if err = os.Chmod(CustomConf, 0o600); err != nil { + log.Warn("Failed changing conf file permissions to -rw-------. Consider changing them manually.") + } + } + return nil } // a file is an implementation ConfigProvider and other implementations are possible, i.e. from docker, k8s, … -var _ ConfigProvider = &ini.File{} +var _ ConfigProvider = &iniFileConfigProvider{} func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting interface{}) { if err := rootCfg.Section(sectionName).MapTo(setting); err != nil { diff --git a/modules/setting/cron_test.go b/modules/setting/cron_test.go index be97e59bd9a7e..8d58cf8b48675 100644 --- a/modules/setting/cron_test.go +++ b/modules/setting/cron_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - ini "gopkg.in/ini.v1" ) func Test_getCronSettings(t *testing.T) { @@ -23,11 +22,11 @@ func Test_getCronSettings(t *testing.T) { iniStr := ` [cron.test] -Base = true -Second = white rabbit -Extend = true +BASE = true +SECOND = white rabbit +EXTEND = true ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) extended := &Extended{ diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index e04cde100b683..1b659dd22b030 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -9,8 +9,6 @@ import ( "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" - - ini "gopkg.in/ini.v1" ) // LFS represents the configuration for Git LFS @@ -38,8 +36,7 @@ func loadLFSFrom(rootCfg ConfigProvider) { // DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version // if these are removed, the warning will not be shown deprecatedSetting(rootCfg, "server", "LFS_CONTENT_PATH", "lfs", "PATH", "v1.19.0") - lfsSec.Key("PATH").MustString( - sec.Key("LFS_CONTENT_PATH").String()) + lfsSec.Key("PATH").MustString(sec.Key("LFS_CONTENT_PATH").String()) LFS.Storage = getStorage(rootCfg, "lfs", storageType, lfsSec) @@ -62,9 +59,11 @@ func loadLFSFrom(rootCfg ConfigProvider) { } // Save secret - CreateOrAppendToCustomConf("server.LFS_JWT_SECRET", func(cfg *ini.File) { - cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64) - }) + sec.Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64) + if err := rootCfg.Save(); err != nil { + log.Fatal("Error saving JWT Secret for custom config: %v", err) + return + } } } } diff --git a/modules/setting/log.go b/modules/setting/log.go index 1ff710073e44f..d9a9e5af8fd5c 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -15,8 +15,6 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" - - ini "gopkg.in/ini.v1" ) var ( @@ -131,12 +129,12 @@ type LogDescription struct { SubLogDescriptions []SubLogDescription } -func getLogLevel(section *ini.Section, key string, defaultValue log.Level) log.Level { +func getLogLevel(section ConfigSection, key string, defaultValue log.Level) log.Level { value := section.Key(key).MustString(defaultValue.String()) return log.FromString(value) } -func getStacktraceLogLevel(section *ini.Section, key, defaultValue string) string { +func getStacktraceLogLevel(section ConfigSection, key, defaultValue string) string { value := section.Key(key).MustString(defaultValue) return log.FromString(value).String() } @@ -165,7 +163,7 @@ func loadLogFrom(rootCfg ConfigProvider) { Log.EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) } -func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) { +func generateLogConfig(sec ConfigSection, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) { level := getLogLevel(sec, "LEVEL", Log.Level) levelName = level.String() stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel) diff --git a/modules/setting/mailer_test.go b/modules/setting/mailer_test.go index 4cfd6142be73e..f65dbaf8f57bd 100644 --- a/modules/setting/mailer_test.go +++ b/modules/setting/mailer_test.go @@ -7,11 +7,10 @@ import ( "testing" "github.com/stretchr/testify/assert" - ini "gopkg.in/ini.v1" ) func Test_loadMailerFrom(t *testing.T) { - iniFile := ini.Empty() + iniFile := NewEmptyConfigProvider() kases := map[string]*Mailer{ "smtp.mydomain.com": { SMTPAddr: "smtp.mydomain.com", diff --git a/modules/setting/markup.go b/modules/setting/markup.go index b71a902be65f5..969e30e888f8d 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -8,8 +8,6 @@ import ( "strings" "code.gitea.io/gitea/modules/log" - - "gopkg.in/ini.v1" ) // ExternalMarkupRenderers represents the external markup renderers @@ -82,7 +80,7 @@ func loadMarkupFrom(rootCfg ConfigProvider) { } } -func newMarkupSanitizer(name string, sec *ini.Section) { +func newMarkupSanitizer(name string, sec ConfigSection) { rule, ok := createMarkupSanitizerRule(name, sec) if ok { if strings.HasPrefix(name, "sanitizer.") { @@ -99,7 +97,7 @@ func newMarkupSanitizer(name string, sec *ini.Section) { } } -func createMarkupSanitizerRule(name string, sec *ini.Section) (MarkupSanitizerRule, bool) { +func createMarkupSanitizerRule(name string, sec ConfigSection) (MarkupSanitizerRule, bool) { var rule MarkupSanitizerRule ok := false @@ -141,7 +139,7 @@ func createMarkupSanitizerRule(name string, sec *ini.Section) (MarkupSanitizerRu return rule, true } -func newMarkupRenderer(name string, sec *ini.Section) { +func newMarkupRenderer(name string, sec ConfigSection) { extensionReg := regexp.MustCompile(`\.\w`) extensions := sec.Key("FILE_EXTENSIONS").Strings(",") diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 44f5568ef4b19..4dab468c1029c 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -4,12 +4,12 @@ package setting import ( + "encoding/base64" "math" "path/filepath" + "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" - - "gopkg.in/ini.v1" ) // OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data @@ -80,7 +80,7 @@ func loadOAuth2ClientFrom(rootCfg ConfigProvider) { } } -func parseScopes(sec *ini.Section, name string) []string { +func parseScopes(sec ConfigSection, name string) []string { parts := sec.Key(name).Strings(" ") scopes := make([]string, 0, len(parts)) for _, scope := range parts { @@ -119,4 +119,19 @@ func loadOAuth2From(rootCfg ConfigProvider) { if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) { OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile) } + + key := make([]byte, 32) + n, err := base64.RawURLEncoding.Decode(key, []byte(OAuth2.JWTSecretBase64)) + if err != nil || n != 32 { + key, err = generate.NewJwtSecret() + if err != nil { + log.Fatal("error generating JWT secret: %v", err) + } + + secretBase64 := base64.RawURLEncoding.EncodeToString(key) + rootCfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64) + if err := rootCfg.Save(); err != nil { + log.Fatal("save oauth2.JWT_SECRET failed: %v", err) + } + } } diff --git a/modules/setting/packages.go b/modules/setting/packages.go index ac0ad62bca3d1..89601c3b99043 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/modules/log" "github.com/dustin/go-humanize" - ini "gopkg.in/ini.v1" ) // Package registry settings @@ -86,7 +85,7 @@ func loadPackagesFrom(rootCfg ConfigProvider) { Packages.LimitSizeVagrant = mustBytes(sec, "LIMIT_SIZE_VAGRANT") } -func mustBytes(section *ini.Section, key string) int64 { +func mustBytes(section ConfigSection, key string) int64 { const noLimit = "-1" value := section.Key(key).MustString(noLimit) diff --git a/modules/setting/queue.go b/modules/setting/queue.go index bd4bf48e33095..8c37e538bbe05 100644 --- a/modules/setting/queue.go +++ b/modules/setting/queue.go @@ -10,8 +10,6 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" - - ini "gopkg.in/ini.v1" ) // QueueSettings represent the settings for a queue from the ini @@ -195,7 +193,7 @@ func handleOldLengthConfiguration(rootCfg ConfigProvider, queueName, oldSection, // toDirectlySetKeysSet returns a set of keys directly set by this section // Note: we cannot use section.HasKey(...) as that will immediately set the Key if a parent section has the Key // but this section does not. -func toDirectlySetKeysSet(section *ini.Section) container.Set[string] { +func toDirectlySetKeysSet(section ConfigSection) container.Set[string] { sections := make(container.Set[string]) for _, key := range section.Keys() { sections.Add(key.Name()) diff --git a/modules/setting/security.go b/modules/setting/security.go index b9841cdb95a53..ce2e7711f1e7e 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -11,8 +11,6 @@ import ( "code.gitea.io/gitea/modules/auth/password/hash" "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" - - ini "gopkg.in/ini.v1" ) var ( @@ -43,7 +41,7 @@ var ( // loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set // If the secret is loaded from uriKey (file), the file should be non-empty, to guarantee the behavior stable and clear. -func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string { +func loadSecret(sec ConfigSection, uriKey, verbatimKey string) string { // don't allow setting both URI and verbatim string uri := sec.Key(uriKey).String() verbatim := sec.Key(verbatimKey).String() @@ -84,16 +82,17 @@ func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string { } // generateSaveInternalToken generates and saves the internal token to app.ini -func generateSaveInternalToken() { +func generateSaveInternalToken(rootCfg ConfigProvider) { token, err := generate.NewInternalToken() if err != nil { log.Fatal("Error generate internal token: %v", err) } InternalToken = token - CreateOrAppendToCustomConf("security.INTERNAL_TOKEN", func(cfg *ini.File) { - cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token) - }) + rootCfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token) + if err := rootCfg.Save(); err != nil { + log.Fatal("Error saving internal token: %v", err) + } } func loadSecurityFrom(rootCfg ConfigProvider) { @@ -141,7 +140,7 @@ func loadSecurityFrom(rootCfg ConfigProvider) { if InstallLock && InternalToken == "" { // if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate // some users do cluster deployment, they still depend on this auto-generating behavior. - generateSaveInternalToken() + generateSaveInternalToken(rootCfg) } cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",") diff --git a/modules/setting/setting.go b/modules/setting/setting.go index e1a57615a8e9a..7a1b7d17a64dc 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -18,9 +18,6 @@ import ( "code.gitea.io/gitea/modules/auth/password/hash" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/user" - "code.gitea.io/gitea/modules/util" - - ini "gopkg.in/ini.v1" ) // settings @@ -208,17 +205,29 @@ func PrepareAppDataPath() error { // InitProviderFromExistingFile initializes config provider from an existing config file (app.ini) func InitProviderFromExistingFile() { - CfgProvider = newFileProviderFromConf(CustomConf, false, "") + var err error + CfgProvider, err = newConfigProviderFromFile(CustomConf, false, "") + if err != nil { + log.Fatal("InitProviderFromExistingFile: %v", err) + } } // InitProviderAllowEmpty initializes config provider from file, it's also fine that if the config file (app.ini) doesn't exist func InitProviderAllowEmpty() { - CfgProvider = newFileProviderFromConf(CustomConf, true, "") + var err error + CfgProvider, err = newConfigProviderFromFile(CustomConf, true, "") + if err != nil { + log.Fatal("InitProviderAllowEmpty: %v", err) + } } // InitProviderAndLoadCommonSettingsForTest initializes config provider and load common setttings for tests func InitProviderAndLoadCommonSettingsForTest(extraConfigs ...string) { - CfgProvider = newFileProviderFromConf(CustomConf, true, strings.Join(extraConfigs, "\n")) + var err error + CfgProvider, err = newConfigProviderFromFile(CustomConf, true, strings.Join(extraConfigs, "\n")) + if err != nil { + log.Fatal("InitProviderAndLoadCommonSettingsForTest: %v", err) + } loadCommonSettingsFrom(CfgProvider) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) @@ -229,33 +238,6 @@ func InitProviderAndLoadCommonSettingsForTest(extraConfigs ...string) { PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy") } -// newFileProviderFromConf initializes configuration context. -// NOTE: do not print any log except error. -func newFileProviderFromConf(customConf string, allowEmpty bool, extraConfig string) *ini.File { - cfg := ini.Empty() - - isFile, err := util.IsFile(customConf) - if err != nil { - log.Error("Unable to check if %s is a file. Error: %v", customConf, err) - } - if isFile { - if err := cfg.Append(customConf); err != nil { - log.Fatal("Failed to load custom conf '%s': %v", customConf, err) - } - } else if !allowEmpty { - log.Fatal("Unable to find configuration file: %q.\nEnsure you are running in the correct environment or set the correct configuration file with -c.", CustomConf) - } // else: no config file, a config file might be created at CustomConf later (might not) - - if extraConfig != "" { - if err = cfg.Append([]byte(extraConfig)); err != nil { - log.Fatal("Unable to append more config: %v", err) - } - } - - cfg.NameMapper = ini.SnackCase - return cfg -} - // LoadCommonSettings loads common configurations from a configuration provider. func LoadCommonSettings() { loadCommonSettingsFrom(CfgProvider) @@ -319,51 +301,6 @@ func loadRunModeFrom(rootCfg ConfigProvider) { } } -// CreateOrAppendToCustomConf creates or updates the custom config. -// Use the callback to set individual values. -func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) { - if CustomConf == "" { - log.Error("Custom config path must not be empty") - return - } - - cfg := ini.Empty() - isFile, err := util.IsFile(CustomConf) - if err != nil { - log.Error("Unable to check if %s is a file. Error: %v", CustomConf, err) - } - if isFile { - if err := cfg.Append(CustomConf); err != nil { - log.Error("failed to load custom conf %s: %v", CustomConf, err) - return - } - } - - callback(cfg) - - if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil { - log.Fatal("failed to create '%s': %v", CustomConf, err) - return - } - if err := cfg.SaveTo(CustomConf); err != nil { - log.Fatal("error saving to custom config: %v", err) - } - log.Info("Settings for %s saved to: %q", purpose, CustomConf) - - // Change permissions to be more restrictive - fi, err := os.Stat(CustomConf) - if err != nil { - log.Error("Failed to determine current conf file permissions: %v", err) - return - } - - if fi.Mode().Perm() > 0o600 { - if err = os.Chmod(CustomConf, 0o600); err != nil { - log.Warn("Failed changing conf file permissions to -rw-------. Consider changing them manually.") - } - } -} - // LoadSettings initializes the settings for normal start up func LoadSettings() { loadDBSetting(CfgProvider) diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 50d4c8439e2b1..6da52807ecdc5 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -6,15 +6,13 @@ package setting import ( "path/filepath" "reflect" - - ini "gopkg.in/ini.v1" ) // Storage represents configuration of storages type Storage struct { Type string Path string - Section *ini.Section + Section ConfigSection ServeDirect bool } @@ -30,7 +28,7 @@ func (s *Storage) MapTo(v interface{}) error { return nil } -func getStorage(rootCfg ConfigProvider, name, typ string, targetSec *ini.Section) Storage { +func getStorage(rootCfg ConfigProvider, name, typ string, targetSec ConfigSection) Storage { const sectionName = "storage" sec := rootCfg.Section(sectionName) @@ -52,7 +50,7 @@ func getStorage(rootCfg ConfigProvider, name, typ string, targetSec *ini.Section storage.Section = targetSec storage.Type = typ - overrides := make([]*ini.Section, 0, 3) + overrides := make([]ConfigSection, 0, 3) nameSec, err := rootCfg.GetSection(sectionName + "." + name) if err == nil { overrides = append(overrides, nameSec) diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go index 7737d233b9b06..9c51bbc081c2d 100644 --- a/modules/setting/storage_test.go +++ b/modules/setting/storage_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - ini "gopkg.in/ini.v1" ) func Test_getStorageCustomType(t *testing.T) { @@ -20,7 +19,7 @@ MINIO_BUCKET = gitea-attachment STORAGE_TYPE = minio MINIO_ENDPOINT = my_minio:9000 ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) sec := cfg.Section("attachment") @@ -43,7 +42,7 @@ MINIO_BUCKET = gitea-attachment [storage.minio] MINIO_BUCKET = gitea ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) sec := cfg.Section("attachment") @@ -65,7 +64,7 @@ MINIO_BUCKET = gitea-minio [storage] MINIO_BUCKET = gitea ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) sec := cfg.Section("attachment") @@ -88,7 +87,7 @@ MINIO_BUCKET = gitea [storage] STORAGE_TYPE = local ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) sec := cfg.Section("attachment") @@ -100,7 +99,7 @@ STORAGE_TYPE = local } func Test_getStorageGetDefaults(t *testing.T) { - cfg, err := ini.Load([]byte("")) + cfg, err := newConfigProviderFromData("") assert.NoError(t, err) sec := cfg.Section("attachment") @@ -121,7 +120,7 @@ MINIO_BUCKET = gitea-attachment [storage] MINIO_BUCKET = gitea-storage ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) { @@ -155,7 +154,7 @@ STORAGE_TYPE = lfs [storage.lfs] MINIO_BUCKET = gitea-storage ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) { @@ -179,7 +178,7 @@ func Test_getStorageInheritStorageType(t *testing.T) { [storage] STORAGE_TYPE = minio ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) sec := cfg.Section("attachment") @@ -194,7 +193,7 @@ func Test_getStorageInheritNameSectionType(t *testing.T) { [storage.attachments] STORAGE_TYPE = minio ` - cfg, err := ini.Load([]byte(iniStr)) + cfg, err := newConfigProviderFromData(iniStr) assert.NoError(t, err) sec := cfg.Section("attachment") diff --git a/modules/timeutil/datetime.go b/modules/timeutil/datetime.go index 02275bca0c325..80b96fa656be3 100644 --- a/modules/timeutil/datetime.go +++ b/modules/timeutil/datetime.go @@ -7,19 +7,54 @@ import ( "fmt" "html" "html/template" + "time" ) -// DateTime renders an absolute time HTML given a time as a string -func DateTime(format, datetime, fallback string) template.HTML { - datetimeEscaped := html.EscapeString(datetime) - fallbackEscaped := html.EscapeString(fallback) +// DateTime renders an absolute time HTML element by datetime. +func DateTime(format string, datetime any) template.HTML { + if p, ok := datetime.(*time.Time); ok { + datetime = *p + } + if p, ok := datetime.(*TimeStamp); ok { + datetime = *p + } + switch v := datetime.(type) { + case TimeStamp: + datetime = v.AsTime() + case int: + datetime = TimeStamp(v).AsTime() + case int64: + datetime = TimeStamp(v).AsTime() + } + + var datetimeEscaped, textEscaped string + switch v := datetime.(type) { + case nil: + return "N/A" + case string: + datetimeEscaped = html.EscapeString(v) + textEscaped = datetimeEscaped + case time.Time: + if v.IsZero() || v.Unix() == 0 { + return "N/A" + } + datetimeEscaped = html.EscapeString(v.Format(time.RFC3339)) + if format == "full" { + textEscaped = html.EscapeString(v.Format("2006-01-02 15:04:05 -07:00")) + } else { + textEscaped = html.EscapeString(v.Format("2006-01-02")) + } + default: + panic(fmt.Sprintf("Unsupported time type %T", datetime)) + } + switch format { case "short": - return template.HTML(fmt.Sprintf(`%s`, datetimeEscaped, fallbackEscaped)) + return template.HTML(fmt.Sprintf(`%s`, datetimeEscaped, textEscaped)) case "long": - return template.HTML(fmt.Sprintf(`%s`, datetimeEscaped, fallbackEscaped)) + return template.HTML(fmt.Sprintf(`%s`, datetimeEscaped, textEscaped)) case "full": - return template.HTML(fmt.Sprintf(`%s`, datetimeEscaped, fallbackEscaped)) + return template.HTML(fmt.Sprintf(`%s`, datetimeEscaped, textEscaped)) } - return template.HTML("error in DateTime") + panic(fmt.Sprintf("Unsupported format %s", format)) } diff --git a/modules/timeutil/datetime_test.go b/modules/timeutil/datetime_test.go new file mode 100644 index 0000000000000..a5639b34f19ae --- /dev/null +++ b/modules/timeutil/datetime_test.go @@ -0,0 +1,45 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package timeutil + +import ( + "testing" + "time" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestDateTime(t *testing.T) { + oldTz := setting.DefaultUILocation + setting.DefaultUILocation, _ = time.LoadLocation("America/New_York") + defer func() { + setting.DefaultUILocation = oldTz + }() + + refTimeStr := "2018-01-01T00:00:00Z" + refTime, _ := time.Parse(time.RFC3339, refTimeStr) + refTimeStamp := TimeStamp(refTime.Unix()) + + assert.EqualValues(t, "N/A", DateTime("short", nil)) + assert.EqualValues(t, "N/A", DateTime("short", 0)) + assert.EqualValues(t, "N/A", DateTime("short", time.Time{})) + assert.EqualValues(t, "N/A", DateTime("short", TimeStamp(0))) + + actual := DateTime("short", "invalid") + assert.EqualValues(t, `invalid`, actual) + + actual = DateTime("short", refTimeStr) + assert.EqualValues(t, `2018-01-01T00:00:00Z`, actual) + + actual = DateTime("short", refTime) + assert.EqualValues(t, `2018-01-01`, actual) + + actual = DateTime("short", refTimeStamp) + assert.EqualValues(t, `2017-12-31`, actual) + + actual = DateTime("full", refTimeStamp) + assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) +} diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index 4aee814ecdc68..04fcff54a3384 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -115,7 +115,7 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string { } func timeSinceUnix(then, now time.Time, lang translation.Locale) template.HTML { - friendlyText := then.Format("2006-01-02 15:04:05 +07:00") + friendlyText := then.Format("2006-01-02 15:04:05 -07:00") // document: https://github.com/github/relative-time-element attrs := `tense="past"` diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 09b0af0dec36e..f0c8efda741fc 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -462,6 +462,7 @@ team_invite.text_3=Σημείωση: Αυτή η πρόσκληση προορι [modal] yes=Ναι no=Όχι +confirm=Επιβεβαίωση cancel=Ακύρωση modify=Ενημέρωση @@ -1622,7 +1623,10 @@ pulls.tab_files=Αρχεία Με Αλλαγές pulls.reopen_to_merge=Παρακαλώ ανοίξτε ξανά αυτό το pull request για να εκτελέσετε μια συγχώνευση. pulls.cant_reopen_deleted_branch=Αυτό το pull request δεν μπορεί να ανοίξει ξανά επειδή ο κλάδος διαγράφηκε. pulls.merged=Συγχωνευμένο +pulls.merged_success=Το pull request συγχωνεύτηκε και έκλεισε επιτυχώς +pulls.closed=Το pull request έκλεισε pulls.manually_merged=Συγχωνεύτηκαν χειροκίνητα +pulls.merged_info_text=Ο κλάδος %s μπορεί τώρα να διαγραφεί. pulls.is_closed=Το pull request έχει κλείσει. pulls.title_wip_desc=`Ξεκινήστε τον τίτλο με %s για να αποτρέψετε την τυχαία συγχώνευση του pull request.` pulls.cannot_merge_work_in_progress=Αυτό το pull request επισημαίνεται ως μια εργασία σε εξέλιξη. @@ -3414,4 +3418,7 @@ runs.no_matching_runner_helper=Δε ταιριάζει εκτελεστής: %s need_approval_desc=Πρέπει να εγκριθεί η εκτέλεση ροών εργασίας για pull request από fork. [projects] +type-1.display_name=Ατομικό Έργο +type-2.display_name=Έργο Αποθετηρίου +type-3.display_name=Έργο Οργανισμού diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index e70cb1ea50de4..41f987bb72cec 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -284,7 +284,7 @@ show_only_public=只显示公开的 issues.in_your_repos=在您的仓库中 [explore] -repos=仓库管理 +repos=仓库 users=用户 organizations=组织管理 search=搜索 diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 287136e64c2b9..92a06e7c14a03 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -966,7 +966,7 @@ func SignInOAuthCallback(ctx *context.Context) { } overwriteDefault := &user_model.CreateUserOverwriteOptions{ - IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm), + IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm && !setting.Service.RegisterManualConfirm), } source := authSource.Cfg.(*oauth2.Source) diff --git a/routers/web/feed/branch.go b/routers/web/feed/branch.go new file mode 100644 index 0000000000000..22b6e2f14b0ea --- /dev/null +++ b/routers/web/feed/branch.go @@ -0,0 +1,50 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package feed + +import ( + "fmt" + "strings" + "time" + + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + + "github.com/gorilla/feeds" +) + +// ShowBranchFeed shows tags and/or releases on the repo as RSS / Atom feed +func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType string) { + commits, err := ctx.Repo.Commit.CommitsByRange(0, 10) + if err != nil { + ctx.ServerError("ShowBranchFeed", err) + return + } + + title := fmt.Sprintf("Latest commits for branch %s", ctx.Repo.BranchName) + link := &feeds.Link{Href: repo.HTMLURL() + "/" + ctx.Repo.BranchNameSubURL()} + + feed := &feeds.Feed{ + Title: title, + Link: link, + Description: repo.Description, + Created: time.Now(), + } + + for _, commit := range commits { + feed.Items = append(feed.Items, &feeds.Item{ + Id: commit.ID.String(), + Title: strings.TrimSpace(strings.Split(commit.Message(), "\n")[0]), + Link: &feeds.Link{Href: repo.HTMLURL() + "/commit/" + commit.ID.String()}, + Author: &feeds.Author{ + Name: commit.Author.Name, + Email: commit.Author.Email, + }, + Description: commit.Message(), + Content: commit.Message(), + }) + } + + writeFeed(ctx, feed, formatType) +} diff --git a/routers/web/feed/file.go b/routers/web/feed/file.go new file mode 100644 index 0000000000000..6a8d0c454d8ce --- /dev/null +++ b/routers/web/feed/file.go @@ -0,0 +1,56 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package feed + +import ( + "fmt" + "strings" + "time" + + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/util" + + "github.com/gorilla/feeds" +) + +// ShowFileFeed shows tags and/or releases on the repo as RSS / Atom feed +func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string) { + fileName := ctx.Repo.TreePath + if len(fileName) == 0 { + return + } + commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(ctx.Repo.RefName, fileName, 1) + if err != nil { + ctx.ServerError("ShowBranchFeed", err) + return + } + + title := fmt.Sprintf("Latest commits for file %s", ctx.Repo.TreePath) + + link := &feeds.Link{Href: repo.HTMLURL() + "/" + ctx.Repo.BranchNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)} + + feed := &feeds.Feed{ + Title: title, + Link: link, + Description: repo.Description, + Created: time.Now(), + } + + for _, commit := range commits { + feed.Items = append(feed.Items, &feeds.Item{ + Id: commit.ID.String(), + Title: strings.TrimSpace(strings.Split(commit.Message(), "\n")[0]), + Link: &feeds.Link{Href: repo.HTMLURL() + "/commit/" + commit.ID.String()}, + Author: &feeds.Author{ + Name: commit.Author.Name, + Email: commit.Author.Email, + }, + Description: commit.Message(), + Content: commit.Message(), + }) + } + + writeFeed(ctx, feed, formatType) +} diff --git a/routers/web/feed/render.go b/routers/web/feed/render.go new file mode 100644 index 0000000000000..8931dae8cce6d --- /dev/null +++ b/routers/web/feed/render.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package feed + +import ( + "code.gitea.io/gitea/modules/context" +) + +// RenderBranchFeed render format for branch or file +func RenderBranchFeed(ctx *context.Context) { + _, _, showFeedType := GetFeedType(ctx.Params(":reponame"), ctx.Req) + if ctx.Repo.TreePath == "" { + ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType) + } else { + ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType) + } +} diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index cd32d99533dc2..a01bb4f28eef9 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -32,43 +32,31 @@ import ( "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" repo_service "code.gitea.io/gitea/services/repository" + + "github.com/go-chi/cors" ) -// httpBase implementation git smart HTTP protocol -func httpBase(ctx *context.Context) (h *serviceHandler) { +func HTTPGitEnabledHandler(ctx *context.Context) { if setting.Repository.DisableHTTPGit { ctx.Resp.WriteHeader(http.StatusForbidden) - _, err := ctx.Resp.Write([]byte("Interacting with repositories by HTTP protocol is not allowed")) - if err != nil { - log.Error(err.Error()) - } - return + _, _ = ctx.Resp.Write([]byte("Interacting with repositories by HTTP protocol is not allowed")) } +} - if len(setting.Repository.AccessControlAllowOrigin) > 0 { - allowedOrigin := setting.Repository.AccessControlAllowOrigin - // Set CORS headers for browser-based git clients - ctx.Resp.Header().Set("Access-Control-Allow-Origin", allowedOrigin) - ctx.Resp.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, User-Agent") - - // Handle preflight OPTIONS request - if ctx.Req.Method == "OPTIONS" { - if allowedOrigin == "*" { - ctx.Status(http.StatusOK) - } else if allowedOrigin == "null" { - ctx.Status(http.StatusForbidden) - } else { - origin := ctx.Req.Header.Get("Origin") - if len(origin) > 0 && origin == allowedOrigin { - ctx.Status(http.StatusOK) - } else { - ctx.Status(http.StatusForbidden) - } - } - return - } +func CorsHandler() func(next http.Handler) http.Handler { + if setting.Repository.AccessControlAllowOrigin != "" { + return cors.Handler(cors.Options{ + AllowedOrigins: []string{setting.Repository.AccessControlAllowOrigin}, + AllowedHeaders: []string{"Content-Type", "Authorization", "User-Agent"}, + }) } + return func(next http.Handler) http.Handler { + return next + } +} +// httpBase implementation git smart HTTP protocol +func httpBase(ctx *context.Context) (h *serviceHandler) { username := ctx.Params(":username") reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git") diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 6a5ebd5dadcba..689994c146cfd 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -29,8 +29,9 @@ import ( ) const ( - tplReleases base.TplName = "repo/release/list" - tplReleaseNew base.TplName = "repo/release/new" + tplReleasesList base.TplName = "repo/release/list" + tplReleaseNew base.TplName = "repo/release/new" + tplTagsList base.TplName = "repo/tag/list" ) // calReleaseNumCommitsBehind calculates given release has how many commits behind release target. @@ -58,16 +59,19 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model // Releases render releases list page func Releases(ctx *context.Context) { + ctx.Data["PageIsReleaseList"] = true + ctx.Data["Title"] = ctx.Tr("repo.release.releases") releasesOrTags(ctx, false) } // TagsList render tags list page func TagsList(ctx *context.Context) { + ctx.Data["PageIsTagList"] = true + ctx.Data["Title"] = ctx.Tr("repo.release.tags") releasesOrTags(ctx, true) } func releasesOrTags(ctx *context.Context, isTagList bool) { - ctx.Data["PageIsReleaseList"] = true ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch ctx.Data["IsViewBranch"] = false ctx.Data["IsViewTag"] = true @@ -75,14 +79,6 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { ctx.Data["CanCreateBranch"] = false ctx.Data["HideBranchesInDropdown"] = true - if isTagList { - ctx.Data["Title"] = ctx.Tr("repo.release.tags") - ctx.Data["PageIsTagList"] = true - } else { - ctx.Data["Title"] = ctx.Tr("repo.release.releases") - ctx.Data["PageIsTagList"] = false - } - listOptions := db.ListOptions{ Page: ctx.FormInt("page"), PageSize: ctx.FormInt("limit"), @@ -196,7 +192,11 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.HTML(http.StatusOK, tplReleases) + if isTagList { + ctx.HTML(http.StatusOK, tplTagsList) + } else { + ctx.HTML(http.StatusOK, tplReleasesList) + } } // ReleasesFeedRSS get feeds for releases in RSS format @@ -282,7 +282,7 @@ func SingleRelease(ctx *context.Context) { } ctx.Data["Releases"] = []*repo_model.Release{release} - ctx.HTML(http.StatusOK, tplReleases) + ctx.HTML(http.StatusOK, tplReleasesList) } // LatestRelease redirects to the latest release diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index f9dca91844c40..9f2770a3acb9c 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -710,7 +710,14 @@ func Home(ctx *context.Context) { if setting.Other.EnableFeed { isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req) if isFeed { - feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType) + switch { + case ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType): + feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType) + case ctx.Repo.TreePath == "": + feed.ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType) + case ctx.Repo.TreePath != "": + feed.ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType) + } return } } diff --git a/routers/web/web.go b/routers/web/web.go index 88b6777d738b7..779499889fb05 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1198,7 +1198,7 @@ func RegisterRoutes(m *web.Route) { }, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty) }, reqSignIn, context.RepoAssignment, context.UnitTypes()) - // Releases + // Tags m.Group("/{username}/{reponame}", func() { m.Group("/tags", func() { m.Get("", repo.TagsList) @@ -1207,6 +1207,12 @@ func RegisterRoutes(m *web.Route) { }, func(ctx *context.Context) { ctx.Data["EnableFeed"] = setting.Other.EnableFeed }, repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true)) + m.Post("/tags/delete", repo.DeleteTag, reqSignIn, + repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef()) + }, reqSignIn, context.RepoAssignment, context.UnitTypes()) + + // Releases + m.Group("/{username}/{reponame}", func() { m.Group("/releases", func() { m.Get("/", repo.Releases) m.Get("/tag/*", repo.SingleRelease) @@ -1224,8 +1230,6 @@ func RegisterRoutes(m *web.Route) { m.Post("/attachments", repo.UploadReleaseAttachment) m.Post("/attachments/remove", repo.DeleteAttachment) }, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, context.RepoRef()) - m.Post("/tags/delete", repo.DeleteTag, reqSignIn, - repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef()) m.Group("/releases", func() { m.Get("/edit/*", repo.EditRelease) m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost) @@ -1450,6 +1454,9 @@ func RegisterRoutes(m *web.Route) { m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick) }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) + m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) + m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) + m.Group("/src", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home) @@ -1508,7 +1515,7 @@ func RegisterRoutes(m *web.Route) { m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject) m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile) m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile) - }, ignSignInAndCsrf, context_service.UserAssignmentWeb()) + }, ignSignInAndCsrf, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb()) }) }) // ***** END: Repository ***** diff --git a/services/auth/source/oauth2/jwtsigningkey.go b/services/auth/source/oauth2/jwtsigningkey.go index 94feddbf6b6a5..ed60952ac783f 100644 --- a/services/auth/source/oauth2/jwtsigningkey.go +++ b/services/auth/source/oauth2/jwtsigningkey.go @@ -18,14 +18,12 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "github.com/golang-jwt/jwt/v4" "github.com/minio/sha256-simd" - ini "gopkg.in/ini.v1" ) // ErrInvalidAlgorithmType represents an invalid algorithm error. @@ -316,8 +314,7 @@ func InitSigningKey() error { case "HS384": fallthrough case "HS512": - key, err = loadOrCreateSymmetricKey() - + key, err = loadSymmetricKey() case "RS256": fallthrough case "RS384": @@ -332,7 +329,6 @@ func InitSigningKey() error { fallthrough case "EdDSA": key, err = loadOrCreateAsymmetricKey() - default: return ErrInvalidAlgorithmType{setting.OAuth2.JWTSigningAlgorithm} } @@ -351,22 +347,16 @@ func InitSigningKey() error { return nil } -// loadOrCreateSymmetricKey checks if the configured secret is valid. -// If it is not valid a new secret is created and saved in the configuration file. -func loadOrCreateSymmetricKey() (interface{}, error) { +// loadSymmetricKey checks if the configured secret is valid. +// If it is not valid, it will return an error. +func loadSymmetricKey() (interface{}, error) { key := make([]byte, 32) n, err := base64.RawURLEncoding.Decode(key, []byte(setting.OAuth2.JWTSecretBase64)) - if err != nil || n != 32 { - key, err = generate.NewJwtSecret() - if err != nil { - log.Fatal("error generating JWT secret: %v", err) - return nil, err - } - - setting.CreateOrAppendToCustomConf("oauth2.JWT_SECRET", func(cfg *ini.File) { - secretBase64 := base64.RawURLEncoding.EncodeToString(key) - cfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64) - }) + if err != nil { + return nil, err + } + if n != 32 { + return nil, fmt.Errorf("JWT secret must be 32 bytes long") } return key, nil diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl index f8e15eddef653..c9f7c0d516491 100644 --- a/templates/admin/auth/list.tmpl +++ b/templates/admin/auth/list.tmpl @@ -26,8 +26,8 @@ {{.Name}} {{.TypeName}} {{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} - {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}} - {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{DateTime "short" .UpdatedUnix}} + {{DateTime "short" .CreatedUnix}} {{svg "octicon-pencil"}} {{end}} diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl index 5dd63149445a0..267da00759b56 100644 --- a/templates/admin/cron.tmpl +++ b/templates/admin/cron.tmpl @@ -21,8 +21,8 @@ {{$.locale.Tr (printf "admin.dashboard.%s" .Name)}} {{.Spec}} - {{DateTime "full" (DateFmtLong .Next) (DateFmtLong .Next)}} - {{if gt .Prev.Year 1}}{{DateTime "full" (DateFmtLong .Prev) (DateFmtLong .Prev)}}{{else}}N/A{{end}} + {{DateTime "full" (DateFmtLong .Next)}} + {{if gt .Prev.Year 1}}{{DateTime "full" .Prev}}{{else}}N/A{{end}} {{.ExecTimes}} {{if eq .Status ""}}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}} diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 51b0c6850a1e7..bd6b74dd2bdf4 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -26,7 +26,7 @@ {{.ID}} {{$.locale.Tr .TrStr}} {{.Description}} - {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{DateTime "short" .CreatedUnix}} {{svg "octicon-note" 16 "view-detail"}} {{end}} diff --git a/templates/admin/org/list.tmpl b/templates/admin/org/list.tmpl index 73435fdd379d8..a400dcbc86308 100644 --- a/templates/admin/org/list.tmpl +++ b/templates/admin/org/list.tmpl @@ -41,7 +41,7 @@ {{.NumTeams}} {{.NumMembers}} {{.NumRepos}} - {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{DateTime "short" .CreatedUnix}} {{svg "octicon-pencil"}} {{end}} diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 2edcad4b7bbfd..f320878b80de9 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -65,7 +65,7 @@ {{end}} {{FileSize .CalculateBlobSize}} - {{DateTime "short" .Version.CreatedUnix.FormatLong .Version.CreatedUnix.FormatShort}} + {{DateTime "short" .Version.CreatedUnix}} {{svg "octicon-trash"}} {{end}} diff --git a/templates/admin/queue.tmpl b/templates/admin/queue.tmpl index d3052c91a937c..3de01a32ab30b 100644 --- a/templates/admin/queue.tmpl +++ b/templates/admin/queue.tmpl @@ -155,8 +155,8 @@ {{range .Queue.Workers}} {{.Workers}}{{if .IsFlusher}}{{svg "octicon-sync"}}{{end}} - {{DateTime "full" (DateFmtLong .Start) (DateFmtLong .Start)}} - {{if .HasTimeout}}{{DateTime "full" (DateFmtLong .Timeout) (DateFmtLong .Timeout)}}{{else}}-{{end}} + {{DateTime "full" .Start}} + {{if .HasTimeout}}{{DateTime "full" .Timeout}}{{else}}-{{end}} {{svg "octicon-trash"}} diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index f9a0a6ef98612..3d09f2de23973 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -80,7 +80,7 @@ {{.NumForks}} {{.NumIssues}} {{FileSize .Size}} - {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{DateTime "short" .CreatedUnix}} {{svg "octicon-trash"}} {{end}} diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl index fef7c7b27f9f0..2f76f2d3ba0ad 100644 --- a/templates/admin/user/list.tmpl +++ b/templates/admin/user/list.tmpl @@ -91,9 +91,9 @@ {{if .IsRestricted}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} {{if index $.UsersTwoFaStatus .ID}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}} {{.NumRepos}} - {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{DateTime "short" .CreatedUnix}} {{if .LastLoginUnix}} - {{DateTime "short" .LastLoginUnix.FormatLong .LastLoginUnix.FormatShort}} + {{DateTime "short" .LastLoginUnix}} {{else}} {{$.locale.Tr "admin.users.never_login"}} {{end}} diff --git a/templates/explore/organizations.tmpl b/templates/explore/organizations.tmpl index e61a72b6edba5..295818f94bde5 100644 --- a/templates/explore/organizations.tmpl +++ b/templates/explore/organizations.tmpl @@ -23,7 +23,7 @@ {{svg "octicon-link"}} {{.Website}} {{end}} - {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}} diff --git a/templates/explore/users.tmpl b/templates/explore/users.tmpl index 4cab94ee86ca8..0c1ba27448c11 100644 --- a/templates/explore/users.tmpl +++ b/templates/explore/users.tmpl @@ -18,7 +18,7 @@ {{svg "octicon-mail"}} {{.Email}} {{end}} - {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}} diff --git a/templates/package/shared/cleanup_rules/preview.tmpl b/templates/package/shared/cleanup_rules/preview.tmpl index ae1ce1b1d515b..5992ea60bea0f 100644 --- a/templates/package/shared/cleanup_rules/preview.tmpl +++ b/templates/package/shared/cleanup_rules/preview.tmpl @@ -22,7 +22,7 @@ {{.Version.Version}} {{.Creator.Name}} {{FileSize .CalculateBlobSize}} - {{DateTime "short" .Version.CreatedUnix.FormatLong .Version.CreatedUnix.FormatShort}} + {{DateTime "short" .Version.CreatedUnix}} {{else}} diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl index 36b0e8a8b3a05..3cb130851fee1 100644 --- a/templates/package/view.tmpl +++ b/templates/package/view.tmpl @@ -86,7 +86,7 @@ {{range .LatestVersions}}
{{.Version}} - {{DateTime "short" (.CreatedUnix.FormatDate) (.CreatedUnix.FormatDate)}} + {{DateTime "short" .CreatedUnix}}
{{end}} diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index 26734e304aeb7..9d15cec051bfe 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -2,7 +2,7 @@
{{template "repo/header" .}}
-

{{DateTime "long" .DateFrom .DateFrom}} - {{DateTime "long" .DateUntil .DateUntil}} +

{{DateTime "long" .DateFrom}} - {{DateTime "long" .DateUntil}}
- {{template "repo/clone_script" .}} {{end}} {{else}}
{{.locale.Tr "repo.empty_message"}}
{{end}} + {{template "repo/clone_script" .}}

diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 4db12f2c95b32..69f7f03880381 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -63,12 +63,13 @@ {{$n := len .TreeNames}} {{$l := Eval $n "-" 1}} + {{if and (eq $n 0) .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} + + {{svg "octicon-git-pull-request"}} + + {{end}} {{if eq $n 0}} - {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} - - - - {{end}} {{.locale.Tr "repo.find_file.go_to_file"}} {{end}} diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index ccbc40586a8ff..472bebb33face 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -35,7 +35,7 @@ {{else}} {{svg "octicon-calendar"}} {{if .Milestone.DeadlineString}} - {{DateTime "short" .Milestone.DeadlineString .Milestone.DeadlineString}} + {{DateTime "short" .Milestone.DeadlineString}} {{else}} {{$.locale.Tr "repo.milestones.no_due_date"}} {{end}} diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl index b2428237a0902..3a23d225c4306 100644 --- a/templates/repo/issue/milestones.tmpl +++ b/templates/repo/issue/milestones.tmpl @@ -77,7 +77,7 @@ {{else}} {{svg "octicon-calendar"}} {{if .DeadlineString}} - {{DateTime "short" .DeadlineString .DeadlineString}} + {{DateTime "short" .DeadlineString}} {{else}} {{$.locale.Tr "repo.milestones.no_due_date"}} {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 142c8153f0e20..b99e49a586342 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -295,7 +295,7 @@ {{template "shared/user/avatarlink" dict "Context" $.Context "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$.locale.Tr "repo.issues.due_date_added" (DateTime "long" .Content .Content) $createdStr | Safe}} + {{$.locale.Tr "repo.issues.due_date_added" (DateTime "long" .Content) $createdStr | Safe}} {{else if eq .Type 17}} @@ -305,8 +305,8 @@ {{template "shared/user/authorlink" .Poster}} {{$parsedDeadline := .Content | ParseDeadline}} - {{$from := DateTime "long" (index $parsedDeadline 1) (index $parsedDeadline 1)}} - {{$to := DateTime "long" (index $parsedDeadline 0) (index $parsedDeadline 0)}} + {{$from := DateTime "long" (index $parsedDeadline 1)}} + {{$to := DateTime "long" (index $parsedDeadline 0)}} {{$.locale.Tr "repo.issues.due_date_modified" $to $from $createdStr | Safe}} @@ -316,7 +316,7 @@ {{template "shared/user/avatarlink" dict "Context" $.Context "user" .Poster}} {{template "shared/user/authorlink" .Poster}} - {{$.locale.Tr "repo.issues.due_date_remove" (DateTime "long" .Content .Content) $createdStr | Safe}} + {{$.locale.Tr "repo.issues.due_date_remove" (DateTime "long" .Content) $createdStr | Safe}} {{else if eq .Type 19}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index bea56474ff27b..738e3a66fb29d 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -385,7 +385,7 @@
{{svg "octicon-calendar" 16 "gt-mr-3"}} - {{DateTime "long" .Issue.DeadlineUnix.FormatDate .Issue.DeadlineUnix.FormatDate}} + {{DateTime "long" .Issue.DeadlineUnix}}
{{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index d0e3b9cc073fc..3d596a49e2b9d 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -1,73 +1,16 @@ {{template "base/head" .}} -
+
{{template "repo/header" .}}
{{template "base/alert" .}} - - {{if .EnableFeed}} - {{svg "octicon-rss" 18}} - {{end}} - {{if (and .CanCreateRelease (not .PageIsTagList))}} + {{template "repo/sub_menu_release_tag" .}} + + {{if .CanCreateRelease}} {{.locale.Tr "repo.release.new_release"}} {{end}} - {{if .PageIsTagList}} -
- {{if gt .ReleasesNum 0}} -

-
- {{svg "octicon-tag" 16 "gt-mr-2"}}{{.locale.Tr "repo.release.tags"}} -
-

-
- - - - {{range $idx, $release := .Releases}} - - - - {{end}} - -
-

- {{.TagName}} -

-
- {{if $.Permission.CanRead $.UnitTypeCode}} - {{if .CreatedUnix}} - {{svg "octicon-clock" 16 "gt-mr-2"}}{{TimeSinceUnix .CreatedUnix $.locale}} - {{end}} - {{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}} - {{if not $.DisableDownloadSourceArchives}} - {{svg "octicon-file-zip" 16 "gt-mr-2"}}ZIP - {{svg "octicon-file-zip" 16 "gt-mr-2"}}TAR.GZ - {{end}} - {{if (and $.CanCreateRelease $release.IsTag)}} - {{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.new_release"}} - {{end}} - {{if (and ($.Permission.CanWrite $.UnitTypeCode) $release.IsTag)}} - - {{svg "octicon-trash" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.delete_tag"}} - - {{end}} - {{if (not $release.IsTag)}} - {{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.detail"}} - {{end}} - {{end}} -
-
-
- {{end}} - {{else}} +
    {{range $idx, $release := .Releases}}
  • @@ -178,7 +121,7 @@
  • {{end}}
- {{end}} + {{template "base/paginate" .}}
diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index caf049acd6fda..1a0f8f826af90 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -60,7 +60,7 @@ {{.Fingerprint}}
- {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - {{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}} + {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - {{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}}
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index a974401e80730..515854609a1eb 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -89,7 +89,7 @@ {{(MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName false).Address}} {{$.locale.Tr "repo.settings.mirror_settings.direction.pull"}} - {{DateTime "full" .Mirror.UpdatedUnix.FormatLong .Mirror.UpdatedUnix.AsTime}} + {{DateTime "full" .Mirror.UpdatedUnix}}
{{.CsrfTokenHtml}} @@ -167,7 +167,7 @@ {{$address := MirrorRemoteAddress $.Context $.Repository .GetRemoteName true}} {{$address.Address}} {{$.locale.Tr "repo.settings.mirror_settings.direction.push"}} - {{if .LastUpdateUnix}}{{DateTime "full" .LastUpdateUnix.FormatLong .LastUpdateUnix.AsTime}}{{else}}{{$.locale.Tr "never"}}{{end}} {{if .LastError}}
{{$.locale.Tr "error"}}
{{end}} + {{if .LastUpdateUnix}}{{DateTime "full" .LastUpdateUnix}}{{else}}{{$.locale.Tr "never"}}{{end}} {{if .LastError}}
{{$.locale.Tr "error"}}
{{end}} {{$.CsrfTokenHtml}} diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 9289295b1d733..2be7d47a1c8ac 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -10,7 +10,7 @@ {{svg "octicon-git-branch"}} {{.BranchesCount}} {{.locale.TrN .BranchesCount "repo.branch" "repo.branches"}} {{if $.Permission.CanRead $.UnitTypeCode}} -
+ {{end}} diff --git a/templates/repo/sub_menu_release_tag.tmpl b/templates/repo/sub_menu_release_tag.tmpl new file mode 100644 index 0000000000000..9e95c3c920b4d --- /dev/null +++ b/templates/repo/sub_menu_release_tag.tmpl @@ -0,0 +1,17 @@ +{{$canReadReleases := $.Permission.CanRead $.UnitTypeReleases}} +{{$canReadCode := $.Permission.CanRead $.UnitTypeCode}} + +{{if $canReadReleases}} + + + {{if .EnableFeed}} + {{svg "octicon-rss" 18}} + {{end}} +{{else if $canReadCode}} + {{template "repo/sub_menu" .}} +{{end}} diff --git a/templates/repo/tag/list.tmpl b/templates/repo/tag/list.tmpl new file mode 100644 index 0000000000000..6f9e1e8d7aed6 --- /dev/null +++ b/templates/repo/tag/list.tmpl @@ -0,0 +1,85 @@ +{{template "base/head" .}} + +
+ {{template "repo/header" .}} +
+ {{template "base/alert" .}} + {{template "repo/sub_menu_release_tag" .}} + +
+ +

+
+ {{svg "octicon-tag" 16 "gt-mr-2"}}{{.locale.Tr "repo.release.tags"}} +
+

+ + {{$canReadReleases := $.Permission.CanRead $.UnitTypeReleases}} + +
+ + + {{range $idx, $release := .Releases}} + + + + {{end}} + +
+

+ {{if $canReadReleases}} + {{.TagName}} + {{else}} + {{.TagName}} + {{end}} +

+
+ {{if $.Permission.CanRead $.UnitTypeCode}} + {{if .CreatedUnix}} + {{svg "octicon-clock" 16 "gt-mr-2"}}{{TimeSinceUnix .CreatedUnix $.locale}} + {{end}} + + {{svg "octicon-git-commit" 16 "gt-mr-2"}}{{ShortSha .Sha1}} + + {{if not $.DisableDownloadSourceArchives}} + {{svg "octicon-file-zip" 16 "gt-mr-2"}}ZIP + {{svg "octicon-file-zip" 16 "gt-mr-2"}}TAR.GZ + {{end}} + + {{if (and $canReadReleases $.CanCreateRelease $release.IsTag)}} + {{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.new_release"}} + {{end}} + + {{if (and ($.Permission.CanWrite $.UnitTypeCode) $release.IsTag)}} + + {{svg "octicon-trash" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.delete_tag"}} + + {{end}} + + {{if and $canReadReleases (not $release.IsTag)}} + {{svg "octicon-tag" 16 "gt-mr-2"}}{{$.locale.Tr "repo.release.detail"}} + {{end}} + {{end}} +
+
+
+ + {{template "base/paginate" .}} +
+
+ +{{if $.Permission.CanWrite $.UnitTypeCode}} + +{{end}} + + +{{template "base/footer" .}} diff --git a/templates/repo/user_cards.tmpl b/templates/repo/user_cards.tmpl index 5acea0b4d91bd..bc159f523a970 100644 --- a/templates/repo/user_cards.tmpl +++ b/templates/repo/user_cards.tmpl @@ -18,7 +18,7 @@ {{else if .Location}} {{svg "octicon-location"}} {{.Location}} {{else}} - {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} + {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}} {{end}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 7ee08c9efc96a..03f90d71f2463 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -42,6 +42,9 @@ {{svg "octicon-download"}} {{svg "octicon-copy" 14}} + {{if .EnableFeed}} + {{svg "octicon-rss" 14}} + {{end}} {{if .Repository.CanEnableEditor}} {{if .CanEditFile}} {{svg "octicon-pencil"}} diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index d3d9729fe40e4..3b354710817c8 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -106,7 +106,7 @@ {{svg "octicon-calendar" 14 "gt-mr-2"}} - {{DateTime "short" .DeadlineUnix.FormatDate .DeadlineUnix.FormatShort}} + {{DateTime "short" .DeadlineUnix}} {{end}} diff --git a/templates/status/500.tmpl b/templates/status/500.tmpl index 27c087bc18224..bca03877561e9 100644 --- a/templates/status/500.tmpl +++ b/templates/status/500.tmpl @@ -6,7 +6,7 @@
{{if .ErrorMsg}}

{{.locale.Tr "error.occurred"}}:

-
{{.ErrorMsg}}
+
{{.ErrorMsg}}
{{end}}
diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 468bde0b78da8..aaa728dab092e 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -97,7 +97,7 @@ {{else}} {{svg "octicon-calendar"}} {{if .DeadlineString}} - {{DateTime "short" .DeadlineString .DeadlineString}} + {{DateTime "short" .DeadlineString}} {{else}} {{$.locale.Tr "repo.milestones.no_due_date"}} {{end}} diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl index 0a8f427f9da15..20638aab41125 100644 --- a/templates/user/dashboard/repolist.tmpl +++ b/templates/user/dashboard/repolist.tmpl @@ -44,8 +44,10 @@ data.teamId = {{.Team.ID}}; {{if not .ContextUser.IsOrganization}} data.organizations = [{{range .Orgs}}{'name': {{.Name}}, 'num_repos': {{.NumRepos}}},{{end}}]; data.isOrganization = false; -data.organizationsTotalCount = {{.UserOrgsCount}} -data.canCreateOrganization = {{.SignedUser.CanCreateOrganization}} +data.organizationsTotalCount = {{.UserOrgsCount}}; +data.canCreateOrganization = {{.SignedUser.CanCreateOrganization}}; +{{else}} +data.organizationId = {{.ContextUser.ID}}; {{end}} window.config.pageData.dashboardRepoList = data; diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 2ad92612a2b6d..c3a06a16ee1b7 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -73,7 +73,7 @@ {{end}} {{end}} -
  • {{svg "octicon-clock"}} {{.locale.Tr "user.join_on"}} {{DateTime "short" .ContextUser.CreatedUnix.FormatLong .ContextUser.CreatedUnix.FormatShort}}
  • +
  • {{svg "octicon-clock"}} {{.locale.Tr "user.join_on"}} {{DateTime "short" .ContextUser.CreatedUnix}}
  • {{if and .Orgs .HasOrgsVisible}}
    • diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 142bfa0a2d60b..ffb9a8f677a07 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -27,7 +27,7 @@
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} + {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}
  • diff --git a/templates/user/settings/grants_oauth2.tmpl b/templates/user/settings/grants_oauth2.tmpl index a3b549722da80..8f48aee15ba79 100644 --- a/templates/user/settings/grants_oauth2.tmpl +++ b/templates/user/settings/grants_oauth2.tmpl @@ -20,7 +20,7 @@
    {{$grant.Application.Name}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" $grant.CreatedUnix.FormatLong $grant.CreatedUnix.FormatShort}} + {{$.locale.Tr "settings.add_on"}} {{DateTime "short" $grant.CreatedUnix}}
    diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index d255760cd555a..b15fb5686128d 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -68,9 +68,9 @@ {{$.locale.Tr "settings.subkeys"}}: {{range .SubsKey}} {{.PaddedKeyID}} {{end}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .AddedUnix.FormatLong .AddedUnix.FormatShort}} + {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .AddedUnix}} - - {{if not .ExpiredUnix.IsZero}}{{$.locale.Tr "settings.valid_until"}} {{DateTime "short" .ExpiredUnix.FormatLong .ExpiredUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.valid_forever"}}{{end}} + {{if not .ExpiredUnix.IsZero}}{{$.locale.Tr "settings.valid_until"}} {{DateTime "short" .ExpiredUnix}}{{else}}{{$.locale.Tr "settings.valid_forever"}}{{end}}
    diff --git a/templates/user/settings/keys_principal.tmpl b/templates/user/settings/keys_principal.tmpl index 7cde3e37af6b9..020a56479e585 100644 --- a/templates/user/settings/keys_principal.tmpl +++ b/templates/user/settings/keys_principal.tmpl @@ -25,7 +25,7 @@
    {{.Name}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} + {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}
    diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index bf2523f57b627..2e46869aebcc9 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -59,7 +59,7 @@ {{.Fingerprint}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix.FormatLong .CreatedUnix.FormatShort}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} + {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix.FormatLong .UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}
    diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 3a13fb4fcb915..6e2d65ca0a9c3 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -22,7 +22,7 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo, branch, titl // Click the PR button to create a pull htmlDoc := NewHTMLParser(t, resp.Body) - link, exists := htmlDoc.doc.Find("#new-pull-request").Parent().Attr("href") + link, exists := htmlDoc.doc.Find("#new-pull-request").Attr("href") assert.True(t, exists, "The template has changed") if branch != "master" { link = strings.Replace(link, ":master", ":"+branch, 1) diff --git a/web_src/css/base.css b/web_src/css/base.css index 39aa37a4375c8..bd1d32e2aff06 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -864,6 +864,9 @@ a.label, margin-top: -0.25rem; margin-bottom: -0.25rem; } +.ui.dropdown .menu > .item > svg { + margin-right: .78rem; /* use the same margin as for */ +} .ui.selection.dropdown .menu > .item { border-color: var(--color-secondary); diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 750ec44229f53..70ac8ff4698d5 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -23,15 +23,6 @@ Gitea's private styles use `g-` prefix. .gt-h-100 { height: 100% !important; } .gt-br-0 { border-radius: 0 !important; } -/* below class names match Tailwind CSS */ -.gt-pointer-events-none { pointer-events: none !important; } -.gt-relative { position: relative !important; } -.gt-overflow-x-scroll { overflow-x: scroll !important; } -.gt-cursor-default { cursor: default !important; } -.gt-items-start { align-items: flex-start !important; } -.gt-whitespace-pre { white-space: pre !important; } -.gt-invisible { visibility: hidden !important; } - .gt-mono { font-family: var(--fonts-monospace) !important; font-size: .95em !important; /* compensate for monospace fonts being usually slightly larger */ @@ -51,6 +42,19 @@ Gitea's private styles use `g-` prefix. text-overflow: ellipsis !important; } +/* below class names match Tailwind CSS */ +.gt-break-all { word-break: break-all !important; } +.gt-content-center { align-content: center !important; } +.gt-cursor-default { cursor: default !important; } +.gt-invisible { visibility: hidden !important; } +.gt-items-start { align-items: flex-start !important; } +.gt-overflow-x-scroll { overflow-x: scroll !important; } +.gt-pointer-events-none { pointer-events: none !important; } +.gt-relative { position: relative !important; } +.gt-whitespace-nowrap { white-space: nowrap !important; } +.gt-whitespace-pre { white-space: pre !important; } +.gt-whitespace-pre-wrap { white-space: pre-wrap !important; } + .gt-w-screen { width: 100vw !important; } .gt-h-screen { height: 100vh !important; } @@ -203,11 +207,7 @@ Gitea's private styles use `g-` prefix. .gt-gap-y-4 { row-gap: 1rem !important; } .gt-gap-y-5 { row-gap: 2rem !important; } -.gt-content-center { align-content: center !important; } - .gt-shrink-0 { flex-shrink: 0 !important; } -.gt-whitespace-nowrap { white-space: nowrap !important; } -.gt-whitespace-pre-wrap { white-space: pre-wrap !important; } @media (max-width: 767px) { .gt-db-small { display: block !important; } diff --git a/web_src/css/index.css b/web_src/css/index.css index 828251180446c..e59f3eb02abda 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -30,6 +30,7 @@ @import "./install.css"; @import "./form.css"; @import "./repository.css"; +@import "./repository-release-tag.css"; @import "./editor.css"; @import "./editor-markdown.css"; @import "./organization.css"; diff --git a/web_src/css/repository-release-tag.css b/web_src/css/repository-release-tag.css new file mode 100644 index 0000000000000..6922ce5179651 --- /dev/null +++ b/web_src/css/repository-release-tag.css @@ -0,0 +1,151 @@ +.repository.releases #release-list { + border-top: 1px solid var(--color-secondary); + margin-top: 20px; + padding-top: 15px; + padding-left: 0; +} + +.repository.releases #release-list .release-list-title { + font-size: 2rem; + font-weight: normal; + margin-top: -4px; + margin-bottom: 0; +} + +.repository.releases #release-list > li { + list-style: none; +} + +.repository.releases #release-list > li .meta, +.repository.releases #release-list > li .detail { + padding-top: 30px; + padding-bottom: 40px; +} + +.repository.releases #release-list > li .meta { + text-align: right; + position: relative; +} + +.repository.releases #release-list > li .meta .label { + margin-right: 0; +} + +.repository.releases #release-list > li .meta .commit { + display: block; + margin-top: 10px; +} + +.repository.releases #release-list > li .meta .choose { + margin-top: 15px; +} + +.repository.releases #release-list > li .meta .choose .button { + margin-right: 0; +} + +.repository.releases #release-list > li .detail { + border-left: 2px solid var(--color-secondary); +} + +.repository.releases #release-list > li .detail .author img { + margin-bottom: 3px; +} + +.repository.releases #release-list > li .detail .download > a .svg { + margin-left: 5px; + margin-right: 5px; +} + +.repository.releases #release-list > li .detail .download .list { + padding-left: 0; +} + +.repository.releases #release-list > li .detail .download .list li { + list-style: none; + display: block; + padding: 8px; + border: 1px solid var(--color-secondary); + background: var(--color-light); +} + +.repository.releases #release-list > li .detail .download .list li a > .text.right { + margin-right: 5px; +} + +.repository.releases #release-list > li .detail .download .list li + li { + border-top: 0; +} + +.repository.releases #release-list > li .detail .download .list li:first-of-type { + border-radius: var(--border-radius) 0 0 var(--border-radius); +} + +.repository.releases #release-list > li .detail .download .list li:last-of-type { + border-radius: 0 var(--border-radius) var(--border-radius) 0; +} + +.repository.releases #release-list > li .detail .dot { + width: 10px; + height: 10px; + background-color: var(--color-secondary-dark-3); + z-index: 9; + position: absolute; + display: block; + left: -6px; + top: 40px; + border-radius: 100%; + border: 2.5px solid var(--color-body); +} + +.repository.tags #tags-table .tag { + padding: 8px 12px; +} + +.repository.tags #tags-table .release-tag-name { + font-size: 18px; + font-weight: normal; +} + +.repository.new.release .target { + min-width: 500px; +} + +.repository.new.release .target #tag-name { + margin-top: -4px; +} + +.repository.new.release .target .at { + margin-left: -5px; + margin-right: 5px; +} + +.repository.new.release .target .selection.dropdown { + padding-top: 10px; + padding-bottom: 10px; +} + +.repository.new.release .prerelease.field { + margin-bottom: 0; +} + +@media (max-width: 438px) { + .repository.new.release .field button, + .repository.new.release .field input { + width: 100%; + } +} + +@media (max-width: 767px) { + .repository.new.release .field button { + margin-bottom: 1em; + } +} + +.repository.new.release .field .wrap_remove { + height: 38px; +} + +.repository.new.release .field .attachment_edit { + width: 450px !important; +} diff --git a/web_src/css/repository.css b/web_src/css/repository.css index 496e517bc87a3..80e2e1cb8b405 100644 --- a/web_src/css/repository.css +++ b/web_src/css/repository.css @@ -1923,157 +1923,6 @@ flex: 1 } -.repository.release #release-list { - border-top: 1px solid var(--color-secondary); - margin-top: 20px; - padding-top: 15px; - padding-left: 0; -} - -.repository.release #release-list .release-list-title { - font-size: 2rem; - font-weight: normal; - margin-top: -4px; - margin-bottom: 0; -} - -.repository.release #release-list > li { - list-style: none; -} - -.repository.release #release-list > li .meta, -.repository.release #release-list > li .detail { - padding-top: 30px; - padding-bottom: 40px; -} - -.repository.release #release-list > li .meta { - text-align: right; - position: relative; -} - -.repository.release #release-list > li .meta .label { - margin-right: 0; -} - -.repository.release #release-list > li .meta .commit { - display: block; - margin-top: 10px; -} - -.repository.release #release-list > li .meta .choose { - margin-top: 15px; -} - -.repository.release #release-list > li .meta .choose .button { - margin-right: 0; -} - -.repository.release #release-list > li .detail { - border-left: 2px solid var(--color-secondary); -} - -.repository.release #release-list > li .detail .author img { - margin-bottom: 3px; -} - -.repository.release #release-list > li .detail .download > a .svg { - margin-left: 5px; - margin-right: 5px; -} - -.repository.release #release-list > li .detail .download .list { - padding-left: 0; -} - -.repository.release #release-list > li .detail .download .list li { - list-style: none; - display: block; - padding: 8px; - border: 1px solid var(--color-secondary); - background: var(--color-light); -} - -.repository.release #release-list > li .detail .download .list li a > .text.right { - margin-right: 5px; -} - -.repository.release #release-list > li .detail .download .list li + li { - border-top: 0; -} - -.repository.release #release-list > li .detail .download .list li:first-of-type { - border-radius: var(--border-radius) 0 0 var(--border-radius); -} - -.repository.release #release-list > li .detail .download .list li:last-of-type { - border-radius: 0 var(--border-radius) var(--border-radius) 0; -} - -.repository.release #release-list > li .detail .dot { - width: 10px; - height: 10px; - background-color: var(--color-secondary-dark-3); - z-index: 9; - position: absolute; - display: block; - left: -6px; - top: 40px; - border-radius: 100%; - border: 2.5px solid var(--color-body); -} - -.repository.release #tags-table .tag { - padding: 8px 12px; -} - -.repository.release #tags-table .release-tag-name { - font-size: 18px; - font-weight: normal; -} - -.repository.new.release .target { - min-width: 500px; -} - -.repository.new.release .target #tag-name { - margin-top: -4px; -} - -.repository.new.release .target .at { - margin-left: -5px; - margin-right: 5px; -} - -.repository.new.release .target .selection.dropdown { - padding-top: 10px; - padding-bottom: 10px; -} - -.repository.new.release .prerelease.field { - margin-bottom: 0; -} - -@media (max-width: 438px) { - .repository.new.release .field button, - .repository.new.release .field input { - width: 100%; - } -} - -@media (max-width: 767px) { - .repository.new.release .field button { - margin-bottom: 1em; - } -} - -.repository.new.release .field .wrap_remove { - height: 38px; -} - -.repository.new.release .field .attachment_edit { - width: 450px !important; -} .repository.packages .empty { padding-top: 70px; diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index a3a02ecadb754..33b312aa6ee72 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -10,7 +10,7 @@ {{ textMyRepos }} {{ reposTotalCount }} - + {{ textNewRepo }} @@ -74,7 +74,7 @@
    -
    {{ repo.full_name }}
    +
    {{ repo.full_name }}
    @@ -199,6 +199,7 @@ const sfc = { isOrganization: true, canCreateOrganization: false, organizationsTotalCount: 0, + organizationId: 0, subUrl: appSubUrl, ...pageData.dashboardRepoList, diff --git a/web_src/js/components/RepoBranchTagSelector.vue b/web_src/js/components/RepoBranchTagSelector.vue index 6a65eeec6faef..d8451e83995f9 100644 --- a/web_src/js/components/RepoBranchTagSelector.vue +++ b/web_src/js/components/RepoBranchTagSelector.vue @@ -39,6 +39,9 @@