Compare commits

..

11 commits

Author SHA1 Message Date
Earl Warren
b4e8b8ac81
[API] Forgejo API /api/forgejo/v1 2023-02-11 11:32:35 +01:00
Percy Ma
7c98a4c54e
[DOCS] LICENSE: add Forgejo Authors 2023-02-11 11:32:19 +01:00
Loïc Dachary
2c23d1c53c
[DOCS] RELEASE-NOTES.md 2023-02-11 11:32:14 +01:00
Loïc Dachary
9dd224f00c
[WORKFLOW] issues & pr templates 2023-02-11 11:32:14 +01:00
Loïc Dachary
a47b474586
[DOCS] README 2023-02-11 11:32:14 +01:00
Loïc Dachary
88b113d081
[DOCS] CONTRIBUTING
Refs: https://codeberg.org/forgejo/forgejo/issues/8
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/153
Refs: https://codeberg.org/forgejo/forgejo/issues/123
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/299
2023-02-11 11:32:07 +01:00
Loïc Dachary
eb85782115
delete Gitea specific files that need rewriting for Forgejo
Although it would be possible to modify these files, it would create
conflicts when rebasing. Instead, this commit removes them entirely
and another commit can start from scratch, borrowing content from the
original files.

The drawback of this approach is that some content updates from Gitea
that also need updating in Forgejo will have to be copy/pasted
instead of being merged.
2023-02-11 11:12:44 +01:00
Loïc Dachary
dd1971d4e6
[CI] implementation: forgejo container images 2023-02-11 08:19:59 +01:00
Loïc Dachary
d6f6ca7d3e
[CI] implementation: Woodpecker based CI
Refs: https://codeberg.org/forgejo/forgejo/issues/73
Refs: https://codeberg.org/forgejo/forgejo/issues/101
Refs: https://codeberg.org/woodpecker-plugins/plugin-docker-buildx/issues/51
Refs: https://codeberg.org/forgejo/forgejo/issues/117
Refs: https://codeberg.org/forgejo/forgejo/issues/25
Refs: https://codeberg.org/forgejo/forgejo/issues/154
Refs: https://codeberg.org/forgejo/forgejo/issues/180
Refs: https://codeberg.org/forgejo/forgejo/issues/230
Refs: https://codeberg.org/forgejo/forgejo/issues/316
2023-02-11 08:19:46 +01:00
Loïc Dachary
6d910daafb
[CI] implementation: publish forgejo- binaries instead of gitea- 2023-02-11 08:19:22 +01:00
Loïc Dachary
dff32676e3
[CI] upstream: remove unstable test
Fixes: https://codeberg.org/forgejo/forgejo/issues/30
2023-02-11 08:19:22 +01:00
5941 changed files with 332576 additions and 321944 deletions

View file

@ -2,28 +2,9 @@ root = "."
tmp_dir = ".air"
[build]
pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs
cmd = "make --no-print-directory backend"
cmd = "make backend"
bin = "gitea"
delay = 2000
include_ext = ["go", "tmpl"]
include_file = ["main.go"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
exclude_dir = [
"models/fixtures",
"models/migrations/fixtures",
"modules/avatar/identicon/testdata",
"modules/avatar/testdata",
"modules/git/tests",
"modules/migration/file_format_testdata",
"modules/markup/tests/repo/repo1_filepreview",
"routers/private/tests",
"services/gitdiff/testdata",
"services/migrations/testdata",
"services/webhook/sourcehut/testdata",
]
exclude_regex = ["_test.go$", "_gen.go$"]
stop_on_error = true
[log]
main_only = true

61
.changelog.yml Normal file
View file

@ -0,0 +1,61 @@
# The full repository name
repo: go-gitea/gitea
# Service type (gitea or github)
service: github
# Base URL for Gitea instance if using gitea service type (optional)
# Default: https://gitea.com
base-url:
# Changelog groups and which labeled PRs to add to each group
groups:
-
name: BREAKING
labels:
- kind/breaking
-
name: SECURITY
labels:
- kind/security
-
name: FEATURES
labels:
- kind/feature
-
name: API
labels:
- kind/api
-
name: ENHANCEMENTS
labels:
- kind/enhancement
- kind/refactor
- kind/ui
-
name: BUGFIXES
labels:
- kind/bug
-
name: TESTING
labels:
- kind/testing
-
name: TRANSLATION
labels:
- kind/translation
-
name: BUILD
labels:
- kind/build
- kind/lint
-
name: DOCS
labels:
- kind/docs
-
name: MISC
default: true
# regex indicating which labels to skip for the changelog
skip-labels: skip-changelog|backport\/.+

View file

@ -1,303 +0,0 @@
code.gitea.io/gitea/cmd
NoMainListener
code.gitea.io/gitea/cmd/forgejo
ContextSetNoInit
ContextSetNoExit
ContextSetStderr
ContextGetStderr
ContextSetStdout
ContextSetStdin
code.gitea.io/gitea/models
IsErrUpdateTaskNotExist
ErrUpdateTaskNotExist.Error
ErrUpdateTaskNotExist.Unwrap
IsErrSHANotFound
IsErrMergeDivergingFastForwardOnly
GetYamlFixturesAccess
code.gitea.io/gitea/models/actions
ScheduleList.GetUserIDs
ScheduleList.GetRepoIDs
ScheduleList.LoadTriggerUser
ScheduleList.LoadRepos
code.gitea.io/gitea/models/asymkey
ErrGPGKeyAccessDenied.Error
ErrGPGKeyAccessDenied.Unwrap
HasDeployKey
code.gitea.io/gitea/models/auth
GetSourceByName
WebAuthnCredentials
code.gitea.io/gitea/models/db
TruncateBeans
InTransaction
DumpTables
code.gitea.io/gitea/models/dbfs
file.renameTo
Create
Rename
code.gitea.io/gitea/models/forgefed
GetFederationHost
code.gitea.io/gitea/models/forgejo/semver
GetVersion
SetVersionString
SetVersion
code.gitea.io/gitea/models/git
RemoveDeletedBranchByID
code.gitea.io/gitea/models/issues
IsErrUnknownDependencyType
ErrNewIssueInsert.Error
IsErrIssueWasClosed
ChangeMilestoneStatus
code.gitea.io/gitea/models/organization
GetTeamNamesByID
UpdateTeamUnits
SearchMembersOptions.ToConds
UsersInTeamsCount
code.gitea.io/gitea/models/perm/access
GetRepoWriters
code.gitea.io/gitea/models/project
UpdateColumnSorting
ChangeProjectStatus
code.gitea.io/gitea/models/repo
DeleteAttachmentsByIssue
FindReposMapByIDs
IsErrTopicNotExist
ErrTopicNotExist.Error
ErrTopicNotExist.Unwrap
GetTopicByName
WatchRepoMode
code.gitea.io/gitea/models/user
ErrUserInactive.Error
ErrUserInactive.Unwrap
IsErrExternalLoginUserAlreadyExist
IsErrExternalLoginUserNotExist
NewFederatedUser
IsErrUserSettingIsNotExist
GetUserAllSettings
DeleteUserSetting
GetUserEmailsByNames
GetUserNamesByIDs
code.gitea.io/gitea/modules/activitypub
NewContext
Context.APClientFactory
code.gitea.io/gitea/modules/assetfs
Bindata
code.gitea.io/gitea/modules/auth/password/hash
DummyHasher.HashWithSaltBytes
NewDummyHasher
code.gitea.io/gitea/modules/auth/password/pwn
WithHTTP
code.gitea.io/gitea/modules/base
SetupGiteaRoot
code.gitea.io/gitea/modules/cache
GetInt
WithNoCacheContext
RemoveContextData
code.gitea.io/gitea/modules/charset
BreakWriter.Write
code.gitea.io/gitea/modules/emoji
ReplaceCodes
code.gitea.io/gitea/modules/eventsource
Event.String
code.gitea.io/gitea/modules/forgefed
GetItemByType
JSONUnmarshalerFn
NotEmpty
ToRepository
OnRepository
code.gitea.io/gitea/modules/git
AllowLFSFiltersArgs
AddChanges
AddChangesWithArgs
CommitChanges
CommitChangesWithArgs
IsErrExecTimeout
ErrExecTimeout.Error
ErrUnsupportedVersion.Error
SetUpdateHook
openRepositoryWithDefaultContext
IsTagExist
ToEntryMode
LimitedReaderCloser.Read
LimitedReaderCloser.Close
code.gitea.io/gitea/modules/gitgraph
Parser.Reset
code.gitea.io/gitea/modules/gitrepo
GetBranchCommitID
GetWikiDefaultBranch
code.gitea.io/gitea/modules/graceful
Manager.TerminateContext
Manager.Err
Manager.Value
Manager.Deadline
code.gitea.io/gitea/modules/hcaptcha
WithHTTP
code.gitea.io/gitea/modules/hostmatcher
HostMatchList.AppendPattern
code.gitea.io/gitea/modules/json
StdJSON.Marshal
StdJSON.Unmarshal
StdJSON.NewEncoder
StdJSON.NewDecoder
StdJSON.Indent
code.gitea.io/gitea/modules/markup
GetRendererByType
RenderString
IsMarkupFile
code.gitea.io/gitea/modules/markup/console
Render
RenderString
code.gitea.io/gitea/modules/markup/markdown
IsDetails
IsSummary
IsTaskCheckBoxListItem
IsIcon
RenderRawString
code.gitea.io/gitea/modules/markup/markdown/math
WithInlineDollarParser
WithBlockDollarParser
code.gitea.io/gitea/modules/markup/mdstripper
stripRenderer.AddOptions
StripMarkdown
code.gitea.io/gitea/modules/markup/orgmode
RenderString
code.gitea.io/gitea/modules/private
ActionsRunnerRegister
code.gitea.io/gitea/modules/process
Manager.ExecTimeout
code.gitea.io/gitea/modules/queue
newBaseChannelSimple
newBaseChannelUnique
newBaseRedisSimple
newBaseRedisUnique
testStateRecorder.Records
testStateRecorder.Reset
newWorkerPoolQueueForTest
code.gitea.io/gitea/modules/queue/lqinternal
QueueItemIDBytes
QueueItemKeyBytes
ListLevelQueueKeys
code.gitea.io/gitea/modules/setting
NewConfigProviderFromData
GitConfigType.GetOption
InitLoggersForTest
code.gitea.io/gitea/modules/storage
ErrInvalidConfiguration.Error
IsErrInvalidConfiguration
code.gitea.io/gitea/modules/structs
ParseCreateHook
ParsePushHook
code.gitea.io/gitea/modules/sync
StatusTable.Start
StatusTable.IsRunning
code.gitea.io/gitea/modules/timeutil
GetExecutableModTime
MockSet
MockUnset
code.gitea.io/gitea/modules/translation
MockLocale.Language
MockLocale.TrString
MockLocale.Tr
MockLocale.TrN
MockLocale.TrSize
MockLocale.PrettyNumber
code.gitea.io/gitea/modules/util/filebuffer
CreateFromReader
code.gitea.io/gitea/modules/validation
IsErrNotValid
code.gitea.io/gitea/modules/web
RouteMock
RouteMockReset
code.gitea.io/gitea/modules/web/middleware
DeleteLocaleCookie
code.gitea.io/gitea/modules/zstd
NewWriter
Writer.Write
Writer.Close
code.gitea.io/gitea/routers/web
NotFound
code.gitea.io/gitea/routers/web/org
MustEnableProjects
code.gitea.io/gitea/services/context
GetPrivateContext
code.gitea.io/gitea/services/convert
ToSecret
code.gitea.io/gitea/services/forms
DeadlineForm.Validate
code.gitea.io/gitea/services/pull
IsCommitStatusContextSuccess
code.gitea.io/gitea/services/repository
IsErrForkAlreadyExist
code.gitea.io/gitea/services/repository/archiver
ArchiveRepository
code.gitea.io/gitea/services/repository/files
ContentType.String
GetFileResponseFromCommit
TemporaryUploadRepository.GetLastCommit
TemporaryUploadRepository.GetLastCommitByRef
code.gitea.io/gitea/services/webhook
NewNotifier

View file

@ -1,42 +0,0 @@
{
"name": "Gitea DevContainer",
"image": "mcr.microsoft.com/devcontainers/go:1.23-bullseye",
"features": {
// installs nodejs into container
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/git-lfs:1.2.3": {},
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
},
"customizations": {
"vscode": {
"settings": {},
// same extensions as Gitpod, should match /.gitpod.yml
"extensions": [
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"golang.go",
"stylelint.vscode-stylelint",
"DavidAnson.vscode-markdownlint",
"Vue.volar",
"ms-azuretools.vscode-docker",
"vitest.explorer",
"cweijan.vscode-database-client2",
"GitHub.vscode-pull-request-github",
"Azurite.azurite"
]
}
},
"portsAttributes": {
"3000": {
"label": "Gitea Web",
"onAutoForward": "notify"
}
},
"postCreateCommand": "make deps"
}

View file

@ -14,7 +14,7 @@ _test
# MS VSCode
.vscode
__debug_bin*
__debug_bin
# Architecture specific extensions/prefixes
*.[568vq]
@ -62,6 +62,7 @@ cpu.out
/data
/indexers
/log
/public/img/avatar
/tests/integration/gitea-integration-*
/tests/integration/indexers-*
/tests/e2e/gitea-e2e-*
@ -70,13 +71,15 @@ cpu.out
/tests/e2e/test-artifacts
/tests/e2e/test-snapshots
/tests/*.ini
/node_modules
/yarn.lock
/yarn-error.log
/npm-debug.log*
/public/assets/js
/public/assets/css
/public/assets/fonts
/public/assets/img/avatar
/public/js
/public/serviceworker.js
/public/css
/public/fonts
/public/img/webpack
/vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
@ -94,9 +97,6 @@ cpu.out
/.air
/.go-licenses
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft
snap/.snapcraft/
parts/

1527
.drone.yml Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.{go,tmpl,html},Makefile,go.mod}]
[*.{go,tmpl,html}]
indent_style = tab
[templates/custom/*.tmpl]
@ -21,8 +21,8 @@ indent_style = space
[templates/user/auth/oidc_wellknown.tmpl]
indent_style = space
[Makefile]
indent_style = tab
[*.svg]
insert_final_newline = false
[options/locale/locale_*.ini]
insert_final_newline = false

1
.envrc
View file

@ -1 +0,0 @@
use flake

View file

@ -3,196 +3,61 @@ reportUnusedDisableDirectives: true
ignorePatterns:
- /web_src/js/vendor
- /web_src/fomantic
- /public/assets/js
parserOptions:
sourceType: module
ecmaVersion: latest
plugins:
- "@eslint-community/eslint-plugin-eslint-comments"
- "@stylistic/eslint-plugin-js"
- "@vitest"
- eslint-plugin-array-func
- eslint-plugin-github
- eslint-plugin-i
- eslint-plugin-no-jquery
- eslint-plugin-no-use-extend-native
- eslint-plugin-regexp
- eslint-plugin-sonarjs
- eslint-plugin-unicorn
- eslint-plugin-vitest-globals
- eslint-plugin-wc
- eslint-plugin-import
- eslint-plugin-jquery
- eslint-plugin-sonarjs
env:
es2024: true
es2022: true
node: true
globals:
__webpack_public_path__: true
overrides:
- files: ["web_src/**/*"]
globals:
__webpack_public_path__: true
process: false # https://github.com/webpack/webpack/issues/15833
- files: ["web_src/**/*", "docs/**/*"]
- files: ["web_src/**/*.js", "docs/**/*.js"]
env:
browser: true
node: false
- files: ["web_src/**/*worker.*"]
- files: ["web_src/**/*worker.js"]
env:
worker: true
rules:
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
- files: ["*.config.*"]
- files: ["build/generate-images.js"]
rules:
i/no-unused-modules: [0]
- files: ["**/*.test.*", "web_src/js/test/setup.js"]
env:
vitest-globals/env: true
import/no-unresolved: [0]
import/no-extraneous-dependencies: [0]
- files: ["*.config.js"]
rules:
"@vitest/consistent-test-filename": [0]
"@vitest/consistent-test-it": [0]
"@vitest/expect-expect": [0]
"@vitest/max-expects": [0]
"@vitest/max-nested-describe": [0]
"@vitest/no-alias-methods": [0]
"@vitest/no-commented-out-tests": [0]
"@vitest/no-conditional-expect": [0]
"@vitest/no-conditional-in-test": [0]
"@vitest/no-conditional-tests": [0]
"@vitest/no-disabled-tests": [0]
"@vitest/no-done-callback": [0]
"@vitest/no-duplicate-hooks": [0]
"@vitest/no-focused-tests": [0]
"@vitest/no-hooks": [0]
"@vitest/no-identical-title": [2]
"@vitest/no-interpolation-in-snapshots": [0]
"@vitest/no-large-snapshots": [0]
"@vitest/no-mocks-import": [0]
"@vitest/no-restricted-matchers": [0]
"@vitest/no-restricted-vi-methods": [0]
"@vitest/no-standalone-expect": [0]
"@vitest/no-test-prefixes": [0]
"@vitest/no-test-return-statement": [0]
"@vitest/prefer-called-with": [0]
"@vitest/prefer-comparison-matcher": [0]
"@vitest/prefer-each": [0]
"@vitest/prefer-equality-matcher": [0]
"@vitest/prefer-expect-resolves": [0]
"@vitest/prefer-hooks-in-order": [0]
"@vitest/prefer-hooks-on-top": [2]
"@vitest/prefer-lowercase-title": [0]
"@vitest/prefer-mock-promise-shorthand": [0]
"@vitest/prefer-snapshot-hint": [0]
"@vitest/prefer-spy-on": [0]
"@vitest/prefer-strict-equal": [0]
"@vitest/prefer-to-be": [0]
"@vitest/prefer-to-be-falsy": [0]
"@vitest/prefer-to-be-object": [0]
"@vitest/prefer-to-be-truthy": [0]
"@vitest/prefer-to-contain": [0]
"@vitest/prefer-to-have-length": [0]
"@vitest/prefer-todo": [0]
"@vitest/require-hook": [0]
"@vitest/require-to-throw-message": [0]
"@vitest/require-top-level-describe": [0]
"@vitest/valid-describe-callback": [2]
"@vitest/valid-expect": [2]
"@vitest/valid-title": [2]
- files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"]
rules:
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
import/no-unused-modules: [0]
rules:
"@eslint-community/eslint-comments/disable-enable-pair": [2]
"@eslint-community/eslint-comments/no-aggregating-enable": [2]
"@eslint-community/eslint-comments/no-duplicate-disable": [2]
"@eslint-community/eslint-comments/no-restricted-disable": [0]
"@eslint-community/eslint-comments/no-unlimited-disable": [2]
"@eslint-community/eslint-comments/no-unused-disable": [2]
"@eslint-community/eslint-comments/no-unused-enable": [2]
"@eslint-community/eslint-comments/no-use": [0]
"@eslint-community/eslint-comments/require-description": [0]
"@stylistic/js/array-bracket-newline": [0]
"@stylistic/js/array-bracket-spacing": [2, never]
"@stylistic/js/array-element-newline": [0]
"@stylistic/js/arrow-parens": [2, always]
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
"@stylistic/js/block-spacing": [0]
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
"@stylistic/js/comma-dangle": [2, always-multiline]
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
"@stylistic/js/comma-style": [2, last]
"@stylistic/js/computed-property-spacing": [2, never]
"@stylistic/js/dot-location": [2, property]
"@stylistic/js/eol-last": [2]
"@stylistic/js/function-call-spacing": [2, never]
"@stylistic/js/function-call-argument-newline": [0]
"@stylistic/js/function-paren-newline": [0]
"@stylistic/js/generator-star-spacing": [0]
"@stylistic/js/implicit-arrow-linebreak": [0]
"@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}]
"@stylistic/js/key-spacing": [2]
"@stylistic/js/keyword-spacing": [2]
"@stylistic/js/linebreak-style": [2, unix]
"@stylistic/js/lines-around-comment": [0]
"@stylistic/js/lines-between-class-members": [0]
"@stylistic/js/max-len": [0]
"@stylistic/js/max-statements-per-line": [0]
"@stylistic/js/multiline-ternary": [0]
"@stylistic/js/new-parens": [2]
"@stylistic/js/newline-per-chained-call": [0]
"@stylistic/js/no-confusing-arrow": [0]
"@stylistic/js/no-extra-parens": [0]
"@stylistic/js/no-extra-semi": [2]
"@stylistic/js/no-floating-decimal": [0]
"@stylistic/js/no-mixed-operators": [0]
"@stylistic/js/no-mixed-spaces-and-tabs": [2]
"@stylistic/js/no-multi-spaces": [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
"@stylistic/js/no-multiple-empty-lines": [2, {max: 1, maxEOF: 0, maxBOF: 0}]
"@stylistic/js/no-tabs": [2]
"@stylistic/js/no-trailing-spaces": [2]
"@stylistic/js/no-whitespace-before-property": [2]
"@stylistic/js/nonblock-statement-body-position": [2]
"@stylistic/js/object-curly-newline": [0]
"@stylistic/js/object-curly-spacing": [2, never]
"@stylistic/js/object-property-newline": [0]
"@stylistic/js/one-var-declaration-per-line": [0]
"@stylistic/js/operator-linebreak": [2, after]
"@stylistic/js/padded-blocks": [2, never]
"@stylistic/js/padding-line-between-statements": [0]
"@stylistic/js/quote-props": [0]
"@stylistic/js/quotes": [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
"@stylistic/js/rest-spread-spacing": [2, never]
"@stylistic/js/semi": [2, always, {omitLastInOneLineBlock: true}]
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
"@stylistic/js/semi-style": [2, last]
"@stylistic/js/space-before-blocks": [2, always]
"@stylistic/js/space-before-function-paren": [2, {anonymous: ignore, named: never, asyncArrow: always}]
"@stylistic/js/space-in-parens": [2, never]
"@stylistic/js/space-infix-ops": [2]
"@stylistic/js/space-unary-ops": [2]
"@stylistic/js/spaced-comment": [2, always]
"@stylistic/js/switch-colon-spacing": [2]
"@stylistic/js/template-curly-spacing": [2, never]
"@stylistic/js/template-tag-spacing": [2, never]
"@stylistic/js/wrap-iife": [2, inside]
"@stylistic/js/wrap-regex": [0]
"@stylistic/js/yield-star-spacing": [2, after]
accessor-pairs: [2]
array-bracket-newline: [0]
array-bracket-spacing: [2, never]
array-callback-return: [2, {checkForEach: true}]
array-func/avoid-reverse: [2]
array-func/from-map: [2]
array-func/no-unnecessary-this-arg: [2]
array-func/prefer-array-from: [2]
array-func/prefer-flat-map: [0] # handled by unicorn/prefer-array-flat-map
array-func/prefer-flat: [0] # handled by unicorn/prefer-array-flat
array-element-newline: [0]
arrow-body-style: [0]
arrow-parens: [2, always]
arrow-spacing: [2, {before: true, after: true}]
block-scoped-var: [2]
brace-style: [2, 1tbs, {allowSingleLine: true}]
camelcase: [0]
capitalized-comments: [0]
class-methods-use-this: [0]
comma-dangle: [2, only-multiline]
comma-spacing: [2, {before: false, after: true}]
comma-style: [2, last]
complexity: [0]
computed-property-spacing: [2, never]
consistent-return: [0]
consistent-this: [0]
constructor-super: [2]
@ -200,96 +65,140 @@ rules:
default-case-last: [2]
default-case: [0]
default-param-last: [0]
dot-location: [2, property]
dot-notation: [0]
eol-last: [2]
eqeqeq: [2]
for-direction: [2]
func-call-spacing: [2, never]
func-name-matching: [2]
func-names: [0]
func-style: [0]
function-call-argument-newline: [0]
function-paren-newline: [0]
generator-star-spacing: [0]
getter-return: [2]
github/a11y-aria-label-is-well-formatted: [0]
github/a11y-no-title-attribute: [0]
github/a11y-no-visually-hidden-interactive-element: [0]
github/a11y-role-supports-aria-props: [0]
github/a11y-svg-has-accessible-name: [0]
github/array-foreach: [0]
github/async-currenttarget: [2]
github/async-preventdefault: [2]
github/authenticity-token: [0]
github/get-attribute: [0]
github/js-class-name: [0]
github/no-blur: [0]
github/no-d-none: [0]
github/no-dataset: [2]
github/no-dynamic-script-tag: [2]
github/no-implicit-buggy-globals: [2]
github/no-inner-html: [0]
github/no-innerText: [2]
github/no-then: [2]
github/no-useless-passive: [2]
github/prefer-observers: [2]
github/require-passive-events: [2]
github/unescaped-html-literal: [0]
grouped-accessor-pairs: [2]
guard-for-in: [0]
id-blacklist: [0]
id-length: [0]
id-match: [0]
i/consistent-type-specifier-style: [0]
i/default: [0]
i/dynamic-import-chunkname: [0]
i/export: [2]
i/exports-last: [0]
i/extensions: [2, always, {ignorePackages: true}]
i/first: [2]
i/group-exports: [0]
i/max-dependencies: [0]
i/named: [2]
i/namespace: [0]
i/newline-after-import: [0]
i/no-absolute-path: [0]
i/no-amd: [2]
i/no-anonymous-default-export: [0]
i/no-commonjs: [2]
i/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
i/no-default-export: [0]
i/no-deprecated: [0]
i/no-dynamic-require: [0]
i/no-empty-named-blocks: [2]
i/no-extraneous-dependencies: [2]
i/no-import-module-exports: [0]
i/no-internal-modules: [0]
i/no-mutable-exports: [0]
i/no-named-as-default-member: [0]
i/no-named-as-default: [2]
i/no-named-default: [0]
i/no-named-export: [0]
i/no-namespace: [0]
i/no-nodejs-modules: [0]
i/no-relative-packages: [0]
i/no-relative-parent-imports: [0]
i/no-restricted-paths: [0]
i/no-self-import: [2]
i/no-unassigned-import: [0]
i/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$", ^vitest/]}]
i/no-unused-modules: [2, {unusedExports: true}]
i/no-useless-path-segments: [2, {commonjs: true}]
i/no-webpack-loader-syntax: [2]
i/order: [0]
i/prefer-default-export: [0]
i/unambiguous: [0]
implicit-arrow-linebreak: [0]
import/consistent-type-specifier-style: [0]
import/default: [0]
import/dynamic-import-chunkname: [0]
import/export: [2]
import/exports-last: [0]
import/extensions: [2, always, {ignorePackages: true}]
import/first: [2]
import/group-exports: [0]
import/max-dependencies: [0]
import/named: [2]
import/namespace: [0]
import/newline-after-import: [0]
import/no-absolute-path: [0]
import/no-amd: [0]
import/no-anonymous-default-export: [0]
import/no-commonjs: [0]
import/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
import/no-default-export: [0]
import/no-deprecated: [0]
import/no-dynamic-require: [0]
import/no-empty-named-blocks: [2]
import/no-extraneous-dependencies: [2]
import/no-import-module-exports: [0]
import/no-internal-modules: [0]
import/no-mutable-exports: [0]
import/no-named-as-default-member: [0]
import/no-named-as-default: [2]
import/no-named-default: [0]
import/no-named-export: [0]
import/no-namespace: [0]
import/no-nodejs-modules: [0]
import/no-relative-packages: [0]
import/no-relative-parent-imports: [0]
import/no-restricted-paths: [0]
import/no-self-import: [2]
import/no-unassigned-import: [0]
import/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}]
import/no-unused-modules: [2, {unusedExports: true}]
import/no-useless-path-segments: [2, {commonjs: true}]
import/no-webpack-loader-syntax: [2]
import/order: [0]
import/prefer-default-export: [0]
import/unambiguous: [0]
indent: [2, 2, {SwitchCase: 1}]
init-declarations: [0]
jquery/no-ajax-events: [2]
jquery/no-ajax: [0]
jquery/no-animate: [2]
jquery/no-attr: [0]
jquery/no-bind: [2]
jquery/no-class: [0]
jquery/no-clone: [2]
jquery/no-closest: [0]
jquery/no-css: [0]
jquery/no-data: [0]
jquery/no-deferred: [2]
jquery/no-delegate: [2]
jquery/no-each: [0]
jquery/no-extend: [2]
jquery/no-fade: [0]
jquery/no-filter: [0]
jquery/no-find: [0]
jquery/no-global-eval: [2]
jquery/no-grep: [2]
jquery/no-has: [2]
jquery/no-hide: [0]
jquery/no-html: [0]
jquery/no-in-array: [2]
jquery/no-is-array: [2]
jquery/no-is-function: [2]
jquery/no-is: [0]
jquery/no-load: [2]
jquery/no-map: [0]
jquery/no-merge: [2]
jquery/no-param: [2]
jquery/no-parent: [0]
jquery/no-parents: [0]
jquery/no-parse-html: [2]
jquery/no-prop: [0]
jquery/no-proxy: [2]
jquery/no-ready: [0]
jquery/no-serialize: [2]
jquery/no-show: [0]
jquery/no-size: [2]
jquery/no-sizzle: [0]
jquery/no-slide: [0]
jquery/no-submit: [0]
jquery/no-text: [0]
jquery/no-toggle: [0]
jquery/no-trigger: [0]
jquery/no-trim: [2]
jquery/no-val: [0]
jquery/no-when: [2]
jquery/no-wrap: [2]
key-spacing: [2]
keyword-spacing: [2]
line-comment-position: [0]
linebreak-style: [2, unix]
lines-around-comment: [0]
lines-between-class-members: [0]
logical-assignment-operators: [0]
max-classes-per-file: [0]
max-depth: [0]
max-len: [0]
max-lines-per-function: [0]
max-lines: [0]
max-nested-callbacks: [0]
max-params: [0]
max-statements-per-line: [0]
max-statements: [0]
multiline-comment-style: [2, separate-lines]
multiline-ternary: [0]
new-cap: [0]
new-parens: [2]
newline-per-chained-call: [0]
no-alert: [0]
no-array-constructor: [2]
no-async-promise-executor: [0]
@ -301,6 +210,7 @@ rules:
no-class-assign: [2]
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-confusing-arrow: [0]
no-console: [1, {allow: [debug, info, warn, error]}]
no-const-assign: [2]
no-constant-binary-expression: [2]
@ -330,7 +240,10 @@ rules:
no-extra-bind: [2]
no-extra-boolean-cast: [2]
no-extra-label: [0]
no-extra-parens: [0]
no-extra-semi: [2]
no-fallthrough: [2]
no-floating-decimal: [0]
no-func-assign: [2]
no-global-assign: [2]
no-implicit-coercion: [2]
@ -343,99 +256,6 @@ rules:
no-invalid-this: [0]
no-irregular-whitespace: [2]
no-iterator: [2]
no-jquery/no-ajax-events: [2]
no-jquery/no-ajax: [2]
no-jquery/no-and-self: [2]
no-jquery/no-animate-toggle: [2]
no-jquery/no-animate: [2]
no-jquery/no-append-html: [2]
no-jquery/no-attr: [2]
no-jquery/no-bind: [2]
no-jquery/no-box-model: [2]
no-jquery/no-browser: [2]
no-jquery/no-camel-case: [2]
no-jquery/no-class-state: [2]
no-jquery/no-class: [0]
no-jquery/no-clone: [2]
no-jquery/no-closest: [0]
no-jquery/no-constructor-attributes: [2]
no-jquery/no-contains: [2]
no-jquery/no-context-prop: [2]
no-jquery/no-css: [2]
no-jquery/no-data: [0]
no-jquery/no-deferred: [2]
no-jquery/no-delegate: [2]
no-jquery/no-each-collection: [0]
no-jquery/no-each-util: [0]
no-jquery/no-each: [0]
no-jquery/no-error-shorthand: [2]
no-jquery/no-error: [2]
no-jquery/no-escape-selector: [2]
no-jquery/no-event-shorthand: [2]
no-jquery/no-extend: [2]
no-jquery/no-fade: [2]
no-jquery/no-filter: [0]
no-jquery/no-find-collection: [0]
no-jquery/no-find-util: [2]
no-jquery/no-find: [0]
no-jquery/no-fx-interval: [2]
no-jquery/no-global-eval: [2]
no-jquery/no-global-selector: [0]
no-jquery/no-grep: [2]
no-jquery/no-has: [2]
no-jquery/no-hold-ready: [2]
no-jquery/no-html: [0]
no-jquery/no-in-array: [2]
no-jquery/no-is-array: [2]
no-jquery/no-is-empty-object: [2]
no-jquery/no-is-function: [2]
no-jquery/no-is-numeric: [2]
no-jquery/no-is-plain-object: [2]
no-jquery/no-is-window: [2]
no-jquery/no-is: [2]
no-jquery/no-jquery-constructor: [0]
no-jquery/no-live: [2]
no-jquery/no-load-shorthand: [2]
no-jquery/no-load: [2]
no-jquery/no-map-collection: [0]
no-jquery/no-map-util: [2]
no-jquery/no-map: [2]
no-jquery/no-merge: [2]
no-jquery/no-node-name: [2]
no-jquery/no-noop: [2]
no-jquery/no-now: [2]
no-jquery/no-on-ready: [2]
no-jquery/no-other-methods: [0]
no-jquery/no-other-utils: [2]
no-jquery/no-param: [2]
no-jquery/no-parent: [0]
no-jquery/no-parents: [2]
no-jquery/no-parse-html-literal: [2]
no-jquery/no-parse-html: [2]
no-jquery/no-parse-json: [2]
no-jquery/no-parse-xml: [2]
no-jquery/no-prop: [2]
no-jquery/no-proxy: [2]
no-jquery/no-ready-shorthand: [2]
no-jquery/no-ready: [2]
no-jquery/no-selector-prop: [2]
no-jquery/no-serialize: [2]
no-jquery/no-size: [2]
no-jquery/no-sizzle: [0]
no-jquery/no-slide: [2]
no-jquery/no-sub: [2]
no-jquery/no-support: [2]
no-jquery/no-text: [0]
no-jquery/no-trigger: [0]
no-jquery/no-trim: [2]
no-jquery/no-type: [2]
no-jquery/no-unique: [2]
no-jquery/no-unload-shorthand: [2]
no-jquery/no-val: [0]
no-jquery/no-visibility: [2]
no-jquery/no-when: [2]
no-jquery/no-wrap: [2]
no-jquery/variable-pattern: [2]
no-label-var: [2]
no-labels: [0] # handled by no-restricted-syntax
no-lone-blocks: [2]
@ -444,7 +264,10 @@ rules:
no-loss-of-precision: [2]
no-magic-numbers: [0]
no-misleading-character-class: [2]
no-mixed-operators: [0]
no-mixed-spaces-and-tabs: [2]
no-multi-assign: [0]
no-multi-spaces: [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
no-multi-str: [2]
no-negated-condition: [0]
no-nested-ternary: [0]
@ -468,8 +291,9 @@ rules:
no-restricted-exports: [0]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
no-restricted-imports: [0]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.js instead"}]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement]
no-return-assign: [0]
no-return-await: [0]
no-script-url: [2]
no-self-assign: [2, {props: true}]
no-self-compare: [2]
@ -478,17 +302,19 @@ rules:
no-shadow-restricted-names: [2]
no-shadow: [0]
no-sparse-arrays: [2]
no-tabs: [2]
no-template-curly-in-string: [2]
no-ternary: [0]
no-this-before-super: [2]
no-throw-literal: [2]
no-trailing-spaces: [2]
no-undef-init: [2]
no-undef: [2, {typeof: true}]
no-undefined: [0]
no-underscore-dangle: [0]
no-unexpected-multiline: [2]
no-unmodified-loop-condition: [2]
no-unneeded-ternary: [2]
no-unneeded-ternary: [0]
no-unreachable-loop: [2]
no-unreachable: [2]
no-unsafe-finally: [2]
@ -498,7 +324,6 @@ rules:
no-unused-private-class-members: [2]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
no-use-extend-native/no-use-extend-native: [2]
no-useless-backreference: [2]
no-useless-call: [2]
no-useless-catch: [2]
@ -511,109 +336,42 @@ rules:
no-var: [2]
no-void: [2]
no-warning-comments: [0]
no-whitespace-before-property: [2]
no-with: [0] # handled by no-restricted-syntax
nonblock-statement-body-position: [2]
object-curly-newline: [0]
object-curly-spacing: [2, never]
object-shorthand: [2, always]
one-var-declaration-per-line: [0]
one-var: [0]
operator-assignment: [2, always]
operator-linebreak: [2, after]
padded-blocks: [2, never]
padding-line-between-statements: [0]
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
prefer-destructuring: [0]
prefer-exponentiation-operator: [2]
prefer-named-capture-group: [0]
prefer-numeric-literals: [2]
prefer-object-has-own: [2]
prefer-object-has-own: [0]
prefer-object-spread: [2]
prefer-promise-reject-errors: [2, {allowEmptyReject: false}]
prefer-regex-literals: [2]
prefer-rest-params: [2]
prefer-spread: [2]
prefer-template: [2]
quote-props: [0]
quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
radix: [2, as-needed]
regexp/confusing-quantifier: [2]
regexp/control-character-escape: [2]
regexp/hexadecimal-escape: [0]
regexp/letter-case: [0]
regexp/match-any: [2]
regexp/negation: [2]
regexp/no-contradiction-with-assertion: [0]
regexp/no-control-character: [0]
regexp/no-dupe-characters-character-class: [2]
regexp/no-dupe-disjunctions: [2]
regexp/no-empty-alternative: [2]
regexp/no-empty-capturing-group: [2]
regexp/no-empty-character-class: [0]
regexp/no-empty-group: [2]
regexp/no-empty-lookarounds-assertion: [2]
regexp/no-empty-string-literal: [2]
regexp/no-escape-backspace: [2]
regexp/no-extra-lookaround-assertions: [0]
regexp/no-invalid-regexp: [2]
regexp/no-invisible-character: [2]
regexp/no-lazy-ends: [2]
regexp/no-legacy-features: [2]
regexp/no-misleading-capturing-group: [0]
regexp/no-misleading-unicode-character: [0]
regexp/no-missing-g-flag: [2]
regexp/no-non-standard-flag: [2]
regexp/no-obscure-range: [2]
regexp/no-octal: [2]
regexp/no-optional-assertion: [2]
regexp/no-potentially-useless-backreference: [2]
regexp/no-standalone-backslash: [2]
regexp/no-super-linear-backtracking: [0]
regexp/no-super-linear-move: [0]
regexp/no-trivially-nested-assertion: [2]
regexp/no-trivially-nested-quantifier: [2]
regexp/no-unused-capturing-group: [0]
regexp/no-useless-assertions: [2]
regexp/no-useless-backreference: [2]
regexp/no-useless-character-class: [2]
regexp/no-useless-dollar-replacements: [2]
regexp/no-useless-escape: [2]
regexp/no-useless-flag: [2]
regexp/no-useless-lazy: [2]
regexp/no-useless-non-capturing-group: [2]
regexp/no-useless-quantifier: [2]
regexp/no-useless-range: [2]
regexp/no-useless-set-operand: [2]
regexp/no-useless-string-literal: [2]
regexp/no-useless-two-nums-quantifier: [2]
regexp/no-zero-quantifier: [2]
regexp/optimal-lookaround-quantifier: [2]
regexp/optimal-quantifier-concatenation: [0]
regexp/prefer-character-class: [0]
regexp/prefer-d: [0]
regexp/prefer-escape-replacement-dollar-char: [0]
regexp/prefer-lookaround: [0]
regexp/prefer-named-backreference: [0]
regexp/prefer-named-capture-group: [0]
regexp/prefer-named-replacement: [0]
regexp/prefer-plus-quantifier: [2]
regexp/prefer-predefined-assertion: [2]
regexp/prefer-quantifier: [0]
regexp/prefer-question-quantifier: [2]
regexp/prefer-range: [2]
regexp/prefer-regexp-exec: [2]
regexp/prefer-regexp-test: [2]
regexp/prefer-result-array-groups: [0]
regexp/prefer-set-operation: [2]
regexp/prefer-star-quantifier: [2]
regexp/prefer-unicode-codepoint-escapes: [2]
regexp/prefer-w: [0]
regexp/require-unicode-regexp: [0]
regexp/simplify-set-operations: [2]
regexp/sort-alternatives: [0]
regexp/sort-character-class-elements: [0]
regexp/sort-flags: [0]
regexp/strict: [2]
regexp/unicode-escape: [0]
regexp/use-ignore-case: [0]
require-atomic-updates: [0]
require-await: [0]
require-unicode-regexp: [0]
require-yield: [2]
rest-spread-spacing: [2, never]
semi-spacing: [2, {before: false, after: true}]
semi-style: [2, last]
semi: [2, always, {omitLastInOneLineBlock: true}]
sonarjs/cognitive-complexity: [0]
sonarjs/elseif-without-else: [0]
sonarjs/max-switch-cases: [0]
@ -635,7 +393,7 @@ rules:
sonarjs/no-nested-template-literals: [0]
sonarjs/no-one-iteration-loop: [2]
sonarjs/no-redundant-boolean: [2]
sonarjs/no-redundant-jump: [2]
sonarjs/no-redundant-jump: [0]
sonarjs/no-same-line-conditional: [2]
sonarjs/no-small-switch: [0]
sonarjs/no-unused-collection: [2]
@ -649,13 +407,20 @@ rules:
sort-imports: [0]
sort-keys: [0]
sort-vars: [0]
space-before-blocks: [2, always]
space-in-parens: [2, never]
space-infix-ops: [2]
space-unary-ops: [2]
spaced-comment: [2, always]
strict: [0]
switch-colon-spacing: [2]
symbol-description: [2]
template-curly-spacing: [2, never]
template-tag-spacing: [2, never]
unicode-bom: [2, never]
unicorn/better-regex: [0]
unicorn/catch-error-name: [0]
unicorn/consistent-destructuring: [2]
unicorn/consistent-empty-array-spread: [2]
unicorn/consistent-function-scoping: [2]
unicorn/custom-error-definition: [0]
unicorn/empty-brace-spaces: [2]
@ -668,43 +433,36 @@ rules:
unicorn/import-style: [0]
unicorn/new-for-builtins: [2]
unicorn/no-abusive-eslint-disable: [0]
unicorn/no-anonymous-default-export: [0]
unicorn/no-array-callback-reference: [0]
unicorn/no-array-for-each: [2]
unicorn/no-array-instanceof: [0]
unicorn/no-array-method-this-argument: [2]
unicorn/no-array-push-push: [2]
unicorn/no-array-reduce: [2]
unicorn/no-await-expression-member: [0]
unicorn/no-await-in-promise-methods: [2]
unicorn/no-console-spaces: [0]
unicorn/no-document-cookie: [2]
unicorn/no-empty-file: [2]
unicorn/no-fn-reference-in-iterator: [0]
unicorn/no-for-loop: [0]
unicorn/no-hex-escape: [0]
unicorn/no-instanceof-array: [0]
unicorn/no-invalid-fetch-options: [2]
unicorn/no-invalid-remove-event-listener: [2]
unicorn/no-keyword-prefix: [0]
unicorn/no-length-as-slice-end: [2]
unicorn/no-lonely-if: [2]
unicorn/no-magic-array-flat-depth: [0]
unicorn/no-negated-condition: [0]
unicorn/no-negation-in-equality-check: [2]
unicorn/no-nested-ternary: [0]
unicorn/no-new-array: [0]
unicorn/no-new-buffer: [0]
unicorn/no-null: [0]
unicorn/no-object-as-default-parameter: [0]
unicorn/no-process-exit: [0]
unicorn/no-single-promise-in-promise-methods: [2]
unicorn/no-reduce: [2]
unicorn/no-static-only-class: [2]
unicorn/no-thenable: [2]
unicorn/no-this-assignment: [2]
unicorn/no-typeof-undefined: [2]
unicorn/no-unnecessary-await: [2]
unicorn/no-unnecessary-polyfills: [2]
unicorn/no-unreadable-array-destructuring: [0]
unicorn/no-unreadable-iife: [2]
unicorn/no-unsafe-regex: [0]
unicorn/no-unused-properties: [2]
unicorn/no-useless-fallback-in-spread: [2]
unicorn/no-useless-length-check: [2]
@ -722,19 +480,15 @@ rules:
unicorn/prefer-array-index-of: [2]
unicorn/prefer-array-some: [2]
unicorn/prefer-at: [0]
unicorn/prefer-blob-reading-methods: [2]
unicorn/prefer-code-point: [0]
unicorn/prefer-dataset: [2]
unicorn/prefer-date-now: [2]
unicorn/prefer-default-parameters: [0]
unicorn/prefer-dom-node-append: [2]
unicorn/prefer-dom-node-dataset: [0]
unicorn/prefer-dom-node-remove: [2]
unicorn/prefer-dom-node-text-content: [2]
unicorn/prefer-event-key: [2]
unicorn/prefer-event-target: [2]
unicorn/prefer-export-from: [0]
unicorn/prefer-export-from: [2]
unicorn/prefer-includes: [2]
unicorn/prefer-json-parse-buffer: [0]
unicorn/prefer-keyboard-event-key: [2]
unicorn/prefer-logical-operator-over-ternary: [2]
unicorn/prefer-math-trunc: [2]
unicorn/prefer-modern-dom-apis: [0]
@ -742,7 +496,9 @@ rules:
unicorn/prefer-module: [2]
unicorn/prefer-native-coercion-functions: [2]
unicorn/prefer-negative-index: [2]
unicorn/prefer-node-append: [0]
unicorn/prefer-node-protocol: [2]
unicorn/prefer-node-remove: [0]
unicorn/prefer-number-properties: [0]
unicorn/prefer-object-from-entries: [2]
unicorn/prefer-object-has-own: [0]
@ -751,19 +507,17 @@ rules:
unicorn/prefer-query-selector: [0]
unicorn/prefer-reflect-apply: [0]
unicorn/prefer-regexp-test: [2]
unicorn/prefer-replace-all: [0]
unicorn/prefer-set-has: [0]
unicorn/prefer-set-size: [2]
unicorn/prefer-spread: [0]
unicorn/prefer-string-raw: [0]
unicorn/prefer-string-replace-all: [0]
unicorn/prefer-starts-ends-with: [2]
unicorn/prefer-string-slice: [0]
unicorn/prefer-string-starts-ends-with: [2]
unicorn/prefer-string-trim-start-end: [2]
unicorn/prefer-structured-clone: [2]
unicorn/prefer-switch: [0]
unicorn/prefer-ternary: [0]
unicorn/prefer-text-content: [2]
unicorn/prefer-top-level-await: [0]
unicorn/prefer-trim-start-end: [2]
unicorn/prefer-type-error: [0]
unicorn/prevent-abbreviations: [0]
unicorn/relative-url-style: [2]
@ -778,26 +532,7 @@ rules:
use-isnan: [2]
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
wc/attach-shadow-constructor: [2]
wc/define-tag-after-class-definition: [0]
wc/expose-class-on-global: [0]
wc/file-name-matches-element: [2]
wc/guard-define-call: [0]
wc/guard-super-call: [2]
wc/max-elements-per-file: [0]
wc/no-child-traversal-in-attributechangedcallback: [2]
wc/no-child-traversal-in-connectedcallback: [2]
wc/no-closed-shadow-root: [2]
wc/no-constructor-attributes: [2]
wc/no-constructor-params: [2]
wc/no-constructor: [2]
wc/no-customized-built-in-elements: [2]
wc/no-exports-with-element: [0]
wc/no-invalid-element-name: [2]
wc/no-invalid-extends: [2]
wc/no-method-prefixed-with-on: [2]
wc/no-self-class: [2]
wc/no-typos: [2]
wc/require-listener-teardown: [2]
wc/tag-name-matches-class: [2]
wrap-iife: [2, inside]
wrap-regex: [0]
yield-star-spacing: [2, after]
yoda: [2, never]

View file

@ -1,34 +0,0 @@
#!/bin/bash
set -ex
end_to_end=$1
end_to_end_pr=$2
forgejo=$3
forgejo_pr_or_ref=$4
cd $forgejo
full_version=$(make show-version-full)
minor_version=$(make show-version-minor)
cd $end_to_end
if ! test -f forgejo/sources/$minor_version; then
echo "FAIL: forgejo/sources/$minor_version does not exist in the end-to-end repository"
false
fi
echo -n $minor_version >forgejo/build-from-sources
date >last-upgrade
if test -f "$forgejo_pr_or_ref"; then
forgejo_pr=$forgejo_pr_or_ref
head_url=$(jq --raw-output .head.repo.html_url <$forgejo_pr)
test "$head_url" != null
branch=$(jq --raw-output .head.ref <$forgejo_pr)
test "$branch" != null
echo $head_url $branch $full_version >forgejo/sources/$minor_version
else
forgejo_ref=$forgejo_pr_or_ref
echo $GITHUB_SERVER_URL/$GITHUB_REPOSITORY ${forgejo_ref#refs/heads/} $full_version >forgejo/sources/$minor_version
fi

View file

@ -1,22 +0,0 @@
#!/bin/bash
set -ex
end_to_end=$1
end_to_end_pr=$2
forgejo=$3
forgejo_ref=$4
cd $end_to_end
date >last-upgrade
organizations=lib/ORGANIZATIONS
if ! test -f $organizations; then
echo "$organizations file not found"
false
fi
#
# Inverse the order of lookup because the goal in the release built
# pipeline is to test the latest build, if available, instead of the
# stable version by the same version.
#
echo forgejo-integration forgejo-experimental forgejo >$organizations

View file

@ -1,57 +0,0 @@
name: 🦋 Bug Report (web interface / frontend)
description: Something doesn't look quite as it should? Report it here!
title: "bug: "
labels: ["bug/new-report", "forgejo/ui"]
body:
- type: markdown
attributes:
value: |
**NOTE: If your issue is a security concern, please email <security@forgejo.org> (GPG: `A4676E79`) instead of opening a public issue.**
- type: markdown
attributes:
value: |
- Please speak English, as this is the language all maintainers can speak and write.
- Be as clear and concise as possible. A very verbose report is harder to interpret in a concrete way.
- Be civil, and follow the [Forgejo Code of Conduct](https://codeberg.org/forgejo/code-of-conduct).
- Take a moment to [check that your issue hasn't been reported before](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78137).
- type: dropdown
id: can-reproduce
attributes:
label: Can you reproduce the bug on the Forgejo test instance?
description: |
Please try reproducing your issue at https://dev.next.forgejo.org.
It is running the latest development branch and will confirm the problem is not already fixed.
If you can reproduce it, provide a URL in the description.
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see above).
If you think this is a JavaScript error, include a copy of the JavaScript console.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Please provide at least one screenshot showing the issue.
validations:
required: true
- type: input
id: forgejo-ver
attributes:
label: Forgejo Version
description: Forgejo version (or commit reference) your instance is running
- type: input
id: browser-ver
attributes:
label: Browser Version
description: The browser and version that you are using to access Forgejo
validations:
required: true

View file

@ -1,72 +0,0 @@
name: 🐛 Bug Report (server / backend)
description: Found something you weren't expecting? Report it here!
title: "bug: "
labels: bug/new-report
body:
- type: markdown
attributes:
value: |
**NOTE: If your issue is a security concern, please email <security@forgejo.org> (GPG: `A4676E79`) instead of opening a public issue.**
- type: markdown
attributes:
value: |
- Please speak English, as this is the language all maintainers can speak and write.
- Be as clear and concise as possible. A very verbose report is harder to interpret in a concrete way.
- Be civil, and follow the [Forgejo Code of Conduct](https://codeberg.org/forgejo/code-of-conduct).
- Take a moment to [check that your issue hasn't been reported before](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78137).
- type: dropdown
id: can-reproduce
attributes:
label: Can you reproduce the bug on the Forgejo test instance?
description: |
Please try reproducing your issue at https://dev.next.forgejo.org.
It is running the latest development branch and will confirm the problem is not already fixed.
If you can reproduce it, provide a URL in the description.
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see above).
validations:
required: true
- type: input
id: forgejo-ver
attributes:
label: Forgejo Version
description: Forgejo version (or commit reference) of your instance
- type: textarea
id: run-info
attributes:
label: How are you running Forgejo?
description: |
Please include information on whether you built Forgejo yourself, used one of our downloads, or are using some other package.
Please also tell us how you are running Forgejo, e.g. if it is being run from a container, a command-line, systemd etc.
If you are using a package or systemd tell us what distribution you are using.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs
description: |
It's really important to provide pertinent logs. You must give us `DEBUG` level logs.
Please read https://forgejo.org/docs/latest/admin/logging-documentation/.
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of `app.ini`.
Please copy and paste your logs here, with any sensitive information (e.g. API keys) removed/hidden.
You can wrap your logs in `<details>...</details>` tags so it doesn't take up too much space in the issue.
- type: dropdown
id: database
attributes:
label: Database
description: What database system are you running?
options:
- SQLite
- PostgreSQL
- MySQL

View file

@ -1,16 +0,0 @@
contact_links:
- name: 🔓 Security Reports
url: mailto:security@forgejo.org
about: "Please email <security@forgejo.org> (GPG: `A4676E79`) instead of opening a public issue."
- name: 💬 Matrix Chat Room
url: https://matrix.to/#/#forgejo-chat:matrix.org
about: Please ask questions and discuss configuration or deployment problems here.
- name: 💬 Matrix Space
url: https://matrix.to/#/#forgejo:matrix.org
about: A collection of Matrix rooms relating to Forgejo in addition to the main chat room.
- name: 📚 Documentation
url: https://forgejo.org/docs/latest/
about: Documentation about Forgejo.
- name: ❓ Frequently Asked Questions
url: https://forgejo.org/faq/
about: Please check if your question is mentioned here.

View file

@ -1,31 +0,0 @@
name: 💡 Feature Request
description: Got an idea for a feature that Forgejo doesn't have yet? Suggest it here!
title: "feat: "
labels: ["enhancement/feature"]
body:
- type: markdown
attributes:
value: |
- Please speak English, as this is the language all maintainers can speak and write.
- Be as clear and concise as possible. A very verbose request is harder to interpret in a concrete way.
- Be civil, and follow the [Forgejo Code of Conduct](https://codeberg.org/forgejo/code-of-conduct).
- Please make sure you are using the latest release of Forgejo and take a moment to [check that your feature hasn't already been suggested](https://codeberg.org/forgejo/forgejo/issues?q=&type=all&labels=78139).
- type: textarea
id: needs-benefits
attributes:
label: Needs and benefits
description: As concisely as possible, describe the benefits your feature request will provide or the problems it will try to solve.
validations:
required: true
- type: textarea
id: description
attributes:
label: Feature Description
description: As concisely as possible, describe the feature you would like to see added or the changes you would like to see made to Forgejo.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If you can, provide screenshots of an implementation on another site, e.g. GitHub.

View file

@ -1,33 +0,0 @@
---
name: "Pull Request Template"
about: "Template for all Pull Requests"
labels:
- test/needed
---
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).
### Tests
- I added test coverage for Go changes...
- [ ] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I added test coverage for JavaScript changes...
- [ ] in `web_src/js/*.test.js` if it can be unit tested.
- [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)).
### Documentation
- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] I do not want this change to show in the release notes.
- [ ] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.

View file

@ -1,6 +0,0 @@
FROM code.forgejo.org/oci/alpine:3.20
ARG RELEASE_VERSION=unkown
LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.version="${RELEASE_VERSION}"
RUN mkdir -p /app/gitea
RUN ( echo '#!/bin/sh' ; echo "echo forgejo v$RELEASE_VERSION" ) > /app/gitea/forgejo-cli ; chmod +x /app/gitea/forgejo-cli

View file

@ -1,5 +0,0 @@
VERSION ?= $(shell cat VERSION 2>/dev/null)
sources-tarbal:
mkdir -p dist/release
echo $(VERSION) > VERSION
sources=forgejo-src-$(VERSION).tar.gz ; tar --transform 's|^./|forgejo-src-$(VERSION)/|' -czf dist/release/forgejo-src-$(VERSION).tar.gz . ; cd dist/release ; shasum -a 256 $$sources > $$sources.sha256

View file

@ -1,3 +0,0 @@
module code.gitea.io/gitea
go 1.23.1

View file

@ -1,29 +0,0 @@
inputs:
packages:
description: 'Packages to install'
required: true
release:
description: 'Release to install from'
default: testing
runs:
using: "composite"
steps:
- name: setup apt package source
run: |
export DEBIAN_FRONTEND=noninteractive
echo "deb http://deb.debian.org/debian/ ${RELEASE} main" > "/etc/apt/sources.list.d/${RELEASE}.list"
env:
RELEASE: ${{inputs.release}}
- name: install packages
run: |
apt-get update -qq
apt-get -q install -qq -y ${PACKAGES}
env:
PACKAGES: ${{inputs.packages}}
- name: remove temporary package list to prevent using it in other steps
run: |
rm "/etc/apt/sources.list.d/${RELEASE}.list"
apt-get update -qq
env:
RELEASE: ${{inputs.release}}

View file

@ -1,15 +0,0 @@
runs:
using: "composite"
steps:
- run: |
su forgejo -c 'make deps-backend'
- uses: actions/cache@v4
id: cache-backend
with:
path: ${{github.workspace}}/gitea
key: backend-build-${{ github.sha }}
- if: steps.cache-backend.outputs.cache-hit != 'true'
run: |
su forgejo -c 'make backend'
env:
TAGS: bindata

View file

@ -1,12 +0,0 @@
runs:
using: "composite"
steps:
- name: setup user and permissions
run: |
git config --add safe.directory '*'
# ignore if the user already exists (like with the playwright image)
adduser --quiet --comment forgejo --disabled-password forgejo || true
chown -R forgejo:forgejo .
- uses: https://codeberg.org/fnetx/setup-cache-go@b2214eaf6fb44c7e8512c0f462a2c3ec31f86a73
with:
username: forgejo

View file

@ -1,59 +0,0 @@
# Copyright 2024 The Forgejo Authors
# SPDX-License-Identifier: MIT
#
# To modify this workflow:
#
# - change pull_request_target: to pull_request:
# so that it runs from a pull request instead of the default branch
#
# - push it to the wip-ci-backport branch on the forgejo repository
# otherwise it will not have access to the secrets required to push
# the PR
#
# - open a pull request targetting wip-ci-backport that includes a change
# that can be backported without conflict in v1.21 and set the
# `backport/v1.21` label.
#
# - once it works, open a pull request for the sake of keeping track
# of the change even if the PR won't run it because it will use
# whatever is in the default branch instead
#
# - after it is merged, double check it works by setting a
# `backport/v1.21` label on a merged pull request that can be backported
# without conflict.
#
on:
pull_request_target:
types:
- closed
- labeled
jobs:
backporting:
if: >
!startsWith(vars.ROLE, 'forgejo-') && (
github.event.pull_request.merged
&&
contains(toJSON(github.event.pull_request.labels), 'backport/v')
)
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- name: event info
run: |
cat <<'EOF'
${{ toJSON(github) }}
EOF
- uses: https://code.forgejo.org/actions/git-backporting@v4.8.2
with:
target-branch-pattern: "^backport/(?<target>(v.*))$"
strategy: ort
strategy-option: find-renames
cherry-pick-options: -x
auth: ${{ secrets.BACKPORT_TOKEN }}
pull-request: ${{ github.event.pull_request.url }}
auto-no-squash: true
enable-err-notification: true
git-user: forgejo-backport-action
git-email: forgejo-backport-action@noreply.codeberg.org

View file

@ -1,135 +0,0 @@
name: Integration tests for the release process
on:
push:
paths:
- Makefile
- Dockerfile
- Dockerfile.rootless
- docker/**
- .forgejo/workflows/build-release.yml
- .forgejo/workflows/build-release-integration.yml
branches-ignore:
- renovate/**
pull_request:
paths:
- Makefile
- Dockerfile
- Dockerfile.rootless
- docker/**
- .forgejo/workflows/build-release.yml
- .forgejo/workflows/build-release-integration.yml
jobs:
release-simulation:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- id: forgejo
uses: https://code.forgejo.org/actions/setup-forgejo@v1
with:
user: root
password: admin1234
image-version: 1.21
lxc-ip-prefix: 10.0.9
- name: publish the forgejo release
shell: bash
run: |
set -x
cat > /etc/docker/daemon.json <<EOF
{
"insecure-registries" : ["${{ steps.forgejo.outputs.host-port }}"]
}
EOF
systemctl restart docker
apt-get install -qq -y xz-utils
dir=$(mktemp -d)
trap "rm -fr $dir" EXIT
url=http://root:admin1234@${{ steps.forgejo.outputs.host-port }}
export FORGEJO_RUNNER_LOGS="${{ steps.forgejo.outputs.runner-logs }}"
function sanity_check() {
local url=$1 version=$2
#
# Minimal sanity checks. Since the binary
# is a script shell it does not test the sanity of the cross
# build, only the sanity of the naming of the binaries.
#
for arch in amd64 arm64 arm-6 ; do
local binary=forgejo-$version-linux-$arch
for suffix in '' '.xz' ; do
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$binary$suffix > $binary$suffix
if test "$suffix" = .xz ; then
unxz --keep $binary$suffix
fi
chmod +x $binary
./$binary --version | grep $version
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$binary$suffix.sha256 > $binary$suffix.sha256
shasum -a 256 --check $binary$suffix.sha256
rm $binary$suffix
done
done
local sources=forgejo-src-$version.tar.gz
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$sources > $sources
curl --fail -L -sS $url/root/forgejo/releases/download/v$version/$sources.sha256 > $sources.sha256
shasum -a 256 --check $sources.sha256
docker pull ${{ steps.forgejo.outputs.host-port }}/root/forgejo:$version
docker pull ${{ steps.forgejo.outputs.host-port }}/root/forgejo:$version-rootless
}
#
# Create a new project with a fake forgejo and the release workflow only
#
cp -a .forgejo/testdata/build-release/* $dir
mkdir -p $dir/.forgejo/workflows
cp .forgejo/workflows/build-release.yml $dir/.forgejo/workflows
cp $dir/Dockerfile $dir/Dockerfile.rootless
forgejo-test-helper.sh push $dir $url root forgejo
forgejo-curl.sh api_json -X PUT --data-raw '{"data":"${{ steps.forgejo.outputs.token }}"}' $url/api/v1/repos/root/forgejo/actions/secrets/TOKEN
forgejo-curl.sh api_json -X PUT --data-raw '{"data":"root"}' $url/api/v1/repos/root/forgejo/actions/secrets/DOER
forgejo-curl.sh api_json -X PUT --data-raw '{"data":"true"}' $url/api/v1/repos/root/forgejo/actions/secrets/VERBOSE
#
# Push a tag to trigger the release workflow and wait for it to complete
#
version=1.2.3
sha=$(forgejo-test-helper.sh branch_tip $url root/forgejo main)
forgejo-curl.sh api_json --data-raw '{"tag_name": "v'$version'", "target": "'$sha'"}' $url/api/v1/repos/root/forgejo/tags
LOOPS=180 forgejo-test-helper.sh wait_success "$url" root/forgejo $sha
sanity_check $url $version
#
# Push a commit to a branch that triggers the build of a test release
#
version=1.2-test
(
git clone $url/root/forgejo /tmp/forgejo
cd /tmp/forgejo
date > DATE
git config user.email root@example.com
git config user.name username
git add .
git commit -m 'update'
git push $url/root/forgejo main:forgejo
)
sha=$(forgejo-test-helper.sh branch_tip $url root/forgejo forgejo)
LOOPS=180 forgejo-test-helper.sh wait_success "$url" root/forgejo $sha
sanity_check $url $version
- name: full logs
if: always()
run: |
sed -e 's/^/[RUNNER LOGS] /' ${{ steps.forgejo.outputs.runner-logs }}
docker logs forgejo | sed -e 's/^/[FORGEJO LOGS]/'
sleep 5 # hack to avoid mixing outputs in Forgejo v1.21

View file

@ -1,231 +0,0 @@
#
# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process
#
# https://codeberg.org/forgejo-integration/forgejo
#
# Builds a release from a codeberg.org/forgejo-integration tag
#
# vars.ROLE: forgejo-integration
#
# secrets.DOER: forgejo-experimental-ci
# secrets.TOKEN: <generated from codeberg.org/forgejo-experimental-ci> scope read:user, write:repository, write:package
#
# secrets.CASCADE_ORIGIN_TOKEN: <generated from codeberg.org/forgejo-experimental-ci> scope read:user, write:repository, write:issue
# secrets.CASCADE_DESTINATION_TOKEN: <generated from code.forgejo.org/forgejo-ci> scope read:user, write:repository, write:issue
# vars.CASCADE_DESTINATION_DOER: forgejo-ci
#
on:
push:
tags: 'v[0-9]+.[0-9]+.*'
branches:
- 'forgejo'
- 'v*/forgejo'
jobs:
release:
runs-on: self-hosted
# root is used for testing, allow it
if: vars.ROLE == 'forgejo-integration' || github.repository_owner == 'root'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Sanitize the name of the repository
id: repository
run: |
repository="${{ github.repository }}"
echo "value=${repository##*/}" >> "$GITHUB_OUTPUT"
- uses: https://code.forgejo.org/actions/setup-node@v4
with:
node-version: 20
- uses: https://code.forgejo.org/actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: version from ref
id: release-info
shell: bash
run: |
set -x
ref="${{ github.ref }}"
if [[ $ref =~ ^refs/heads/ ]] ; then
if test "$ref" = "refs/heads/forgejo" ; then
version=$(git tag -l --sort=version:refname --merged | grep -v -e '-test$' | tail -1 | sed -E -e 's/^(v[0-9]+\.[0-9]+).*/\1/')-test
else
version=${ref#refs/heads/}
version=${version%/forgejo}-test
fi
override=true
fi
if [[ $ref =~ ^refs/tags/ ]] ; then
version=${ref#refs/tags/}
override=false
fi
if test -z "$version" ; then
echo failed to figure out the release version from the reference=$ref
exit 1
fi
version=${version#v}
git describe --exclude '*-test' --tags --always
echo "sha=${{ github.sha }}" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "override=$override" >> "$GITHUB_OUTPUT"
- name: release notes
id: release-notes
run: |
anchor=${{ steps.release-info.outputs.version }}
anchor=${anchor//./-}
cat >> "$GITHUB_OUTPUT" <<EOF
value<<ENDVAR
See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#$anchor
ENDVAR
EOF
- name: cache node_modules
id: node
uses: https://code.forgejo.org/actions/cache@v4
with:
path: |
node_modules
key: node-${{ steps.release-info.outputs.version }}
- name: skip if node cache hit
if: steps.node.outputs.cache-hit != 'true'
run: echo no hit
- name: Build sources
run: |
set -x
apt-get -qq install -y make
version=${{ steps.release-info.outputs.version }}
#
# Make sure all files are owned by the current user.
# When run as root `npx webpack` will assume the identity
# of the owner of the current working directory and may
# fail to create files if some sub-directories are not owned
# by the same user.
#
# Binaries:
# Node: 18.17.0 - /usr/local/node-v18.17.0-linux-x64/bin/node
# npm: 9.6.7 - /usr/local/node-v18.17.0-linux-x64/bin/npm
# Packages:
# add-asset-webpack-plugin: 2.0.1 => 2.0.1
# css-loader: 6.8.1 => 6.8.1
# esbuild-loader: 3.0.1 => 3.0.1
# license-checker-webpack-plugin: 0.2.1 => 0.2.1
# monaco-editor-webpack-plugin: 7.0.1 => 7.0.1
# vue-loader: 17.2.2 => 17.2.2
# webpack: 5.87.0 => 5.87.0
# webpack-cli: 5.1.4 => 5.1.4
#
chown -R $(id -u) .
make VERSION=$version TAGS=bindata sources-tarbal
mv dist/release release
(
tmp=$(mktemp -d)
tar --directory $tmp -zxvf release/*$version*.tar.gz
cd $tmp/*
#
# Verify `make frontend` files are available
#
test -d public/assets/css
test -d public/assets/fonts
test -d public/assets/js
#
# Verify `make generate` files are available
#
test -f modules/public/bindata.go
#
# Sanity check to verify that the source tarbal knows the
# version and is able to rebuild itself from it.
#
# When in sources the version is determined with git.
# When in the tarbal the version is determined from a VERSION file.
#
make sources-tarbal
tarbal=$(echo dist/release/*$version*.tar.gz)
if ! test -f $tarbal ; then
echo $tarbal does not exist
find dist release
exit 1
fi
)
- name: build container & release
if: ${{ secrets.TOKEN != '' }}
uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v5.1.1
with:
forgejo: "${{ env.GITHUB_SERVER_URL }}"
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
repository: "${{ steps.repository.outputs.value }}"
doer: "${{ secrets.DOER }}"
release-version: "${{ steps.release-info.outputs.version }}"
sha: "${{ steps.release-info.outputs.sha }}"
token: "${{ secrets.TOKEN }}"
platforms: linux/amd64,linux/arm64,linux/arm/v6
release-notes: "${{ steps.release-notes.outputs.value }}"
binary-name: forgejo
binary-path: /app/gitea/forgejo-cli
override: "${{ steps.release-info.outputs.override }}"
verify-labels: "maintainer=contact@forgejo.org,org.opencontainers.image.version=${{ steps.release-info.outputs.version }}"
verbose: ${{ vars.VERBOSE || secrets.VERBOSE || 'false' }}
- name: build rootless container
if: ${{ secrets.TOKEN != '' }}
uses: https://code.forgejo.org/forgejo/forgejo-build-publish/build@v5.1.1
with:
forgejo: "${{ env.GITHUB_SERVER_URL }}"
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
repository: "${{ steps.repository.outputs.value }}"
doer: "${{ secrets.DOER }}"
release-version: "${{ steps.release-info.outputs.version }}"
sha: "${{ steps.release-info.outputs.sha }}"
token: "${{ secrets.TOKEN }}"
platforms: linux/amd64,linux/arm64,linux/arm/v6
suffix: -rootless
dockerfile: Dockerfile.rootless
override: "${{ steps.release-info.outputs.override }}"
verify-labels: "maintainer=contact@forgejo.org,org.opencontainers.image.version=${{ steps.release-info.outputs.version }}"
verbose: ${{ vars.VERBOSE || secrets.VERBOSE || 'false' }}
- name: end-to-end tests
if: ${{ secrets.TOKEN != '' && vars.ROLE == 'forgejo-integration' }}
uses: https://code.forgejo.org/actions/cascading-pr@v2
with:
origin-url: ${{ env.GITHUB_SERVER_URL }}
origin-repo: ${{ github.repository }}
origin-token: ${{ secrets.CASCADE_ORIGIN_TOKEN }}
origin-ref: refs/heads/forgejo
destination-url: https://code.forgejo.org
destination-fork-repo: ${{ vars.CASCADE_DESTINATION_DOER }}/end-to-end
destination-repo: forgejo/end-to-end
destination-branch: main
destination-token: ${{ secrets.CASCADE_DESTINATION_TOKEN }}
update: .forgejo/cascading-release-end-to-end
- name: copy to experimental
if: vars.ROLE == 'forgejo-integration' && secrets.TOKEN != ''
run: |
if test "${{ vars.VERBOSE }}" = true ; then
set -x
fi
tag=v${{ steps.release-info.outputs.version }}
url=https://any:${{ secrets.TOKEN }}@codeberg.org
if test "${{ steps.release-info.outputs.override }}" = "true" ; then
curl -sS -X DELETE $url/api/v1/repos/forgejo-experimental/forgejo/releases/tags/$tag > /dev/null
curl -sS -X DELETE $url/api/v1/repos/forgejo-experimental/forgejo/tags/$tag > /dev/null
fi
# actions/checkout@v3 sets http.https://codeberg.org/.extraheader with the automatic token.
# Get rid of it so it does not prevent using the token that has write permissions
git config --local --unset http.https://codeberg.org/.extraheader
if test -f .git/shallow ; then
echo "unexptected .git/shallow file is present"
echo "it suggests a checkout --depth X was used which may prevent pushing the commit"
echo "it happens when actions/checkout is called without depth: 0"
fi
git push $url/forgejo-experimental/forgejo ${{ steps.release-info.outputs.sha }}:refs/tags/$tag

View file

@ -1,74 +0,0 @@
# Copyright 2024 The Forgejo Authors
# SPDX-License-Identifier: MIT
#
# To modify this workflow:
#
# - push it to the wip-ci-end-to-end branch on the forgejo repository
# otherwise it will not have access to the secrets required to push
# the cascading PR
#
# - once it works, open a pull request for the sake of keeping track
# of the change even if the PR won't run it because it will use
# whatever is in the default branch instead
#
# - after it is merged, double check it works by setting the
# run-end-to-end-test on a pull request (any pull request will doe
#
on:
push:
branches:
- 'wip-ci-end-to-end'
pull_request_target:
types:
- labeled
jobs:
info:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
container:
image: code.forgejo.org/oci/node:20-bookworm
steps:
- name: event
run: |
echo github.event.pull_request.head.repo.fork = ${{ github.event.pull_request.head.repo.fork }}
echo github.event.action = ${{ github.event.action }}
echo github.event.pull_request.merged = ${{ github.event.pull_request.merged }}
echo github.event.pull_request.labels.*.name
cat <<'EOF'
${{ toJSON(github.event.pull_request.labels.*.name) }}
EOF
cat <<'EOF'
${{ toJSON(github.event) }}
EOF
cascade:
if: >
!startsWith(vars.ROLE, 'forgejo-') && (
github.event_name == 'push' ||
(
github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests')
)
)
runs-on: docker
container:
image: code.forgejo.org/oci/node:20-bookworm
steps:
- uses: actions/checkout@v4
with:
fetch-depth: '0'
show-progress: 'false'
- uses: actions/cascading-pr@v2
with:
origin-url: ${{ env.GITHUB_SERVER_URL }}
origin-repo: ${{ github.repository }}
origin-token: ${{ secrets.END_TO_END_CASCADING_PR_ORIGIN }}
origin-pr: ${{ github.event.pull_request.number }}
origin-ref: ${{ github.event_name == 'push' && github.event.ref || '' }}
destination-url: https://code.forgejo.org
destination-fork-repo: cascading-pr/end-to-end
destination-repo: forgejo/end-to-end
destination-branch: main
destination-token: ${{ secrets.END_TO_END_CASCADING_PR_DESTINATION }}
close-merge: true
update: .forgejo/cascading-pr-end-to-end

View file

@ -1,39 +0,0 @@
on:
workflow_dispatch:
schedule:
- cron: '@daily'
jobs:
integration-cleanup:
if: vars.ROLE == 'forgejo-integration'
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- name: apt install curl jq
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get -q install -qq -y curl jq
- name: remove old releases and tags
run: |
url=https://any:${{ secrets.TOKEN }}@codeberg.org
curl -sS "$url/api/v1/repos/forgejo-integration/forgejo/releases" | jq -r '.[] | "\(.published_at) \(.tag_name)"' | sort | while read published_at version ; do
if echo $version | grep -e '-test$' >/dev/null; then
old="18 months"
else
old="1 day"
fi
too_old=$(env -i date --date="- $old" +%F)
too_old_seconds=$(env -i date --date="- $old" +%s)
published_at_seconds=$(env -i date --date="$published_at" +%s)
if test $published_at_seconds -le $too_old_seconds ; then
echo "$version was published more than $old ago ($published_at <= $too_old) and will be removed"
curl -X DELETE -sS "$url/api/v1/repos/forgejo-integration/forgejo/releases/tags/$version"
else
echo "$version was published less than $old ago"
fi
done

View file

@ -1,27 +0,0 @@
name: mirror
on:
workflow_dispatch:
schedule:
- cron: '@daily'
jobs:
mirror:
if: ${{ secrets.MIRROR_TOKEN != '' }}
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- name: git push {v*/,}forgejo
run: |
git init --bare .
git remote add origin ${{ env.GITHUB_SERVER_URL }}/${{ env.GITHUB_REPOSITORY }}
git fetch origin refs/heads/forgejo:refs/mirror/forgejo
git ls-remote origin refs/heads/v*/forgejo | while read sha full_ref ; do
ref=${full_ref#refs/heads/}
echo git fetch origin $full_ref:refs/mirror/$ref
git fetch origin $full_ref:refs/mirror/$ref
done
echo git push --force https://${{ vars.MIRROR_DESTINATION }} refs/mirror/*:refs/heads/*
git push --force https://any:${{ secrets.MIRROR_TOKEN }}@${{ vars.MIRROR_DESTINATION }} refs/mirror/*:refs/heads/*

View file

@ -1,88 +0,0 @@
# SPDX-License-Identifier: MIT
#
# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process
#
# https://codeberg.org/forgejo-experimental/forgejo
#
# Copies a release from codeberg.org/forgejo-integration to codeberg.org/forgejo-experimental
#
# vars.ROLE: forgejo-experimental
# vars.FORGEJO: https://codeberg.org
# vars.FROM_OWNER: forgejo-integration
# vars.TO_OWNER: forgejo-experimental
# vars.REPO: forgejo
# vars.DOER: forgejo-experimental-ci
# secrets.TOKEN: <generated from codeberg.org/forgejo-experimental-ci>
#
# http://private.forgejo.org/forgejo/forgejo
#
# Copies & sign a release from codeberg.org/forgejo-integration to codeberg.org/forgejo
#
# vars.ROLE: forgejo-release
# vars.FORGEJO: https://codeberg.org
# vars.FROM_OWNER: forgejo-integration
# vars.TO_OWNER: forgejo
# vars.REPO: forgejo
# vars.DOER: release-team
# secrets.TOKEN: <generated from codeberg.org/release-team>
# secrets.GPG_PRIVATE_KEY: <XYZ>
# secrets.GPG_PASSPHRASE: <ABC>
#
name: Pubish release
on:
push:
tags: 'v*'
jobs:
publish:
runs-on: self-hosted
if: vars.DOER != '' && vars.FORGEJO != '' && vars.TO_OWNER != '' && vars.FROM_OWNER != '' && secrets.TOKEN != ''
steps:
- uses: actions/checkout@v4
- name: copy & sign
uses: https://code.forgejo.org/forgejo/forgejo-build-publish/publish@v5
with:
from-forgejo: ${{ vars.FORGEJO }}
to-forgejo: ${{ vars.FORGEJO }}
from-owner: ${{ vars.FROM_OWNER }}
to-owner: ${{ vars.TO_OWNER }}
repo: ${{ vars.REPO }}
release-notes: "See https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#{ANCHOR}"
ref-name: ${{ github.ref_name }}
sha: ${{ github.sha }}
from-token: ${{ secrets.TOKEN }}
to-doer: ${{ vars.DOER }}
to-token: ${{ secrets.TOKEN }}
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }}
verbose: ${{ vars.VERBOSE }}
- name: upgrade v*.next.forgejo.org
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get -q install -y -qq curl
version="${{ github.ref_name }}"
version=${version##*v}
major=$(echo $version | sed -E -e 's/^([0-9]+).*/\1/')
# https://forgejo.org/docs/next/developer/infrastructure
curl -o /dev/null -sS https://v$major.next.forgejo.org/.well-known/wakeup-on-logs/forgejo-v$major
- name: set up go for the DNS update below
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
uses: https://code.forgejo.org/actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: update the _release.experimental DNS record
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''
uses: https://code.forgejo.org/actions/ovh-dns-update@v1
with:
subdomain: _release.experimental
domain: forgejo.com # there is a CNAME from .org to .com (for security reasons)
record-id: 5283602601
value: v=${{ github.ref_name }}
ovh-app-key: ${{ secrets.OVH_APP_KEY }}
ovh-app-secret: ${{ secrets.OVH_APP_SECRET }}
ovh-consumer-key: ${{ secrets.OVH_CON_KEY }}

View file

@ -1,33 +0,0 @@
on:
workflow_dispatch:
schedule:
- cron: '@daily'
jobs:
release-notes:
if: ${{ !startsWith(vars.ROLE, 'forgejo-')
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: https://code.forgejo.org/actions/setup-go@v5
with:
go-version-file: "go.mod"
cache: false
- name: apt install jq
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get -q install -y -qq jq
- name: update open milestones
run: |
set -x
curl -sS $GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/milestones?state=open | jq -r '.[] | .title' | while read forgejo version ; do
milestone="$forgejo $version"
go run code.forgejo.org/forgejo/release-notes-assistant@v1.1.1 --config .release-notes-assistant.yaml --storage milestone --storage-location "$milestone" --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} release $version
done

View file

@ -1,39 +0,0 @@
on:
pull_request_target:
types:
- edited
- synchronize
- labeled
jobs:
release-notes:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') && contains(github.event.pull_request.labels.*.name, 'worth a release-note') }}
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- name: event
run: |
cat <<'EOF'
${{ toJSON(github.event.pull_request.labels.*.name) }}
EOF
cat <<'EOF'
${{ toJSON(github.event) }}
EOF
- uses: https://code.forgejo.org/actions/setup-go@v5
with:
go-version-file: "go.mod"
cache: false
- name: apt install jq
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get -q install -y -qq jq
- name: release-notes-assistant preview
run: |
go run code.forgejo.org/forgejo/release-notes-assistant@v1.1.1 --config .release-notes-assistant.yaml --storage pr --storage-location ${{ github.event.pull_request.number }} --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} preview ${{ github.event.pull_request.number }}

View file

@ -1,69 +0,0 @@
#
# Runs every 2 hours, but Renovate is limited to create new PR before 4am.
# See renovate.json for more settings.
# Automerge is enabled for Renovate PR's but need to be approved before.
#
name: renovate
on:
push:
branches:
- 'renovate/**' # self-test updates
schedule:
- cron: '0 0/2 * * *'
workflow_dispatch:
env:
RENOVATE_DRY_RUN: ${{ (github.event_name != 'schedule' && github.ref_name != github.event.repository.default_branch) && 'full' || '' }}
RENOVATE_REPOSITORIES: ${{ github.repository }}
jobs:
renovate:
if: ${{ secrets.RENOVATE_TOKEN != '' }}
runs-on: docker
container:
image: code.forgejo.org/forgejo-contrib/renovate:38.110.2
steps:
- name: Load renovate repo cache
uses: https://code.forgejo.org/actions/cache/restore@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1
with:
path: |
.tmp/cache/renovate/repository
.tmp/cache/renovate/renovate-cache-sqlite
.tmp/osv
key: repo-cache-${{ github.run_id }}
restore-keys: |
repo-cache-
- name: Run renovate
run: renovate
env:
GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_COM_TOKEN }}
LOG_LEVEL: debug
RENOVATE_BASE_DIR: ${{ github.workspace }}/.tmp
RENOVATE_ENDPOINT: ${{ github.server_url }}
RENOVATE_PLATFORM: gitea
RENOVATE_REPOSITORY_CACHE: 'enabled'
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
RENOVATE_GIT_AUTHOR: 'Renovate Bot <forgejo-renovate-action@forgejo.org>'
RENOVATE_X_SQLITE_PACKAGE_CACHE: true
GIT_AUTHOR_NAME: 'Renovate Bot'
GIT_AUTHOR_EMAIL: 'forgejo-renovate-action@forgejo.org'
GIT_COMMITTER_NAME: 'Renovate Bot'
GIT_COMMITTER_EMAIL: 'forgejo-renovate-action@forgejo.org'
OSV_OFFLINE_ROOT_DIR: ${{ github.workspace }}/.tmp/osv
- name: Save renovate repo cache
if: always() && env.RENOVATE_DRY_RUN != 'full'
uses: https://code.forgejo.org/actions/cache/save@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1
with:
path: |
.tmp/cache/renovate/repository
.tmp/cache/renovate/renovate-cache-sqlite
.tmp/osv
key: repo-cache-${{ github.run_id }}

View file

@ -1,262 +0,0 @@
name: testing
on:
pull_request:
push:
branches:
- 'forgejo*'
- 'v*/forgejo*'
jobs:
backend-checks:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- name: event info
run: |
cat <<'EOF'
${{ toJSON(github) }}
EOF
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- run: su forgejo -c 'make deps-backend deps-tools'
- run: su forgejo -c 'make --always-make -j$(nproc) lint-backend tidy-check swagger-check fmt-check swagger-validate' # ensure the "go-licenses" make target runs
- uses: ./.forgejo/workflows-composite/build-backend
frontend-checks:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- run: make deps-frontend
- run: make lint-frontend
- run: make checks-frontend
- run: make test-frontend-coverage
- run: make frontend
- name: Install zstd for cache saving
# works around https://github.com/actions/cache/issues/1169, because the
# consuming job has zstd and doesn't restore the cache otherwise
run: |
apt-get update -qq
apt-get -q install -qq -y zstd
- name: "Cache frontend build for playwright testing"
uses: actions/cache/save@v4
with:
path: ${{github.workspace}}/public/assets
key: frontend-build-${{ github.sha }}
test-unit:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs: [backend-checks, frontend-checks]
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
services:
elasticsearch:
image: docker.io/bitnami/elasticsearch:7
env:
discovery.type: single-node
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
minio:
image: docker.io/bitnami/minio:2024.8.17
options: >-
--hostname gitea.minio
env:
MINIO_DOMAIN: minio
MINIO_ROOT_USER: 123456
MINIO_ROOT_PASSWORD: 12345678
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- name: install git >= 2.42
uses: ./.forgejo/workflows-composite/apt-install-from
with:
packages: git
- name: test release-notes-assistant.sh
run: |
apt-get -q install -qq -y jq
./release-notes-assistant.sh test_main
- uses: ./.forgejo/workflows-composite/build-backend
- run: |
su forgejo -c 'make test-backend test-check'
timeout-minutes: 50
env:
RACE_ENABLED: 'true'
TAGS: bindata
TEST_ELASTICSEARCH_URL: http://elasticsearch:9200
test-e2e:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs: [backend-checks, frontend-checks]
container:
image: 'code.forgejo.org/oci/playwright:latest'
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
with:
fetch-depth: 20
- uses: ./.forgejo/workflows-composite/setup-env
- name: "Restore frontend build"
uses: actions/cache/restore@v4
id: cache-frontend
with:
path: ${{github.workspace}}/public/assets
key: frontend-build-${{ github.sha }}
- name: "Build frontend (if not cached)"
if: steps.cache-frontend.outputs.cache-hit != 'true'
run: |
su forgejo -c 'make deps-frontend frontend'
- uses: ./.forgejo/workflows-composite/build-backend
- name: Get changed files
id: changed-files
uses: https://code.forgejo.org/tj-actions/changed-files@v45
with:
separator: '\n'
- run: |
su forgejo -c 'make generate test-e2e-sqlite'
timeout-minutes: 40
env:
USE_REPO_TEST_DIR: 1
CHANGED_FILES: ${{steps.changed-files.outputs.all_changed_files}}
test-remote-cacher:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs: [backend-checks, frontend-checks, test-unit]
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
strategy:
matrix:
cacher:
# redis
- image: docker.io/bitnami/redis:7.2
port: 6379
# redict
- image: registry.redict.io/redict:7.3.0-scratch
port: 6379
# valkey
- image: docker.io/bitnami/valkey:7.2
port: 6379
# garnet
- image: ghcr.io/microsoft/garnet-alpine:1.0.14
port: 6379
services:
cacher:
image: ${{ matrix.cacher.image }}
options: ${{ matrix.cacher.options }}
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- name: install git >= 2.42
uses: ./.forgejo/workflows-composite/apt-install-from
with:
packages: git
- uses: ./.forgejo/workflows-composite/build-backend
- run: |
su forgejo -c 'make test-remote-cacher test-check'
timeout-minutes: 50
env:
RACE_ENABLED: 'true'
TAGS: bindata
TEST_REDIS_SERVER: cacher:${{ matrix.cacher.port }}
test-mysql:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs: [backend-checks, frontend-checks]
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
services:
mysql:
image: 'docker.io/bitnami/mysql:8.4'
env:
ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
#
# See also https://codeberg.org/forgejo/forgejo/issues/976
#
MYSQL_EXTRA_FLAGS: --innodb-adaptive-flushing=OFF --innodb-buffer-pool-size=4G --innodb-log-buffer-size=128M --innodb-flush-log-at-trx-commit=0 --innodb-flush-log-at-timeout=30 --innodb-flush-method=nosync --innodb-fsync-threshold=1000000000
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- name: install dependencies & git >= 2.42
uses: ./.forgejo/workflows-composite/apt-install-from
with:
packages: git git-lfs
- uses: ./.forgejo/workflows-composite/build-backend
- run: |
su forgejo -c 'make test-mysql-migration test-mysql'
timeout-minutes: 50
env:
USE_REPO_TEST_DIR: 1
test-pgsql:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs: [backend-checks, frontend-checks]
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
services:
minio:
image: docker.io/bitnami/minio:2024.8.17
env:
MINIO_ROOT_USER: 123456
MINIO_ROOT_PASSWORD: 12345678
ldap:
image: docker.io/gitea/test-openldap:latest
pgsql:
image: 'code.forgejo.org/oci/postgres:15'
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- name: install dependencies & git >= 2.42
uses: ./.forgejo/workflows-composite/apt-install-from
with:
packages: git git-lfs
- uses: ./.forgejo/workflows-composite/build-backend
- run: |
su forgejo -c 'make test-pgsql-migration test-pgsql'
timeout-minutes: 50
env:
RACE_ENABLED: true
USE_REPO_TEST_DIR: 1
TEST_LDAP: 1
test-sqlite:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs: [backend-checks, frontend-checks]
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- name: install dependencies & git >= 2.42
uses: ./.forgejo/workflows-composite/apt-install-from
with:
packages: git git-lfs
- uses: ./.forgejo/workflows-composite/build-backend
- run: |
su forgejo -c 'make test-sqlite-migration test-sqlite'
timeout-minutes: 50
env:
TAGS: sqlite sqlite_unlock_notify
RACE_ENABLED: true
TEST_TAGS: sqlite sqlite_unlock_notify
USE_REPO_TEST_DIR: 1
security-check:
if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker
needs:
- test-sqlite
- test-pgsql
- test-mysql
- test-remote-cacher
- test-unit
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env
- run: su forgejo -c 'make deps-backend deps-tools'
- run: su forgejo -c 'make security-check'

7
.gitattributes vendored
View file

@ -1,11 +1,8 @@
* text=auto eol=lf
*.tmpl linguist-language=go-html-template
*.pb.go linguist-generated
*.tmpl linguist-language=Handlebars
/assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated
/public/vendor/** -text -eol linguist-vendored
/vendor/** -text -eol linguist-vendored
/web_src/fomantic/build/** linguist-generated
/web_src/fomantic/_site/globals/site.variables linguist-language=Less
/web_src/js/vendor/** -text -eol linguist-vendored
Dockerfile.* linguist-language=Dockerfile

View file

@ -0,0 +1,53 @@
---
name: "Bug Report"
about: "Found something you weren't expecting? Report it here!"
title: "[BUG] "
---
<!--
NOTE: If your issue is a security concern, please email security@forgejo.org (GPG: A4676E79) instead of opening a public issue.
1. Please speak English, as this is the language all maintainers can
speak and write.
2. Please ask questions or troubleshoot configuration/deploy problems
in our Matrix space (https://matrix.to/#/#forgejo:matrix.org).
3. Please make sure you are using the latest release of Forgejo and
take a moment to check that your issue hasn't been reported before.
4. Please give all relevant information below for bug reports, because
incomplete details will be handled as an invalid report.
5. If you are using a proxy or a CDN (e.g. CloudFlare) in front of
Forgejo, please disable the proxy/CDN fully and connect to Forgejo
directly to confirm the issue still persists without those services.
-->
- Forgejo version (or commit ref):
- Git version:
- Operating system:
- Database (use `[x]`):
- [ ] PostgreSQL
- [ ] MySQL
- [ ] MSSQL
- [ ] SQLite
- How are you running Forgejo?
<!--
Please include information on whether you built Forgejo yourself, used one of our downloads, or are using some other package.
Please also tell us how you are running Forgejo, e.g. if it is being run from docker, a command-line, systemd etc.
If you are using a package or systemd tell us what distribution you are using.
-->
## Description
<!-- Please describe the issue you are having as clearly and succinctly as possible. -->
## Logs
<!--
It is really important to provide pertinent logs. We need DEBUG level logs.
Please read https://docs.gitea.io/en-us/logging-configuration/#debugging-problems
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of `app.ini`.
Please copy and paste your logs here, with any sensitive information (e.g. API keys) removed/hidden.
-->
## Screenshots
<!-- If this issue involves the Web Interface, please provide one or more screenshots -->

View file

@ -0,0 +1,24 @@
---
name: "Feature Request"
about: "Got an idea for a feature that Forgejo doesn't have yet? Submit it here!"
title: "[FEAT] "
---
<!--
1. Please speak English, as this is the language all maintainers can
speak and write.
2. Please ask questions or troubleshoot configuration/deploy problems
in our Matrix space (https://matrix.to/#/#forgejo:matrix.org).
3. Please make sure you are using the latest release of Forgejo and
take a moment to check that your feature hasn't already been suggested.
-->
## Needs and benefits
<!-- Please describe the needs this feature intends to address and the benefits it brings. -->
## Feature Description
<!-- Please describe the feature you would like to see added as clearly and succinctly as possible. -->
## Screenshots
<!-- If you can, provide screenshots of an implementation on another site, e.g. GitHub. -->

View file

@ -0,0 +1,4 @@
<!--
Before submitting a PR, please read the contributing guidelines:
https://codeberg.org/forgejo/forgejo/src/branch/main/CONTRIBUTING.md
-->

34
.gitignore vendored
View file

@ -14,11 +14,14 @@ _test
.idea
# Goland's output filename can not be set manually
/go_build_*
/gitea_*
# MS VSCode
.vscode
__debug_bin*
__debug_bin
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
@ -28,9 +31,6 @@ _cgo_export.*
_testmain.go
# folder for project related local files
/local/
*.exe
*.test
*.prof
@ -50,7 +50,6 @@ cpu.out
*.db
*.log
*.log.*.gz
/gitea
/gitea-vet
@ -60,11 +59,13 @@ cpu.out
/bin
/dist
/custom/*
!/custom/conf
/custom/conf/*
!/custom/conf/app.example.ini
/data
/indexers
/log
/public/assets/img/avatar
/public/img/avatar
/tests/integration/gitea-integration-*
/tests/integration/indexers-*
/tests/e2e/gitea-e2e-*
@ -73,16 +74,15 @@ cpu.out
/tests/e2e/test-artifacts
/tests/e2e/test-snapshots
/tests/*.ini
/tests/**/*.git/**/*.sample
/node_modules
/.venv
/yarn.lock
/yarn-error.log
/npm-debug.log*
/public/assets/js
/public/assets/css
/public/assets/fonts
/public/assets/licenses.txt
/public/js
/public/serviceworker.js
/public/css
/public/fonts
/public/img/webpack
/vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
@ -99,13 +99,8 @@ cpu.out
/VERSION
/.air
/.go-licenses
/.cur-deadcode-out
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft
/gitea_a*.txt
snap/.snapcraft/
parts/
stage/
@ -115,9 +110,6 @@ prime/
*_source.tar.bz2
.DS_Store
# nix-direnv generated files
.direnv/
# Make evidence files
/.make_evidence

0
.gitmodules vendored
View file

View file

@ -10,21 +10,9 @@ tasks:
- name: Run backend
command: |
gp sync-await setup
# Get the URL and extract the domain
url=$(gp url 3000)
domain=$(echo $url | awk -F[/:] '{print $4}')
if [ -f custom/conf/app.ini ]; then
sed -i "s|^ROOT_URL =.*|ROOT_URL = ${url}/|" custom/conf/app.ini
sed -i "s|^DOMAIN =.*|DOMAIN = ${domain}|" custom/conf/app.ini
sed -i "s|^SSH_DOMAIN =.*|SSH_DOMAIN = ${domain}|" custom/conf/app.ini
sed -i "s|^NO_REPLY_ADDRESS =.*|SSH_DOMAIN = noreply.${domain}|" custom/conf/app.ini
else
mkdir -p custom/conf/
echo -e "[server]\nROOT_URL = ${url}/" > custom/conf/app.ini
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
fi
mkdir -p custom/conf/
echo -e "[server]\nROOT_URL=$(gp url 3000)/" > custom/conf/app.ini
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
export TAGS="sqlite sqlite_unlock_notify"
make watch-backend
- name: Run frontend
@ -32,6 +20,10 @@ tasks:
gp sync-await setup
make watch-frontend
openMode: split-right
- name: Run docs
before: sudo bash -c "$(grep 'https://github.com/gohugoio/hugo/releases/download' Makefile | tr -d '\')" # install hugo
command: cd docs && make clean update && hugo server -D -F --baseUrl $(gp url 1313) --liveReloadPort=443 --appendPort=false --bind=0.0.0.0
openMode: split-right
vscode:
extensions:
@ -40,12 +32,13 @@ vscode:
- golang.go
- stylelint.vscode-stylelint
- DavidAnson.vscode-markdownlint
- Vue.volar
- johnsoncodehk.volar
- ms-azuretools.vscode-docker
- vitest.explorer
- cweijan.vscode-database-client2
- GitHub.vscode-pull-request-github
- zixuanchen.vitest-explorer
- alexcvzz.vscode-sqlite
ports:
- name: Gitea
port: 3000
- name: Docs
port: 1313

View file

@ -1,14 +1,12 @@
linters:
enable-all: false
disable-all: true
fast: false
enable:
- bidichk
# - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- depguard
- dupl
- errcheck
- forbidigo
- gocritic
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- gofumpt
- gosimple
@ -18,22 +16,24 @@ linters:
- nolintlint
- revive
- staticcheck
# - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- stylecheck
- tenv
- testifylint
- typecheck
- unconvert
- unused
- unparam
- wastedassign
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
# - wastedassign # disabled - https://github.com/golangci/golangci-lint/issues/2649
enable-all: false
disable-all: true
fast: false
run:
go: 1.20
timeout: 10m
output:
sort-results: true
sort-order: [file]
show-stats: true
skip-dirs:
- node_modules
- public
- web_src
linters-settings:
stylecheck:
@ -43,73 +43,54 @@ linters-settings:
gocritic:
disabled-checks:
- ifElseChain
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
revive:
severity: error
ignore-generated-header: false
severity: warning
confidence: 0.8
errorCode: 1
warningCode: 1
rules:
- name: atomic
- name: bare-return
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: empty-lines
- name: error-naming
- name: error-return
- name: error-strings
- name: errorf
- name: error-naming
- name: exported
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: indent-error-flow
- name: modifies-value-receiver
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: string-of-int
- name: superfluous-else
- name: time-naming
- name: unconditional-recursion
- name: unexported-return
- name: unreachable-code
- name: var-declaration
- name: var-naming
- name: indent-error-flow
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: "1.20"
depguard:
rules:
main:
deny:
- pkg: encoding/json
desc: use gitea's modules/json instead of encoding/json
- pkg: github.com/unknwon/com
desc: use gitea's util and replacements
- pkg: io/ioutil
desc: use os or io instead
- pkg: golang.org/x/exp
desc: it's experimental and unreliable
- pkg: code.gitea.io/gitea/modules/git/internal
desc: do not use the internal package, use AddXxx function instead
- pkg: gopkg.in/ini.v1
desc: do not use the ini package, use gitea's config system instead
- pkg: github.com/minio/sha256-simd
desc: use crypto/sha256 instead, see https://codeberg.org/forgejo/forgejo/pulls/1528
testifylint:
disable:
- go-require
list-type: denylist
# Check the list against standard lib.
include-go-root: true
packages-with-error-message:
- encoding/json: "use gitea's modules/json instead of encoding/json"
- github.com/unknwon/com: "use gitea's util and replacements"
- io/ioutil: "use os or io instead"
- golang.org/x/exp: "it's experimental and unreliable."
- code.gitea.io/gitea/modules/git/internal: "do not use the internal package, use AddXxx function instead"
issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-dirs: [node_modules, public, web_src]
exclude-case-sensitive: true
exclude-rules:
- path: models/db/sql_postgres_with_schema.go
linters:
- nolintlint
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
@ -124,25 +105,73 @@ issues:
- errcheck
- dupl
- gosec
- path: cmd
linters:
- forbidigo
- text: "webhook"
linters:
- linters:
- dupl
- text: "`ID' should not be capitalized"
text: "webhook"
- linters:
- gocritic
text: "`ID' should not be capitalized"
- path: modules/templates/helper.go
linters:
- gocritic
- text: "swagger"
linters:
- linters:
- unused
- deadcode
- text: "argument x is overwritten before first use"
text: "swagger"
- path: contrib/pr/checkout.go
linters:
- errcheck
- path: models/issue.go
linters:
- errcheck
- path: models/migrations/
linters:
- errcheck
- path: modules/log/
linters:
- errcheck
- path: routers/api/v1/repo/issue_subscription.go
linters:
- dupl
- path: routers/repo/view.go
linters:
- dupl
- path: models/migrations/
linters:
- unused
- linters:
- staticcheck
text: "argument x is overwritten before first use"
- path: modules/httplib/httplib.go
linters:
- staticcheck
# Enabling this would require refactoring the methods and how they are called.
- path: models/issue_comment_list.go
linters:
- dupl
- path: models/update.go
linters:
- unused
- path: cmd/dump.go
linters:
- dupl
- path: services/webhook/webhook.go
linters:
- structcheck
- text: "commentFormatting: put a space between `//` and comment text"
linters:
- gocritic
- text: "exitAfterDefer:"
linters:
- gocritic
- path: modules/graceful/manager_windows.go
linters:
- staticcheck
text: "svc.IsAnInteractiveSession is deprecated: Use IsWindowsService instead."
- path: models/user/openid.go
linters:
- golint
- path: models/user/badge.go
linters:
- revive
text: "exported: type name will be used as user.UserBadge by other packages, and that stutters; consider calling this Badge"

View file

@ -1,11 +1,8 @@
*.min.css
*.min.js
/assets/*.json
/modules/options/bindata.go
/modules/public/bindata.go
/modules/templates/bindata.go
/options/gitignore
/options/license
/public/assets
/public/vendor/plugins
/vendor
node_modules

3
.lgtm Normal file
View file

@ -0,0 +1,3 @@
pattern = "(?)LGTM"
self_approval_off = true
ignore_maintainers_file = true

View file

@ -1,2 +0,0 @@
Unknwon <u@gogs.io> <joe2010xtmf@163.com>
Unknwon <u@gogs.io> 无闻 <u@gogs.io>

View file

@ -1,12 +1,13 @@
commands-show-output: false
fenced-code-language: false
first-line-h1: false
heading-increment: false
header-increment: false
line-length: {code_blocks: false, tables: false, stern: true, line_length: -1}
no-alt-text: false
no-bare-urls: false
no-blanks-blockquote: false
no-emphasis-as-heading: false
no-duplicate-header: {allow_different_nesting: true}
no-emphasis-as-header: false
no-empty-links: false
no-hard-tabs: {code_blocks: false}
no-inline-html: false

1
.npmrc
View file

@ -3,4 +3,3 @@ fund=false
update-notifier=false
package-lock=true
save-exact=true
lockfile-version=3

View file

@ -1,27 +0,0 @@
categorize: './release-notes-assistant.sh'
branch-development: 'forgejo'
branch-pattern: 'v*/forgejo'
branch-find-version: 'v(?P<version>\d+\.\d+)/forgejo'
branch-to-version: '${version}.0'
branch-from-version: 'v%[1]d.%[2]d/forgejo'
tag-from-version: 'v%[1]d.%[2]d.%[3]d'
branch-known:
- 'v7.0/forgejo'
cleanup-line: 'sed -Ee "s/^(feat|fix):\s*//g" -e "s/^\[WIP\] //" -e "s/^WIP: //" -e "s;\[(UI|BUG|FEAT|v.*?/forgejo)\]\s*;;g"'
render-header: |
## Draft release notes
comment: |
<details>
<summary>Where does that come from?</summary>
The following is a preview of the release notes for this pull request, as they will appear in the upcoming release. They are derived from the content of the `%[2]s/%[3]s.md` file, if it exists, or the title of the pull request. They were also added at the bottom of the description of this pull request for easier reference.
This message and the release notes originate from a call to the [release-notes-assistant](https://code.forgejo.org/forgejo/release-notes-assistant).
```diff
%[4]s
```
</details>
%[1]s

44
.stylelintrc.yaml Normal file
View file

@ -0,0 +1,44 @@
extends: stylelint-config-standard
plugins:
- stylelint-declaration-strict-value
overrides:
- files: ["**/*.less"]
customSyntax: postcss-less
- files: ["**/*.less"]
rules:
scale-unlimited/declaration-strict-value: [color, {
ignoreValues: /^(inherit|transparent|unset|initial)$/
}]
- files: ["**/chroma/*", "**/codemirror/*", "**/standalone/*", "**/console/*"]
rules:
scale-unlimited/declaration-strict-value: null
rules:
alpha-value-notation: null
at-rule-empty-line-before: null
block-closing-brace-empty-line-before: null
color-function-notation: null
color-hex-length: null
comment-empty-line-before: null
declaration-block-no-redundant-longhand-properties: null
declaration-block-single-line-max-declarations: null
declaration-empty-line-before: null
function-no-unknown: null
hue-degree-notation: null
import-notation: string
indentation: 2
max-line-length: null
no-descending-specificity: null
no-invalid-position-at-import-rule: null
number-leading-zero: never
number-max-precision: null
property-no-vendor-prefix: null
rule-empty-line-before: null
selector-class-pattern: null
selector-id-pattern: null
selector-pseudo-element-colon-notation: double
shorthand-property-no-redundant-values: true
string-quotes: null
value-no-vendor-prefix: null

View file

@ -0,0 +1,77 @@
platform: linux/amd64
when:
event: [ push, pull_request, manual ]
branch:
exclude: [ soft-fork/*/*, soft-fork/*/*/* ]
path:
exclude: [ '*.md', 'CONTRIBUTING/**' ]
variables:
- &golang_image 'golang:1.20'
- &test_image 'codeberg.org/forgejo/test_env:main'
- &goproxy_override ''
- &goproxy_setup |-
if [ -n "$${GOPROXY_OVERRIDE:-}" ]; then
export GOPROXY="$${GOPROXY_OVERRIDE}";
echo "Using goproxy from goproxy_override \"$${GOPROXY}\"";
elif [ -n "$${GOPROXY_DEFAULT:-}" ]; then
export GOPROXY="$${GOPROXY_DEFAULT}";
echo "Using goproxy from goproxy_default (secret) not displaying";
else
export GOPROXY="https://proxy.golang.org,direct";
echo "No goproxy overrides or defaults given, using \"$${GOPROXY}\"";
fi
workspace:
base: /go
path: src/codeberg/gitea
pipeline:
deps-backend:
image: *golang_image
pull: true
environment:
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
commands:
- *goproxy_setup
- make deps-backend
security-check:
image: *golang_image
group: checks
pull: true
environment:
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
commands:
- *goproxy_setup
- make security-check
lint-backend:
image: *test_image
pull: true
group: checks
environment:
GOPROXY_OVERRIDE: *goproxy_override
TAGS: 'bindata sqlite sqlite_unlock_notify'
GOSUMDB: 'sum.golang.org'
secrets:
- goproxy_default
commands:
- *goproxy_setup
- make lint-backend
checks-backend:
image: *test_image
group: checks
environment:
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
commands:
- *goproxy_setup
- make --always-make checks-backend

View file

@ -0,0 +1,144 @@
platform: linux/amd64
when:
event: [ push, pull_request, manual ]
branch:
exclude: [ soft-fork/*/*, soft-fork/*/*/* ]
path:
exclude: [ '*.md', 'CONTRIBUTING/**' ]
depends_on:
- compliance
variables:
- &golang_image 'golang:1.20'
- &test_image 'codeberg.org/forgejo/test_env:main'
- &mysql_image 'mysql:8'
- &pgsql_image 'postgres:10'
- &goproxy_override ''
- &goproxy_setup |-
if [ -n "$${GOPROXY_OVERRIDE:-}" ]; then
export GOPROXY="$${GOPROXY_OVERRIDE}";
echo "Using goproxy from goproxy_override \"$${GOPROXY}\"";
elif [ -n "$${GOPROXY_DEFAULT:-}" ]; then
export GOPROXY="$${GOPROXY_DEFAULT}";
echo "Using goproxy from goproxy_default (secret) not displaying";
else
export GOPROXY="https://proxy.golang.org,direct";
echo "No goproxy overrides or defaults given, using \"$${GOPROXY}\"";
fi
services:
mysql8:
image: *mysql_image
pull: true
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
pgsql:
image: *pgsql_image
pull: true
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
workspace:
base: /go
path: src/codeberg/gitea
pipeline:
fetch-tags:
image: *golang_image
pull: true
commands:
- git config --add safe.directory '*'
- git fetch --tags --force
deps-backend:
image: *golang_image
pull: true
environment:
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
commands:
- *goproxy_setup
- make deps-backend
tag-pre-condition:
image: *golang_image
pull: true
commands:
- git update-ref refs/heads/tag_test ${CI_COMMIT_SHA}
prepare-test-env:
image: *test_image
pull: true
commands:
- ./build/test-env-prepare.sh
build:
image: *test_image
environment:
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
commands:
- *goproxy_setup
- su gitea -c './build/test-env-check.sh'
- su gitea -c 'make backend'
unit-test:
image: *test_image
environment:
TAGS: 'bindata sqlite sqlite_unlock_notify'
RACE_ENABLED: 'true'
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- github_read_token
- goproxy_default
commands:
- *goproxy_setup
- su gitea -c 'make unit-test-coverage test-check'
test-mysql8:
group: integration
image: *test_image
commands:
- *goproxy_setup
- su gitea -c 'timeout -s ABRT 50m make test-mysql8-migration test-mysql8'
environment:
TAGS: 'bindata'
RACE_ENABLED: 'true'
USE_REPO_TEST_DIR: '1'
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
test-pgsql:
group: integration
image: *test_image
commands:
- *goproxy_setup
- su gitea -c 'timeout -s ABRT 50m make test-pgsql-migration test-pgsql'
environment:
TAGS: 'bindata'
RACE_ENABLED: 'true'
USE_REPO_TEST_DIR: '1'
GOPROXY_OVERRIDE: *goproxy_override
secrets:
- goproxy_default
test-sqlite:
group: integration
image: *test_image
environment:
- USE_REPO_TEST_DIR=1
- GOPROXY=off
- TAGS=bindata gogit sqlite sqlite_unlock_notify
- TEST_TAGS=bindata gogit sqlite sqlite_unlock_notify
commands:
- su gitea -c 'timeout -s ABRT 120m make test-sqlite-migration test-sqlite'

View file

@ -1,44 +0,0 @@
extends: default
rules:
braces:
min-spaces-inside: 0
max-spaces-inside: 1
min-spaces-inside-empty: 0
max-spaces-inside-empty: 0
brackets:
min-spaces-inside: 0
max-spaces-inside: 1
min-spaces-inside-empty: 0
max-spaces-inside-empty: 0
comments:
require-starting-space: true
ignore-shebangs: true
min-spaces-from-content: 1
comments-indentation:
level: error
document-start:
level: error
present: false
document-end:
present: false
empty-lines:
max: 1
indentation:
spaces: 2
line-length: disable
truthy:
allowed-values: ["true", "false", "on", "off"]
ignore: |
.venv
node_modules

View file

@ -1,7 +1,6 @@
# GNU makefile proxy script for BSD make
#
# Written and maintained by Mahmoud Al-Qudsi <mqudsi@neosmart.net>
# Copyright NeoSmart Technologies <https://neosmart.net/> 2014-2019
# Copyright NeoSmart Technologies <https://neosmart.net/> 2014-2018
# Obtain updates from <https://github.com/neosmart/gmake-proxy>
#
# Redistribution and use in source and binary forms, with or without
@ -27,32 +26,26 @@
JARG =
GMAKE = "gmake"
# When gmake is called from another make instance, -w is automatically added
# which causes extraneous messages about directory changes to be emitted.
# Running with --no-print-directory silences these messages.
#When gmake is called from another make instance, -w is automatically added
#which causes extraneous messages about directory changes to be emitted.
#--no-print-directory silences these messages.
GARGS = "--no-print-directory"
.if "$(.MAKE.JOBS)" != ""
JARG = -j$(.MAKE.JOBS)
JARG = -j$(.MAKE.JOBS)
.endif
# bmake prefers out-of-source builds and tries to cd into ./obj (among others)
# where possible. GNU Make doesn't, so override that value.
#by default bmake will cd into ./obj first
.OBJDIR: ./
# The GNU convention is to use the lowercased `prefix` variable/macro to
# specify the installation directory. Humor them.
GPREFIX =
.if defined(PREFIX) && ! defined(prefix)
GPREFIX = 'prefix = "$(PREFIX)"'
.endif
.BEGIN: .SILENT
which $(GMAKE) || (printf "Error: GNU Make is required!\n\n" 1>&2 && false)
.PHONY: FRC
$(.TARGETS): FRC
$(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
$(GMAKE) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
.DONE .DEFAULT: .SILENT
$(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
$(GMAKE) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
.ERROR: .SILENT
if ! which $(GMAKE) > /dev/null; then \
echo "GNU Make is required!"; \
fi

6525
CHANGELOG.md Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
# This file describes the expected reviewers for a PR based on the changed
# files. Unlike what the name of the file suggests they don't own the code, but
# merely have a good understanding of that area of the codebase and therefore
# are usually suited as a reviewer.
# Please mind the alphabetic order of reviewers.
# Files related to frontend development.
# Javascript and CSS code.
web_src/.* @caesar @crystal @gusted
# HTML templates used by the backend.
templates/.* @caesar @crystal @gusted
## the issue sidebar was touched by fnetx
templates/repo/issue/view_content/sidebar.* @fnetx
# Playwright tests
tests/e2e/.* @fnetx
# Files related to Go development.
# The modules usually don't require much knowledge about Forgejo and could
# be reviewed by Go developers.
modules/.* @gusted
# Models has code related to SQL queries, general database knowledge and XORM.
models/.* @gusted
# The routers directory contains the most amount code that requires a good grasp
# of how Forgejo comes together. It's tedious to write good integration testing
# for code that lives in here.
routers/.* @gusted
# Let new strings be checked by the translation team.
options/locale/locale_en-US.ini @0ko
# Personal interest
.*/webhook.* @oliverpool

View file

@ -4,4 +4,20 @@ The Forgejo project is run by a community of people who are expected to follow t
Sensitive security-related issues should be reported to [security@forgejo.org](mailto:security@forgejo.org) using [encryption](https://keyoxide.org/security@forgejo.org).
You can find links to the different aspects of Developer documentation on this page: [Forgejo Contributor Guide](https://forgejo.org/docs/next/contributor/).
## For everyone involved
- [Code of Conduct](CONTRIBUTING/COC.md)
- [Bugs, features, security and others discussions](CONTRIBUTING/DISCUSSIONS.md)
- [Governance](CONTRIBUTING/GOVERNANCE.md)
- [Sustainability and funding](https://codeberg.org/forgejo/sustainability/src/branch/master/README.md)
## For contributors
- [Developer Certificate of Origin (DCO)](CONTRIBUTING/DCO.md)
- [Development workflow](CONTRIBUTING/WORKFLOW.md)
## For maintainers
- [Release management](CONTRIBUTING/RELEASE.md)
- [Secrets](CONTRIBUTING/SECRETS.md)

31
CONTRIBUTING/COC.md Normal file
View file

@ -0,0 +1,31 @@
# Code of Conduct, Well Being and Moderation teams
Forgejo strives to be an inclusive project where everyone can participate in a safe environment. The **Well Being** team is doing its best to defuse tensions before they escalate and is available to answer all requests sent its way. When diplomacy fails, the **Moderation** team will be forced to act to put a stop to actions that are contrary to the [Code of Conduct](https://codeberg.org/forgejo/code-of-conduct).
## Well Being and Moderation teams
Temporary Well Being and Moderation teams [were appointed 10 November 2022](https://codeberg.org/forgejo/meta/issues/13).
The moderation team will rely on this [Code of Conduct](https://codeberg.org/forgejo/code-of-conduct) when diplomacy fails.
### Well Being
Their goal is to defuse tensions.
It has no power whatsover. The members are approved by the organization and trusted to:
- Read all communications to detect tensions between people before they escalate.
- Do their best to defuse tensions.
* https://codeberg.org/Gusted
* https://codeberg.org/dachary
### Moderation
Their goal is to enforce the [Code of Conduct](https://codeberg.org/forgejo/code-of-conduct) when diplomacy fails.
It has the power to exclude people from a space.
Their decisions must be logical, fact based and transparent to the Forgejo community who trust them with this responsibility.
* https://codeberg.org/circlebuilder

29
CONTRIBUTING/DCO.md Normal file
View file

@ -0,0 +1,29 @@
# Developer Certificate of Origin (DCO)
Contributions to Forgejo, in all the repositories in the [Forgejo organization](https://codeberg.org/forgejo) are accepted provided the author agrees to the following Developer Certificate of Origin (DCO).
```
By making a contribution to Forgejo, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the Free Software license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate Free Software
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same Free Software license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the Free Software license(s) involved.
```

View file

@ -0,0 +1,18 @@
# Bugs, features and discussions
The [Forgejo issue tracker](https://codeberg.org/forgejo/forgejo/issues) is where **bugs** should be reported and **features** requested.
Dedicated repositories in the [Forgejo organization](https://codeberg.org/forgejo) cover areas such as:
- the [website](https://codeberg.org/forgejo/website)
- the [Code of Conduct](https://codeberg.org/forgejo/code-of-conduct)
- the [sustainability and funding](https://codeberg.org/forgejo/sustainability).
Other discussions regarding all **non technical aspects** of Forgejo, such as the governance, happen in the [meta issue tracker](https://codeberg.org/forgejo/meta/issues) and in the [matrix chatroom](https://matrix.to/#/#forgejo-chat:matrix.org).
# Security
The [security team](https://codeberg.org/forgejo/meta/src/branch/readme/TEAMS.md#security) takes care of security vulnerabilities. It handles sensitive security-related issues reported to [security@forgejo.org](mailto:security@forgejo.org) using [encryption](https://keyoxide.org/security@forgejo.org).
The security team also keeps the content of the [security.txt](https://codeberg.org/forgejo/website/src/branch/main/public/.well-known/security.txt) file up to date.
The private GPG key for `security@forgejo.org` is shared among all members of the security team and not stored online.

View file

@ -0,0 +1,19 @@
# Governance
## Codeberg e.V. custodian of the domains
The Forgejo [domains](https://codeberg.org/forgejo/meta/issues/41) are owned by the democratic non-profit dedicated to Free Software [Codeberg e.V.](https://codeberg.org/Codeberg/org/src/branch/main/en/bylaws.md). Forgejo is therefore ultimately under the control of Codeberg e.V. and its governance. However, although Codeberg e.V. is committed to use and host Forgejo, it is expected that Forgejo defines its own governance, in a way that is compatible with the Codeberg e.V. governance.
## Forgejo Governance
See our [decision-making system](https://codeberg.org/forgejo/meta/src/branch/readme/DECISION-MAKING.md) (contains team agreements and guidelines).
Forgejo was bootstraped in November 2022 and is in the process of [defining its governance](https://codeberg.org/forgejo/meta/issues/19). The [first meeting happened November 24th](https://codeberg.org/forgejo/meta/issues/19#issuecomment-694460) and everyone is welcome to participate.
## Interim Forgejo Governance
While the governance is being defined, there was a need to establish an interim Forgejo governance for safeguarding credentials, enforcing the Code of Conduct and ensuring security vulnerabilities are handled responsibly for the Forgejo releases.
All people with a role in the interim Forgejo governance pledge to resign as soon as the Forgejo governance is in place.
The people and teams that are part of the interim governance are [listed publicly](https://codeberg.org/forgejo/meta/src/branch/readme/TEAMS.md).

150
CONTRIBUTING/RELEASE.md Normal file
View file

@ -0,0 +1,150 @@
# Release management
## Release numbering
The Forgejo release numbers are composed of the Gitea release number followed by a dash and a serial number. For instance:
* Gitea **v1.18.0** will be Forgejo **v1.18.0-0**, **v1.18.0-1**, etc
The Gitea release candidates are suffixed with **-rcN** which is handled as a special case for packaging: although **X.Y.Z** is lexicographically lower than **X.Y.Z-rc1** is is considered greater. The Forgejo serial number must therefore be inserted before the **-rcN** suffix to preserve the expected version ordering.
* Gitea **v1.18.0-rc0** will be Forgejo **v1.18.0-0-rc0**, **v1.18.0-1-rc0**
* Gitea **v1.18.0-rc1** will be Forgejo **v1.18.0-2-rc1**, **v1.18.0-3-rc1**, **v1.18.0-4-rc1**
* Gitea **v1.18.0** will be Forgejo **v1.18.0-5**, **v1.18.0-6**, **v1.18.0-7**
* etc.
Because Forgejo is a soft fork of Gitea, it must retain the same release numbering scheme to be compatible with libraries and tools that depend on it. For instance, the tea CLI or the Gitea SDK will behave differently depending on the server version they connect to. If Forgejo had a different numbering scheme, it would no longer be compatible with the Gitea ecosystem.
From a [Semantic Versioning](https://semver.org/) standpoint, all Forgejo releases are [pre-releases](https://semver.org/#spec-item-9) because they are suffixed with a dash. They are syntactically correct but do not comply with the Semantic Versioning recommendations. Gitea is not compliant either and as long as Forgejo is a soft fork, it inherits this problem.
## Release process
When publishing the vX.Y.Z-N release, the following steps must be followed:
### Create a milestone and a check list
* Create a `Forgejo vX.X.Z-N` milestone set to the date of the release
* Create an issue named `[RELEASE] Forgejo vX.Y.Z-N` with a description that includes a list of what needs to be done for the release with links to follow the progress
* Set the milestone of this issue to `Forgejo vX.X.Z-N`
* Close the milestone when the release is complete
### Cherry pick the latest commits from Gitea
The vX.Y/forgejo branch is populated as part of the [rebase on top of Gitea](WORKFLOW.md). The release happens in between rebase and it is worth checking if the matching Gitea branch, release/vX.Y contains commits that should be included in the release.
* `cherry-pick -x` the commits
* push the vX.Y/forgejo branch including the commits
* verify that the tests pass
### Release Notes
* Add an entry in RELEASE-NOTES.md
* Copy/paste the matching entry from CHANGELOG.md
* Update the PR references prefixing them with https://github.com/go-gitea/gitea/pull/
### Testing
When Forgejo is released, artefacts (packages, binaries, etc.) are first published by the CI/CD pipelines in the https://codeberg.org/forgejo-experimental organization, to be downloaded and verified to work.
* Push the vX.Y.Z-N tag to https://codeberg.org/forgejo-integration (if it fails for whatever reason, the tag and the release can be removed manually)
* Binaries are built and uploaded to https://codeberg.org/forgejo/forgejo-integration/releases
* Container images are built and uploaded to https://codeberg.org/forgejo-integration/-/packages/container/forgejo/versions
* Push the vX.Y.Z-N tag to https://codeberg.org/forgejo/experimental
* Binaries are downloaded from https://codeberg.org/forgejo-integration, signed and copied to https://codeberg.org/forgejo-experimental
* Container images are copied from https://codeberg.org/forgejo-integration to https://codeberg.org/forgejo-experimental
* Fetch the Forgejo release as part of the [forgejo-ci](https://codeberg.org/Codeberg-Infrastructure/scripted-configuration/src/branch/main/hosts/forgejo-ci) test suite. Push the change to a branch of a repository enabled in https://ci.dachary.org/ ([read more...](https://codeberg.org/forgejo/forgejo/issues/208)). It will deploy the release and run high level integration tests.
* Reach out to packagers and users to manually verify the release works as expected
### Publication
* Push the vX.Y.Z-N tag to https://codeberg.org/forgejo/release
* Binaries are downloaded from https://codeberg.org/forgejo-integration, signed and copied to https://codeberg.org/forgejo
* Container images are copied from https://codeberg.org/forgejo-integration to https://codeberg.org/forgejo
### Website update
* Restart the last CI build at https://codeberg.org/forgejo/website/src/branch/main/
* Verify https://forgejo.org/download/ points to the expected release
* Manually try the instructions to work
### DNS update
* Update the `release.forgejo.org` TXT record that starts with `forgejo_versions=` to be `forgejo_versions=vX.Y.Z-N`
### Standard toot
The following toot can be re-used to announce a minor release at `https://floss.social/@forgejo`. For more significant releases it is best to consider a dedicated and non-standard toot.
```
#Forgejo vX.Y.Z-N was just released! This is a minor patch. Check out the release notes and download it at https://forgejo.org/releases/. If you experience any issues with this release, please report to https://codeberg.org/forgejo/forgejo/issues.
```
## Release signing keys management
A GPG master key with no expiration date is created and shared with members of the Owners team via encrypted email. A subkey with a one year expiration date is created and stored in the secrets repository, to be used by the CI pipeline. The public master key is stored in the secrets repository and published where relevant.
### Master key creation
* gpg --expert --full-generate-key
* key type: ECC and ECC option with Curve 25519 as curve
* no expiration
* id: Forgejo Releases <contact@forgejo.org>
* gpg --export-secret-keys --armor EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 and send via encrypted email to Owners
* gpg --export --armor EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 > release-team-gpg.pub
* commit to the secret repository
### Subkey creation and renewal
* gpg --expert --edit-key EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
* addkey
* key type: ECC (signature only)
* key validity: one year
* create [an issue](https://codeberg.org/forgejo/forgejo/issues) to schedule the renewal
#### 2023
* gpg --export --armor F7CBF02094E7665E17ED6C44E381BF3E50D53707 > 2023-release-team-gpg.pub
* gpg --export-secret-keys --armor F7CBF02094E7665E17ED6C44E381BF3E50D53707 > 2023-release-team-gpg
* commit to the secrets repository
* renewal issue https://codeberg.org/forgejo/forgejo/issues/58
### CI configuration
In the Woodpecker CI configuration the following secrets must be set:
* `releaseteamgpg` is the secret GPG key used to sign the releases
* `releaseteamuser` is the user name to authenticate with the Forgejo API and publish the releases
* `releaseteamtoken` is the token to authenticate `releaseteamuser` with the Forgejo API and publish the releases
* `domain` is `codeberg.org`
## Users, organizations and repositories
### Shared user: release-team
The [release-team](https://codeberg.org/release-team) user publishes and signs all releases. The associated email is mailto:release@forgejo.org.
The public GPG key used to sign the releases is [EB114F5E6C0DC2BCDD183550A4B61A2DC5923710](https://codeberg.org/release-team.gpg) `Forgejo Releases <release@forgejo.org>`
### Shared user: forgejo-ci
The [forgejo-ci](https://codeberg.org/forgejo-ci) user is dedicated to https://forgejo-ci.codeberg.org/ and provides it with OAuth2 credentials it uses to run.
### Shared user: forgejo-experimental-ci
The [forgejo-experimental-ci](https://codeberg.org/forgejo-experimental-ci) user is dedicated to provide the application tokens used by Woodpecker CI repositories to build releases and publish them to https://codeberg.org/forgejo-experimental. It does not (and must not) have permission to publish releases at https://codeberg.org/forgejo.
### Integration and experimental organization
The https://codeberg.org/forgejo-integration organization is dedicated to integration testing. Its purpose is to ensure all artefacts can effectively be published and retrieved by the CI/CD pipelines.
The https://codeberg.org/forgejo-experimental organization is dedicated to publishing experimental Forgejo releases. They are copied from the https://codeberg.org/forgejo-integration organization.
The `forgejo-experimental-ci` user as well as all Forgejo contributors working on the CI/CD pipeline should be owners of both organizations.
The https://codeberg.org/forgejo-integration/forgejo repository is coupled with a Woodpecker CI repository configured with the credentials provided by the https://codeberg.org/forgejo-experimental-ci user. It runs the pipelines found in `releases/woodpecker-build/*.yml` which builds and publishes an unsigned release in https://codeberg.org/forgejo-integration.
### Experimental and release repositories
The https://codeberg.org/forgejo/experimental private repository is coupled with a Woodpecker CI repository configured with the credentials provided by the https://codeberg.org/forgejo-experimental-ci user. It runs the pipelines found in `releases/woodpecker-publish/*.yml` which signs and copies a release from https://codeberg.org/forgejo-integration into https://codeberg.org/forgejo-experimental.
The https://codeberg.org/forgejo/release private repository is coupled with a Woodpecker CI repository configured with the credentials provided by the https://codeberg.org/release-team user. It runs the pipelines found in `releases/woodpecker-publish/*.yml` which signs and copies a release from https://codeberg.org/forgejo-integration into https://codeberg.org/forgejo.

56
CONTRIBUTING/SECRETS.md Normal file
View file

@ -0,0 +1,56 @@
# Secrets
All Forgejo credentials are shared among the [secret keepers](https://codeberg.org/forgejo/meta/src/branch/readme/TEAMS.md#secrets-keeper) teams in a private repository with encrypted content.
## Get started
1. Make sure you have a GPG Key, or [create one](https://github.com/NicoHood/gpgit#12-key-generation)
2. Send someone else your public key and ask this person to add yourself as a recipient
```
# Commands for the other person
$ gpg --import public_key.asc
# The following command will open a prompt, with the available public keys.
# Choose the one you just added and all secrets will be re-encrypted with this new key.
$ gopass recipients add
```
3. [Install gopass](https://www.gopass.pw/#install)
> :warning: When installing on Ubuntu or Debian you can either download the deb package, install manually or build from source or use our APT repository ([github comment](https://github.com/gopasspw/gopass/issues/1849#issuecomment-802789285) with more information).
4. Clone this repo using `gopass` (the name and email are for `git config`)
```
$ gopass clone git@codeberg.org:forgejo/gopass.git
```
5. Check the consistency of the gopass storage
```
$ gopass fsck
```
## Get a secret
Show the whole secret file:
```
$ gopass show ovh.com/manager
```
Copy the password in the clipboard:
```
$ gopass show -c ovh.com/manager
```
Copy the `user` part of the secret in the clipboard:
```
$ gopass show -c ovh.com/manager user
```
## Insert or edit a secret
```
$ gopass edit ovh.com/manager
```
In the editor, insert the password on the first line.
You may then add lines with a `key: value` syntax (`user: username` for instance).
## Debugging and manual git operations
The following command will show the location and status of the git repo (all git commands are available).
```
$ gopass git status
```

124
CONTRIBUTING/WORKFLOW.md Normal file
View file

@ -0,0 +1,124 @@
# Development workflow
Forgejo is a soft fork, i.e. a set of commits applied to the Gitea development branch and the stable branches. On a regular basis those commits are rebased and modified if necessary to keep working. All Forgejo commits are merged into a branch from which binary releases and packages are created and distributed. The development workflow is a set of conventions Forgejo developers are expected to follow to work together.
Discussions on how the workflow should evolve happen [in the isssue tracker](https://codeberg.org/forgejo/forgejo/issues?type=all&state=open&labels=&milestone=0&assignee=0&q=%5BWORKFLOW%5D).
## Naming conventions
### Development
* Gitea: main
* Forgejo: forgejo
* Feature branches: forgejo-feature-name
### Stable
* Gitea: release/vX.Y
* Forgejo: vX.Y/forgejo
* Feature branches: vX.Y/forgejo-feature-name
### Soft fork history
Before rebasing on top of Gitea, all branches are copied to `soft-fork/YYYY-MM-DD/<branch>` for safekeeping. Older `soft-fork/*/<branch>` branches are converted into references under the same name. Similar to how pull requests store their head, they do not clutter the list of branches but can be retrieved if needed with `git fetch +refs/soft-fork/*:refs/soft-fork/*`. Tooling to automate this archival process [is available](https://codeberg.org/forgejo-contrib/soft-fork-tools/src/branch/master/README.md#archive-branches).
### Tags
Because the branches are rebased on top of Gitea, only the latest tag will be found in a given branch. For instance `v1.18.0-1` won't be found in the `v1.18/forgejo` branch after it is rebased.
## Rebasing
### *Feature branch*
The *Gitea* branches are mirrored with the Gitea development and stable branches.
On a regular basis, each *Feature branch* is rebased against the base *Gitea* branch.
### forgejo branch
The latest *Gitea* branch resets the *forgejo* branch and all *Feature branches* are merged into it.
If tests pass after pushing *forgejo* to the https://codeberg.org/forgejo-integration/forgejo repository, it can be pushed to the https://codeberg.org/forgejo/forgejo repository.
If tests do not pass, an issue is filed to the *Feature branch* that fails the test. Once the issue is resolved, another round of rebasing starts.
### Cherry picking and rebasing
Because Forgejo is a soft fork of Gitea, the commits in feature branches need to be cherry-picked on top of their base branch. They cannot be rebased using `git rebase`, because their base branch has been rebased.
Here is how the commits in the `forgejo-f3` branch can be cherry-picked on top of the latest `forgejo-development` branch:
```
$ git fetch --all
$ git remote get-url forgejo
git@codeberg.org:forgejo/forgejo.git
$ git checkout -b forgejo/forgejo-f3
$ git reset --hard forgejo/forgejo-development
$ git cherry-pick $(git rev-list --reverse forgejo/soft-fork/2022-12-10/forgejo-development..forgejo/soft-fork/2022-12-10/forgejo-f3)
$ git push --force forgejo-f3 forgejo/forgejo-f3
```
## Feature branches
All *Feature branches* are based on the {vX.Y/,}forgejo-development branch which provides development tools and documentation.
The `forgejo-development` branch is based on the {vX.Y/,}forgejo-ci branch which provides the Woodpecker CI configuration.
The purpose of each *Feature branch* is documented below:
### General purpose
* [forgejo-ci](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-ci) based on [main](https://codeberg.org/forgejo/forgejo/src/branch/main)
Woodpecker CI configuration, including the release process.
* Backports: [v1.18/forgejo-ci](https://codeberg.org/forgejo/forgejo/src/branch/v1.18/forgejo-ci)
* [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development) based on [forgejo-ci](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-ci)
Forgejo development tools and documentation.
* Backports: [v1.18/forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/v1.18/forgejo-development)
### Dependency
* [forgejo-dependency](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-dependency) based on [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development)
Each commit is prefixed with the name of dependency in uppercase, for instance **[GOTH]** or **[GITEA]**. They are standalone and implement either a bug fix or a feature that is in the process of being contributed to the dependency. It is better to contribute directly to the dependency instead of adding a commit to this branch but it is sometimes not possible, for instance when someone does not have a GitHub account. The author of the commit is responsible for rebasing and resolve conflicts. The ultimate goal of this branch is to be empty and it is expected that a continuous effort is made to reduce its content so that the technical debt it represents does not burden Forgejo long term.
* Backports: [v1.18/forgejo-dependency](https://codeberg.org/forgejo/forgejo/src/branch/v1.18/forgejo-dependency)
### [Privacy](https://codeberg.org/forgejo/forgejo/issues?labels=83271)
* [forgejo-privacy](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-privacy) based on [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development)
Customize Forgejo to have more privacy.
* Backports: [v1.18/forgejo-privacy](https://codeberg.org/forgejo/forgejo/src/branch/v1.18/forgejo-privacy)
### Branding
* [forgejo-branding](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-branding) based on [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development)
Replacing upstream branding with Forgejo branding
### [Internationalization](https://codeberg.org/forgejo/forgejo/issues?labels=82637)
* [forgejo-i18n](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-i18n) based on [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development)
Internationalization support for Forgejo with a workflow based on Weblate.
### [Accessibility](https://codeberg.org/forgejo/forgejo/issues?labels=81214)
* Backports only: [v1.18/forgejo-a11y](https://codeberg.org/forgejo/forgejo/src/branch/v1.18/forgejo-a11y) based on [v1.18/forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/v1.18/forgejo-development)
Backport future upstream a11y improvements to the current release of Forgejo
### [Federation](https://codeberg.org/forgejo/forgejo/issues?labels=79349)
* [forgejo-federation](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-federation) based on [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development)
Federation support for Forgejo
* [forgejo-f3](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-f3) based on [forgejo-development](https://codeberg.org/forgejo/forgejo/src/branch/forgejo-development)
[F3](https://lab.forgefriends.org/friendlyforgeformat/gof3) support for Forgejo
## Pull requests and feature branches
Most people who are used to contributing will be familiar with the workflow of sending a pull request against the default branch. When that happens the reviewer should change the base branch to the appropriate *Feature branch* instead. If the pull request does not fit in any *Feature branch*, the reviewer needs to make decision to either:
* Decline the pull request because it is best contributed to Gitea
* Create a new *Feature branch*
Returning contributors can figure out which *Feature branch* to base their pull request on using the list of *Feature branches*.
## Granularity
*Feature branches* can contain a number of commits grouped together, for instance for branding the documentation, the landing page and the footer. It makes it convenient for people working on that topic to get the big picture without browsing multiple branches. Creating a new *Feature branch* for each individual commit, while possible, is likely to be difficult to work with.
Observing the granularity of the existing *Feature branches* is the best way to figure out what works and what does not. It requires adjustments from time to time depending on the number of contributors and the complexity of the Forgejo codebase that sits on top of Gitea.

View file

@ -1,68 +1,30 @@
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.23-alpine3.20 as build-env
#Build stage
FROM --platform=$BUILDPLATFORM golang:1.20-alpine3.17 AS build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}
ENV GOPROXY ${GOPROXY:-direct}
ARG RELEASE_VERSION
ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS="bindata timetzdata $TAGS"
ENV TAGS "bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS
#
# Transparently cross compile for the target platform
#
COPY --from=xx / /
ARG TARGETPLATFORM
RUN apk --no-cache add clang lld
RUN xx-apk --no-cache add gcc musl-dev
ENV CGO_ENABLED=1
RUN xx-go --wrap
#
# for go generate and binfmt to find
# without it the generate phase will fail with
# #19 25.04 modules/public/public_bindata.go:8: running "go": exit status 1
# #19 25.39 aarch64-binfmt-P: Could not open '/lib/ld-musl-aarch64.so.1': No such file or directory
# why exactly is it needed? where is binfmt involved?
#
RUN cp /*-alpine-linux-musl*/lib/ld-musl-*.so.1 /lib || true
#Build deps
RUN apk --no-cache add build-base git nodejs npm
#Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
RUN make clean
RUN make frontend
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
RUN LDFLAGS="-buildid=" make RELEASE_VERSION=$RELEASE_VERSION GOFLAGS="-trimpath" go-check generate-backend static-executable && xx-verify gitea
#Checkout version if set
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean-all build
# Copy local files
COPY docker/root /tmp/local
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
# Set permissions
RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/tmp/local/usr/local/bin/gitea \
/tmp/local/etc/s6/gitea/* \
/tmp/local/etc/s6/openssh/* \
/tmp/local/etc/s6/.s6-svscan/* \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM code.forgejo.org/oci/golang:1.23-alpine3.20
ARG RELEASE_VERSION
LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.authors="Forgejo" \
org.opencontainers.image.url="https://forgejo.org" \
org.opencontainers.image.documentation="https://forgejo.org/download/#container-image" \
org.opencontainers.image.source="https://codeberg.org/forgejo/forgejo" \
org.opencontainers.image.version="${RELEASE_VERSION}" \
org.opencontainers.image.vendor="Forgejo" \
org.opencontainers.image.licenses="GPL-3.0-or-later" \
org.opencontainers.image.title="Forgejo. Beyond coding. We forge." \
org.opencontainers.image.description="Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job."
FROM alpine:3.17
LABEL maintainer="contact@forgejo.org"
EXPOSE 22 3000
@ -77,8 +39,7 @@ RUN apk --no-cache add \
s6 \
sqlite \
su-exec \
gnupg \
&& rm -rf /var/cache/apk/*
gnupg
RUN addgroup \
-S -g 1000 \
@ -92,17 +53,16 @@ RUN addgroup \
git && \
echo "git:*" | chpasswd -e
ENV USER=git
ENV GITEA_CUSTOM=/data/gitea
ENV USER git
ENV GITEA_CUSTOM /data/gitea
VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"]
COPY --from=build-env /tmp/local /
RUN cd /usr/local/bin ; ln -s gitea forgejo
COPY docker/root /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
RUN ln /app/gitea/gitea /app/gitea/forgejo-cli
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
RUN chmod 755 /usr/bin/entrypoint /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
RUN chmod 755 /etc/s6/gitea/* /etc/s6/openssh/* /etc/s6/.s6-svscan/*

View file

@ -1,65 +1,30 @@
FROM --platform=$BUILDPLATFORM docker.io/tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM code.forgejo.org/oci/golang:1.23-alpine3.20 as build-env
#Build stage
FROM --platform=$BUILDPLATFORM golang:1.20-alpine3.17 AS build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}
ENV GOPROXY ${GOPROXY:-direct}
ARG RELEASE_VERSION
ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS="bindata timetzdata $TAGS"
ENV TAGS "bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS
#
# Transparently cross compile for the target platform
#
COPY --from=xx / /
ARG TARGETPLATFORM
RUN apk --no-cache add clang lld
RUN xx-apk --no-cache add gcc musl-dev
ENV CGO_ENABLED=1
RUN xx-go --wrap
#
# for go generate and binfmt to find
# without it the generate phase will fail with
# #19 25.04 modules/public/public_bindata.go:8: running "go": exit status 1
# #19 25.39 aarch64-binfmt-P: Could not open '/lib/ld-musl-aarch64.so.1': No such file or directory
# why exactly is it needed? where is binfmt involved?
#
RUN cp /*-alpine-linux-musl*/lib/ld-musl-*.so.1 /lib || true
#Build deps
RUN apk --no-cache add build-base git nodejs npm
#Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
RUN make clean
RUN make frontend
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
RUN make RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea
#Checkout version if set
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean-all build
# Copy local files
COPY docker/rootless /tmp/local
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
# Set permissions
RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/tmp/local/usr/local/bin/docker-setup.sh \
/tmp/local/usr/local/bin/gitea \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM code.forgejo.org/oci/golang:1.23-alpine3.20
LABEL maintainer="contact@forgejo.org" \
org.opencontainers.image.authors="Forgejo" \
org.opencontainers.image.url="https://forgejo.org" \
org.opencontainers.image.documentation="https://forgejo.org/download/#container-image" \
org.opencontainers.image.source="https://codeberg.org/forgejo/forgejo" \
org.opencontainers.image.version="${RELEASE_VERSION}" \
org.opencontainers.image.vendor="Forgejo" \
org.opencontainers.image.licenses="GPL-3.0-or-later" \
org.opencontainers.image.title="Forgejo. Beyond coding. We forge." \
org.opencontainers.image.description="Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job."
FROM alpine:3.17
LABEL maintainer="contact@forgejo.org"
EXPOSE 2222 3000
@ -70,8 +35,7 @@ RUN apk --no-cache add \
gettext \
git \
curl \
gnupg \
&& rm -rf /var/cache/apk/*
gnupg
RUN addgroup \
-S -g 1000 \
@ -87,28 +51,24 @@ RUN addgroup \
RUN mkdir -p /var/lib/gitea /etc/gitea
RUN chown git:git /var/lib/gitea /etc/gitea
COPY --from=build-env /tmp/local /
RUN cd /usr/local/bin ; ln -s gitea forgejo
COPY docker/rootless /
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
RUN ln /app/gitea/gitea /app/gitea/forgejo-cli
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh /usr/local/bin/docker-setup.sh /app/gitea/gitea /usr/local/bin/gitea /usr/local/bin/environment-to-ini
#git:git
USER 1000:1000
ENV GITEA_WORK_DIR=/var/lib/gitea
ENV GITEA_CUSTOM=/var/lib/gitea/custom
ENV GITEA_TEMP=/tmp/gitea
ENV TMPDIR=/tmp/gitea
ENV GITEA_WORK_DIR /var/lib/gitea
ENV GITEA_CUSTOM /var/lib/gitea/custom
ENV GITEA_TEMP /tmp/gitea
ENV TMPDIR /tmp/gitea
# Legacy config file for backwards compatibility
# TODO: remove on next major version release
ENV GITEA_APP_INI_LEGACY=/etc/gitea/app.ini
ENV GITEA_APP_INI=${GITEA_CUSTOM}/conf/app.ini
ENV HOME="/var/lib/gitea/git"
#TODO add to docs the ability to define the ini to load (useful to test and revert a config)
ENV GITEA_APP_INI /etc/gitea/app.ini
ENV HOME "/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"]
WORKDIR /var/lib/gitea
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD []

695
LICENSE
View file

@ -1,674 +1,21 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
Copyright (c) 2022 The Forgejo Authors
Copyright (c) 2016 The Gitea Authors
Copyright (c) 2015 The Gogs Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

50
MAINTAINERS Normal file
View file

@ -0,0 +1,50 @@
Alexey Makhov <amakhov@avito.ru> (@makhov)
Bo-Yi Wu <appleboy.tw@gmail.com> (@appleboy)
Ethan Koenig <ethantkoenig@gmail.com> (@ethantkoenig)
Kees de Vries <bouwko@gmail.com> (@Bwko)
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
Matthias Loibl <mail@matthiasloibl.com> (@metalmatze)
Morgan Bazalgette <the@howl.moe> (@thehowl)
Rachid Zarouali <nobody@nobody.tld> (@xinity)
Rémy Boulanouar <admin@dblk.org> (@DblK)
Sandro Santilli <strk@kbt.io> (@strk)
Thibault Meyer <meyer.thibault@gmail.com> (@0xbaadf00d)
Thomas Boerger <thomas@webhippie.de> (@tboerger)
Patrick G <geek1011@outlook.com> (@geek1011)
Antoine Girard <sapk@sapk.fr> (@sapk)
Lauris Bukšis-Haberkorns <lauris@nix.lv> (@lafriks)
Jonas Östanbäck <jonas.ostanback@gmail.com> (@cez81)
David Schneiderbauer <dschneiderbauer@gmail.com> (@daviian)
Peter Žeby <morlinest@gmail.com> (@morlinest)
Matti Ranta <techknowlogick@gitea.io> (@techknowlogick)
Jonas Franz <info@jonasfranz.software> (@jonasfranz)
Alexey Terentyev <axifnx@gmail.com> (@axifive)
Lanre Adelowo <yo@lanre.wtf> (@adelowo)
Konrad Langenberg <k@knt.li> (@kolaente)
He-Long Zhang <outman99@hotmail.com> (@BetaCat0)
Andrew Thornton <art27@cantab.net> (@zeripath)
John Olheiser <john.olheiser@gmail.com> (@jolheiser)
Richard Mahn <rich.mahn@unfoldingword.org> (@richmahn)
Mrsdizzie <info@mrsdizzie.com> (@mrsdizzie)
silverwind <me@silverwind.io> (@silverwind)
Gary Kim <gary@garykim.dev> (@gary-kim)
Guillermo Prandi <gitea.maint@mailfilter.com.ar> (@guillep2k)
Mura Li <typeless@ctli.io> (@typeless)
6543 <6543@obermui.de> (@6543)
jaqra <jaqra@hotmail.com> (@jaqra)
David Svantesson <davidsvantesson@gmail.com> (@davidsvantesson)
a1012112796 <1012112796@qq.com> (@a1012112796)
Karl Heinz Marbaise <kama@soebes.de> (@khmarbaise)
Norwin Roosen <git@nroo.de> (@noerw)
Kyle Dumont <kdumontnu@gmail.com> (@kdumontnu)
Patrick Schratz <patrick.schratz@gmail.com> (@pat-s)
Janis Estelmann <admin@oldschoolhack.me> (@KN4CK3R)
Steven Kriegler <sk.bunsenbrenner@gmail.com> (@justusbunsi)
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
Leon Hofmeister <dev.lh@web.de> (@delvh)
Wim <wim@42.be> (@42wim)
Xinyu Zhou <i@sourcehut.net> (@xin-u)
Jason Song <i@wolfogre.com> (@wolfogre)
Yarden Shoham <hrsi88@gmail.com> (@yardenshoham)

777
Makefile

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
<div align="center">
<img src="./assets/logo.svg" alt="" width="192" align="center" />
<img src="https://codeberg.org/forgejo/meta/raw/branch/readme/logo/forgejo.svg" alt="" width="192" align="center" />
<h1 align="center">Welcome to Forgejo</h1>
</div>
@ -35,16 +35,12 @@ If you like any of the following, Forgejo is literally meant for you:
- Privacy: From update checker to default settings: Forgejo is built to be **privacy first** for you and your crew.
- Federation: (WIP) We are actively working to connect software forges with each other through **ActivityPub**,
and create a collaborative network of personal instances.
Interested? [Read more](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/CONTRIBUTING/WORKFLOW.md#federation-https-codeberg-org-forgejo-forgejo-issues-labels-79349)
## Learn more
Dive into the [documentation](https://forgejo.org/docs/latest/), subscribe to releases and blog post on [our website](https://forgejo.org), <a href="https://floss.social/@forgejo" rel="me">find us on the Fediverse</a> or hop into [our Matrix room](https://matrix.to/#/#forgejo-chat:matrix.org) if you have any questions or want to get involved.
Subscribe to releases and blog post on [our website](https://forgejo.org), <a href="https://floss.social/@forgejo" rel="me">find us on the Fediverse</a> or hop into [our Matrix room](https://matrix.to/#/#forgejo-chat:matrix.org) if you have any questions or want to get involved.
## License
Forgejo is distributed under the terms of the [GPL version 3.0](LICENSE) or any later version.
The agreement for this license [was documented in June 2023](https://codeberg.org/forgejo/governance/pulls/24) and implemented during the development of Forgejo v9.0. All Forgejo versions before v9.0 are distributed under the MIT license.
## Get involved

File diff suppressed because it is too large Load diff

2
assets/emoji.json generated

File diff suppressed because one or more lines are too long

View file

@ -1,27 +1,31 @@
<svg viewBox="0 0 212 212" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
circle {
fill: none;
stroke: #000;
stroke-width: 15;
}
path {
fill: none;
stroke: #000;
stroke-width: 25;
}
.orange {
stroke:#ff6600;
}
.red {
stroke:#d40000;
}
</style>
<g transform="translate(6,6)">
<path d="M58 168 v-98 a50 50 0 0 1 50-50 h20" class="orange" />
<path d="M58 168 v-30 a50 50 0 0 1 50-50 h20" class="red" />
<circle cx="142" cy="20" r="18" class="orange" />
<circle cx="142" cy="88" r="18" class="red" />
<circle cx="58" cy="180" r="18" class="red" />
</g>
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="main_outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 640 640" style="enable-background:new 0 0 640 640;" xml:space="preserve">
<g>
<path id="teabag" style="fill:#FFFFFF" d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8
c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4
c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"/>
<g>
<g>
<path style="fill:#609926" d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2
c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5
c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5
c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3
c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1
C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4
c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7
S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55
c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8
l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"/>
<path style="fill:#609926" d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4
c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1
c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9
c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3
c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3
c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29
c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8
C343.2,346.5,335,363.3,326.8,380.1z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 677 B

After

Width:  |  Height:  |  Size: 2.5 KiB

378
assets/go-licenses.json generated

File diff suppressed because one or more lines are too long

View file

@ -1,27 +1,31 @@
<svg viewBox="0 0 212 212" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
circle {
fill: none;
stroke: #000;
stroke-width: 15;
}
path {
fill: none;
stroke: #000;
stroke-width: 25;
}
.orange {
stroke:#ff6600;
}
.red {
stroke:#d40000;
}
</style>
<g transform="translate(6,6)">
<path d="M58 168 v-98 a50 50 0 0 1 50-50 h20" class="orange" />
<path d="M58 168 v-30 a50 50 0 0 1 50-50 h20" class="red" />
<circle cx="142" cy="20" r="18" class="orange" />
<circle cx="142" cy="88" r="18" class="red" />
<circle cx="58" cy="180" r="18" class="red" />
</g>
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="main_outline" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 640 640" style="enable-background:new 0 0 640 640;" xml:space="preserve">
<g>
<path id="teabag" style="fill:#FFFFFF" d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8
c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4
c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"/>
<g>
<g>
<path style="fill:#609926" d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2
c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5
c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5
c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3
c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1
C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4
c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7
S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55
c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8
l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"/>
<path style="fill:#609926" d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4
c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1
c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9
c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3
c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3
c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29
c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8
C343.2,346.5,335,363.3,326.8,380.1z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 677 B

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -1,6 +1,7 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build vendor
package main

View file

@ -1,115 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/setting"
)
func main() {
if len(os.Args) != 2 {
fmt.Println("usage: backport-locales <to-ref>")
fmt.Println("eg: backport-locales release/v1.19")
os.Exit(1)
}
mustNoErr := func(err error) {
if err != nil {
panic(err)
}
}
collectInis := func(ref string) map[string]setting.ConfigProvider {
inis := map[string]setting.ConfigProvider{}
err := filepath.WalkDir("options/locale", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() || !strings.HasSuffix(d.Name(), ".ini") {
return nil
}
cfg, err := setting.NewConfigProviderForLocale(path)
mustNoErr(err)
inis[path] = cfg
fmt.Printf("collecting: %s @ %s\n", path, ref)
return nil
})
mustNoErr(err)
return inis
}
// collect new locales from current working directory
inisNew := collectInis("HEAD")
// switch to the target ref, and collect the old locales
cmd := exec.Command("git", "checkout", os.Args[1])
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
mustNoErr(cmd.Run())
inisOld := collectInis(os.Args[1])
// use old en-US as the base, and copy the new translations to the old locales
enUsOld := inisOld["options/locale/locale_en-US.ini"]
brokenWarned := make(container.Set[string])
for path, iniOld := range inisOld {
if iniOld == enUsOld {
continue
}
iniNew := inisNew[path]
if iniNew == nil {
continue
}
for _, secEnUS := range enUsOld.Sections() {
secOld := iniOld.Section(secEnUS.Name())
secNew := iniNew.Section(secEnUS.Name())
for _, keyEnUs := range secEnUS.Keys() {
if secNew.HasKey(keyEnUs.Name()) {
oldStr := secOld.Key(keyEnUs.Name()).String()
newStr := secNew.Key(keyEnUs.Name()).String()
broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
if broken {
brokenWarned.Add(secOld.Name() + "." + keyEnUs.Name())
fmt.Println("----")
fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
fmt.Printf("\tnew: %s\n", strings.ReplaceAll(newStr, "\n", "\\n"))
continue
}
secOld.Key(keyEnUs.Name()).SetValue(newStr)
}
}
}
mustNoErr(iniOld.SaveTo(path))
}
fmt.Println("========")
for path, iniNew := range inisNew {
for _, sec := range iniNew.Sections() {
for _, key := range sec.Keys() {
str := sec.Key(key.Name()).String()
broken := strings.Contains(str, "\n")
broken = broken || strings.HasPrefix(str, "`") != strings.HasSuffix(str, "`")
broken = broken || strings.HasPrefix(str, "\"`")
broken = broken || strings.HasPrefix(str, "`\"")
broken = broken || strings.Count(str, `"`)%2 == 1
broken = broken || strings.Count(str, "`")%2 == 1
if broken && !brokenWarned.Contains(sec.Name()+"."+key.Name()) {
fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
fmt.Println("----")
}
}
}
}
}

View file

@ -25,7 +25,7 @@ import (
var optionLogVerbose bool
func logVerbose(msg string, args ...any) {
func logVerbose(msg string, args ...interface{}) {
if optionLogVerbose {
log.Printf(msg, args...)
}
@ -65,11 +65,11 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
"modules",
"routers",
"services",
"tools",
}
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
@ -204,6 +204,17 @@ Example:
`, "file-batch-exec")
}
func getGoVersion() string {
goModFile, err := os.ReadFile("go.mod")
if err != nil {
log.Fatalf(`Faild to read "go.mod": %v`, err)
os.Exit(1)
}
goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`)
goModVersionLine := goModVersionRegex.Find(goModFile)
return string(goModVersionLine[3:])
}
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"]
if fileFilter == "" {
@ -268,8 +279,7 @@ func main() {
log.Print("the -d option is not supported by gitea-fmt")
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}

View file

@ -7,7 +7,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFormatImportsSimple(t *testing.T) {
@ -30,7 +29,7 @@ import (
)
`
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, string(formatted))
}
@ -93,7 +92,7 @@ import (
)
`
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, string(formatted))
}
@ -121,5 +120,5 @@ import (
"image/gif"
)
`))
require.ErrorIs(t, err, errInvalidCommentBetweenImports)
assert.ErrorIs(t, err, errInvalidCommentBetweenImports)
}

View file

@ -25,7 +25,7 @@ import (
const (
gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
maxUnicodeVersion = 15
maxUnicodeVersion = 14
)
var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
@ -60,13 +60,13 @@ func main() {
// generate data
buf, err := generate()
if err != nil {
log.Fatalf("generate err: %v", err)
log.Fatal(err)
}
// write
err = os.WriteFile(*flagOut, buf, 0o644)
if err != nil {
log.Fatalf("WriteFile err: %v", err)
log.Fatal(err)
}
}
@ -142,7 +142,7 @@ func generate() ([]byte, error) {
}
}
// Forgejo customizations
// gitea customizations
i, ok := aliasMap["tada"]
if ok {
data[i].Aliases = append(data[i].Aliases, "hooray")

View file

@ -7,16 +7,13 @@ package main
import (
"encoding/json"
"fmt"
"io/fs"
"os"
"path"
goPath "path"
"path/filepath"
"regexp"
"sort"
"strings"
"code.gitea.io/gitea/modules/container"
)
// regexp is based on go-license, excluding README and NOTICE
@ -30,41 +27,14 @@ type LicenseEntry struct {
}
func main() {
if len(os.Args) != 3 {
fmt.Println("usage: go run generate-go-licenses.go <base-dir> <out-json-file>")
os.Exit(1)
}
base, out := os.Args[1], os.Args[2]
// Add ext for excluded files because license_test.go will be included for some reason.
// And there are more files that should be excluded, check with:
//
// go run github.com/google/go-licenses@v1.6.0 save . --force --save_path=.go-licenses 2>/dev/null
// find .go-licenses -type f | while read FILE; do echo "${$(basename $FILE)##*.}"; done | sort -u
// AUTHORS
// COPYING
// LICENSE
// Makefile
// NOTICE
// gitignore
// go
// md
// mod
// sum
// toml
// txt
// yml
//
// It could be removed once we have a better regex.
excludedExt := container.SetOf(".gitignore", ".go", ".mod", ".sum", ".toml", ".yml")
var paths []string
paths := []string{}
err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
if err != nil {
return err
}
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt.Contains(filepath.Ext(entry.Name())) {
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) {
return nil
}
paths = append(paths, path)
@ -76,41 +46,28 @@ func main() {
sort.Strings(paths)
var entries []LicenseEntry
entries := []LicenseEntry{}
for _, path := range paths {
path := filepath.ToSlash(path)
{
licenseText, err := os.ReadFile("LICENSE")
licenseText, err := os.ReadFile(path)
if err != nil {
panic(err)
}
entries = append(entries, LicenseEntry{
Name: "codeberg.org/forgejo/forgejo",
Path: "codeberg.org/forgejo/forgejo/GPL-3.0-or-later",
LicenseText: string(licenseText),
})
}
for _, filePath := range paths {
licenseText, err := os.ReadFile(filePath)
if err != nil {
panic(err)
}
pkgPath := filepath.ToSlash(filePath)
pkgPath = strings.TrimPrefix(pkgPath, base+"/")
pkgName := path.Dir(pkgPath)
path = strings.Replace(path, base+"/", "", 1)
name := goPath.Dir(path)
// There might be a bug somewhere in go-licenses that sometimes interprets the
// root package as "." and sometimes as "code.gitea.io/gitea". Workaround by
// removing both of them for the sake of stable output.
if pkgName == "." || pkgName == "code.gitea.io/gitea" {
if name == "." || name == "code.gitea.io/gitea" {
continue
}
entries = append(entries, LicenseEntry{
Name: pkgName,
Path: pkgPath,
Name: name,
Path: path,
LicenseText: string(licenseText),
})
}
@ -120,11 +77,6 @@ func main() {
panic(err)
}
// Ensure file has a final newline
if jsonBytes[len(jsonBytes)-1] != '\n' {
jsonBytes = append(jsonBytes, '\n')
}
err = os.WriteFile(out, jsonBytes, 0o644)
if err != nil {
panic(err)

82
build/generate-images.js Executable file
View file

@ -0,0 +1,82 @@
#!/usr/bin/env node
import imageminZopfli from 'imagemin-zopfli';
import {optimize} from 'svgo';
import {fabric} from 'fabric';
import {readFile, writeFile} from 'node:fs/promises';
function exit(err) {
if (err) console.error(err);
process.exit(err ? 1 : 0);
}
function loadSvg(svg) {
return new Promise((resolve) => {
fabric.loadSVGFromString(svg, (objects, options) => {
resolve({objects, options});
});
});
}
async function generate(svg, path, {size, bg}) {
const outputFile = new URL(path, import.meta.url);
if (String(outputFile).endsWith('.svg')) {
const {data} = optimize(svg, {
plugins: [
'preset-default',
'removeDimensions',
{
name: 'addAttributesToSVGElement',
params: {attributes: [{width: size}, {height: size}]}
},
],
});
await writeFile(outputFile, data);
return;
}
const {objects, options} = await loadSvg(svg);
const canvas = new fabric.Canvas();
canvas.setDimensions({width: size, height: size});
const ctx = canvas.getContext('2d');
ctx.scale(options.width ? (size / options.width) : 1, options.height ? (size / options.height) : 1);
if (bg) {
canvas.add(new fabric.Rect({
left: 0,
top: 0,
height: size * (1 / (size / options.height)),
width: size * (1 / (size / options.width)),
fill: 'white',
}));
}
canvas.add(fabric.util.groupSVGElements(objects, options));
canvas.renderAll();
let png = Buffer.from([]);
for await (const chunk of canvas.createPNGStream()) {
png = Buffer.concat([png, chunk]);
}
png = await imageminZopfli({more: true})(png);
await writeFile(outputFile, png);
}
async function main() {
const gitea = process.argv.slice(2).includes('gitea');
const logoSvg = await readFile(new URL('../assets/logo.svg', import.meta.url), 'utf8');
const faviconSvg = await readFile(new URL('../assets/favicon.svg', import.meta.url), 'utf8');
await Promise.all([
generate(logoSvg, '../public/img/logo.svg', {size: 32}),
generate(logoSvg, '../public/img/logo.png', {size: 512}),
generate(faviconSvg, '../public/img/favicon.svg', {size: 32}),
generate(faviconSvg, '../public/img/favicon.png', {size: 180}),
generate(logoSvg, '../public/img/avatar_default.png', {size: 200}),
generate(logoSvg, '../public/img/apple-touch-icon.png', {size: 180, bg: true}),
gitea && generate(logoSvg, '../public/img/gitea.svg', {size: 32}),
]);
}
main().then(exit).catch(exit);

58
build/generate-svg.js Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env node
import fastGlob from 'fast-glob';
import {optimize} from 'svgo';
import {parse} from 'node:path';
import {readFile, writeFile, mkdir} from 'node:fs/promises';
import {fileURLToPath} from 'node:url';
const glob = (pattern) => fastGlob.sync(pattern, {
cwd: fileURLToPath(new URL('..', import.meta.url)),
absolute: true,
});
function exit(err) {
if (err) console.error(err);
process.exit(err ? 1 : 0);
}
async function processFile(file, {prefix, fullName} = {}) {
let name;
if (fullName) {
name = fullName;
} else {
name = parse(file).name;
if (prefix) name = `${prefix}-${name}`;
if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons
}
const {data} = optimize(await readFile(file, 'utf8'), {
plugins: [
{name: 'preset-default'},
{name: 'removeXMLNS'},
{name: 'removeDimensions'},
{name: 'prefixIds', params: {prefix: () => name}},
{name: 'addClassesToSVGElement', params: {classNames: ['svg', name]}},
{name: 'addAttributesToSVGElement', params: {attributes: [{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'}]}},
],
});
await writeFile(fileURLToPath(new URL(`../public/img/svg/${name}.svg`, import.meta.url)), data);
}
function processFiles(pattern, opts) {
return glob(pattern).map((file) => processFile(file, opts));
}
async function main() {
try {
await mkdir(fileURLToPath(new URL('../public/img/svg', import.meta.url)), {recursive: true});
} catch {}
await Promise.all([
...processFiles('node_modules/@primer/octicons/build/svg/*-16.svg', {prefix: 'octicon'}),
...processFiles('web_src/svg/*.svg'),
...processFiles('public/img/gitea.svg', {fullName: 'gitea-gitea'}),
]);
}
main().then(exit).catch(exit);

View file

@ -1,15 +0,0 @@
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import (
"fmt"
)
func main() {
fmt.Println("NOT NEEDED: THIS IS A NOOP AS OF Forgejo 7.0 BUT KEPT FOR BACKWARD COMPATIBILITY")
}

View file

@ -1,20 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"fmt"
"io"
"os"
)
func main() {
_, err := io.Copy(os.Stdout, os.Stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v", err)
os.Exit(1)
}
}

View file

@ -1,43 +1,14 @@
#!/bin/sh
# this script runs in alpine image which only has `sh` shell
set +e
if sed --version 2>/dev/null | grep -q GNU; then
SED_INPLACE="sed -i"
else
SED_INPLACE="sed -i ''"
fi
set -e
if [ ! -f ./options/locale/locale_en-US.ini ]; then
echo "please run this script in the root directory of the project"
exit 1
fi
mv ./options/locale/locale_en-US.ini ./options/
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
# see i18n_test.go for more details
# this script helps to unquote the Crowdin outputs for the quirky ini library
# * find all `key="...\"..."` lines
# * remove the leading quote
# * remove the trailing quote
# * unescape the quotes
# * eg: key="...\"..." => key=..."...
$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
s/"$//
# Make sure to only change lines that have the translation enclosed between quotes
sed -i -r -e '/^[a-zA-Z0-9_.-]+[ ]*=[ ]*".*"$/ {
s/^([a-zA-Z0-9_.-]+)[ ]*="/\1=/
s/\\"/"/g
s/"$//
}' ./options/locale/*.ini
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
# * eg: key="... => key=`"...`
# * eg: key=..." => key=`..."`
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
# Remove translation under 25% of en_us
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
baselines=$((baselines / 4))

View file

@ -1,55 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli/v2"
)
var (
// CmdActions represents the available actions sub-commands.
CmdActions = &cli.Command{
Name: "actions",
Usage: "Manage Forgejo Actions",
Subcommands: []*cli.Command{
subcmdActionsGenRunnerToken,
},
}
subcmdActionsGenRunnerToken = &cli.Command{
Name: "generate-runner-token",
Usage: "Generate a new token for a runner to use to register with the server",
Action: runGenerateActionsRunnerToken,
Aliases: []string{"grt"},
Flags: []cli.Flag{
&cli.StringFlag{
Name: "scope",
Aliases: []string{"s"},
Value: "",
Usage: "{owner}[/{repo}] - leave empty for a global runner",
},
},
}
)
func runGenerateActionsRunnerToken(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setting.MustInstalled()
scope := c.String("scope")
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
if extra.HasError() {
return handleCliResponseExtra(extra)
}
_, _ = fmt.Printf("%s\n", respText.Text)
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -1,111 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
"os"
"text/tabwriter"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
auth_service "code.gitea.io/gitea/services/auth"
"github.com/urfave/cli/v2"
)
var (
microcmdAuthDelete = &cli.Command{
Name: "delete",
Usage: "Delete specific auth source",
Flags: []cli.Flag{idFlag},
Action: runDeleteAuth,
}
microcmdAuthList = &cli.Command{
Name: "list",
Usage: "List auth sources",
Action: runListAuth,
Flags: []cli.Flag{
&cli.IntFlag{
Name: "min-width",
Usage: "Minimal cell width including any padding for the formatted table",
Value: 0,
},
&cli.IntFlag{
Name: "tab-width",
Usage: "width of tab characters in formatted table (equivalent number of spaces)",
Value: 8,
},
&cli.IntFlag{
Name: "padding",
Usage: "padding added to a cell before computing its width",
Value: 1,
},
&cli.StringFlag{
Name: "pad-char",
Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`,
Value: "\t",
},
&cli.BoolFlag{
Name: "vertical-bars",
Usage: "Set to true to print vertical bars between columns",
},
},
}
)
func runListAuth(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
authSources, err := db.Find[auth_model.Source](ctx, auth_model.FindSourcesOptions{})
if err != nil {
return err
}
flags := tabwriter.AlignRight
if c.Bool("vertical-bars") {
flags |= tabwriter.Debug
}
padChar := byte('\t')
if len(c.String("pad-char")) > 0 {
padChar = c.String("pad-char")[0]
}
// loop through each source and print
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
fmt.Fprintf(w, "ID\tName\tType\tEnabled\n")
for _, source := range authSources {
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive)
}
w.Flush()
return nil
}
func runDeleteAuth(c *cli.Context) error {
if !c.IsSet("id") {
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
if err != nil {
return err
}
return auth_service.DeleteSource(ctx, source)
}

View file

@ -11,131 +11,131 @@ import (
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/services/auth/source/ldap"
"github.com/urfave/cli/v2"
"github.com/urfave/cli"
)
type (
authService struct {
initDB func(ctx context.Context) error
createAuthSource func(context.Context, *auth.Source) error
updateAuthSource func(context.Context, *auth.Source) error
getAuthSourceByID func(ctx context.Context, id int64) (*auth.Source, error)
createAuthSource func(*auth.Source) error
updateAuthSource func(*auth.Source) error
getAuthSourceByID func(id int64) (*auth.Source, error)
}
)
var (
commonLdapCLIFlags = []cli.Flag{
&cli.StringFlag{
cli.StringFlag{
Name: "name",
Usage: "Authentication name.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "not-active",
Usage: "Deactivate the authentication source.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "active",
Usage: "Activate the authentication source.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "security-protocol",
Usage: "Security protocol name.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "skip-tls-verify",
Usage: "Disable TLS verification.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "host",
Usage: "The address where the LDAP server can be reached.",
},
&cli.IntFlag{
cli.IntFlag{
Name: "port",
Usage: "The port to use when connecting to the LDAP server.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "user-search-base",
Usage: "The LDAP base at which user accounts will be searched for.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "user-filter",
Usage: "An LDAP filter declaring how to find the user record that is attempting to authenticate.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "admin-filter",
Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "restricted-filter",
Usage: "An LDAP filter specifying if a user should be given restricted status.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "allow-deactivate-all",
Usage: "Allow empty search results to deactivate all users.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "username-attribute",
Usage: "The attribute of the users LDAP record containing the user name.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "firstname-attribute",
Usage: "The attribute of the users LDAP record containing the users first name.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "surname-attribute",
Usage: "The attribute of the users LDAP record containing the users surname.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "email-attribute",
Usage: "The attribute of the users LDAP record containing the users email address.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "public-ssh-key-attribute",
Usage: "The attribute of the users LDAP record containing the users public ssh key.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "skip-local-2fa",
Usage: "Set to true to skip local 2fa for users authenticated by this source",
},
&cli.StringFlag{
cli.StringFlag{
Name: "avatar-attribute",
Usage: "The attribute of the users LDAP record containing the users avatar.",
},
}
ldapBindDnCLIFlags = append(commonLdapCLIFlags,
&cli.StringFlag{
cli.StringFlag{
Name: "bind-dn",
Usage: "The DN to bind to the LDAP server with when searching for the user.",
},
&cli.StringFlag{
cli.StringFlag{
Name: "bind-password",
Usage: "The password for the Bind DN, if any.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "attributes-in-bind",
Usage: "Fetch attributes in bind DN context.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "synchronize-users",
Usage: "Enable user synchronization.",
},
&cli.BoolFlag{
cli.BoolFlag{
Name: "disable-synchronize-users",
Usage: "Disable user synchronization.",
},
&cli.UintFlag{
cli.UintFlag{
Name: "page-size",
Usage: "Search page size.",
})
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
&cli.StringFlag{
cli.StringFlag{
Name: "user-dn",
Usage: "The user's DN.",
Usage: "The users DN.",
})
microcmdAuthAddLdapBindDn = &cli.Command{
cmdAuthAddLdapBindDn = cli.Command{
Name: "add-ldap",
Usage: "Add new LDAP (via Bind DN) authentication source",
Action: func(c *cli.Context) error {
@ -144,7 +144,7 @@ var (
Flags: ldapBindDnCLIFlags,
}
microcmdAuthUpdateLdapBindDn = &cli.Command{
cmdAuthUpdateLdapBindDn = cli.Command{
Name: "update-ldap",
Usage: "Update existing LDAP (via Bind DN) authentication source",
Action: func(c *cli.Context) error {
@ -153,7 +153,7 @@ var (
Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...),
}
microcmdAuthAddLdapSimpleAuth = &cli.Command{
cmdAuthAddLdapSimpleAuth = cli.Command{
Name: "add-ldap-simple",
Usage: "Add new LDAP (simple auth) authentication source",
Action: func(c *cli.Context) error {
@ -162,7 +162,7 @@ var (
Flags: ldapSimpleAuthCLIFlags,
}
microcmdAuthUpdateLdapSimpleAuth = &cli.Command{
cmdAuthUpdateLdapSimpleAuth = cli.Command{
Name: "update-ldap-simple",
Usage: "Update existing LDAP (simple auth) authentication source",
Action: func(c *cli.Context) error {
@ -289,12 +289,12 @@ func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) {
// getAuthSource gets the login source by its id defined in the command line flags.
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
func (a *authService) getAuthSource(ctx context.Context, c *cli.Context, authType auth.Type) (*auth.Source, error) {
func (a *authService) getAuthSource(c *cli.Context, authType auth.Type) (*auth.Source, error) {
if err := argsSet(c, "id"); err != nil {
return nil, err
}
authSource, err := a.getAuthSourceByID(ctx, c.Int64("id"))
authSource, err := a.getAuthSourceByID(c.Int64("id"))
if err != nil {
return nil, err
}
@ -332,7 +332,7 @@ func (a *authService) addLdapBindDn(c *cli.Context) error {
return err
}
return a.createAuthSource(ctx, authSource)
return a.createAuthSource(authSource)
}
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
@ -344,7 +344,7 @@ func (a *authService) updateLdapBindDn(c *cli.Context) error {
return err
}
authSource, err := a.getAuthSource(ctx, c, auth.LDAP)
authSource, err := a.getAuthSource(c, auth.LDAP)
if err != nil {
return err
}
@ -354,7 +354,7 @@ func (a *authService) updateLdapBindDn(c *cli.Context) error {
return err
}
return a.updateAuthSource(ctx, authSource)
return a.updateAuthSource(authSource)
}
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
@ -383,7 +383,7 @@ func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
return err
}
return a.createAuthSource(ctx, authSource)
return a.createAuthSource(authSource)
}
// updateLdapBindDn updates a new LDAP (simple auth) authentication source.
@ -395,7 +395,7 @@ func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
return err
}
authSource, err := a.getAuthSource(ctx, c, auth.DLDAP)
authSource, err := a.getAuthSource(c, auth.DLDAP)
if err != nil {
return err
}
@ -405,5 +405,5 @@ func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
return err
}
return a.updateAuthSource(ctx, authSource)
return a.updateAuthSource(authSource)
}

View file

@ -11,8 +11,7 @@ import (
"code.gitea.io/gitea/services/auth/source/ldap"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
"github.com/urfave/cli"
)
func TestAddLdapBindDn(t *testing.T) {
@ -211,15 +210,15 @@ func TestAddLdapBindDn(t *testing.T) {
initDB: func(context.Context) error {
return nil
},
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
createAuthSource: func(authSource *auth.Source) error {
createdAuthSource = authSource
return nil
},
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
updateAuthSource: func(authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call updateAuthSource", n)
return nil
},
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
getAuthSourceByID: func(id int64) (*auth.Source, error) {
assert.FailNow(t, "case %d: should not call getAuthSourceByID", n)
return nil, nil
},
@ -227,7 +226,7 @@ func TestAddLdapBindDn(t *testing.T) {
// Create a copy of command to test
app := cli.NewApp()
app.Flags = microcmdAuthAddLdapBindDn.Flags
app.Flags = cmdAuthAddLdapBindDn.Flags
app.Action = service.addLdapBindDn
// Run it
@ -235,7 +234,7 @@ func TestAddLdapBindDn(t *testing.T) {
if c.errMsg != "" {
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
} else {
require.NoError(t, err, "case %d: should have no errors", n)
assert.NoError(t, err, "case %d: should have no errors", n)
assert.Equal(t, c.source, createdAuthSource, "case %d: wrong authSource", n)
}
}
@ -442,15 +441,15 @@ func TestAddLdapSimpleAuth(t *testing.T) {
initDB: func(context.Context) error {
return nil
},
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
createAuthSource: func(authSource *auth.Source) error {
createdAuthSource = authSource
return nil
},
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
updateAuthSource: func(authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call updateAuthSource", n)
return nil
},
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
getAuthSourceByID: func(id int64) (*auth.Source, error) {
assert.FailNow(t, "case %d: should not call getAuthSourceByID", n)
return nil, nil
},
@ -458,7 +457,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
// Create a copy of command to test
app := cli.NewApp()
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
app.Flags = cmdAuthAddLdapSimpleAuth.Flags
app.Action = service.addLdapSimpleAuth
// Run it
@ -466,7 +465,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
if c.errMsg != "" {
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
} else {
require.NoError(t, err, "case %d: should have no errors", n)
assert.NoError(t, err, "case %d: should have no errors", n)
assert.Equal(t, c.authSource, createdAuthSource, "case %d: wrong authSource", n)
}
}
@ -897,15 +896,15 @@ func TestUpdateLdapBindDn(t *testing.T) {
initDB: func(context.Context) error {
return nil
},
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
createAuthSource: func(authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call createAuthSource", n)
return nil
},
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
updateAuthSource: func(authSource *auth.Source) error {
updatedAuthSource = authSource
return nil
},
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
getAuthSourceByID: func(id int64) (*auth.Source, error) {
if c.id != 0 {
assert.Equal(t, c.id, id, "case %d: wrong id", n)
}
@ -921,7 +920,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
// Create a copy of command to test
app := cli.NewApp()
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
app.Flags = cmdAuthUpdateLdapBindDn.Flags
app.Action = service.updateLdapBindDn
// Run it
@ -929,7 +928,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
if c.errMsg != "" {
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
} else {
require.NoError(t, err, "case %d: should have no errors", n)
assert.NoError(t, err, "case %d: should have no errors", n)
assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n)
}
}
@ -1287,15 +1286,15 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
initDB: func(context.Context) error {
return nil
},
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
createAuthSource: func(authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call createAuthSource", n)
return nil
},
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
updateAuthSource: func(authSource *auth.Source) error {
updatedAuthSource = authSource
return nil
},
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
getAuthSourceByID: func(id int64) (*auth.Source, error) {
if c.id != 0 {
assert.Equal(t, c.id, id, "case %d: wrong id", n)
}
@ -1311,7 +1310,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
// Create a copy of command to test
app := cli.NewApp()
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
app.Flags = cmdAuthUpdateLdapSimpleAuth.Flags
app.Action = service.updateLdapSimpleAuth
// Run it
@ -1319,7 +1318,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
if c.errMsg != "" {
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
} else {
require.NoError(t, err, "case %d: should have no errors", n)
assert.NoError(t, err, "case %d: should have no errors", n)
assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n)
}
}

View file

@ -1,299 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
"net/url"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/services/auth/source/oauth2"
"github.com/urfave/cli/v2"
)
var (
oauthCLIFlags = []cli.Flag{
&cli.StringFlag{
Name: "name",
Value: "",
Usage: "Application Name",
},
&cli.StringFlag{
Name: "provider",
Value: "",
Usage: "OAuth2 Provider",
},
&cli.StringFlag{
Name: "key",
Value: "",
Usage: "Client ID (Key)",
},
&cli.StringFlag{
Name: "secret",
Value: "",
Usage: "Client Secret",
},
&cli.StringFlag{
Name: "auto-discover-url",
Value: "",
Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)",
},
&cli.StringFlag{
Name: "use-custom-urls",
Value: "false",
Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints",
},
&cli.StringFlag{
Name: "custom-tenant-id",
Value: "",
Usage: "Use custom Tenant ID for OAuth endpoints",
},
&cli.StringFlag{
Name: "custom-auth-url",
Value: "",
Usage: "Use a custom Authorization URL (option for GitLab/GitHub)",
},
&cli.StringFlag{
Name: "custom-token-url",
Value: "",
Usage: "Use a custom Token URL (option for GitLab/GitHub)",
},
&cli.StringFlag{
Name: "custom-profile-url",
Value: "",
Usage: "Use a custom Profile URL (option for GitLab/GitHub)",
},
&cli.StringFlag{
Name: "custom-email-url",
Value: "",
Usage: "Use a custom Email URL (option for GitHub)",
},
&cli.StringFlag{
Name: "icon-url",
Value: "",
Usage: "Custom icon URL for OAuth2 login source",
},
&cli.BoolFlag{
Name: "skip-local-2fa",
Usage: "Set to true to skip local 2fa for users authenticated by this source",
},
&cli.StringSliceFlag{
Name: "scopes",
Value: nil,
Usage: "Scopes to request when to authenticate against this OAuth2 source",
},
&cli.StringFlag{
Name: "required-claim-name",
Value: "",
Usage: "Claim name that has to be set to allow users to login with this source",
},
&cli.StringFlag{
Name: "required-claim-value",
Value: "",
Usage: "Claim value that has to be set to allow users to login with this source",
},
&cli.StringFlag{
Name: "group-claim-name",
Value: "",
Usage: "Claim name providing group names for this source",
},
&cli.StringFlag{
Name: "admin-group",
Value: "",
Usage: "Group Claim value for administrator users",
},
&cli.StringFlag{
Name: "restricted-group",
Value: "",
Usage: "Group Claim value for restricted users",
},
&cli.StringFlag{
Name: "group-team-map",
Value: "",
Usage: "JSON mapping between groups and org teams",
},
&cli.BoolFlag{
Name: "group-team-map-removal",
Usage: "Activate automatic team membership removal depending on groups",
},
}
microcmdAuthAddOauth = &cli.Command{
Name: "add-oauth",
Usage: "Add new Oauth authentication source",
Action: runAddOauth,
Flags: oauthCLIFlags,
}
microcmdAuthUpdateOauth = &cli.Command{
Name: "update-oauth",
Usage: "Update existing Oauth authentication source",
Action: runUpdateOauth,
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
}
)
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
var customURLMapping *oauth2.CustomURLMapping
if c.IsSet("use-custom-urls") {
customURLMapping = &oauth2.CustomURLMapping{
TokenURL: c.String("custom-token-url"),
AuthURL: c.String("custom-auth-url"),
ProfileURL: c.String("custom-profile-url"),
EmailURL: c.String("custom-email-url"),
Tenant: c.String("custom-tenant-id"),
}
} else {
customURLMapping = nil
}
return &oauth2.Source{
Provider: c.String("provider"),
ClientID: c.String("key"),
ClientSecret: c.String("secret"),
OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
CustomURLMapping: customURLMapping,
IconURL: c.String("icon-url"),
SkipLocalTwoFA: c.Bool("skip-local-2fa"),
Scopes: c.StringSlice("scopes"),
RequiredClaimName: c.String("required-claim-name"),
RequiredClaimValue: c.String("required-claim-value"),
GroupClaimName: c.String("group-claim-name"),
AdminGroup: c.String("admin-group"),
RestrictedGroup: c.String("restricted-group"),
GroupTeamMap: c.String("group-team-map"),
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
}
}
func runAddOauth(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
config := parseOAuth2Config(c)
if config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
}
}
return auth_model.CreateSource(ctx, &auth_model.Source{
Type: auth_model.OAuth2,
Name: c.String("name"),
IsActive: true,
Cfg: config,
})
}
func runUpdateOauth(c *cli.Context) error {
if !c.IsSet("id") {
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
if err != nil {
return err
}
oAuth2Config := source.Cfg.(*oauth2.Source)
if c.IsSet("name") {
source.Name = c.String("name")
}
if c.IsSet("provider") {
oAuth2Config.Provider = c.String("provider")
}
if c.IsSet("key") {
oAuth2Config.ClientID = c.String("key")
}
if c.IsSet("secret") {
oAuth2Config.ClientSecret = c.String("secret")
}
if c.IsSet("auto-discover-url") {
oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url")
}
if c.IsSet("icon-url") {
oAuth2Config.IconURL = c.String("icon-url")
}
if c.IsSet("scopes") {
oAuth2Config.Scopes = c.StringSlice("scopes")
}
if c.IsSet("required-claim-name") {
oAuth2Config.RequiredClaimName = c.String("required-claim-name")
}
if c.IsSet("required-claim-value") {
oAuth2Config.RequiredClaimValue = c.String("required-claim-value")
}
if c.IsSet("group-claim-name") {
oAuth2Config.GroupClaimName = c.String("group-claim-name")
}
if c.IsSet("admin-group") {
oAuth2Config.AdminGroup = c.String("admin-group")
}
if c.IsSet("restricted-group") {
oAuth2Config.RestrictedGroup = c.String("restricted-group")
}
if c.IsSet("group-team-map") {
oAuth2Config.GroupTeamMap = c.String("group-team-map")
}
if c.IsSet("group-team-map-removal") {
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
}
// update custom URL mapping
customURLMapping := &oauth2.CustomURLMapping{}
if oAuth2Config.CustomURLMapping != nil {
customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL
customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL
customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL
customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL
customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") {
customURLMapping.TokenURL = c.String("custom-token-url")
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") {
customURLMapping.AuthURL = c.String("custom-auth-url")
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") {
customURLMapping.ProfileURL = c.String("custom-profile-url")
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") {
customURLMapping.EmailURL = c.String("custom-email-url")
}
if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") {
customURLMapping.Tenant = c.String("custom-tenant-id")
}
oAuth2Config.CustomURLMapping = customURLMapping
source.Cfg = oAuth2Config
return auth_model.UpdateSource(ctx, source)
}

View file

@ -1,200 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"strings"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/auth/source/smtp"
"github.com/urfave/cli/v2"
)
var (
smtpCLIFlags = []cli.Flag{
&cli.StringFlag{
Name: "name",
Value: "",
Usage: "Application Name",
},
&cli.StringFlag{
Name: "auth-type",
Value: "PLAIN",
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
},
&cli.StringFlag{
Name: "host",
Value: "",
Usage: "SMTP Host",
},
&cli.IntFlag{
Name: "port",
Usage: "SMTP Port",
},
&cli.BoolFlag{
Name: "force-smtps",
Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.",
Value: true,
},
&cli.BoolFlag{
Name: "skip-verify",
Usage: "Skip TLS verify.",
Value: true,
},
&cli.StringFlag{
Name: "helo-hostname",
Value: "",
Usage: "Hostname sent with HELO. Leave blank to send current hostname",
},
&cli.BoolFlag{
Name: "disable-helo",
Usage: "Disable SMTP helo.",
Value: true,
},
&cli.StringFlag{
Name: "allowed-domains",
Value: "",
Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')",
},
&cli.BoolFlag{
Name: "skip-local-2fa",
Usage: "Skip 2FA to log on.",
Value: true,
},
&cli.BoolFlag{
Name: "active",
Usage: "This Authentication Source is Activated.",
Value: true,
},
}
microcmdAuthAddSMTP = &cli.Command{
Name: "add-smtp",
Usage: "Add new SMTP authentication source",
Action: runAddSMTP,
Flags: smtpCLIFlags,
}
microcmdAuthUpdateSMTP = &cli.Command{
Name: "update-smtp",
Usage: "Update existing SMTP authentication source",
Action: runUpdateSMTP,
Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...),
}
)
func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
if c.IsSet("auth-type") {
conf.Auth = c.String("auth-type")
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
if !util.SliceContainsString(validAuthTypes, strings.ToUpper(c.String("auth-type"))) {
return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5")
}
conf.Auth = c.String("auth-type")
}
if c.IsSet("host") {
conf.Host = c.String("host")
}
if c.IsSet("port") {
conf.Port = c.Int("port")
}
if c.IsSet("allowed-domains") {
conf.AllowedDomains = c.String("allowed-domains")
}
if c.IsSet("force-smtps") {
conf.ForceSMTPS = c.Bool("force-smtps")
}
if c.IsSet("skip-verify") {
conf.SkipVerify = c.Bool("skip-verify")
}
if c.IsSet("helo-hostname") {
conf.HeloHostname = c.String("helo-hostname")
}
if c.IsSet("disable-helo") {
conf.DisableHelo = c.Bool("disable-helo")
}
if c.IsSet("skip-local-2fa") {
conf.SkipLocalTwoFA = c.Bool("skip-local-2fa")
}
return nil
}
func runAddSMTP(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
if !c.IsSet("name") || len(c.String("name")) == 0 {
return errors.New("name must be set")
}
if !c.IsSet("host") || len(c.String("host")) == 0 {
return errors.New("host must be set")
}
if !c.IsSet("port") {
return errors.New("port must be set")
}
active := true
if c.IsSet("active") {
active = c.Bool("active")
}
var smtpConfig smtp.Source
if err := parseSMTPConfig(c, &smtpConfig); err != nil {
return err
}
// If not set default to PLAIN
if len(smtpConfig.Auth) == 0 {
smtpConfig.Auth = "PLAIN"
}
return auth_model.CreateSource(ctx, &auth_model.Source{
Type: auth_model.SMTP,
Name: c.String("name"),
IsActive: active,
Cfg: &smtpConfig,
})
}
func runUpdateSMTP(c *cli.Context) error {
if !c.IsSet("id") {
return errors.New("--id flag is missing")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
if err != nil {
return err
}
smtpConfig := source.Cfg.(*smtp.Source)
if err := parseSMTPConfig(c, smtpConfig); err != nil {
return err
}
if c.IsSet("name") {
source.Name = c.String("name")
}
if c.IsSet("active") {
source.IsActive = c.Bool("active")
}
source.Cfg = smtpConfig
return auth_model.UpdateSource(ctx, source)
}

View file

@ -1,46 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/modules/graceful"
repo_service "code.gitea.io/gitea/services/repository"
"github.com/urfave/cli/v2"
)
var (
microcmdRegenHooks = &cli.Command{
Name: "hooks",
Usage: "Regenerate git-hooks",
Action: runRegenerateHooks,
}
microcmdRegenKeys = &cli.Command{
Name: "keys",
Usage: "Regenerate authorized_keys file",
Action: runRegenerateKeys,
}
)
func runRegenerateHooks(_ *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
}
func runRegenerateKeys(_ *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
return asymkey_model.RewriteAllPublicKeys(ctx)
}

View file

@ -1,21 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"github.com/urfave/cli/v2"
)
var subcmdUser = &cli.Command{
Name: "user",
Usage: "Modify users",
Subcommands: []*cli.Command{
microcmdUserCreate,
microcmdUserList,
microcmdUserChangePassword,
microcmdUserDelete,
microcmdUserGenerateAccessToken,
microcmdUserMustChangePassword,
},
}

View file

@ -1,80 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
user_service "code.gitea.io/gitea/services/user"
"github.com/urfave/cli/v2"
)
var microcmdUserChangePassword = &cli.Command{
Name: "change-password",
Usage: "Change a user's password",
Action: runChangePassword,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Value: "",
Usage: "The user to change password for",
},
&cli.StringFlag{
Name: "password",
Aliases: []string{"p"},
Value: "",
Usage: "New password to set for user",
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "User must change password",
Value: true,
},
},
}
func runChangePassword(c *cli.Context) error {
if err := argsSet(c, "username", "password"); err != nil {
return err
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
user, err := user_model.GetUserByName(ctx, c.String("username"))
if err != nil {
return err
}
opts := &user_service.UpdateAuthOptions{
Password: optional.Some(c.String("password")),
MustChangePassword: optional.Some(c.Bool("must-change-password")),
}
if err := user_service.UpdateAuth(ctx, user, opts); err != nil {
switch {
case errors.Is(err, password.ErrMinLength):
return fmt.Errorf("password is not long enough, needs to be at least %d characters", setting.MinPasswordLength)
case errors.Is(err, password.ErrComplexity):
return errors.New("password does not meet complexity requirements")
case errors.Is(err, password.ErrIsPwned):
return errors.New("the password is in a list of stolen passwords previously exposed in public data breaches, please try again with a different password, to see more details: https://haveibeenpwned.com/Passwords")
default:
return err
}
}
fmt.Printf("%s's password has been successfully updated!\n", user.Name)
return nil
}

View file

@ -1,175 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
pwd "code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli/v2"
)
var microcmdUserCreate = &cli.Command{
Name: "create",
Usage: "Create a new user in database",
Action: runCreateUser,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "Username. DEPRECATED: use username instead",
},
&cli.StringFlag{
Name: "username",
Usage: "Username",
},
&cli.StringFlag{
Name: "password",
Usage: "User password",
},
&cli.StringFlag{
Name: "email",
Usage: "User email address",
},
&cli.BoolFlag{
Name: "admin",
Usage: "User is an admin",
},
&cli.BoolFlag{
Name: "random-password",
Usage: "Generate a random password for the user",
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
Value: true,
DisableDefaultText: true,
},
&cli.IntFlag{
Name: "random-password-length",
Usage: "Length of the random password to be generated",
Value: 12,
},
&cli.BoolFlag{
Name: "access-token",
Usage: "Generate access token for the user",
},
&cli.BoolFlag{
Name: "restricted",
Usage: "Make a restricted user account",
},
},
}
func runCreateUser(c *cli.Context) error {
if err := argsSet(c, "email"); err != nil {
return err
}
if c.IsSet("name") && c.IsSet("username") {
return errors.New("cannot set both --name and --username flags")
}
if !c.IsSet("name") && !c.IsSet("username") {
return errors.New("one of --name or --username flags must be set")
}
if c.IsSet("password") && c.IsSet("random-password") {
return errors.New("cannot set both -random-password and -password flags")
}
var username string
if c.IsSet("username") {
username = c.String("username")
} else {
username = c.String("name")
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
var password string
if c.IsSet("password") {
password = c.String("password")
} else if c.IsSet("random-password") {
var err error
password, err = pwd.Generate(c.Int("random-password-length"))
if err != nil {
return err
}
fmt.Printf("generated random password is '%s'\n", password)
} else {
return errors.New("must set either password or random-password flag")
}
isAdmin := c.Bool("admin")
mustChangePassword := true // always default to true
if c.IsSet("must-change-password") {
// if the flag is set, use the value provided by the user
mustChangePassword = c.Bool("must-change-password")
} else {
// check whether there are users in the database
hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{})
if err != nil {
return fmt.Errorf("IsTableNotEmpty: %w", err)
}
if !hasUserRecord {
// if this is the first admin being created, don't force to change password (keep the old behavior)
mustChangePassword = false
}
}
restricted := optional.None[bool]()
if c.IsSet("restricted") {
restricted = optional.Some(c.Bool("restricted"))
}
// default user visibility in app.ini
visibility := setting.Service.DefaultUserVisibilityMode
u := &user_model.User{
Name: username,
Email: c.String("email"),
Passwd: password,
IsAdmin: isAdmin,
MustChangePassword: mustChangePassword,
Visibility: visibility,
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: optional.Some(true),
IsRestricted: restricted,
}
if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %w", err)
}
if c.Bool("access-token") {
t := &auth_model.AccessToken{
Name: "gitea-admin",
UID: u.ID,
}
if err := auth_model.NewAccessToken(ctx, t); err != nil {
return err
}
fmt.Printf("Access token was successfully created... %s\n", t.Token)
}
fmt.Printf("New user '%s' has been successfully created!\n", username)
return nil
}

View file

@ -1,81 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"errors"
"fmt"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/storage"
user_service "code.gitea.io/gitea/services/user"
"github.com/urfave/cli/v2"
)
var microcmdUserDelete = &cli.Command{
Name: "delete",
Usage: "Delete specific user by id, name or email",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "id",
Usage: "ID of user of the user to delete",
},
&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Usage: "Username of the user to delete",
},
&cli.StringFlag{
Name: "email",
Aliases: []string{"e"},
Usage: "Email of the user to delete",
},
&cli.BoolFlag{
Name: "purge",
Usage: "Purge user, all their repositories, organizations and comments",
},
},
Action: runDeleteUser,
}
func runDeleteUser(c *cli.Context) error {
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
return errors.New("You must provide the id, username or email of a user to delete")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
if err := storage.Init(); err != nil {
return err
}
var err error
var user *user_model.User
if c.IsSet("email") {
user, err = user_model.GetUserByEmail(ctx, c.String("email"))
} else if c.IsSet("username") {
user, err = user_model.GetUserByName(ctx, c.String("username"))
} else {
user, err = user_model.GetUserByID(ctx, c.Int64("id"))
}
if err != nil {
return err
}
if c.IsSet("username") && user.LowerName != strings.ToLower(strings.TrimSpace(c.String("username"))) {
return fmt.Errorf("The user %s who has email %s does not match the provided username %s", user.Name, c.String("email"), c.String("username"))
}
if c.IsSet("id") && user.ID != c.Int64("id") {
return fmt.Errorf("The user %s does not match the provided id %d", user.Name, c.Int64("id"))
}
return user_service.DeleteUser(ctx, user, c.Bool("purge"))
}

Some files were not shown because too many files have changed in this diff Show more