Compare commits

..

183 Commits

Author SHA1 Message Date
Lunny Xiao d0b8e3c8e1 Changelog for v1.14.4 (#16348) 2021-07-06 15:56:15 +03:00
6543 7ff8e863a5 Fix error message if user not exist (#16343)
Co-authored-by: Sergey Dryabzhinsky <sergey@rusoft.ru>
2021-07-05 23:58:47 +03:00
zeripath c65e49d72f Fix relative links in postprocessed images (#16334) (#16340)
* Fix relative links in postprocessed images (#16334)

If a pre-post-processed file contains relative img tags these need to be updated
and joined correctly with the prefix. Finally, the node attributes need to be updated.

Fix #16308

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
2021-07-04 16:28:29 +02:00
6543 50084daa4c Fix list_options GetStartEnd (#16303) (#16305)
end is start + pageSize and not start + page

Co-authored-by: sebastian-sauer <sauer.sebastian@gmail.com>
2021-06-30 00:23:24 +01:00
6543 c7db7438b7 Fix API to return author for author on commits(#16276) (#16277) 2021-06-27 21:37:42 -04:00
zeripath e11f042a95 Handle misencoding of login_source cfg in mssql (#16268) (#16275)
Backport #16268

Unfortunately due a bug in xorm (see https://gitea.com/xorm/xorm/pulls/1957) updating
loginsources on MSSQL causes them to become corrupted. (#16252)

Whilst waiting for the referenced PR to be merged and to handle the corrupted
loginsources correctly we need to add a wrapper to the `FromDB()` methods to look
for and ignore the misplaced BOMs that have been added.

Fix #16252

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-06-27 22:33:25 +01:00
KN4CK3R 87782636e6 Fixed issues not updated by commits (#16254) (#16261)
`UpdateIssuesCommit` may get called with fewer commits because of `FeedMaxCommitNum` and therefore may miss some commands.
2021-06-26 14:11:31 +02:00
zeripath b935472cdf Improve efficiency in FindRenderizableReferenceNumeric and getReference (#16251) (#16255)
* Improve efficiency in FindRenderizableReferenceNumeric and getReferences (#16251)

* The Fuzzer is running on a non-repo urlprefix which is incorrect for RenderRaw
* Make FindRenderizableReferenceNumeric and getReferences more efficient

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>

* as per comment on original pr

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-06-26 08:31:03 +01:00
6543 8ac48584ec Use html.Parse rather than html.ParseFragment (#16223) (#16225)
* Use html.Parse rather than html.ParseFragment
  There have been a few issues with html.ParseFragment - just use html.Parse instead.

* Skip document node

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2021-06-22 09:46:39 +08:00
KN4CK3R e898590c81 Update milestone counters on new issue (#16183) (#16224)
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2021-06-22 00:25:08 +02:00
zeripath d407857d97 reqOrgMembership calls need to be preceded by reqToken (#16198) (#16219)
Backport #16198

ReqOrgMembership calls need to be preceded by reqToken

Fix #16192

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
2021-06-21 16:20:45 +01:00
6543 8cfd6695da Changelog v1.14.3 (#16131)
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: zeripath <art27@cantab.net>
2021-06-18 17:25:20 +02:00
6543 f832e8eeea Fix some API bugs (#16184) (#16190)
* Fix some API bugs (#16184)

* Repository object only count releases as releases (fix #16144)

* EditOrg respect RepoAdminChangeTeamAccess option (fix #16013)

* adjut to v1.14
2021-06-18 19:47:34 +08:00
zeripath 544ef7d394 Encrypt migration credentials at rest (#15895) (#16187)
Backport #15895

Storing these credentials is a liability.

* Encrypt credentials with SECRET_KEY before persisting to task queue table (they need to be persisted due to the nature of the task queue)
  - security in depth: helps when attacker has access to DB only, but not app.ini
* Delete all credentials (even encrypted) from the task table, once the migration is done, for safety
  - security in depth: minimizes leaked data if attacker gains access to snapshot of both DB and app.ini
2021-06-17 22:59:28 +02:00
zeripath 5ff807acde Run processors on whole of text (#16155) (#16185)
Backport #16155

There is an inefficiency in the design of our processors which means that Emoji
and other processors run in order n^2 time.

This PR forces the processors to process the entirety of text node before passing
back up. The fundamental inefficiency remains but it should be significantly
ameliorated.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-06-17 20:01:33 +02:00
zeripath 849d316d8d issue-keyword class is being incorrectly stripped off spans (#16163) (#16172)
Backport #16163

Bluemonday sanitizer regexp rules are not additive, so the addition of the icons,
emojis and chroma syntax policy has led to this being stripped.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-06-16 06:35:54 -04:00
zeripath 946eb1321c Only check access tokens if they are likely to be tokens (#16164) (#16171)
Backprt #16164

Gitea will currently check every if every password is an access token even though
most passwords are not and cannot be access tokens.

By creation access tokens are 40 byte hexadecimal strings therefore only these should
be checked.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-06-16 05:06:27 -04:00
Andrei Yankovich bc82bb9cda Removable media support (#16138)
Add support removable media for snap version of gitia.
for get more info about removable media interface see the snapcraft [documentation](https://snapcraft.io/docs/removable-media-interface)
2021-06-12 21:27:16 +02:00
zeripath f034804e5d Set self-adjusting deadline for connection writing (#16068) (#16123)
In #16055 it appears that the simple 5s deadline doesn't work for large
file writes. Now we can't - or at least shouldn't just set no deadline
as go will happily let these connections block indefinitely. However,
what seems reasonable is to set some minimum rate we expect for writing.

This PR suggests the following algorithm:

* Every write has a minimum timeout of 5s (adjustable at compile time.)
* If there has been a previous write - then consider its previous
deadline, add half of the minimum timeout + 2s per kb about to written.
* If that new deadline is after the minimum timeout use that.

Fix #16055

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-06-11 00:26:32 +03:00
a1012112796 c1887bfc9b Fix language switch for install page (#16043) (#16128)
Signed-off-by: a1012112796 <1012112796@qq.com>
2021-06-10 21:19:40 +08:00
Lunny Xiao 41a4047e79 Fix bug on getIssueIDsByRepoID (#16119) (#16124)
* Fix bug on getIssueIDsByRepoID

* Add test
2021-06-10 06:12:18 +01:00
6543 ac84bb7183 Fix data URI scramble (#16098) (#16118)
* Fix data URI scramble (#16098)

* Removed unused method.

* No prefix for data uris.

* Added test to prevent regressions.

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2021-06-09 16:31:40 +02:00
6543 3be67e9a2b Fix http path bug (#16117) (#16120)
* Fix http path bug

* Add missed request

* add tests

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-06-09 15:58:00 +02:00
Lunny Xiao ce2ade05e6 Merge all deleteBranch as one function and also fix bug when delete branch don't close related PRs (#16067) (#16097)
* Fix bug when delete branch don't close related PRs

* Merge all deletebranch as one method

Co-authored-by: Lauris BH <lauris@nix.lv>
2021-06-07 18:27:41 +02:00
6543 1e76f7b5b7 api: fix overly strict edit pr permissions (#15900) (#16081)
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Norwin <noerw@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-06-06 12:22:05 +02:00
6543 2265058c31 git migration: don't prompt interactively for clone credentials (#15902) (#16082)
* don't prompt interactively for clone credentials

* apply GIT_TERMINAL_PROMPT=0 to all git cmds

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Norwin <noerw@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-06-06 14:02:34 +08:00
zeripath ba74fdbda9 Fix case change in ownernames (#16045) (#16050)
Backport #16045

If you change the case of a username the change needs to be propagated to their
repositories.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-06-03 13:09:43 +08:00
zeripath 0600f7972a Add missing SameSite settings for the i_like_gitea cookie (#16037) (#16039)
Backport #16037

The i_like_gitea cookie appears to be missing the SameSite settings. I think they
were present at some point but may have been removed in a merge.

This PR ensures that they are set.

Fix #15972

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-31 21:33:22 -04:00
Jimmy Praet 8007602b40 Don't manipulate input params in email notification (#16011) (#16033)
Backport #16011
2021-05-31 02:17:34 -04:00
techknowlogick 3a79f1190f Fix setting of SameSite on cookies (#15989) (#15991)
Fix #15972

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-05-27 10:02:39 -04:00
techknowlogick d95489b7ed follow redirect when fetching theme archive (#15986) (#15990) 2021-05-26 21:05:24 -04:00
fnetX (aka fralix) a9e1a37b71 Remove branch URL before IssueRefURL (#15970)
Revert change for account / org dashboard where IssueRefURLs do not
contain the full repo URL (case RepoLink is not true)

Co-authored-by: Norwin <noerw@users.noreply.github.com>

Co-authored-by: Norwin <noerw@users.noreply.github.com>
2021-05-25 16:02:19 -04:00
Tomás Warynyca 5a589ef9ec fix layout of milestone view (#15940) 2021-05-22 10:38:51 +08:00
zeripath 159bc8842a Restore PAM user autocreation functionality (#15825) (#15867)
Backport #15825

* Restore PAM user autocreation functionality

PAM autoregistration of users currently fails due to email invalidity.
This PR adds a new setting to PAM to allow an email domain to be set
or just sets the email to the noreply address and if that fails falls
back to uuid@localhost

Fix #15702

Signed-off-by: Andrew Thornton <art27@cantab.net>

* As per KN4CKER

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-05-19 10:42:36 -04:00
Norwin 4b771d393e remove unimplemented searchbar from project view (#15905) 2021-05-17 13:22:08 +02:00
zeripath 0c2cbfcb3b Move sans-serif fallback font higher than emoji fonts (#15855) (#15892)
Backport #15855

The Tor browser does not use the system-ui font and no other fonts in the stack match
its default fonts. In fact it is possible that it will in future only
match generic fonts. This means that all rendering will first try the
emoji fonts before falling back to the sans-serif font for glyphs.

In this case has the emoji fall back fonts for Tor contains empty glyphs
for numbers - in order to protect privacy - and leads to numbers being
rendered as empty glyphs. This is clearly not ideal and whilst we could
use the Arimo font - as I state above I suspect that Tor will eventually
ban detecting this and we should instead move the sans-serif font higher
in the stack so that it matches before the emoji fonts.

Partial fix of #15844

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-16 16:42:12 +03:00
6543 8c4bf4c3b4 GitHub: migrate draft releases too (#15884) (#15888)
* GitHub: migrate draft releases too

* refactor
2021-05-16 09:24:28 +02:00
6543 3bcf2e5c18 Close the gitrepo when deleting the repository (#15876) (#15887)
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2021-05-16 00:45:17 +03:00
Lunny Xiao ad54f008ac Upgrade xorm to v1.1.0 (#15869) (#15885) 2021-05-15 20:32:17 +02:00
zeripath c21167e3a2 Fix bound address/port for caddy's certmagic library (see #15848) (#15859) (#15878)
Co-authored-by: Blake Miner <miner.blake@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
2021-05-15 18:28:14 +01:00
Norwin aaa539dd2d Fix blame row height alignment (#15863) (#15883)
* fix blame row alignment on firefox
* fix blame row alignment in chrome
* fix blame row alignment in safari

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-05-15 18:12:07 +02:00
Naohisa Murakami e38134f707 Fix error message when saving generated LOCAL_ROOT_URL config (#15880) (#15882)
Backport of #15880.
2021-05-15 15:06:39 +01:00
zeripath fa96ddb327 Only write config in environment-to-ini if there are changes (#15861) (#15868)
Backport #15861

* Only write config in environment-to-ini if there are changes

Only write the new config in environment-to-ini if there are changes or the
destination is not the same as the customconf.

Fix #15719
Fix #15857

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
2021-05-15 13:07:16 +01:00
zeripath a3e8450fd5 Return go-get info on subdirs (#15642) (#15871)
Backport #15642

This PR is an alternative to #15628 and makes the go get handler a
handler.

Fix #15625

Close #15628

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-05-15 12:06:02 +01:00
zeripath 41422f0df0 Add timeout to writing to responses (#15831) (#15872)
Backport #15831

In #15826 it has become apparent that there are a few occasions when a response can
hang during writing, and because there is no timeout go will happily just block
interminably. This PR adds a fixed 5 second timeout to all writes to a connection.

Fix #15826

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-14 17:42:27 +01:00
KN4CK3R f773733252 Fix LFS commit finder not working (#15856) (#15874)
* Create a copy of the sha bytes.

Co-authored-by: Andrew Thornton <art27@cantab.net>
2021-05-14 16:39:59 +01:00
zeripath cbaf8e8785 Stop calling WriteHeader in Write (#15862) (#15873)
Backport #15862

Fixes http: superfluous response.WriteHeader call from code.gitea.io/gitea/modules/context.(*Response).WriteHeader (response.go:67)

* Looking again we don't need this writeHeader as all of our downstream
implementations will always do it for us

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-14 15:38:35 +01:00
zeripath 1bf46836da Only offer hostcertificates if they exist (#15849) (#15853)
Backport #15849

A common bug report is the otherwise harmless sshd logging:

```
Could not load host certificate "/data/ssh/ssh_host_ed25519_cert": No such file or directory
```

This PR simply checks if these files exist before creation of sshd_config and if
they do not exist, doesn't add a reference to them.

Fix #14110 amongst others.

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: 6543 <6543@obermui.de>
2021-05-13 11:12:41 -04:00
zeripath 387a1bc472 fix truncate utf8 string (#15828) (#15854)
Backport #15828

* fix truncate utf8 string.

* revoke truncated user info.

Co-authored-by: yan <sxty32@gmail.com>
2021-05-13 16:10:29 +02:00
zeripath 62daf84596 Fix bound address/port for caddy's certmagic library (#15758) (#15848)
Backport #15758

* Fix bound address/port for caddy's certmagic library

* Fix bug

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: Blake Miner <miner.blake@gmail.com>
2021-05-12 23:36:46 +01:00
techknowlogick 39d209dccc change s3 bucket name (#15847) 2021-05-12 16:12:36 -04:00
zeripath c88392e772 Upgrade unrolled/render to v1.1.1 (#15845) (#15846)
Backport #15845

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-05-12 21:54:50 +02:00
zeripath a83cde2f3f Tagger can be empty, as can Commit and Author - tolerate this (#15835) (#15839)
Backport #15835

Unfortunately some old repositories can have tags with empty Tagger, Commit
or Author. Go-Git variants will always have empty values for these whereas
the native git variant leaves them at nil. The simplest solution is just to
always have these set to empty Signatures.

v156 migration also makes the incorrect assumption that these cannot be empty.
Therefore add some handling to this and add logging and adjust broken
logging elsewhere in this migration.

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-05-12 20:09:16 +01:00
zeripath 332eb2f6d2 Queue manager FlushAll can loop rapidly - add delay (#15733) (#15840)
Backport #15733

* Queue manager FlushAll can loop rapidly - add delay

Add delay within FlushAll to prevent rapid loop when workers are busy

Signed-off-by: Andrew Thornton <art27@cantab.net>

* as per lunny

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-12 18:48:11 +01:00
zeripath 3ae1d7a59f Set autocomplete off on branches selector (#15809) (#15833)
Backport #15809

Fix #15782

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-11 23:18:07 +01:00
John Olheiser d054c4e7f3 Add err to log (#15813) (#15824)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2021-05-10 16:38:37 -04:00
Lunny Xiao 5e562e9b30 Move restore repo to internal router and invoke from command to avoid open the same db file or queues files (#15790) (#15816)
* Move restore repo to internal router and invoke from command to avoid open the same db file or queues files

* Follow @zeripath's review

* set no timeout for resotre repo private request

* make restore repo cancelable
2021-05-10 21:14:59 +08:00
6543 c57e908f36 Tests should use test files (#15801) (#15806) 2021-05-10 01:39:14 +08:00
6543 1112fef93d Changelog v1.14.2 (#15794)
* changelog tool generate

* format & add

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2021-05-09 11:26:49 +02:00
6543 af11549fb2 Ensure that ctx.Written is checked after issues(...) calls (#15797) (#15798)
Fix issue noted in #15783

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2021-05-09 09:48:52 +01:00
zeripath 76d6184cd0 Display conflict-free merge messages for pull requests (#15773) (#15796)
Backport #15773

Repositories using external issue tracker tend to use numeric issues in
commits. To prevent conflicts during issue reference parsing or inside
commit hooks, this change respects these configuration and uses the !
character to refer to pull requests in merge commit messages.

For repositories using squash merges, this was already handled.

Signed-off-by: JustusBunsi <61625851+justusbunsi@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: Steven <61625851+justusbunsi@users.noreply.github.com>
2021-05-09 10:32:48 +08:00
6543 d644709b22 Exponential Backoff for ByteFIFO (#15724) (#15793)
This PR is another in the vein of queue improvements. It suggests an
exponential backoff for bytefifo queues to reduce the load from queue
polling. This will mostly be useful for redis queues.

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
2021-05-08 14:27:00 -04:00
6543 30584a6df8 [API] make change repo settings work on empty repos (#15778) (#15789)
* API: Fix #15602

* Add TEST
2021-05-08 15:14:42 +02:00
6543 78710946f2 Use pulls in commit graph unless pulls are disabled (#15734 & #15740 & #15774) (#15775)
* Commit Graph: Pull-Requests should not link to issues (#15734)

Use `/pulls` and simplify code.

* reverse #15734 partial and comment (#15740)

* reverse & comment

* Update templates/repo/graph/commits.tmpl

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: zeripath <art27@cantab.net>

* Use pulls in commit graph unless pulls are disabled

Fix #15370

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: KN4CK3R <KN4CK3R@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>
2021-05-07 15:12:24 -04:00
6543 22d700edfd Set GIT_DIR correctly if it is not set (#15751) (#15769)
* Set GIT_DIR correctly if it is not set

* Expand out templates

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: zeripath <art27@cantab.net>
2021-05-07 20:01:25 +02:00
zeripath 6782a64a4a Defer closing the gitrepo until the end of the wrapped context functions (#15653) (#15746)
* Defer closing the gitrepo until the end of the wrapped context functions (#15653)

Backport #15653

There was a mistake in #15372 where deferral of gitrepo close occurs before it should.

This PR fixes this.
2021-05-07 18:28:02 +02:00
zeripath 1ec11ac87e Drop back to use IsAnInteractiveSession for SVC (#15749) (#15762)
Backport #15749

* Drop back to use IsAnInteractiveSession for SVC

There is an apparent permission change problem when using
IsWindowsService to determine if the SVC manager should be
used.

This PR simply drops back to using IsAnInteractiveSession as
this does not change behaviour.

Fix #15454

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Yes staticcheck I know this is deprecated

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Just leave me alone lint

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-05-07 17:44:35 +02:00
6543 2c2a30d6bb Fix bug where repositories appear unadopted (#15757) (#15767)
Fix bug where repositories with capital letters in their names appear unadopted.

Fix #15755

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-05-07 17:07:39 +02:00
6543 717b313c34 not show ref-in-new-issue pop when issue was disabled (#15761) (#15765)
fix #15718

Signed-off-by: a1012112796 <1012112796@qq.com>
Co-authored-by: a1012112796 <1012112796@qq.com>
2021-05-07 16:13:20 +02:00
6543 0a32861b28 Issue list alignment tweaks (#15483) (#15766)
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
2021-05-07 15:06:19 +02:00
zeripath 52ca7b9b65 Fix setting version table in dump (#15753) (#15759)
Backport #15753

* Fix setting version table in dump

As noted on Discord there is a problem with gitea dump where the version table
is not being dumped correctly.

This is due to a missing pointer in the TableInfo.

This PR fixes this.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update models_test.go
2021-05-07 14:04:17 +02:00
zeripath e078d08ecd Fix close button change on delete in simplemde area (#15737) (#15747)
Backport #15737

* Fix close button change on delete in simplemde area

Fix issue with close button changing when deleting in the simplemde textarea.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* apply suggestion

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
2021-05-06 23:14:15 +01:00
a1012112796 a83fb3a83a fix some ui bug about draft release (#15137) (#15745)
* fix some ui bug about draft release

- should not show draft release in tag list because
  it will't create real tag
- still show draft release without tag and commit message
  for draft release instead of 404 error
- remove tag load for attachement links because it's useless

Signed-off-by: a1012112796 <1012112796@qq.com>

* add test code

* fix test

That's because has added a new release in relaese test database.

* fix dropdown link for draft release
2021-05-06 21:23:26 +02:00
Tomás Warynyca f9b1fac4ea Fix webkit calendar icon color on arc-green (#15728) 2021-05-05 13:10:01 +08:00
6543 f1e8b8c0d7 Only log Error on getLastCommitStatus error to let pull list still be visible (#15715) 2021-05-04 14:03:31 +02:00
Kyle D dbbb75712d Move tooltip down to allow selection of Remove File on error (#15672) (#15714) 2021-05-04 07:00:29 +01:00
zeripath 462c6fdee2 Fix setting redis db path (#15698) (#15708)
Backport #15698

There is a bug setting the redis db in the common nosql manager whereby the db path
always fails.

This PR fixes this.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-03 22:30:30 +01:00
Kyle D cead819cb5 Implement delete release attachments and update release attachments' name (#14130) (#15666)
* Implement delete release attachment

* Add attachments on release edit page

* Fix bug

* Finish del release attachments

* Fix frontend lint

* Fix tests

* Support edit release attachments

* Added tests

* Remove the unnecessary parameter isCreate from UpdateReleaseOrCreatReleaseFromTag

* Rename UpdateReleaseOrCreatReleaseFromTag to UpdateRelease

* Fix middle align

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-05-03 13:27:00 -04:00
zeripath 4fa2804238 Performance improvement for last commit cache and show-ref (#15455) (#15701)
Backport #15455

* Improve performance when there are multiple commits in the last commit cache

* read refs directly if we can

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-03 16:51:41 +02:00
zeripath 3ce46a7fbd Fix DB session cleanup (#15697) (#15700)
Backport #15697

The DB session clean up needs to check expiry not created_unix.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-05-02 10:43:01 +01:00
6543 15886ce048 Fixed several activation bugs (#15473) (#15685)
* Removed unneeded form tag.

* Fixed typo.

* Fixed NPE.

* Use better error page.

* Splitted GET and POST.

Co-authored-by: KN4CK3R <KN4CK3R@users.noreply.github.com>
2021-04-30 20:14:36 -04:00
6543 a725d31496 Delete references if repository gets deleted (#15681) (#15684)
* Remove DeletedBranch and LFSLocks.

* Sort beans.

Co-authored-by: KN4CK3R <KN4CK3R@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>
2021-05-01 00:09:58 +02:00
6543 8e27f6e814 Fix orphaned objects deletion bug (#15657) (#15683)
* Fix orphaned objects deletion bug

* extend test

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
2021-04-30 22:27:26 +01:00
KN4CK3R 54263ff123 Delete protected branch if repository gets removed (#15658) (#15676)
* Added missing error parameters.

* Delete protected branch if repository gets removed.

* Added doctor fix.
2021-04-30 19:59:42 +01:00
6543 3bde297121 [API] pull notification subject status: add "merged" (#15344) (#15654)
Current subject status can be "", "open" and "closed". This add "merged" to it.
2021-04-28 20:24:56 +01:00
zeripath 0dfde367c1 Remove spurious set name from eventsource.sharedworker.js (#15643) (#15652)
Backport #15643

Fix #15617

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-28 19:50:56 +02:00
zeripath 875501584b not update updated uinx for git gc (#15637) (#15641)
Backport #15637

fix #15634

Signed-off-by: a1012112796 <1012112796@qq.com>

Co-authored-by: a1012112796 <1012112796@qq.com>
2021-04-28 03:20:47 +03:00
zeripath 4190c134e6 Fix commit graph author link (#15627) (#15630)
Backport #15627

The author link on the commit graph is incorrect and isn't providing a link to the author.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-26 20:25:51 +01:00
Lunny Xiao cae46216e4 fix webhook timeout bug (#15613) (#15621)
* Also fix the potential problem in httplib
2021-04-26 14:42:12 +02:00
techknowlogick 761111f9ed Resolve panic on failed interface conversion in migration v156 (#15604) (#15610)
go panics otherwise with `panic: interface conversion: error is git.ErrNotExist, not *git.ErrNotExist`, thanks to Codeberg/Andi for reporting this.

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-25 11:58:42 -04:00
Nathan Smith 57f1476093 Bump unrolled/render to v1.1.0 (#15581) (#15608)
v1.1.0 has improved buffer pooling
2021-04-25 14:01:52 +08:00
Lunny Xiao bdba89452d Fix missing storage init (#15589) (#15598) 2021-04-23 20:56:21 +08:00
zeripath 6e2dacfef6 If the default branch is not present do not report error on stats indexing (follow-up of #15546) (#15583) (#15594)
Backport #15546
Backport #15583

 #15546 doesn't completely fix this problem because the error returned is an ObjectNotExist
error not a BranchNotExist error.

Add test for ErrObjectNotExist too

Fix #15257

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-22 22:30:18 +02:00
Lunny Xiao c0869c295a Fix lfs management find (#15537) (#15578)
* Fix lfs management find (#15537)

Fix #15236

* Do not do 40byte conversion within ParseTreeLine
* Missed a to40ByteSHA

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Andrew Thornton <art27@cantab.net>

* Remove space

Co-authored-by: Andrew Thornton <art27@cantab.net>
2021-04-22 20:32:48 +02:00
zeripath a719311f6d Add placeholder text to deploy key textarea (#15575) (#15576)
Backport #15575

Add placeholder text to deploy key textarea

Related #15574

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-21 23:59:50 +02:00
zeripath 248b67af6f Fix NPE on view commit with notes (#15561) (#15573)
Backport #15561

Fix #15558

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-21 15:11:43 -04:00
silverwind 990c6089db Project board improvements (#15429) (#15560)
* Project board improvements

- Fix link colors
- Extract CSS to own file
- Various minor tweaks to make it look better

Fixes: https://github.com/go-gitea/gitea/issues/15424
Fixes: https://github.com/go-gitea/gitea/issues/15506
Fixes: https://github.com/go-gitea/gitea/pull/15511

* fix squashed cards on small view area

* more css fixes, add second row from issue list

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-20 20:45:00 +01:00
KN4CK3R 5da024a019 Add ETag header (#15370) (#15552)
* Add ETag header.

* Comply with RFC 7232.

* Moved logic into httpcache.go

* Changed name.

* Lint

* Implemented If-None-Match list.

* Fixed missing header on *

* Removed weak etag support.

* Removed * support.

* Added unit test.

* Lint

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-20 12:01:58 -04:00
Lunny Xiao eff2499be7 Fix bug on commit graph (#15517) (#15530) 2021-04-17 14:46:30 +02:00
zeripath 4a3c6384ac Send size to /avatars if requested (#15459) (#15528)
Backport #15459

If an avatar is requested in a particular size ensure that /avatars also gets the size request

Fix #15453

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-04-17 12:30:58 +01:00
zeripath 2b1989e59f Prevent migration 156 failure if tag commit missing (#15519) (#15527)
Backport #15519

It is possible that tag commits could be deleted or missing from repos. This causes
migration 156 to fail and breaks upgrade.

This PR simply logs the failure.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-17 12:13:15 +02:00
Mike L 340c4fc7c7 Repo branch page: label size, PR ref, new PR button alignment (#15363) (#15365) 2021-04-16 07:53:51 +02:00
6543 918d3d96ff Changelog v1.14.1 (#15498)
* RAW Changelog v1.14.1

* wordings

* Apply suggestions from code review

Co-authored-by: techknowlogick <matti@mdranta.net>

* Update CHANGELOG.md

Co-authored-by: 6543 <6543@obermui.de>

* Update CHANGELOG.md

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: techknowlogick <matti@mdranta.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-15 22:19:09 -04:00
6543 92c91d7d8b Performance improvement for list pull requests (#15447) (#15500)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-16 01:14:14 +03:00
zeripath 9dc76b2036 Fix bug clone wiki (#15499) (#15502)
Backport #15499

Fix #15494

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
2021-04-15 21:40:10 +02:00
zeripath 802a4314ef dump: Add option to skip LFS/attachment files (#15407) (#15492)
Backport #15407

* Add option to skip dumping LFS/attachment files

* Fix fmt issues

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Johan Van de Wauw <johan@gisky.be>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
2021-04-15 18:41:47 +03:00
zeripath edd4ab49c8 Ensure review dismissal only dismisses the correct review (#15477) (#15489)
Backport #15477

Fix #15472

Signed-off-by: Andrew Thornton art27@cantab.net

Co-authored-by: 6543 <6543@obermui.de>
2021-04-15 18:24:59 +03:00
zeripath 55e6cde7c1 Use subdir for URL (#15446) (#15493)
Backport #15446

Fixes #15444

Co-authored-by: KN4CK3R <KN4CK3R@users.noreply.github.com>

Co-authored-by: KN4CK3R <KN4CK3R@users.noreply.github.com>
2021-04-15 18:24:30 +03:00
6543 729fa06468 migration: github: if rate limit is not enabled, ignore it (#15490) (#15495)
Co-authored-by: Lauris BH <lauris@nix.lv>
2021-04-15 18:24:01 +03:00
zeripath b228a0aa44 Use index of the supported tags to choose user lang (#15452) (#15488)
Backport #15452

Fix #14793.

The previous implementation used the first return value of matcher.Match, which is the chosen language tag but may contain extensions such as de-DE-u-rg-chzzzz.

As mentioned in the documentation of language package, matcher.Match also returns the index of the supported tags, so I think it is better to use it rather than manipulate the returned language tag.

Co-authored-by: Naohisa Murakami <tiqwab.ch90@gmail.com>
2021-04-15 16:47:43 +02:00
Lunny Xiao 9e7e11224f Fix potential copy lfs records failure when fork a repository (#15441) (#15485) 2021-04-15 16:13:14 +02:00
zeripath 85880b2a0b Query the DB for the hash before inserting in to email_hash (#15457) (#15491)
Backport #15457

Some postgres users have logging which logs even failed transactions. So
just query the db before trying to insert.

Fix #15451

Signed-off-by: Andrew Thornton art27@cantab.net
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-15 09:29:13 -04:00
zeripath 211bb911e3 Build go-git variants for windows (#15482) (#15487)
Backport #15482

It appears that there are significant performance problems with the pure git backend
on windows.

Therefore until we can sort this out - provide go-git backend builds.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-15 13:21:27 +01:00
silverwind 0554d1dd01 Lock down build-images dependencies (#15480)
Partial extraction from #15479 for 1.14. Locks down build-images
dependencies and adds missing node_modules dependency.
2021-04-15 12:02:57 +01:00
zeripath 00e55dd223 Prevent superfluous response.WriteHeader (#15456) (#15476)
Backport #15456

This PR simply checks the status before writing the header.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-15 11:02:42 +01:00
a1012112796 b28c3245cc fix wrong file link in code search page (#15466) (#15486)
in previous the grenrated link is
``testg/testrepo/src/commit/....``
which is not right.

the right version is ``/testg/testrepo/.......``
(start wiht ``/``)
or ``http://127.0.0.1:3000/xxxxx`` (full link)

to make it hase same result with explore page
I choose the secound style.

fix #15438

Signed-off-by: a1012112796 <1012112796@qq.com>

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
2021-04-15 12:04:25 +03:00
silverwind ddfb729168 Clone panel fixes (#15436)
- Use <button> over <div> for a button
- Fix absent border-right on wiki
- Fix absent border-radius on wiki
2021-04-14 22:16:33 +01:00
John Olheiser 6ef62e3f8e quick fix (#15464) (#15481)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2021-04-14 20:42:30 +01:00
zeripath 2c4f1ed13e Fix ambiguous argument error on tags (#15432) (#15474)
Backport #15432

There is a weird gotcha with GetTagCommitID that because it uses git rev-list
can cause an ambiguous argument error.

This PR simply makes tags use the same code as branches.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-14 14:53:01 -04:00
techknowlogick fa3fe1e28a v172 migration adds created_unix field instead of expiry (#15458) (#15463)
The Session table must have an Expiry field not a created_unix field - somehow
this migration adds the incorrect named field leading to #15445 reports.

Fix #15445

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2021-04-14 08:03:42 +02:00
techknowlogick 62f5cf4386 Fix repository search (#15428) (#15442)
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: KN4CK3R <KN4CK3R@users.noreply.github.com>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-13 12:30:28 +08:00
techknowlogick 779d1185e7 Prevent NPE on avatar direct rendering if federated avatars disabled (#15434) (#15439)
#13649 assumed that direct avatar urls would always be libravatar urls - this leads
to NPEs if federated avatar service is disabled.

Fix #15421

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: zeripath <art27@cantab.net>
2021-04-12 22:50:07 -04:00
silverwind f3d0c76afc Fix wiki clone urls (#15430) (#15431)
Fix wiki clone urls

Regressed by: https://github.com/go-gitea/gitea/commit/9a4050f1e839af1bd072aff9ac5fc69e650747c8
Fixes: https://github.com/go-gitea/gitea/issues/15420
2021-04-12 23:59:56 +02:00
Tomás Warynyca 5a4729d5e2 fix dingtalk icon url (#15426)
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-12 11:10:49 -04:00
zeripath 88a7349375 Standardise icon on projects PR page (#15387) (#15408)
Backport #15387

Fix #15272

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-12 10:05:20 +02:00
6543 c3398906a1 use repo1_bare to test against (#15402) (#15404) 2021-04-11 19:48:35 +02:00
Mike L 330fa75945 Use semantic dropdown for code search query type (#15276) (#15364)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
2021-04-11 11:50:03 -04:00
6543 55e159ca5f Changelog v1.14.0 (#15360)
* clean & merge & update v1.14.0 changelog

* backport v1.13.x changelogs
2021-04-11 06:07:02 +02:00
Lunny Xiao 87074ec860 Fix delete nonexist oauth application 500 and prevent deadlock (#15384) (#15396)
* Fix delete nonexist oauth application 500

* Fix test

* Close the session

* Fix more missed sess.Close

* Remove unnecessary blank line

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
2021-04-11 04:57:44 +02:00
zeripath 1fe5fe419e Always set the merge base used to merge the commit (#15352) (#15385)
Backport #15352

The issue is that the TestPatch will reset the PR MergeBase - and it is possible for TestPatch to update the MergeBase whilst a merge is ongoing. The ensuing merge will then complete but it doesn't re-set the MergeBase it used to merge the PR.

Fixes the intermittent error in git test.

Signed-off-by: Andrew Thornton art27@cantab.net
2021-04-10 14:08:30 +02:00
zeripath 67a12b8fac Turn RepoRef and RepoAssignment back into func(*Context) (#15372) (#15377)
Backport #15372

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-09 22:24:40 -04:00
silverwind e861dcbbaf Dropzone styling improvements (#15291) (#15374)
* Dropzone styling improvements

- Move all dropzone styles to separate file
- Fix white background in arc-green
- Fix rendering of non-square images and previews

* increase thumbnail quality, set contain in js, replace blur effect with opacity

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-09 19:43:36 -04:00
zeripath 53c2136a9a Upgrade to bluemonday 1.0.7 (#15379) (#15380)
* Upgrade to bluemonday 1.0.7 (#15379)

Backport #15379

Fix #15349

Signed-off-by: Andrew Thornton <art27@cantab.net>

* resolve CI

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-09 19:41:30 -04:00
zeripath 24ebc7e517 Move FCGI req.URL.Path fix-up to the FCGI listener (#15292) (#15361)
Backport #15292

Simplify the web.go FCGI path by moving the req.URL.Path fix-up to listener

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-09 17:45:02 +01:00
6543 b072907987 Fix admin user list (#15358) (#15359)
* Fix `admin user list` (#15358)

* fix routers/api/v1/repo/issue.go
2021-04-09 12:39:40 +02:00
silverwind 942b0360ad Fix button border issue (#15351) 2021-04-09 05:38:06 +02:00
silverwind 1ec4913add Disable cssnano's colormin plugin (#15348)
It produces odd rgba values which also seem to cause issues in monaco's
color parser where the scoll shadow went red for some reason.

Regression by: https://github.com/go-gitea/gitea/pull/15333
2021-04-09 03:54:24 +02:00
zeripath 16e34025b4 Show diff on rename with diff changes (#15338) (#15339)
Backport #15338

More recent versions of git have increased support for detection of renames meaning
that a rename with diff changes is now supported.

Although ParsePatch supports this - our templates do not and the simplest solution
is simply to show the diff.

Fix #15335

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-04-08 15:36:17 -04:00
zeripath 456d63b6cf Prepend AppSubUrl to links for default avatar (#15341) (#15342)
Backport #15341

Fix #15334

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-08 17:51:10 +01:00
zeripath 798ac3f85a Fix handling of logout event (#15323) (#15337)
Backport #15323

It appears that there is a slight bug in the handling of the data of logout event -
the javascript should be testing the data field of the data field for the logout
instruction.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-08 17:28:30 +02:00
silverwind 460093b952 Monaco improvements (#15333) (#15345)
- Create theme at runtime which follows the CSS variables of the site
- Disable a few opinionated Monaco defaults like minimap and word highlights
- Move styles to separate file
2021-04-08 13:24:23 +02:00
6543 38d184d518 Fix CanCreateRepo check (#15311) (#15321)
Signed-off-by: jolheiser <john.olheiser@gmail.com>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
2021-04-07 22:14:11 +02:00
6543 80b55263d8 Fix xorm log stack level (#15285) (#15316)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-07 08:36:15 +01:00
6543 32232db55f Reduce memory usage in testgit (#15306) (#15310)
* reduce memory use in rawtest

* just use hashsum for diffs

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-07 11:07:39 +08:00
KN4CK3R cf9b6c281f Close file on invalid range (Addition to #15166) (#15268) (#15308)
* Close file on invalid range.

* Close on seek error

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Moved 'Seek' into server.

* io.ReadSeekCloser is only available in Go 1.16

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-06 15:25:31 -04:00
6543 a8c6a4a70e Fix bug in Wrap (#15302) (#15309)
Whilst doing other work I have noticed that there is an issue with Wrap when passing an
http.Handler - the next should be the next handler in line not empty.

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: zeripath <art27@cantab.net>
2021-04-06 18:44:24 +02:00
6543 e6050e80f7 Update to bluemonday-1.0.6 (#15294) (#15297)
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2021-04-06 01:36:58 +01:00
zeripath 3803b15d76 Drop the event source if we are unauthorized (#15275) (#15280)
Backport #15275

A previous commit that sent unauthorized if the user is unauthorized
simply leads to the repeated reopening of the eventsource. #

This PR changes the event returned to tell the client to close the
eventsource and thus prevents the repeated reopening.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-04 20:39:22 -04:00
zeripath af73e1ee35 Add size to Save function (#15264) (#15270)
This PR proposes an alternative solution to #15255 - just add the size to the
save function. Yes it is less apparently clean but it may be more correct.

Close #15255
Fix #15253

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-04-04 12:04:55 -04:00
silverwind 4bc8dfc6a3 Branch page and misc css improvements (#15208) (#15274)
- Improve branches page, increase icon size, use octicons, use css vars
- Style placeholder color via css var
- Slightly increase contrast of input fields and active/hover states
- Add styling for select boxes in arc-green
2021-04-04 16:31:54 +03:00
techknowlogick 33c4e246fe update golang libraries (#15258) (#15259) 2021-04-03 10:42:18 +02:00
KN4CK3R 8ec7beb9f4 Fix graph pagination (#15225) (#15249)
* Fixed invalid HTML tag.

* Fixed pagination.

* Update templates/repo/graph/commits.tmpl

Co-authored-by: zeripath <art27@cantab.net>
2021-04-02 04:29:14 +01:00
a1012112796 c6eb9b30ae response 404 for diff/patch of a commit that not exist (#15221) (#15237)
* response 404 for diff/patch of a commit that not exist

fix #15217

Signed-off-by: a1012112796 <1012112796@qq.com>

* Update routers/repo/commit.go

Co-authored-by: silverwind <me@silverwind.io>

* use ctx.NotFound()

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: silverwind <me@silverwind.io>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: 6543 <6543@obermui.de>
2021-04-01 19:57:05 -04:00
zeripath f75a9b27b0 Speed up enry.IsVendor (#15213) (#15245)
Backport #15213

`enry.IsVendor` is kinda slow as it simply iterates across all regexps.
This PR ajdusts the regexps to combine them to make this process a
little quicker.

Related #15143

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-02 01:16:00 +02:00
zeripath 2705696d4d Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15200)
Backport #15199

I do not understand how this can happen or why.

There is an apparent possibility for a comment.Patch to be missing a hunk header
- this should not happen and do not understand how. But it appears to happen on
1.13 at least in some case.

This PR will simply add a new section if the cursection is empty
thus preventing the NPE.

Fix #15198

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-04-01 15:14:56 -04:00
mayswind 2b68f66e0e Fix timezone bug when clicking heatmap (#15141) (#15231) 2021-04-01 18:22:54 +08:00
silverwind 5c7d30cf52 Diff box fixes (#15214) (#15227)
- Fix misaligned "Show Outdated" buttons via flexbox
- Add hover effect to "Show Outdated" buttons
- Remove overreaching margin from selector .diff-file-box and handle
  cases individually.

Fixes: https://github.com/go-gitea/gitea/issues/15097

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2021-04-01 08:04:47 +03:00
zeripath e520dff4da Improve /api/v1/repos/issues/search by just getting repo ids (#15179) (#15192)
Backport #15179

/api/v1/repos/issues/search is a highly inefficient search which is unfortunately
the basis for our dependency searching algorithm. In particular it currently loads
all of the repositories and their owners and their primary coding language all of
which is immediately thrown away.

This PR makes one simple change - just get the IDs.

Related #14560
Related #12827

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-04-01 01:15:08 +02:00
zeripath 2bc759518e Fix regression from #14623 - use debug SVC handler only on interactive sessions (#15210) (#15211)
Backport #15210

Unfortunately #14623 changed from the deprecated IsInteractiveSession to
IsWindowsService without recognising that they are the complement of
each other.

This means that Windows SVC control is not working correctly. This PR
adds some Tracing statements but also fixes the bug.

Fix #15159

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-31 20:49:46 +01:00
a1012112796 92b2883058 add 'fonts' into 'KnownPublicEntries' (#15188) (#15218)
fix #15184

Signed-off-by: a1012112796 <1012112796@qq.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-03-31 04:56:19 +02:00
silverwind 0ebfc1405c Fix webhook delivery and issue checklist for arc-green (#15195) (#15204)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-03-30 19:15:12 +08:00
silverwind fd5c67226e Fix margin between avatars on org pages (#15194) (#15197)
Fixes: https://github.com/go-gitea/gitea/issues/15191
2021-03-29 23:36:00 +02:00
a1012112796 61308825a6 should run RetrieveRepoMetas() for empty pr (#15187) (#15190)
Signed-off-by: a1012112796 <1012112796@qq.com>
2021-03-29 17:02:01 +01:00
Norwin 0cccad04f0 fix org navbar (#15174)
Co-authored-by: Jimmy Praet <jimmy.praet@telenet.be>
2021-03-27 15:57:02 +01:00
zeripath a0e5c49ac3 Clusterfuzz found another way (#15160) (#15168)
Backport #15160

Clusterfuzz found another way so I found another way to stop it

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-26 22:48:38 -04:00
sotho 3558310c1f Fix wrong user returned in API (#15139) (#15151)
The API call: GET /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments
returns always the reviewer, but should return the poster.

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2021-03-26 04:20:52 +01:00
zeripath e99534cfd2 Fix Migration 176 yet again (#15132)
Backport #15131

Whilst creating a test for v176 in the migrations_test PR
it has become clear that this was still wrong.

This is now fixed. Genuinely.

Also fix repo transfer

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-23 23:18:05 +00:00
6543 27acf6165e update changelog for rc2 release (#15130) 2021-03-23 15:52:43 -04:00
zeripath f286a28568 Fix consistency check (#15120) (#15128)
In my last fix I missed adding the label_ prefix to the
consistency check count.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-23 20:20:34 +01:00
6543 b5c4cb1bde Fix bug on avatar middleware (#15124) (#15126)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2021-03-23 18:44:37 +00:00
6543 26b98417ad [Vendor] update gitea-sdk v0.14.0 (#15103) (#15107)
* upgraded code.gitea.io/sdk/gitea v0.13.2 => v0.14.0

* rm workaround
2021-03-23 10:10:32 +00:00
zeripath 8b0cf88c0c Changelog for v1.14-rc2 (#15115)
Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-22 22:00:51 +01:00
zeripath 23db3375df Fix another clusterfuzz identified issue (#15096) (#15113)
Backport #15096

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2021-03-22 15:16:08 -04:00
zeripath 14011d77c9 Fix the v176 migration (#15110) (#15111)
Backport #15110

There is a serious issue with the v176 migration where there is a mistaken missing
label_id selection.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-22 14:47:58 -04:00
silverwind 5519e26c2f Fix lock modal content rendering outside modal (#15095) (#15100)
* Fix lock modal content rendering outside modal

The .content was not a child to .modal so was rendering outside. This is
a recent regression but I'm not certain when it was introduced.

* remove extraneous closing div

Co-authored-by: zeripath <art27@cantab.net>
2021-03-22 02:00:42 +01:00
zeripath 6feb435867 Place wrapper around comment as diff to catch panics (#15085) (#15094)
Backport #15085

There are a few recurrent issues with comment as diff reporting panics that are resistant to fixing due to the fact that the panic occurs in the template render and is swallowed by the template renderer.

This PR just adds some logging to force the panic to properly logged and re-propagates back up to the template renderer so we can actually detect what the issue is.

Signed-off-by: Andrew Thornton art27@cantab.net
2021-03-21 23:41:40 +01:00
silverwind 61444ed8ca Fix markdown rendering in milestone content (#15056) (#15091)
- Add missing markdown class for rendered markdown.
- Increase font size of milestone name in list.

Fixes: https://github.com/go-gitea/gitea/issues/15046
2021-03-21 18:57:06 +01:00
6543 d770cc9886 Remove possible resource leak (#15067) (#15082)
* move "copy uploaded lfs files 2 repo" to own function for "defer file.Close()"

* rm type overload

Co-authored-by: zeripath <art27@cantab.net>
2021-03-21 17:07:37 +01:00
a1012112796 fbaa01998a fix double 'push tag' action feed (#15078) (#15083)
Signed-off-by: a1012112796 <1012112796@qq.com>
2021-03-21 14:51:31 +00:00
Lauris BH ac2ae66ae7 Handle unauthorized user events gracefully (#15071) (#15074) 2021-03-21 10:21:28 +00:00
Lauris BH ed60fe0986 Update release date (#15065)
* Update release date

* Remove unneeded entry
2021-03-20 21:29:01 +08:00
zeripath 29e0d62790 Update to goldmark 1.3.3 (#15059) (#15060)
Backport #15059

Signed-off-by: Andrew Thornton <art27@cantab.net>
2021-03-20 12:24:09 +01:00
6543 7b464fa67b Fix bug when upload on web (#15042) (#15054)
* Fix bug when upload on web

* move into own function

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: zeripath <art27@cantab.net>
2021-03-20 09:37:57 +08:00
15035 changed files with 3077571 additions and 708147 deletions
+9
View File
@@ -0,0 +1,9 @@
root = "."
tmp_dir = ".air"
[build]
cmd = "make backend"
bin = "gitea"
include_ext = ["go", "tmpl"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"]
-26
View File
@@ -1,26 +0,0 @@
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"
entrypoint = ["./gitea"]
delay = 2000
include_ext = ["go", "tmpl"]
include_file = ["main.go"]
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",
"routers/private/tests",
"services/gitdiff/testdata",
]
exclude_regex = ["_test.go$", "_gen.go$"]
stop_on_error = true
[log]
main_only = true
+21 -19
View File
@@ -13,44 +13,46 @@ groups:
-
name: BREAKING
labels:
- pr/breaking
-
name: SECURITY
labels:
- topic/security
- kind/breaking
-
name: FEATURES
labels:
- type/feature
- kind/feature
-
name: ENHANCEMENTS
name: SECURITY
labels:
- type/enhancement
- kind/security
-
name: PERFORMANCE
name: API
labels:
- performance/memory
- performance/speed
- performance/bigrepo
- performance/cpu
- kind/api
-
name: BUGFIXES
labels:
- type/bug
- kind/bug
-
name: ENHANCEMENTS
labels:
- kind/enhancement
- kind/refactor
- kind/ui
-
name: TESTING
labels:
- type/testing
- kind/testing
-
name: TRANSLATION
labels:
- kind/translation
-
name: BUILD
labels:
- topic/build
- topic/code-linting
- kind/build
- kind/lint
-
name: DOCS
labels:
- type/docs
- kind/docs
-
name: MISC
default: true
-45
View File
@@ -1,45 +0,0 @@
{
"name": "Gitea DevContainer",
"image": "mcr.microsoft.com/devcontainers/go:1.26-trixie",
"containerEnv": {
// override "local" from packaged version
"GOTOOLCHAIN": "auto"
},
"features": {
// installs nodejs into container
"ghcr.io/devcontainers/features/node:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/git-lfs:1.2.5": {},
"ghcr.io/jsburckhardt/devcontainer-features/uv:1": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.14"
},
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
},
"customizations": {
"vscode": {
"settings": {},
"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"
}
-90
View File
@@ -1,90 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# IntelliJ
.idea
# Goland's output filename can not be set manually
/go_build_*
# MS VSCode
.vscode
__debug_bin*
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*coverage.out
coverage.all
cpu.out
*.db
*.log
/gitea
/debug
/bin
/dist
/custom/*
!/custom/conf
/custom/conf/*
!/custom/conf/app.example.ini
/data
/indexers
/log
/tests/integration/gitea-integration-*
/tests/*.ini
/node_modules
/yarn.lock
/yarn-error.log
/npm-debug.log*
/pnpm-debug.log*
/public/assets/js
/public/assets/css
/public/assets/fonts
/public/assets/img/avatar
/vendor
/VERSION
/.air
/.go-licenses
/Dockerfile
/Dockerfile.rootless
/.venv
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft
snap/.snapcraft/
parts/
stage/
prime/
*.snap
*.snap-build
*_source.tar.bz2
.DS_Store
# Make evidence files
/.make_evidence
# Manpage
/man
+934
View File
@@ -0,0 +1,934 @@
---
kind: pipeline
name: compliance
platform:
os: linux
arch: arm64
trigger:
event:
- push
- tag
- pull_request
steps:
- name: deps-frontend
pull: always
image: node:14
commands:
- make node_modules
- name: lint-frontend
image: node:14
commands:
- make lint-frontend
depends_on: [deps-frontend]
- name: lint-backend
pull: always
image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env
commands:
- make lint-backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
- name: lint-backend-windows
pull: always
image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env
commands:
- make golangci-lint vet
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
GOOS: windows
GOARCH: amd64
- name: lint-backend-gogit
pull: always
image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env
commands:
- make lint-backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
- name: checks-frontend
image: node:14
commands:
- make checks-frontend
depends_on: [deps-frontend]
- name: checks-backend
pull: always
image: golang:1.16
commands:
- make checks-backend
depends_on: [lint-backend]
- name: build-frontend
image: node:14
commands:
- make frontend
depends_on: [lint-frontend]
- name: build-backend-no-gcc
pull: always
image: golang:1.14 # this step is kept as the lowest version of golang that we support
environment:
GO111MODULE: on
GOPROXY: off
commands:
- go build -mod=vendor -o gitea_no_gcc # test if build succeeds without the sqlite tag
depends_on: [checks-backend]
- name: build-backend-arm64
image: golang:1.16
environment:
GO111MODULE: on
GOPROXY: off
GOOS: linux
GOARCH: arm64
TAGS: bindata gogit
commands:
- make backend # test cross compile
- rm ./gitea # clean
depends_on: [checks-backend]
- name: build-backend-windows
image: golang:1.16
environment:
GO111MODULE: on
GOPROXY: off
GOOS: windows
GOARCH: amd64
TAGS: bindata gogit
commands:
- go build -mod=vendor -o gitea_windows
depends_on: [checks-backend]
- name: build-backend-386
image: golang:1.16
environment:
GO111MODULE: on
GOPROXY: off
GOOS: linux
GOARCH: 386
commands:
- go build -mod=vendor -o gitea_linux_386 # test if compatible with 32 bit
depends_on: [checks-backend]
---
kind: pipeline
name: testing-amd64
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- push
- tag
- pull_request
services:
- name: mysql
image: mysql:5.7
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: test
- name: mysql8
image: mysql:8.0
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
- name: mssql
image: mcr.microsoft.com/mssql/server:latest
environment:
ACCEPT_EULA: Y
MSSQL_PID: Standard
SA_PASSWORD: MwantsaSecurePassword1
- name: ldap
image: gitea/test-openldap:latest
- name: elasticsearch
environment:
discovery.type: single-node
image: elasticsearch:7.5.0
- name: minio
image: minio/minio:RELEASE.2021-03-12T00-00-47Z
commands:
- minio server /data
environment:
MINIO_ACCESS_KEY: 123456
MINIO_SECRET_KEY: 12345678
steps:
- name: fetch-tags
image: docker:git
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: build
pull: always
image: golang:1.16
commands:
- make backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
- name: tag-pre-condition
pull: always
image: drone/git
commands:
- git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
- name: unit-test
image: golang:1.16
commands:
- make unit-test-coverage test-check
environment:
GOPROXY: off
TAGS: bindata sqlite sqlite_unlock_notify
GITHUB_READ_TOKEN:
from_secret: github_read_token
- name: unit-test-gogit
pull: always
image: golang:1.16
commands:
- make unit-test-coverage test-check
environment:
GOPROXY: off
TAGS: bindata gogit sqlite sqlite_unlock_notify
GITHUB_READ_TOKEN:
from_secret: github_read_token
- name: test-mysql
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
commands:
- make test-mysql-migration integration-test-coverage
environment:
GOPROXY: off
TAGS: bindata
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
depends_on:
- build
- name: test-mysql8
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
commands:
- timeout -s ABRT 40m make test-mysql8-migration test-mysql8
environment:
GOPROXY: off
TAGS: bindata
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on:
- build
- name: test-mssql
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
commands:
- make test-mssql-migration test-mssql
environment:
GOPROXY: off
TAGS: bindata
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on:
- build
- name: generate-coverage
image: golang:1.16
commands:
- make coverage
environment:
GOPROXY: off
TAGS: bindata
depends_on:
- unit-test
- test-mysql
when:
branch:
- master
event:
- push
- pull_request
- name: coverage-codecov
pull: always
image: plugins/codecov
settings:
files:
- coverage.all
token:
from_secret: codecov_token
depends_on:
- generate-coverage
when:
branch:
- master
event:
- push
- pull_request
---
kind: pipeline
name: testing-arm64
platform:
os: linux
arch: arm64
depends_on:
- compliance
trigger:
event:
- push
- tag
- pull_request
services:
- name: pgsql
pull: default
image: postgres:9.5
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
- name: ldap
pull: default
image: gitea/test-openldap:latest
steps:
- name: fetch-tags
image: docker:git
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: build
pull: always
image: golang:1.16
commands:
- make backend
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
- name: test-sqlite
image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env
commands:
- timeout -s ABRT 40m make test-sqlite-migration test-sqlite
environment:
GOPROXY: off
TAGS: bindata gogit sqlite sqlite_unlock_notify
TEST_TAGS: gogit sqlite sqlite_unlock_notify
USE_REPO_TEST_DIR: 1
depends_on:
- build
- name: test-pgsql
image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env
commands:
- timeout -s ABRT 40m make test-pgsql-migration test-pgsql
environment:
GOPROXY: off
TAGS: bindata gogit
TEST_TAGS: gogit
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on:
- build
---
kind: pipeline
name: update_translations
platform:
os: linux
arch: arm64
trigger:
branch:
- master
event:
- cron
cron:
- update_translations
steps:
- name: download
pull: always
image: jonasfranz/crowdin
settings:
download: true
export_dir: options/locale/
ignore_branch: true
project_identifier: gitea
environment:
CROWDIN_KEY:
from_secret: crowdin_key
- name: update
pull: default
image: alpine:3.13
commands:
- ./build/update-locales.sh
- name: push
pull: always
image: appleboy/drone-git-push
settings:
author_email: "teabot@gitea.io"
author_name: GiteaBot
commit: true
commit_message: "[skip ci] Updated translations via Crowdin"
remote: "git@github.com:go-gitea/gitea.git"
environment:
GIT_PUSH_SSH_KEY:
from_secret: git_push_ssh_key
- name: upload_translations
pull: always
image: jonasfranz/crowdin
settings:
files:
locale_en-US.ini: options/locale/locale_en-US.ini
ignore_branch: true
project_identifier: gitea
environment:
CROWDIN_KEY:
from_secret: crowdin_key
---
kind: pipeline
name: update_gitignore_and_licenses
platform:
os: linux
arch: arm64
trigger:
branch:
- master
event:
- cron
cron:
- update_gitignore_and_licenses
steps:
- name: download
image: golang:1.16
commands:
- timeout -s ABRT 40m make generate-license generate-gitignore
- name: push
pull: always
image: appleboy/drone-git-push
settings:
author_email: "teabot@gitea.io"
author_name: GiteaBot
commit: true
commit_message: "[skip ci] Updated licenses and gitignores "
remote: "git@github.com:go-gitea/gitea.git"
environment:
GIT_PUSH_SSH_KEY:
from_secret: git_push_ssh_key
---
kind: pipeline
name: release-latest
platform:
os: linux
arch: amd64
workspace:
base: /source
path: /
trigger:
branch:
- master
- "release/*"
event:
- push
depends_on:
- testing-amd64
- testing-arm64
steps:
- name: fetch-tags
image: docker:git
commands:
- git fetch --tags --force
- name: static
pull: always
image: techknowlogick/xgo:go-1.16.x
commands:
- curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt -y install nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
TAGS: bindata sqlite sqlite_unlock_notify
- name: gpg-sign
pull: always
image: plugins/gpgsign:1
settings:
detach_sign: true
excludes:
- "dist/release/*.sha256"
files:
- "dist/release/*"
environment:
GPGSIGN_KEY:
from_secret: gpgsign_key
GPGSIGN_PASSPHRASE:
from_secret: gpgsign_passphrase
- name: release-branch
pull: always
image: plugins/s3:1
settings:
acl: public-read
bucket: gitea-artifacts
endpoint: https://storage.gitea.io
path_style: true
source: "dist/release/*"
strip_prefix: dist/release/
target: "/gitea/${DRONE_BRANCH##release/v}"
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
AWS_SECRET_ACCESS_KEY:
from_secret: aws_secret_access_key
when:
branch:
- "release/*"
event:
- push
- name: release-master
image: plugins/s3:1
settings:
acl: public-read
bucket: gitea-artifacts
endpoint: https://storage.gitea.io
path_style: true
source: "dist/release/*"
strip_prefix: dist/release/
target: /gitea/master
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
AWS_SECRET_ACCESS_KEY:
from_secret: aws_secret_access_key
when:
branch:
- master
event:
- push
---
kind: pipeline
name: release-version
platform:
os: linux
arch: amd64
workspace:
base: /source
path: /
trigger:
event:
- tag
depends_on:
- testing-arm64
- testing-amd64
steps:
- name: fetch-tags
pull: default
image: docker:git
commands:
- git fetch --tags --force
- name: static
pull: always
image: techknowlogick/xgo:go-1.16.x
commands:
- curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt -y install nodejs
- export PATH=$PATH:$GOPATH/bin
- make release
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
TAGS: bindata sqlite sqlite_unlock_notify
- name: gpg-sign
pull: always
image: plugins/gpgsign:1
settings:
detach_sign: true
excludes:
- "dist/release/*.sha256"
files:
- "dist/release/*"
environment:
GPGSIGN_KEY:
from_secret: gpgsign_key
GPGSIGN_PASSPHRASE:
from_secret: gpgsign_passphrase
- name: release-tag
pull: always
image: plugins/s3:1
settings:
acl: public-read
bucket: gitea-artifacts
endpoint: https://storage.gitea.io
path_style: true
source: "dist/release/*"
strip_prefix: dist/release/
target: "/gitea/${DRONE_TAG##v}"
environment:
AWS_ACCESS_KEY_ID:
from_secret: aws_access_key_id
AWS_SECRET_ACCESS_KEY:
from_secret: aws_secret_access_key
- name: github
pull: always
image: plugins/github-release:1
settings:
files:
- "dist/release/*"
environment:
GITHUB_TOKEN:
from_secret: github_token
---
kind: pipeline
name: docs
platform:
os: linux
arch: arm64
depends_on:
- compliance
trigger:
event:
- push
- tag
- pull_request
steps:
- name: build-docs
pull: always
image: plugins/hugo:latest
commands:
- apk add --no-cache make bash curl
- cd docs
- make trans-copy clean build
- name: publish-docs
pull: always
image: techknowlogick/drone-netlify:latest
settings:
path: docs/public/
site_id: d2260bae-7861-4c02-8646-8f6440b12672
environment:
NETLIFY_TOKEN:
from_secret: netlify_token
when:
branch:
- master
event:
- push
---
kind: pipeline
name: docker-linux-amd64-release
platform:
os: linux
arch: amd64
depends_on:
- testing-amd64
- testing-arm64
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
event:
exclude:
- cron
steps:
- name: fetch-tags
image: docker:git
commands:
- git fetch --tags --force
- name: publish
pull: always
image: plugins/docker:linux-amd64
settings:
auto_tag: true
auto_tag_suffix: linux-amd64
repo: gitea/gitea
build_args:
- GOPROXY=off
password:
from_secret: docker_password
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
- name: publish-rootless
image: plugins/docker:linux-amd64
settings:
dockerfile: Dockerfile.rootless
auto_tag: true
auto_tag_suffix: linux-amd64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=off
password:
from_secret: docker_password
username:
from_secret: docker_username
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
when:
event:
exclude:
- pull_request
---
kind: pipeline
name: docker-linux-arm64-dry-run
platform:
os: linux
arch: arm64
depends_on:
- compliance
trigger:
ref:
- "refs/pull/**"
steps:
- name: dryrun
pull: always
image: plugins/docker:linux-arm64
settings:
dry_run: true
repo: gitea/gitea
tags: linux-arm64
build_args:
- GOPROXY=off
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
when:
event:
- pull_request
---
kind: pipeline
name: docker-linux-arm64-release
platform:
os: linux
arch: arm64
depends_on:
- testing-amd64
- testing-arm64
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
event:
exclude:
- cron
steps:
- name: fetch-tags
image: docker:git
commands:
- git fetch --tags --force
- name: publish
pull: always
image: plugins/docker:linux-arm64
settings:
auto_tag: true
auto_tag_suffix: linux-arm64
repo: gitea/gitea
build_args:
- GOPROXY=off
password:
from_secret: docker_password
username:
from_secret: docker_username
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
when:
event:
exclude:
- pull_request
- name: publish-rootless
image: plugins/docker:linux-arm64
settings:
dockerfile: Dockerfile.rootless
auto_tag: true
auto_tag_suffix: linux-arm64-rootless
repo: gitea/gitea
build_args:
- GOPROXY=off
password:
from_secret: docker_password
username:
from_secret: docker_username
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
when:
event:
exclude:
- pull_request
---
kind: pipeline
name: docker-manifest
platform:
os: linux
arch: amd64
steps:
- name: manifest-rootless
pull: always
image: plugins/manifest
settings:
auto_tag: true
ignore_missing: true
spec: docker/manifest.rootless.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
- name: manifest
image: plugins/manifest
settings:
auto_tag: true
ignore_missing: true
spec: docker/manifest.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
event:
exclude:
- cron
depends_on:
- docker-linux-amd64-release
- docker-linux-arm64-release
---
kind: pipeline
name: notifications
platform:
os: linux
arch: arm64
clone:
disable: true
trigger:
branch:
- master
- "release/*"
event:
- push
- tag
status:
- success
- failure
depends_on:
- testing-amd64
- testing-arm64
- release-version
- release-latest
- docker-linux-amd64-release
- docker-linux-arm64-release
- docker-manifest
- docs
steps:
- name: discord
pull: always
image: appleboy/drone-discord:1.2.4
settings:
message: "{{#success build.status}} ✅ Build #{{build.number}} of `{{repo.name}}` succeeded.\n\n📝 Commit by {{commit.author}} on `{{commit.branch}}`:\n``` {{commit.message}} ```\n\n🌐 {{ build.link }} {{else}} ❌ Build #{{build.number}} of `{{repo.name}}` failed.\n\n📝 Commit by {{commit.author}} on `{{commit.branch}}`:\n``` {{commit.message}} ```\n\n🌐 {{ build.link }} {{/success}}\n"
webhook_id:
from_secret: discord_webhook_id
webhook_token:
from_secret: discord_webhook_token
+3 -17
View File
@@ -12,25 +12,11 @@ insert_final_newline = true
[*.{go,tmpl,html}]
indent_style = tab
[go.*]
indent_style = tab
[templates/custom/*.tmpl]
insert_final_newline = false
[templates/swagger/*_json.tmpl]
indent_style = space
insert_final_newline = false
[templates/user/auth/oidc_wellknown.tmpl]
indent_style = space
[templates/shared/actions/runner_badge_*.tmpl]
# editconfig lint requires these XML-like files to have charset defined, but the files don't have.
charset = unset
[Makefile]
indent_style = tab
[*.svg]
insert_final_newline = false
[*.md]
trim_trailing_whitespace = false
-1
View File
@@ -1 +0,0 @@
use flake
+417
View File
@@ -0,0 +1,417 @@
root: true
reportUnusedDisableDirectives: true
ignorePatterns:
- /web_src/js/vendor
- /templates/base/head.tmpl
- /templates/repo/activity.tmpl
- /templates/repo/view_file.tmpl
parserOptions:
sourceType: module
ecmaVersion: 2021
plugins:
- eslint-plugin-unicorn
- eslint-plugin-import
- eslint-plugin-vue
- eslint-plugin-html
extends:
- plugin:vue/recommended
env:
es2021: true
node: true
globals:
__webpack_public_path__: true
CodeMirror: false
Dropzone: false
SimpleMDE: false
u2fApi: false
settings:
html/html-extensions: [".tmpl"]
overrides:
- files: ["web_src/**/*.js", "web_src/**/*.vue", "templates/**/*.tmpl"]
env:
browser: true
jquery: true
node: false
- files: ["templates/**/*.tmpl"]
rules:
no-tabs: [0]
indent: [2, tab, {SwitchCase: 1}]
- 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, 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, status, statusbar, stop, toolbar, top]
- files: ["build/generate-images.js"]
rules:
import/no-unresolved: [0]
import/no-extraneous-dependencies: [0]
rules:
accessor-pairs: [2]
array-bracket-newline: [0]
array-bracket-spacing: [2, never]
array-callback-return: [0]
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]
curly: [0]
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]
grouped-accessor-pairs: [2]
guard-for-in: [0]
id-blacklist: [0]
id-length: [0]
id-match: [0]
implicit-arrow-linebreak: [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}]
import/no-default-export: [0]
import/no-deprecated: [0]
import/no-dynamic-require: [0]
import/no-extraneous-dependencies: [2]
import/no-internal-modules: [0]
import/no-mutable-exports: [2]
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-parent-imports: [0]
import/no-restricted-paths: [0]
import/no-self-import: [2]
import/no-unassigned-import: [0]
import/no-unresolved: [2, {commonjs: true}]
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]
key-spacing: [2]
keyword-spacing: [2]
line-comment-position: [0]
linebreak-style: [2, unix]
lines-around-comment: [0]
lines-between-class-members: [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: [2]
no-await-in-loop: [0]
no-bitwise: [0]
no-buffer-constructor: [0]
no-caller: [2]
no-case-declarations: [2]
no-class-assign: [2]
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-confusing-arrow: [0]
no-console: [1, {allow: [info, warn, error]}]
no-const-assign: [2]
no-constant-condition: [0]
no-constructor-return: [2]
no-continue: [0]
no-control-regex: [0]
no-debugger: [1]
no-delete-var: [2]
no-div-regex: [0]
no-dupe-args: [2]
no-dupe-class-members: [2]
no-dupe-else-if: [2]
no-dupe-keys: [2]
no-duplicate-case: [2]
no-duplicate-imports: [2]
no-else-return: [2]
no-empty-character-class: [2]
no-empty-function: [0]
no-empty-pattern: [2]
no-empty: [2, {allowEmptyCatch: true}]
no-eq-null: [2]
no-eval: [2]
no-ex-assign: [2]
no-extend-native: [2]
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: [0]
no-implicit-globals: [0]
no-implied-eval: [2]
no-import-assign: [2]
no-inline-comments: [0]
no-inner-declarations: [2]
no-invalid-regexp: [2]
no-invalid-this: [0]
no-irregular-whitespace: [2]
no-iterator: [2]
no-label-var: [2]
no-labels: [2]
no-lone-blocks: [2]
no-lonely-if: [0]
no-loop-func: [0]
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]
no-new-func: [2]
no-new-object: [2]
no-new-symbol: [2]
no-new-wrappers: [2]
no-new: [0]
no-nonoctal-decimal-escape: [2]
no-obj-calls: [2]
no-octal-escape: [2]
no-octal: [2]
no-param-reassign: [0]
no-plusplus: [0]
no-promise-executor-return: [0]
no-proto: [2]
no-prototype-builtins: [2]
no-redeclare: [2]
no-regex-spaces: [2]
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]
no-restricted-imports: [0]
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]
no-sequences: [2]
no-setter-return: [2]
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: [0]
no-unreachable-loop: [2]
no-unreachable: [2]
no-unsafe-finally: [2]
no-unsafe-negation: [2]
no-unused-expressions: [2]
no-unused-labels: [2]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, ignoreRestSiblings: false}]
no-use-before-define: [2, nofunc]
no-useless-backreference: [0]
no-useless-call: [2]
no-useless-catch: [2]
no-useless-computed-key: [2]
no-useless-concat: [2]
no-useless-constructor: [2]
no-useless-escape: [2]
no-useless-rename: [2]
no-useless-return: [2]
no-var: [2]
no-void: [2]
no-warning-comments: [0]
no-whitespace-before-property: [2]
no-with: [2]
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}]
prefer-destructuring: [0]
prefer-exponentiation-operator: [2]
prefer-named-capture-group: [0]
prefer-numeric-literals: [2]
prefer-object-spread: [0]
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]
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}]
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-function-scoping: [2]
unicorn/custom-error-definition: [0]
unicorn/empty-brace-spaces: [2]
unicorn/error-message: [0]
unicorn/escape-case: [0]
unicorn/expiring-todo-comments: [0]
unicorn/explicit-length-check: [0]
unicorn/filename-case: [0]
unicorn/import-index: [0]
unicorn/import-style: [0]
unicorn/new-for-builtins: [2]
unicorn/no-abusive-eslint-disable: [0]
unicorn/no-array-instanceof: [0]
unicorn/no-console-spaces: [0]
unicorn/no-fn-reference-in-iterator: [0]
unicorn/no-for-loop: [0]
unicorn/no-hex-escape: [0]
unicorn/no-keyword-prefix: [0]
unicorn/no-lonely-if: [2]
unicorn/no-nested-ternary: [0]
unicorn/no-new-buffer: [0]
unicorn/no-null: [0]
unicorn/no-object-as-default-parameter: [2]
unicorn/no-process-exit: [0]
unicorn/no-reduce: [2]
unicorn/no-unreadable-array-destructuring: [0]
unicorn/no-unsafe-regex: [0]
unicorn/no-unused-properties: [2]
unicorn/no-useless-undefined: [0]
unicorn/no-zero-fractions: [2]
unicorn/number-literal-case: [0]
unicorn/numeric-separators-style: [0]
unicorn/prefer-add-event-listener: [2]
unicorn/prefer-array-find: [2]
unicorn/prefer-dataset: [2]
unicorn/prefer-date-now: [2]
unicorn/prefer-event-key: [2]
unicorn/prefer-includes: [2]
unicorn/prefer-math-trunc: [2]
unicorn/prefer-modern-dom-apis: [0]
unicorn/prefer-negative-index: [2]
unicorn/prefer-node-append: [0]
unicorn/prefer-node-remove: [0]
unicorn/prefer-number-properties: [0]
unicorn/prefer-optional-catch-binding: [2]
unicorn/prefer-query-selector: [0]
unicorn/prefer-reflect-apply: [0]
unicorn/prefer-replace-all: [0]
unicorn/prefer-set-has: [0]
unicorn/prefer-spread: [0]
unicorn/prefer-starts-ends-with: [2]
unicorn/prefer-string-slice: [0]
unicorn/prefer-ternary: [0]
unicorn/prefer-text-content: [2]
unicorn/prefer-trim-start-end: [2]
unicorn/prefer-type-error: [0]
unicorn/prevent-abbreviations: [0]
unicorn/string-content: [0]
unicorn/throw-new-error: [2]
use-isnan: [2]
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
vue/attributes-order: [0]
vue/component-definition-name-casing: [0]
vue/html-closing-bracket-spacing: [0]
vue/max-attributes-per-line: [0]
vue/one-component-per-file: [0]
wrap-iife: [2, inside]
wrap-regex: [0]
yield-star-spacing: [2, after]
yoda: [2, never]
+4 -9
View File
@@ -1,11 +1,6 @@
* text=auto eol=lf
*.tmpl linguist-language=Handlebars
*.pb.go linguist-generated
/assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated
/options/fileicon/** linguist-generated
/vendor/** -text -eol linguist-vendored
/web_src/js/vendor/** -text -eol linguist-vendored
Dockerfile.* linguist-language=Dockerfile
Makefile.* linguist-language=Makefile
/public/vendor/** -text -eol linguist-vendored
/templates/**/*.tmpl linguist-language=Handlebars
/.eslintrc linguist-language=YAML
/.stylelintrc linguist-language=YAML
+1
View File
@@ -1 +1,2 @@
open_collective: gitea
custom: https://www.bountysource.com/teams/gitea
-91
View File
@@ -1,91 +0,0 @@
name: Bug Report
description: Found something you weren't expecting? Report it here!
labels: ["type/bug"]
body:
- type: markdown
attributes:
value: |
NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue.
- type: markdown
attributes:
value: |
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Make sure you are using the latest release and
take a moment to check that your issue hasn't been reported before.
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
5. It's really important to provide pertinent details and logs (https://docs.gitea.com/help/support),
incomplete details will be handled as an invalid report.
- 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 below)
If you are using a proxy or a CDN (e.g. Cloudflare) in front of Gitea, please disable the proxy/CDN fully and access Gitea directly to confirm the issue still persists without those services.
- type: input
id: gitea-ver
attributes:
label: Gitea Version
description: Gitea version (or commit reference) of your instance
validations:
required: true
- type: dropdown
id: can-reproduce
attributes:
label: Can you reproduce the bug on the Gitea demo site?
description: |
If so, please provide a URL in the Description field
URL of Gitea demo: https://demo.gitea.com
options:
- "Yes"
- "No"
validations:
required: true
- type: markdown
attributes:
value: |
It's really important to provide pertinent logs
Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
- type: input
id: logs
attributes:
label: Log Gist
description: Please provide a gist URL of your logs, with any sensitive information (e.g. API keys) removed/hidden
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If this issue involves the Web Interface, please provide one or more screenshots
- type: input
id: git-ver
attributes:
label: Git Version
description: The version of git running on the server
- type: input
id: os-ver
attributes:
label: Operating System
description: The operating system you are using to run Gitea
- type: textarea
id: run-info
attributes:
label: How are you running Gitea?
description: |
Please include information on whether you built Gitea yourself, used one of our downloads, are using https://demo.gitea.com or are using some other package
Please also tell us how you are running Gitea, 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
validations:
required: true
- type: dropdown
id: database
attributes:
label: Database
description: What database system are you running?
options:
- PostgreSQL
- MySQL/MariaDB
- MSSQL
- SQLite
-17
View File
@@ -1,17 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Security Concern
url: https://tinyurl.com/security-gitea
about: For security concerns, please send a mail to security@gitea.io instead of opening a public issue.
- name: Discord Server
url: https://discord.gg/Gitea
about: Please ask questions and discuss configuration or deployment problems here.
- name: Discourse Forum
url: https://forum.gitea.com
about: Questions and configuration or deployment problems can also be discussed on our forum.
- name: Frequently Asked Questions
url: https://docs.gitea.com/help/faq
about: Please check if your question isn't mentioned here.
- name: Crowdin Translations
url: https://translate.gitea.com
about: Translations are managed here.
@@ -1,24 +0,0 @@
name: Feature Request
description: Got an idea for a feature that Gitea doesn't have currently? Submit your idea here!
labels: ["type/proposal"]
body:
- type: markdown
attributes:
value: |
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Please take a moment to check that your feature hasn't already been suggested.
- type: textarea
id: description
attributes:
label: Feature Description
placeholder: |
I think it would be great if Gitea had...
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
-66
View File
@@ -1,66 +0,0 @@
name: Web Interface Bug Report
description: Something doesn't look quite as it should? Report it here!
labels: ["type/bug", "topic/ui"]
body:
- type: markdown
attributes:
value: |
NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue.
- type: markdown
attributes:
value: |
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
3. Please take a moment to check that your issue doesn't already exist.
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
5. Please give all relevant information below for bug reports, because
incomplete details will be handled as an invalid report.
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
DEBUG level logs. (See https://docs.gitea.com/administration/logging-config#collecting-logs-for-help)
- 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 below)
If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please disable the proxy/CDN fully and connect to gitea directly to confirm the issue still persists without those services.
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Please provide at least 1 screenshot showing the issue.
validations:
required: true
- type: input
id: gitea-ver
attributes:
label: Gitea Version
description: Gitea version (or commit reference) your instance is running
validations:
required: true
- type: dropdown
id: can-reproduce
attributes:
label: Can you reproduce the bug on the Gitea demo site?
description: |
If so, please provide a URL in the Description field
URL of Gitea demo: https://demo.gitea.com
options:
- "Yes"
- "No"
validations:
required: true
- type: input
id: os-ver
attributes:
label: Operating System
description: The operating system you are using to access Gitea
- type: input
id: browser-ver
attributes:
label: Browser Version
description: The browser and version that you are using to access Gitea
validations:
required: true
-7
View File
@@ -1,7 +0,0 @@
self-hosted-runner:
labels:
- actuated-4cpu-8gb
- actuated-4cpu-16gb
- nscloud
- namespace-profile-gitea-release-docker
- namespace-profile-gitea-release-binary
-29
View File
@@ -1,29 +0,0 @@
name: docker-dryrun
description: Composite action that performs the container build steps for a single platform.
inputs:
platform:
description: "The target platform: linux/amd64, linux/arm64, linux/riscv64."
required: true
runs:
using: composite
steps:
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Build regular image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: ${{ inputs.platform }}
push: false
file: Dockerfile
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
- name: Build rootless image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: ${{ inputs.platform }}
push: false
file: Dockerfile.rootless
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
-47
View File
@@ -1,47 +0,0 @@
name: go-caches
description: Restore and save go module, build, and golangci-lint caches
inputs:
cache-name:
description: Short identifier used in the per-caller build cache key
required: true
build-cache:
description: Whether to include ~/.cache/go-build
default: "true"
build-cache-rotate:
description: Whether to rotate the build cache key per run so Go's test result cache can accumulate across runs
default: "false"
lint-cache:
description: Whether to include ~/.cache/golangci-lint
default: "false"
runs:
using: composite
steps:
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/go/pkg/mod
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gomod-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.build-cache == 'true' && inputs.build-cache-rotate == 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}-${{ hashFiles('go.sum') }}-${{ github.run_id }}
restore-keys: |
gobuild-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}-${{ hashFiles('go.sum') }}
gobuild-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}
gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
gobuild-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.build-cache == 'true' && inputs.build-cache-rotate != 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/go-build
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}
- if: ${{ inputs.lint-cache == 'true' }}
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/golangci-lint
key: golangci-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}-${{ hashFiles('go.sum', '.golangci.yml') }}
restore-keys: golangci-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cache-name }}
@@ -3,9 +3,9 @@
<!--
1. Please speak English, this is the language all maintainers can speak and write.
2. Please ask questions or configuration/deploy problems on our Discord
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
server (https://discord.gg/gitea) or forum (https://discourse.gitea.io).
3. Please take a moment to check that your issue doesn't already exist.
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.io/en-us/faq)
5. Please give all relevant information below for bug reports, because
incomplete details will be handled as an invalid report.
-->
@@ -21,12 +21,12 @@
- [ ] MySQL
- [ ] MSSQL
- [ ] SQLite
- Can you reproduce the bug at https://demo.gitea.com:
- Can you reproduce the bug at https://try.gitea.io:
- [ ] Yes (provide example URL)
- [ ] No
- Log gist:
<!-- It really is important to provide pertinent logs -->
<!-- Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help -->
<!-- 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 -->
## Description
-14
View File
@@ -1,14 +0,0 @@
docs-update-needed:
- changed-files:
- any-glob-to-any-file:
- "custom/conf/app.example.ini"
topic/code-linting:
- changed-files:
- any-glob-to-any-file:
- ".golangci.yml"
- ".markdownlint.yaml"
- ".spectral.yaml"
- ".yamllint.yaml"
- "eslint*.config.*"
- "stylelint.config.*"
+23
View File
@@ -0,0 +1,23 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 60
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). `false` is disabled
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored.
exemptLabels: []
# Label to add before locking, such as `outdated`. `false` is disabled
lockLabel: false
# Comment to post before locking.
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs and link to relevant comments in this thread.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true
+6 -10
View File
@@ -1,11 +1,7 @@
<!-- start tips -->
Please check the following:
1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports.
2. Use a Conventional Commits PR title, for example `fix(repo): handle empty branch names`.
3. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md .
4. For documentations contribution, please go to https://gitea.com/gitea/docs
5. Describe what your pull request does and which issue you're targeting (if any).
6. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
7. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
8. Delete all these tips before posting.
<!-- end tips -->
1. Make sure you are targeting the `master` branch, pull requests on release branches are only allowed for bug fixes.
2. Read contributing guidelines: https://github.com/go-gitea/gitea/blob/master/CONTRIBUTING.md
3. Describe what your pull request does and which issue you're targeting (if any)
**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**
+54
View File
@@ -0,0 +1,54 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 14
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- status/blocked
- kind/security
- lgtm/done
- reviewed/confirmed
- priority/critical
- kind/proposal
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had recent activity.
I am here to help clear issues left open even if solved or waiting for more insight.
This issue will be closed if no further activity occurs during the next 2 weeks.
If the issue is still valid just add a comment to keep it alive.
Thank you for your contributions.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue has been automatically closed because of inactivity.
You can re-open it if needed.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 1
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
pulls:
daysUntilStale: 60
daysUntilClose: 60
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs during the next 2 months. Thank you
for your contributions.
closeComment: >
This pull request has been automatically closed because of inactivity.
You can re-open it if needed.
-73
View File
@@ -1,73 +0,0 @@
# Populates the go module, build, and golangci-lint caches under the default
# branch's cache scope so that PR runs have a warm fallback to restore from.
#
# GitHub Actions caches are scoped per ref: a PR run can only write to its own
# branch's scope, but can read from the base branch's scope as a fallback.
# PRs therefore cannot seed main's scope themselves. Running the same cache
# steps on push-to-main is the only opportunity to populate that fallback
# scope so fresh PR branches start with a useful cache on first run.
# A PR job's exact key lives in its own PR-scope (empty on first run, filled
# by later runs of the same PR); on miss, actions/cache's restore-keys fall
# back to prefix matches against entries this seeder saves in main's scope.
name: cache-seeder
on:
push:
branches:
- main
paths:
- "go.sum"
- ".golangci.yml"
- ".github/actions/go-cache/action.yml"
- ".github/workflows/cache-seeder.yml"
concurrency:
group: cache-seeder
cancel-in-progress: true
permissions:
contents: read
jobs:
gobuild:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: seed
- run: make deps-backend
- run: TAGS="bindata" make backend
- run: TAGS="bindata gogit" GOEXPERIMENT="" make backend
lint:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- { job: lint-backend, tags: "bindata", target: "lint-backend" }
- { job: lint-go-windows, tags: "bindata", target: "lint-go-windows" }
- { job: lint-go-gogit, tags: "bindata gogit", target: "lint-go" }
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: ${{ matrix.job }}
lint-cache: "true"
- run: make deps-backend deps-tools
- run: make ${{ matrix.target }}
env:
TAGS: ${{ matrix.tags }}
-31
View File
@@ -1,31 +0,0 @@
name: cron-licenses
on:
# schedule:
# - cron: "7 0 * * 1" # every Monday at 00:07 UTC
workflow_dispatch:
jobs:
cron-licenses:
runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea'
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
- run: make generate-gitignore
timeout-minutes: 40
- name: push translations to repo
uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0
with:
author_email: "teabot@gitea.io"
author_name: GiteaBot
branch: main
commit: true
commit_message: "[skip ci] Updated licenses and gitignores"
remote: "git@github.com:go-gitea/gitea.git"
ssh_key: ${{ secrets.DEPLOY_KEY }}
-32
View File
@@ -1,32 +0,0 @@
name: cron-renovate
on:
schedule:
- cron: "23 * * * *" # hourly at :23
workflow_dispatch:
concurrency:
group: cron-renovate
env:
RENOVATE_VERSION: 43.141.5 # renovate: datasource=docker depName=ghcr.io/renovatebot/renovate
permissions:
contents: read
jobs:
cron-renovate:
runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea' # prevent running on forks
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: renovatebot/github-action@f66d8679fcfcfa051abde6e7a623007173bf5164 # v46.1.12
with:
renovate-version: ${{ env.RENOVATE_VERSION }}
configurationFile: renovate.json5
token: ${{ secrets.RENOVATE_TOKEN }}
env:
RENOVATE_BINARY_SOURCE: install # auto-install go/node toolchains needed by post-upgrade tasks.
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^make (tidy|svg nolyfill)$"]'
RENOVATE_REPOSITORIES: '["go-gitea/gitea"]'
-40
View File
@@ -1,40 +0,0 @@
name: cron-translations
on:
schedule:
- cron: "7 0 * * *" # every day at 00:07 UTC
workflow_dispatch:
jobs:
crowdin-pull:
runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea'
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2.16.2
with:
upload_sources: true
upload_translations: false
download_sources: false
download_translations: true
push_translations: false
push_sources: false
create_pull_request: false
config: crowdin.yml
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
- name: update locales
run: ./build/update-locales.sh
- name: push translations to repo
uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0
with:
author_email: "teabot@gitea.io"
author_name: GiteaBot
branch: main
commit: true
commit_message: "[skip ci] Updated translations via Crowdin"
remote: "git@github.com:go-gitea/gitea.git"
ssh_key: ${{ secrets.DEPLOY_KEY }}
-125
View File
@@ -1,125 +0,0 @@
name: files-changed
on:
workflow_call:
outputs:
backend:
value: ${{ jobs.detect.outputs.backend }}
frontend:
value: ${{ jobs.detect.outputs.frontend }}
docs:
value: ${{ jobs.detect.outputs.docs }}
actions:
value: ${{ jobs.detect.outputs.actions }}
templates:
value: ${{ jobs.detect.outputs.templates }}
docker:
value: ${{ jobs.detect.outputs.docker }}
dockerfile:
value: ${{ jobs.detect.outputs.dockerfile }}
swagger:
value: ${{ jobs.detect.outputs.swagger }}
yaml:
value: ${{ jobs.detect.outputs.yaml }}
json:
value: ${{ jobs.detect.outputs.json }}
e2e:
value: ${{ jobs.detect.outputs.e2e }}
permissions:
contents: read
jobs:
detect:
runs-on: ubuntu-latest
timeout-minutes: 3
outputs:
backend: ${{ steps.changes.outputs.backend }}
frontend: ${{ steps.changes.outputs.frontend }}
docs: ${{ steps.changes.outputs.docs }}
actions: ${{ steps.changes.outputs.actions }}
templates: ${{ steps.changes.outputs.templates }}
docker: ${{ steps.changes.outputs.docker }}
dockerfile: ${{ steps.changes.outputs.dockerfile }}
swagger: ${{ steps.changes.outputs.swagger }}
yaml: ${{ steps.changes.outputs.yaml }}
json: ${{ steps.changes.outputs.json }}
e2e: ${{ steps.changes.outputs.e2e }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
filters: |
backend:
- "**/*.go"
- "templates/**/*.tmpl"
- "assets/emoji.json"
- "go.mod"
- "go.sum"
- "Makefile"
- ".golangci.yml"
- ".editorconfig"
- "options/locale/locale_en-US.json"
frontend:
- "*.js"
- "*.ts"
- "web_src/**"
- "tools/*.js"
- "tools/*.ts"
- "assets/emoji.json"
- "package.json"
- "pnpm-lock.yaml"
- "Makefile"
- ".eslintrc.cjs"
- ".npmrc"
docs:
- "**/*.md"
- ".markdownlint.yaml"
- "package.json"
- "pnpm-lock.yaml"
actions:
- ".github/workflows/*"
- "Makefile"
templates:
- "tools/lint-templates-*.js"
- "templates/**/*.tmpl"
- "pyproject.toml"
- "uv.lock"
docker:
- ".github/workflows/pull-docker-dryrun.yml"
- "Dockerfile"
- "Dockerfile.rootless"
- "docker/**"
- "Makefile"
dockerfile:
- "Dockerfile"
- "Dockerfile.rootless"
swagger:
- "templates/swagger/v1_json.tmpl"
- "templates/swagger/v1_input.json"
- "Makefile"
- "package.json"
- "pnpm-lock.yaml"
- ".spectral.yaml"
yaml:
- "**/*.yml"
- "**/*.yaml"
- ".yamllint.yaml"
- "pyproject.toml"
json:
- "**/*.json"
e2e:
- "tests/e2e/**"
- "tools/test-e2e.sh"
- "playwright.config.ts"
-178
View File
@@ -1,178 +0,0 @@
name: compliance
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
files-changed:
uses: ./.github/workflows/files-changed.yml
lint-backend:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: lint-backend
lint-cache: "true"
- run: make deps-backend deps-tools
- run: make lint-backend
env:
TAGS: bindata
lint-on-demand:
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make lint-spell
- if: needs.files-changed.outputs.templates == 'true' || needs.files-changed.outputs.yaml == 'true'
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- if: needs.files-changed.outputs.templates == 'true' || needs.files-changed.outputs.yaml == 'true'
run: uv python install 3.14 && make deps-py lint-templates lint-yaml
- if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.swagger == 'true' || needs.files-changed.outputs.json == 'true'
run: make deps-frontend lint-md lint-swagger lint-json
- if: needs.files-changed.outputs.actions == 'true'
run: make lint-actions
lint-go-windows:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: lint-go-windows
lint-cache: "true"
- run: make deps-backend deps-tools
- run: make lint-go-windows
env:
TAGS: bindata
GOOS: windows
GOARCH: amd64
lint-go-gogit:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: lint-go-gogit
lint-cache: "true"
- run: make deps-backend deps-tools
- run: make lint-go
env:
TAGS: bindata gogit
checks-backend:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: checks-backend
build-cache: "false"
- run: make deps-backend deps-tools
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
frontend:
if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend
- run: make lint-frontend
- run: make checks-frontend
- run: make test-frontend
- run: make frontend
backend:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: compliance-backend
- run: make deps-backend generate-go
# no frontend build here as backend should be able to build, even without any frontend files
# CGO is not used when cross-compile, so these steps also test if the code is compatible with CGO disabled
- name: build-backend-arm64
run: go build -o gitea_linux_arm64
env:
GOOS: linux
GOARCH: arm64
TAGS: bindata gogit
- name: build-backend-windows
run: go build -o gitea_windows
env:
GOOS: windows
GOARCH: amd64
TAGS: bindata gogit
- name: build-backend-386
run: go build -o gitea_linux_386
env:
GOOS: linux
GOARCH: 386
-262
View File
@@ -1,262 +0,0 @@
name: db-tests
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
files-changed:
uses: ./.github/workflows/files-changed.yml
test-pgsql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
services:
pgsql:
image: postgres:14
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
ldap:
image: gitea/test-openldap:latest
ports:
- "389:389"
- "636:636"
minio:
# as github actions doesn't support "entrypoint", we need to use a non-official image
# that has a custom entrypoint set to "minio server /data"
image: bitnamilegacy/minio:2023.12.23
env:
MINIO_ROOT_USER: 123456
MINIO_ROOT_PASSWORD: 12345678
ports:
- "9000:9000"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: pgsql
- name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts'
- run: make deps-backend
- run: make backend
env:
TAGS: bindata
- name: run migration tests
run: GITEA_TEST_DATABASE=pgsql make test-migration
- name: run tests
run: GITEA_TEST_DATABASE=pgsql make test-integration
timeout-minutes: 50
env:
# pgsql is chosen to be the unlucky one to run with the slow "race detector", it is about 60% slower.
GOTEST_FLAGS: -race -timeout=40m
TAGS: bindata gogit
TEST_LDAP: 1
test-sqlite:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: sqlite
- run: make deps-backend
- run: make backend
env:
TAGS: bindata gogit
GOEXPERIMENT:
- name: run migration tests
run: GITEA_TEST_DATABASE=sqlite make test-migration
env:
TAGS: bindata gogit
- name: run tests
run: GITEA_TEST_DATABASE=sqlite make test-integration
timeout-minutes: 50
env:
# sqlite driver can contain large amount of Golang code, so don't use race detector for it, otherwise, extremely slow
GOTEST_FLAGS: -timeout=40m
TAGS: bindata gogit
GOEXPERIMENT:
test-unit:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.14
env:
discovery.type: single-node
xpack.security.enabled: false
ports:
- "9200:9200"
meilisearch:
image: getmeili/meilisearch:v1
env:
MEILI_ENV: development # disable auth
ports:
- "7700:7700"
redis:
image: redis
options: >- # wait until redis has started
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 10
ports:
- 6379:6379
minio:
image: bitnamilegacy/minio:2021.12.29
env:
MINIO_ACCESS_KEY: 123456
MINIO_SECRET_KEY: 12345678
ports:
- "9000:9000"
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
image: mcr.microsoft.com/azure-storage/azurite:latest
ports:
- 10000:10000
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: unit
build-cache-rotate: "true"
- name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
- run: make deps-backend
- run: make backend
env:
TAGS: bindata
- name: unit-tests
run: make test-backend test-check
env:
GOTEST_FLAGS: -race -timeout=20m
TAGS: bindata
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
- name: unit-tests-gogit
run: make test-backend test-check
env:
GOTEST_FLAGS: -race -timeout=20m
TAGS: bindata gogit
GOEXPERIMENT:
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
test-mysql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
services:
mysql:
# the bitnami mysql image has more options than the official one, it's easier to customize
image: bitnamilegacy/mysql:8.4
env:
ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: testgitea
ports:
- "3306:3306"
options: >-
--mount type=tmpfs,destination=/bitnami/mysql/data
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.14
env:
discovery.type: single-node
xpack.security.enabled: false
ports:
- "9200:9200"
smtpimap:
image: tabascoterrier/docker-imap-devel:latest
ports:
- "25:25"
- "143:143"
- "587:587"
- "993:993"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: mysql
- name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
- run: make deps-backend
- run: make backend
env:
TAGS: bindata
- name: run migration tests
run: GITEA_TEST_DATABASE=mysql make test-migration
- name: run tests
run: GITEA_TEST_DATABASE=mysql make test-integration
env:
TAGS: bindata
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
test-mssql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
services:
mssql:
image: mcr.microsoft.com/mssql/server:2019-latest
env:
ACCEPT_EULA: Y
MSSQL_PID: Standard
SA_PASSWORD: MwantsaSecurePassword1
ports:
- "1433:1433"
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
image: mcr.microsoft.com/azure-storage/azurite:latest
ports:
- 10000:10000
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: mssql
- name: Add hosts to /etc/hosts
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts'
- run: make deps-backend
- run: make backend
env:
TAGS: bindata
- run: GITEA_TEST_DATABASE=mssql make test-migration
- name: run tests
run: GITEA_TEST_DATABASE=mssql make test-integration
timeout-minutes: 50
env:
TAGS: bindata
-47
View File
@@ -1,47 +0,0 @@
name: docker-dryrun
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
files-changed:
uses: ./.github/workflows/files-changed.yml
# QEMU-based build is slow (40-50 minutes), so run arm64 and riscv64 when dockerfile changes.
# Run amd64 when any docker-related files change, which is fast (4 minutes).
container-amd64:
if: needs.files-changed.outputs.docker == 'true'
needs: [files-changed]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/docker-dryrun
with:
platform: linux/amd64
container-arm64:
if: needs.files-changed.outputs.dockerfile == 'true'
needs: [files-changed]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/docker-dryrun
with:
platform: linux/arm64
container-riscv64:
if: needs.files-changed.outputs.dockerfile == 'true'
needs: [files-changed]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/docker-dryrun
with:
platform: linux/riscv64
-50
View File
@@ -1,50 +0,0 @@
name: e2e-tests
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
files-changed:
uses: ./.github/workflows/files-changed.yml
test-e2e:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.e2e == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
cache: false
- uses: ./.github/actions/go-cache
with:
cache-name: e2e
build-cache: "false"
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend
- run: make frontend
- run: make deps-backend
- run: make backend
env:
TAGS: bindata
- run: make playwright
- run: make test-e2e
timeout-minutes: 10
env:
TAGS: bindata
FORCE_COLOR: 1
GITEA_TEST_E2E_DEBUG: 1
-20
View File
@@ -1,20 +0,0 @@
name: labeler
on:
pull_request_target:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
labeler:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
with:
sync-labels: true
-28
View File
@@ -1,28 +0,0 @@
name: pr-title
on:
pull_request:
types:
- opened
- edited
- reopened
- synchronize
- ready_for_review
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint-pr-title:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- run: make lint-pr-title
env:
PR_TITLE: ${{ github.event.pull_request.title }}
-135
View File
@@ -1,135 +0,0 @@
name: release-nightly
on:
push:
branches: [main, release/v*]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
nightly-binary:
runs-on: namespace-profile-gitea-release-binary
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend deps-backend
# xgo build
- run: make release
env:
TAGS: bindata
- name: import gpg key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
- name: sign binaries
run: |
for f in dist/release/*; do
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
done
# clean branch name to get the folder name in S3
- name: Get cleaned branch name
id: clean_name
run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: configure aws
uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: upload binaries to s3
run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
nightly-container:
runs-on: namespace-profile-gitea-release-docker
permissions:
contents: read
packages: write # to publish to ghcr.io
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Get cleaned branch name
id: clean_name
run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
tags: |
type=raw,value=${{ steps.clean_name.outputs.branch }}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta_rootless
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# each tag below will have the suffix of -rootless
flavor: |
suffix=-rootless
tags: |
type=raw,value=${{ steps.clean_name.outputs.branch }}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular docker image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max
- name: build rootless docker image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }}
annotations: ${{ steps.meta_rootless.outputs.annotations }}
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless,mode=max
-141
View File
@@ -1,141 +0,0 @@
name: release-tag-rc
on:
push:
tags:
- "v1*-rc*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
binary:
runs-on: namespace-profile-gitea-release-binary
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend deps-backend
# xgo build
- run: make release
env:
TAGS: bindata
- name: import gpg key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
- name: sign binaries
run: |
for f in dist/release/*; do
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
done
# clean branch name to get the folder name in S3
- name: Get cleaned branch name
id: clean_name
run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//')
echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
- name: configure aws
uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: upload binaries to s3
run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
- name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1
with:
gh-cli-version: 2.39.1
- name: create github release
run: |
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
container:
runs-on: namespace-profile-gitea-release-docker
permissions:
contents: read
packages: write # to publish to ghcr.io
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
flavor: |
latest=false
# 1.2.3-rc0
tags: |
type=semver,pattern={{version}}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta_rootless
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# each tag below will have the suffix of -rootless
flavor: |
latest=false
suffix=-rootless
# 1.2.3-rc0
tags: |
type=semver,pattern={{version}}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular container image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
- name: build rootless container image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }}
annotations: ${{ steps.meta_rootless.outputs.annotations }}
-153
View File
@@ -1,153 +0,0 @@
name: release-tag-version
on:
push:
tags:
- "v1.*"
- "!v1*-rc*"
- "!v1*-dev"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
binary:
runs-on: namespace-profile-gitea-release-binary
permissions:
contents: read
packages: write # to publish to ghcr.io
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend deps-backend
# xgo build
- run: make release
env:
TAGS: bindata
- name: import gpg key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
- name: sign binaries
run: |
for f in dist/release/*; do
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
done
# clean branch name to get the folder name in S3
- name: Get cleaned branch name
id: clean_name
run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//')
echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
- name: configure aws
uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: upload binaries to s3
run: |
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
- name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1
with:
gh-cli-version: 2.39.1
- name: create github release
run: |
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/*
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
container:
runs-on: namespace-profile-gitea-release-docker
permissions:
contents: read
packages: write # to publish to ghcr.io
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# this will generate tags in the following format:
# latest
# 1
# 1.2
# 1.2.3
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
id: meta_rootless
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# each tag below will have the suffix of -rootless
flavor: |
suffix=-rootless,onlatest=true
# this will generate tags in the following format (with -rootless suffix added):
# latest
# 1
# 1.2
# 1.2.3
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular container image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
- name: build rootless container image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }}
annotations: ${{ steps.meta_rootless.outputs.annotations }}
+46 -57
View File
@@ -9,24 +9,14 @@ _test
# IntelliJ
.idea
.run
# IntelliJ Gateway
.uuid
# Goland's output filename can not be set manually
/go_build_*
/gitea_*
# MS VSCode
.vscode
__debug_bin*
__debug_bin
# Visual Studio
/.vs/
# mise version managment tool
mise.toml
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
@@ -39,55 +29,72 @@ _testmain.go
*.exe
*.test
*.prof
*.tsbuildinfo
*coverage.out
coverage.all
cpu.out
/modules/migration/bindata.*
/modules/options/bindata.*
/modules/public/bindata.*
/modules/templates/bindata.*
/modules/options/bindata.go
/modules/options/bindata.go.hash
/modules/public/bindata.go
/modules/public/bindata.go.hash
/modules/templates/bindata.go
/modules/templates/bindata.go.hash
*.db
*.log
*.log.*.gz
/gitea
/gitea-vet
/debug
/integrations.test
/bin
/dist
/custom/*
!/custom/conf
/custom/conf/*
!/custom/conf/app.example.ini
/data
/indexers
/log
/public/assets/img/avatar
/tests/e2e-output
/tests/integration/gitea-integration-*
/tests/integration/indexers-*
/tests/*.ini
/tests/**/*.git/**/*.sample
/public/img/avatar
/integrations/gitea-integration-mysql
/integrations/gitea-integration-mysql8
/integrations/gitea-integration-pgsql
/integrations/gitea-integration-sqlite
/integrations/gitea-integration-mssql
/integrations/indexers-mysql
/integrations/indexers-mysql8
/integrations/indexers-pgsql
/integrations/indexers-sqlite
/integrations/indexers-mssql
/integrations/sqlite.ini
/integrations/mysql.ini
/integrations/mysql8.ini
/integrations/pgsql.ini
/integrations/mssql.ini
/node_modules
/.venv
/yarn.lock
/yarn-error.log
/npm-debug.log*
/.pnpm-store
/public/assets/.vite
/public/assets/js
/public/assets/css
/public/assets/fonts
/public/assets/licenses.txt
/vendor
/public/js
/public/serviceworker.js
/public/css
/public/fonts
/public/img/webpack
/web_src/fomantic/build/*
!/web_src/fomantic/build/semantic.js
!/web_src/fomantic/build/semantic.css
!/web_src/fomantic/build/themes
/web_src/fomantic/build/themes/*
!/web_src/fomantic/build/themes/default
/web_src/fomantic/build/themes/default/assets/*
!/web_src/fomantic/build/themes/default/assets/fonts
/web_src/fomantic/build/themes/default/assets/fonts/*
!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
/VERSION
/.air
# Snapcraft
/gitea_a*.txt
snap/.snapcraft/
parts/
stage/
@@ -97,26 +104,8 @@ prime/
*_source.tar.bz2
.DS_Store
# nix-direnv generated files
.direnv/
# Make evidence files
/.make_evidence
# Manpage
/man
# Ignore AI/LLM instruction files
/.claude/
/.cursorrules
/.cursor/
/.goosehints
/.windsurfrules
/.github/copilot-instructions.md
/llms.txt
# Ignore worktrees when working on multiple branches
.worktrees/
# A Makefile for custom make targets
Makefile.local
+109 -189
View File
@@ -1,196 +1,116 @@
version: "2"
output:
sort-order:
- file
linters:
default: none
enable:
- bidichk
- bodyclose
- depguard
- dupl
- errcheck
- forbidigo
- gocheckcompilerdirectives
- gocritic
- goheader
- gosimple
- deadcode
- typecheck
- govet
- ineffassign
- mirror
- modernize
- nakedret
- nilnil
- nolintlint
- perfsprint
- revive
- errcheck
- staticcheck
- testifylint
- unconvert
- unparam
- unused
- usestdlibvars
- usetesting
- wastedassign
settings:
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.mokoconsulting.tech/MokoConsulting/MokoGitea/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: gitea.com/go-chi/cache
desc: do not use the go-chi cache package, use gitea's cache system
- pkg: github.com/pkg/errors
desc: use builtin errors package instead
migrations:
files:
- '**/models/migrations/**/*.go'
deny:
- pkg: code.mokoconsulting.tech/MokoConsulting/MokoGitea/models$
desc: migrations must not depend on the models package
- pkg: code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/structs
desc: migrations must not depend on modules/structs (API structures change over time)
nolintlint:
allow-unused: false
require-explanation: true
require-specific: true
gocritic:
enabled-checks:
- equalFold
disabled-checks:
- ifElseChain
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
- deprecatedComment # conflicts with go-swagger comments
revive:
severity: error
rules:
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: empty-lines
- name: error-return
- name: error-strings
- name: exported
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: modifies-value-receiver
- name: package-comments
- name: redefines-builtin-id
- name: superfluous-else
- name: time-naming
- name: unexported-return
- name: var-declaration
- name: var-naming
arguments:
- [] # AllowList - do not remove as args for the rule are positional and won't work without lists first
- [] # DenyList
- - skip-package-name-checks: true # supress errors from underscore in migration packages
staticcheck:
checks:
- all
- -ST1003
- -ST1005
- -QF1001
- -QF1006
- -QF1008
testifylint:
disable:
- go-require
- require-error
usetesting:
os-temp-dir: true
perfsprint:
concat-loop: false
govet:
enable:
- nilness
- unusedwrite
goheader:
values:
regexp:
HEADER: '((Copyright [^\n]+|All rights reserved\.)\n)*Copyright \d{4} (The (Gogs|Gitea) Authors|Gitea Authors|Gitea)\.( All rights reserved\.)?(\n(Copyright [^\n]+|All rights reserved\.))*\nSPDX-License-Identifier: [\w.-]+'
template: '{{ HEADER }}'
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- dupl
- errcheck
- staticcheck
- unparam
path: _test\.go
- linters:
- dupl
- errcheck
path: models/migrations/v
- linters:
- forbidigo
path: cmd
- linters:
- dupl
text: (?i)webhook
- linters:
- gocritic
text: (?i)`ID' should not be capitalized
- linters:
- unused
text: (?i)swagger
- linters:
- gocritic
text: '(?i)commentFormatting: put a space between `//` and comment text'
- linters:
- gocritic
text: '(?i)exitAfterDefer:'
paths:
- node_modules
- .venv
- public
- web_src
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gci
- gofumpt
settings:
gci:
custom-order: true
sections:
- standard
- prefix(code.mokoconsulting.tech/MokoConsulting/MokoGitea)
- blank
- default
gofumpt:
extra-rules: true
exclusions:
generated: lax
paths:
- node_modules
- .venv
- public
- web_src
- structcheck
- varcheck
- golint
- dupl
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
- gocritic
enable-all: false
disable-all: true
fast: false
run:
timeout: 10m
timeout: 3m
linters-settings:
gocritic:
disabled-checks:
- ifElseChain
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
issues:
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- unparam
- staticcheck
- path: models/migrations/v
linters:
- gocyclo
- errcheck
- dupl
- gosec
- linters:
- dupl
text: "webhook"
- linters:
- gocritic
text: "`ID' should not be capitalized"
- path: modules/templates/helper.go
linters:
- gocritic
- linters:
- unused
- deadcode
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/routes/web.go
linters:
- dupl
- 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
- linters:
- misspell
text: '`Unknwon` is a misspelling of `Unknown`'
- 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."
+4 -7
View File
@@ -1,8 +1,5 @@
*.min.css
*.min.js
/assets/*.json
/options/gitignore
/options/license
/public/assets
/vendor
node_modules
/public/vendor/plugins
/modules/options/bindata.go
/modules/public/bindata.go
/modules/templates/bindata.go
+3
View File
@@ -0,0 +1,3 @@
pattern = "(?)LGTM"
self_approval_off = true
ignore_maintainers_file = true
-2
View File
@@ -1,2 +0,0 @@
Unknwon <u@gogs.io> <joe2010xtmf@163.com>
Unknwon <u@gogs.io> 无闻 <u@gogs.io>
-15
View File
@@ -1,15 +0,0 @@
commands-show-output: false
fenced-code-language: false
first-line-h1: false
heading-increment: false
line-length: {code_blocks: false, tables: false, stern: true, line_length: -1}
no-alt-text: false
no-bare-urls: false
no-emphasis-as-heading: false
no-empty-links: false
no-hard-tabs: {code_blocks: false}
no-inline-html: false
no-space-in-code: false
no-space-in-emphasis: false
no-trailing-spaces: {br_spaces: 0}
single-h1: false
-25
View File
@@ -1,25 +0,0 @@
{
"mcpServers": {
"ssh": {
"type": "stdio",
"command": "node",
"args": [
"A:/ssh-mcp/src/index.js"
]
},
"wiki": {
"type": "stdio",
"command": "node",
"args": [
"A:/wiki-mcp/dist/index.js"
]
},
"project": {
"type": "stdio",
"command": "node",
"args": [
"A:/project-mcp/dist/index.js"
]
}
}
}
-42
View File
@@ -1,42 +0,0 @@
# MokoGitea
Fork of Gitea -- self-hosted Git service at git.mokoconsulting.tech. Go backend + TypeScript frontend.
## Quick Reference
| Field | Value |
|---|---|
| **Language** | Go 1.26+ / TypeScript |
| **Module** | `code.mokoconsulting.tech/MokoConsulting/MokoGitea` |
| **Branch** | develop on `dev`, merge to `main` (protected) |
| **Wiki** | [MokoGitea Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki) |
## Commands
```bash
make help # List all available targets
make fmt # Format .go files
make lint-go # Lint Go code
make lint-js # Lint TypeScript
make tidy # After go.mod changes
make build # Build binary
# Testing
go test -run '^TestName$' ./modulepath/ # Single Go test
pnpm exec vitest <path-filter> # Single JS test
GITEA_TEST_E2E_FLAGS='<filepath>' make test-e2e # Single Playwright test
```
## Rules
- Add current year copyright header on new `.go` files
- No trailing whitespace in edited files
- Conventional Commits for commit messages and PR titles
- Never force-push, amend, or squash unless asked -- use new commits
- Preserve existing code comments
- TypeScript: use `!` (non-null assertion) not `?.`/`??` when value is known to exist
- CSS: prefer `flex-*` helpers over per-child `tw-ml-*`/`tw-mr-*` margins
- Add `Co-Authored-By` lines to all commits
- **Workflow directory**: `.mokogitea/` (not `.gitea/` or `.github/`)
- **Attribution**: `Authored-by: Moko Consulting`
- **Standards**: [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/mokoplatform/wiki/Home)
-110
View File
@@ -1,110 +0,0 @@
---
name: Architecture Decision Record (ADR)
about: Propose or document an architectural decision
title: '[ADR] '
labels: 'architecture, decision'
assignees: ''
---
## ADR Number
ADR-XXXX
## Status
- [ ] Proposed
- [ ] Accepted
- [ ] Deprecated
- [ ] Superseded by ADR-XXXX
## Context
Describe the issue or problem that motivates this decision.
## Decision
State the architecture decision and provide rationale.
## Consequences
### Positive
- List positive consequences
### Negative
- List negative consequences or trade-offs
### Neutral
- List neutral aspects
## Alternatives Considered
### Alternative 1
- Description
- Pros
- Cons
- Why not chosen
### Alternative 2
- Description
- Pros
- Cons
- Why not chosen
## Implementation Plan
1. Step 1
2. Step 2
3. Step 3
## Stakeholders
- **Decision Makers**: @user1, @user2
- **Consulted**: @user3, @user4
- **Informed**: team-name
## Technical Details
### Architecture Diagram
```
[Add diagram or link]
```
### Dependencies
- Dependency 1
- Dependency 2
### Impact Analysis
- **Performance**: [Impact description]
- **Security**: [Impact description]
- **Scalability**: [Impact description]
- **Maintainability**: [Impact description]
## Testing Strategy
- [ ] Unit tests
- [ ] Integration tests
- [ ] Performance tests
- [ ] Security tests
## Documentation
- [ ] Architecture documentation updated
- [ ] API documentation updated
- [ ] Developer guide updated
- [ ] Runbook created
## Migration Path
Describe how to migrate from current state to new architecture.
## Rollback Plan
Describe how to rollback if issues occur.
## Timeline
- **Proposal Date**:
- **Decision Date**:
- **Implementation Start**:
- **Expected Completion**:
## References
- Related ADRs:
- External resources:
- RFCs:
## Review Checklist
- [ ] Aligns with enterprise architecture principles
- [ ] Security implications reviewed
- [ ] Performance implications reviewed
- [ ] Cost implications reviewed
- [ ] Compliance requirements met
- [ ] Team consensus achieved
-48
View File
@@ -1,48 +0,0 @@
---
name: Bug Report
about: Report a bug or issue with the project
title: '[BUG] '
labels: 'bug'
assignees: ''
---
## Bug Description
A clear and concise description of what the bug is.
## Steps to Reproduce
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
## Expected Behavior
A clear and concise description of what you expected to happen.
## Actual Behavior
A clear and concise description of what actually happened.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Environment
- **Project**: [e.g., MokoDoliTools, moko-cassiopeia]
- **Version**: [e.g., 1.2.3]
- **Platform**: [e.g., Dolibarr 18.0, Joomla 5.0]
- **PHP Version**: [e.g., 8.1]
- **Database**: [e.g., MySQL 8.0, PostgreSQL 14]
- **Browser** (if applicable): [e.g., Chrome 120, Firefox 121]
- **OS**: [e.g., Ubuntu 22.04, Windows 11]
## Additional Context
Add any other context about the problem here.
## Possible Solution
If you have suggestions on how to fix the issue, please describe them here.
## Checklist
- [ ] I have searched for similar issues before creating this one
- [ ] I have provided all the requested information
- [ ] I have tested this on the latest stable version
- [ ] I have checked the documentation and couldn't find a solution
-18
View File
@@ -1,18 +0,0 @@
---
blank_issues_enabled: true
contact_links:
- name: 💼 Enterprise Support
url: https://mokoconsulting.tech/enterprise
about: Enterprise-level support and consultation services
- name: 💬 Ask a Question
url: https://mokoconsulting.tech/
about: Get help or ask questions through our website
- name: 📚 MokoStandards Documentation
url: https://code.mokoconsulting.tech/MokoConsulting/mokoplatform
about: View our coding standards and best practices
- name: 🔒 Report a Security Vulnerability
url: https://code.mokoconsulting.tech/mokoconsulting-tech/.github-private/security/advisories/new
about: Report security vulnerabilities privately (for critical issues)
- name: 💡 Community Discussions
url: https://github.com/orgs/mokoconsulting-tech/discussions
about: Join community discussions and Q&A
@@ -1,52 +0,0 @@
---
name: Documentation Issue
about: Report an issue with documentation
title: '[DOCS] '
labels: 'documentation'
assignees: ''
---
## Documentation Issue
**Location**:
<!-- Specify the file, page, or section with the issue -->
## Issue Type
<!-- Mark the relevant option with an "x" -->
- [ ] Typo or grammar error
- [ ] Outdated information
- [ ] Missing documentation
- [ ] Unclear explanation
- [ ] Broken links
- [ ] Missing examples
- [ ] Other (specify below)
## Description
<!-- Clearly describe the documentation issue -->
## Current Content
<!-- Quote or describe the current documentation (if applicable) -->
```
Current text here
```
## Suggested Improvement
<!-- Provide your suggestion for how to improve the documentation -->
```
Suggested text here
```
## Additional Context
<!-- Add any other context, screenshots, or references -->
## Standards Alignment
- [ ] Follows MokoStandards documentation guidelines
- [ ] Uses en_US/en_GB localization
- [ ] Includes proper SPDX headers where applicable
## Checklist
- [ ] I have searched for similar documentation issues
- [ ] I have provided a clear description
- [ ] I have suggested an improvement (if applicable)
@@ -1,51 +0,0 @@
---
name: Feature Request
about: Suggest a new feature or enhancement
title: '[FEATURE] '
labels: 'enhancement'
assignees: ''
---
## Feature Description
A clear and concise description of the feature you'd like to see.
## Problem or Use Case
Describe the problem this feature would solve or the use case it addresses.
Ex. I'm always frustrated when [...]
## Proposed Solution
A clear and concise description of what you want to happen.
## Alternative Solutions
A clear and concise description of any alternative solutions or features you've considered.
## Benefits
Describe how this feature would benefit users:
- Who would use this feature?
- What problems does it solve?
- What value does it add?
## Implementation Details (Optional)
If you have ideas about how this could be implemented, share them here:
- Technical approach
- Files/components that might need changes
- Any concerns or challenges you foresee
## Additional Context
Add any other context, mockups, or screenshots about the feature request here.
## Relevant Standards
Does this relate to any standards in [MokoStandards](https://code.mokoconsulting.tech/MokoConsulting/MokoStandards)?
- [ ] Accessibility (WCAG 2.1 AA)
- [ ] Localization (en_US/en_GB)
- [ ] Security best practices
- [ ] Code quality standards
- [ ] Other: [specify]
## Checklist
- [ ] I have searched for similar feature requests before creating this one
- [ ] I have clearly described the use case and benefits
- [ ] I have considered alternative solutions
- [ ] This feature aligns with the project's goals and scope
-82
View File
@@ -1,82 +0,0 @@
---
name: Question
about: Ask a question about usage, features, or best practices
title: '[QUESTION] '
labels: ['question']
assignees: ['jmiller']
---
## Question
**Your question:**
## Context
**What are you trying to accomplish?**
**What have you already tried?**
**Category**:
- [ ] Script usage
- [ ] Configuration
- [ ] Workflow setup
- [ ] Documentation interpretation
- [ ] Best practices
- [ ] Integration
- [ ] Other: __________
## Environment (if relevant)
**Your setup**:
- Operating System:
- Version:
## What You've Researched
**Documentation reviewed**:
- [ ] README.md
- [ ] Project documentation
- [ ] Other (specify): __________
**Similar issues/questions found**:
- #
- #
## Expected Outcome
**What result are you hoping for?**
## Code/Configuration Samples
**Relevant code or configuration** (if applicable):
```bash
# Your code here
```
## Additional Context
**Any other relevant information:**
**Screenshots** (if helpful):
## Urgency
- [ ] Urgent (blocking work)
- [ ] Normal (can work on other things meanwhile)
- [ ] Low priority (just curious)
## Checklist
- [ ] I have searched existing issues and discussions
- [ ] I have reviewed relevant documentation
- [ ] I have provided sufficient context
- [ ] I have included code/configuration samples if relevant
- [ ] This is a genuine question (not a bug report or feature request)
-126
View File
@@ -1,126 +0,0 @@
---
name: Request for Comments (RFC)
about: Propose a significant change for community discussion
title: '[RFC] '
labels: 'rfc, discussion'
assignees: ''
---
## RFC Summary
One-paragraph summary of the proposal.
## Motivation
Why are we doing this? What use cases does it support? What is the expected outcome?
## Detailed Design
### Overview
Provide a detailed explanation of the proposed change.
### API Changes (if applicable)
```php
// Before
function oldApi($param1) { }
// After
function newApi($param1, $param2) { }
```
### User Experience Changes
Describe how users will interact with this change.
### Implementation Approach
High-level implementation strategy.
## Drawbacks
Why should we *not* do this?
## Alternatives
What other designs have been considered? What is the impact of not doing this?
### Alternative 1
- Description
- Trade-offs
### Alternative 2
- Description
- Trade-offs
## Adoption Strategy
How will existing users adopt this? Is this a breaking change?
### Migration Guide
```bash
# Steps to migrate
```
### Deprecation Timeline
- **Announcement**:
- **Deprecation**:
- **Removal**:
## Unresolved Questions
- Question 1
- Question 2
## Future Possibilities
What future work does this enable?
## Impact Assessment
### Performance
Expected performance impact.
### Security
Security considerations and implications.
### Compatibility
- **Backward Compatible**: [Yes / No]
- **Breaking Changes**: [List]
### Maintenance
Long-term maintenance considerations.
## Community Input
### Stakeholders
- [ ] Core team
- [ ] Module developers
- [ ] End users
- [ ] Enterprise customers
### Feedback Period
**Duration**: [e.g., 2 weeks]
**Deadline**: [date]
## Implementation Timeline
### Phase 1: Design
- [ ] RFC discussion
- [ ] Design finalization
- [ ] Approval
### Phase 2: Implementation
- [ ] Core implementation
- [ ] Tests
- [ ] Documentation
### Phase 3: Release
- [ ] Beta release
- [ ] Feedback collection
- [ ] Stable release
## Success Metrics
How will we measure success?
- Metric 1
- Metric 2
## References
- Related RFCs:
- External documentation:
- Prior art:
## Open Questions for Community
1. Question 1?
2. Question 2?
---
**Note**: This RFC is open for community discussion. Please provide feedback in the comments below.
-51
View File
@@ -1,51 +0,0 @@
---
name: Security Vulnerability Report
about: Report a security vulnerability (use only for non-critical issues)
title: '[SECURITY] '
labels: 'security'
assignees: ''
---
## ⚠️ IMPORTANT: Private Disclosure Required
**For critical security vulnerabilities, DO NOT use this template.**
Follow the process in [SECURITY.md](../SECURITY.md) for responsible disclosure.
Use this template only for:
- Security improvements
- Non-critical security suggestions
- Security documentation updates
---
## Security Issue
**Severity**:
<!-- Low, Medium, or informational only -->
## Description
<!-- Describe the security concern or improvement suggestion -->
## Affected Components
<!-- List the affected files, features, or components -->
## Suggested Mitigation
<!-- Describe how this could be addressed -->
## Standards Reference
Does this relate to security standards in [MokoStandards](https://code.mokoconsulting.tech/MokoConsulting/MokoStandards)?
- [ ] SPDX license identifiers
- [ ] Secret management
- [ ] Dependency security
- [ ] Access control
- [ ] Other: [specify]
## Additional Context
<!-- Add any other context about the security concern -->
## Checklist
- [ ] This is NOT a critical vulnerability requiring private disclosure
- [ ] I have reviewed the SECURITY.md policy
- [ ] I have provided sufficient detail for evaluation
@@ -1,9 +0,0 @@
---
name: ".mokogitea Test Template"
about: "Verify .mokogitea issue templates work"
labels: ["test"]
---
This template was loaded from `.mokogitea/ISSUE_TEMPLATE/`.
If you can see this, the `.mokogitea` dot-folder feature is working.
-24
View File
@@ -1,24 +0,0 @@
---
name: Version Bump
about: Request or track a version change
title: '[VERSION] '
labels: 'version, type: version'
assignees: 'jmiller'
---
## Version Change
**Current version**: <!-- e.g., 01.02.03 -->
**Requested version**: <!-- e.g., 01.03.00 -->
**Change type**: <!-- patch / minor / major -->
## Reason
<!-- Why is this version bump needed? -->
## Checklist
- [ ] README.md `VERSION:` field updated
- [ ] CHANGELOG.md entry added
- [ ] Module descriptor version updated (Dolibarr: `$this->version`, Joomla: `<version>`)
- [ ] All file headers will be auto-propagated by `sync-version-on-merge` workflow
-251
View File
@@ -1,251 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokoplatform.Automation
# REPO: https://code.mokoconsulting.tech/MokoConsulting/mokoplatform
# PATH: /.gitea/workflows/branch-protection.yml
# BRIEF: Apply standardised branch protection rules to all governed repositories
#
# +========================================================================+
# | BRANCH PROTECTION SETUP |
# +========================================================================+
# | |
# | Applies protection rules for: main, dev, rc, beta, alpha |
# | |
# | main — Require PR, block rejected reviews, no force push |
# | dev — Allow push, no force push, no delete |
# | rc — Allow push, no force push, no delete |
# | beta — Allow push, no force push, no delete |
# | alpha — Allow push, no force push, no delete |
# | |
# | jmiller has override authority on all branches. |
# | |
# +========================================================================+
name: Branch Protection Setup
on:
schedule:
- cron: '0 2 * * 1' # Weekly Monday 02:00 UTC
workflow_dispatch:
inputs:
dry_run:
description: 'Preview mode (no changes)'
required: false
type: boolean
default: false
repos:
description: 'Comma-separated repo names (empty = all governed repos)'
required: false
type: string
default: ''
env:
GITEA_URL: https://code.mokoconsulting.tech
GITEA_ORG: MokoConsulting
permissions:
contents: read
jobs:
protect:
name: Apply Branch Protection Rules
runs-on: ubuntu-latest
steps:
- name: Determine target repos
id: repos
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1"
# Platform/standards/infra repos to exclude
EXCLUDE="gitea-org-config org-profile gitea-private .mokogitea-private MokoStandards mokoplatform MokoTesting"
EXCLUDE="$EXCLUDE MokoStandards-Template-Client MokoStandards-Template-Dolibarr MokoStandards-Template-Generic MokoStandards-Template-Joomla MokoDoliProjTemplate"
if [ -n "${{ inputs.repos }}" ]; then
# User-specified repos
REPOS=$(echo "${{ inputs.repos }}" | tr ',' ' ')
else
# Fetch all org repos
PAGE=1
REPOS=""
while true; do
BATCH=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/orgs/${GITEA_ORG}/repos?page=${PAGE}&limit=50" \
| jq -r '.[].name // empty')
[ -z "$BATCH" ] && break
REPOS="$REPOS $BATCH"
PAGE=$((PAGE + 1))
done
# Filter out excluded repos
FILTERED=""
for REPO in $REPOS; do
SKIP=false
for EX in $EXCLUDE; do
if [ "$REPO" = "$EX" ]; then
SKIP=true
break
fi
done
if [ "$SKIP" = "false" ]; then
FILTERED="$FILTERED $REPO"
fi
done
REPOS="$FILTERED"
fi
echo "repos=$REPOS" >> "$GITHUB_OUTPUT"
COUNT=$(echo "$REPOS" | wc -w)
echo "📋 Target repos (${COUNT}): $REPOS"
- name: Apply protection rules
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
API="${GITEA_URL}/api/v1"
REPOS="${{ steps.repos.outputs.repos }}"
SUCCESS=0
FAILED=0
SKIPPED=0
# ── Rule definitions ──────────────────────────────────────
# Only the CI bot (jmiller token) can push directly.
# All human contributors must use PRs.
# Force push disabled on all branches.
RULE_MAIN='{
"rule_name": "main",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"dismiss_stale_approvals": true,
"block_on_rejected_reviews": true,
"block_on_outdated_branch": false,
"priority": 1
}'
RULE_DEV='{
"rule_name": "dev",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 2
}'
RULE_RC='{
"rule_name": "rc",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 3
}'
RULE_BETA='{
"rule_name": "beta",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 4
}'
RULE_ALPHA='{
"rule_name": "alpha",
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["jmiller"],
"enable_force_push": false,
"enable_force_push_allowlist": false,
"force_push_allowlist_usernames": [],
"enable_merge_whitelist": false,
"required_approvals": 0,
"block_on_rejected_reviews": false,
"priority": 5
}'
RULES=("$RULE_MAIN" "$RULE_DEV" "$RULE_RC" "$RULE_BETA" "$RULE_ALPHA")
RULE_NAMES=("main" "dev" "rc" "beta" "alpha")
# ── Apply rules to each repo ──────────────────────────────
for REPO in $REPOS; do
echo ""
echo "═══ ${REPO} ═══"
for i in "${!RULES[@]}"; do
RULE="${RULES[$i]}"
NAME="${RULE_NAMES[$i]}"
if [ "$DRY_RUN" = "true" ]; then
echo " [DRY RUN] Would apply rule: ${NAME}"
SKIPPED=$((SKIPPED + 1))
continue
fi
# Delete existing rule if present (idempotent recreate)
ENCODED_NAME=$(echo "$NAME" | sed 's|/|%2F|g')
curl -sS -o /dev/null -w "" \
-X DELETE \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/repos/${GITEA_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true
# Create rule
RESPONSE=$(curl -sS -w "\n%{http_code}" \
-X POST \
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$RULE" \
"${API}/repos/${GITEA_ORG}/${REPO}/branch_protections")
HTTP=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP" = "201" ]; then
echo " ✅ ${NAME}"
SUCCESS=$((SUCCESS + 1))
else
echo " ❌ ${NAME} (HTTP ${HTTP}): $(echo "$BODY" | jq -r '.message // .' 2>/dev/null | head -1)"
FAILED=$((FAILED + 1))
fi
done
done
# ── Summary ───────────────────────────────────────────────
echo ""
echo "════════════════════════════════════════"
echo " ✅ Success: ${SUCCESS}"
echo " ❌ Failed: ${FAILED}"
echo " ⏭️ Skipped: ${SKIPPED}"
echo "════════════════════════════════════════"
if [ "$FAILED" -gt 0 ]; then
echo "::warning::${FAILED} rule(s) failed to apply"
fi
-21
View File
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<mokoplatform xmlns="https://standards.mokoconsulting.tech/mokoplatform/1.0" schema-version="1.0">
<identity>
<name>MokoGitea</name>
<org>MokoConsulting</org>
<description>Moko fork of Gitea - adding project board REST API endpoints and custom enhancements</description>
<version>06.13.00</version>
<version-prefix>v1.26.1+MOKO</version-prefix>
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
</identity>
<governance>
<platform>go</platform>
<standards-version>05.00.00</standards-version>
<standards-source>https://code.mokoconsulting.tech/MokoConsulting/mokoplatform</standards-source>
</governance>
<build>
<language>Go</language>
<package-type>application</package-type>
<entry-point>./</entry-point>
</build>
</mokoplatform>
-129
View File
@@ -1,129 +0,0 @@
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
DEFGROUP: gitea-api-mcp.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/gitea-api-mcp
-->
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Changed
- **Renamed** package from `@mokoconsulting/gitea-api-mcp` to `@mokoconsulting/mokogitea-api-mcp` to distinguish Moko's forked Gitea MCP from upstream
- **Renamed** McpServer name and bin entry to `mokogitea-api-mcp`
## [0.0] - 2026-05-07
### Added
#### User / Auth (3 tools)
- `gitea_me` -- Get the authenticated user info
- `gitea_user_orgs` -- List organizations the authenticated user belongs to
- `gitea_user_repos` -- List repositories owned by the authenticated user
#### Repositories (8 tools)
- `gitea_repo_get` -- Get repository details
- `gitea_repo_create` -- Create a new repository
- `gitea_repo_delete` -- Delete a repository
- `gitea_repo_edit` -- Edit repository settings
- `gitea_repo_fork` -- Fork a repository
- `gitea_repo_search` -- Search repositories
- `gitea_org_repos` -- List repositories in an organization
- `gitea_list_connections` -- List configured Gitea connections
#### File Contents (5 tools)
- `gitea_file_get` -- Get file contents from a repository
- `gitea_dir_get` -- Get directory contents (file listing) from a repository
- `gitea_file_create_or_update` -- Create or update a file in a repository
- `gitea_file_delete` -- Delete a file from a repository
- `gitea_tree_get` -- Get the git tree for a repository (recursive file listing)
#### Branches (4 tools)
- `gitea_branches_list` -- List branches in a repository
- `gitea_branch_get` -- Get a specific branch
- `gitea_branch_create` -- Create a new branch
- `gitea_branch_delete` -- Delete a branch
#### Commits (2 tools)
- `gitea_commits_list` -- List commits in a repository
- `gitea_commit_get` -- Get a specific commit
#### Issues (7 tools)
- `gitea_issues_list` -- List issues in a repository
- `gitea_issue_get` -- Get a single issue by number
- `gitea_issue_create` -- Create a new issue
- `gitea_issue_update` -- Update an issue
- `gitea_issue_comments_list` -- List comments on an issue
- `gitea_issue_comment_create` -- Add a comment to an issue
- `gitea_issue_search` -- Search issues across all repositories
#### Labels (2 tools)
- `gitea_labels_list` -- List labels in a repository
- `gitea_label_create` -- Create a label
#### Milestones (2 tools)
- `gitea_milestones_list` -- List milestones in a repository
- `gitea_milestone_create` -- Create a milestone
#### Pull Requests (6 tools)
- `gitea_pulls_list` -- List pull requests
- `gitea_pull_get` -- Get a single pull request
- `gitea_pull_create` -- Create a pull request
- `gitea_pull_merge` -- Merge a pull request
- `gitea_pull_files` -- List files changed in a pull request
- `gitea_pull_review_create` -- Create a pull request review
#### Releases (5 tools)
- `gitea_releases_list` -- List releases
- `gitea_release_get` -- Get a single release by ID
- `gitea_release_latest` -- Get the latest release
- `gitea_release_create` -- Create a new release
- `gitea_release_delete` -- Delete a release
#### Tags (3 tools)
- `gitea_tags_list` -- List tags
- `gitea_tag_create` -- Create a tag
- `gitea_tag_delete` -- Delete a tag
#### Actions (2 tools)
- `gitea_actions_runs_list` -- List workflow runs for a repository
- `gitea_actions_run_get` -- Get a specific workflow run
#### Organizations (3 tools)
- `gitea_org_get` -- Get organization details
- `gitea_org_teams_list` -- List teams in an organization
- `gitea_org_members_list` -- List members of an organization
#### Users (2 tools)
- `gitea_user_get` -- Get a user profile
- `gitea_users_search` -- Search users
#### Webhooks (2 tools)
- `gitea_webhooks_list` -- List webhooks for a repository
- `gitea_webhook_create` -- Create a webhook
#### Wiki (2 tools)
- `gitea_wiki_pages_list` -- List wiki pages
- `gitea_wiki_page_get` -- Get a wiki page
#### Notifications (2 tools)
- `gitea_notifications_list` -- List notifications for the authenticated user
- `gitea_notifications_read` -- Mark all notifications as read
#### Generic (2 tools)
- `gitea_api_request` -- Make a raw API request to any Gitea v1 endpoint
- `gitea_list_connections` -- List configured Gitea connections
### Infrastructure
- Multi-connection config support via `~/.gitea-api-mcp.json`
- Token-based authentication (Gitea native `Authorization: token` header)
- Built on `node:https` / `node:http` (zero HTTP dependencies)
- MCP SDK v1.12.x with stdio transport
[0.0.1]: https://git.mokoconsulting.tech/MokoConsulting/gitea-api-mcp/releases/tag/v0.0.1
-18
View File
@@ -1,18 +0,0 @@
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production=false
COPY tsconfig.json ./
COPY src/ ./src/
RUN npx tsc && npm prune --production
EXPOSE 3100
ENV PORT=3100
ENV NODE_ENV=production
# SSE mode by default for Docker deployments
CMD ["node", "dist/sse.js"]
-116
View File
@@ -1,116 +0,0 @@
# MokoGitea MCP Server
A comprehensive [Model Context Protocol](https://modelcontextprotocol.io) server for [Gitea](https://gitea.com) and [MokoGitea](https://git.mokoconsulting.tech/MokoConsulting/MokoGitea). 120+ tools for repos, issues, PRs, projects, releases, custom fields, statuses, priorities, and manifests.
Works with any Gitea instance. MokoGitea-specific features degrade gracefully on vanilla Gitea.
## Quick Start
### npx (no install)
```bash
GITEA_URL=https://gitea.example.com GITEA_TOKEN=your_token npx @mokoconsulting/mokogitea-mcp
```
### Claude Code
Add to `.claude.json`:
```json
{
"mcpServers": {
"mokogitea": {
"command": "npx",
"args": ["@mokoconsulting/mokogitea-mcp"],
"env": {
"GITEA_URL": "https://gitea.example.com",
"GITEA_TOKEN": "your_token"
}
}
}
}
```
### Docker (SSE mode)
```bash
docker run -p 3100:3100 \
-e GITEA_URL=https://gitea.example.com \
-e GITEA_TOKEN=your_token \
mokoconsulting/mokogitea-mcp
```
Connect MCP client to `http://localhost:3100/sse`.
### Multi-instance config
Create `~/.mcp_mokogitea.json`:
```json
{
"defaultConnection": "production",
"connections": {
"production": { "baseUrl": "https://gitea.example.com", "token": "your_token" },
"dev": { "baseUrl": "https://dev.gitea.example.com", "token": "dev_token" }
}
}
```
## Configuration
| Method | Use Case |
|--------|----------|
| `GITEA_URL` + `GITEA_TOKEN` env vars | Single instance, quick setup |
| `~/.mcp_mokogitea.json` config file | Multiple instances |
| `GITEA_API_MCP_CONFIG` env var | Custom config path |
| `GITEA_INSECURE=true` | Skip TLS verification |
## Tools (120+)
### Repositories
`gitea_repo_create` `gitea_repo_get` `gitea_repo_edit` `gitea_repo_delete` `gitea_repo_search` `gitea_repo_fork` `gitea_repo_generate` `gitea_repo_languages` `gitea_repo_contributors` `gitea_repo_topics` `gitea_repo_topics_set`
### Issues
`gitea_issue_create` (dedup by title) `gitea_issue_get` `gitea_issue_update` `gitea_issues_list` `gitea_issue_search` `gitea_issue_comment_create` `gitea_issue_comments_list` `gitea_issue_labels_set` `gitea_issue_bulk_set_status`
### Pull Requests
`gitea_pull_create` `gitea_pull_get` `gitea_pulls_list` `gitea_pull_merge` `gitea_pull_files` `gitea_pull_review_create`
### Branches and Tags
`gitea_branches_list` `gitea_branch_create` `gitea_branch_delete` `gitea_branch_get` `gitea_tags_list` `gitea_tag_create` `gitea_tag_delete`
### Releases
`gitea_releases_list` `gitea_release_create` `gitea_release_get` `gitea_release_latest` `gitea_release_delete` `gitea_release_asset_upload` `gitea_release_asset_delete`
### Files and Trees
`gitea_file_get` `gitea_file_create_or_update` `gitea_file_delete` `gitea_dir_get` `gitea_tree_get` `gitea_bulk_file_push`
### Projects
`gitea_project_list` `gitea_project_create` `gitea_project_get` `gitea_project_update` `gitea_project_delete` `gitea_project_overview` `gitea_project_columns_list` `gitea_project_column_create` `gitea_project_column_delete` `gitea_project_cards_list` `gitea_project_card_add` `gitea_project_card_move` `gitea_project_card_remove`
### Organizations
`gitea_org_get` `gitea_org_repos` `gitea_org_members_list` `gitea_org_teams_list` `gitea_org_labels_list` `gitea_org_label_create`
### Wiki
`gitea_wiki_pages_list` `gitea_wiki_page_get`
### MokoGitea Extensions
`gitea_manifest_get` `gitea_manifest_update` `gitea_org_custom_fields_list` `gitea_org_custom_field_create` `gitea_org_custom_field_delete` `gitea_issue_custom_fields_get` `gitea_issue_custom_fields_set` `gitea_org_issue_statuses_list` `gitea_issue_set_status` `gitea_org_issue_priorities_list` `gitea_issue_set_priority`
### Admin and Other
`gitea_me` `gitea_users_search` `gitea_user_get` `gitea_notifications_list` `gitea_notifications_read` `gitea_commits_list` `gitea_commit_get` `gitea_compare` `gitea_webhooks_list` `gitea_webhook_create` `gitea_admin_users_list` `gitea_admin_orgs_list` `gitea_admin_cron_list` `gitea_admin_cron_run` `gitea_list_connections`
## SSE Server
For hosted deployments:
```
GET / Server info
GET /sse SSE connection endpoint
POST /message Tool call messages
GET /health Health check
```
## License
GPL-3.0-or-later - [Moko Consulting](https://mokoconsulting.tech)
-13
View File
@@ -1,13 +0,0 @@
{
"defaultConnection": "moko",
"connections": {
"moko": {
"baseUrl": "https://git.mokoconsulting.tech",
"token": "your-gitea-access-token"
},
"github-mirror": {
"baseUrl": "https://gitea.example.com",
"token": "your-other-token"
}
}
}
-1198
View File
File diff suppressed because it is too large Load Diff
-58
View File
@@ -1,58 +0,0 @@
{
"name": "@mokoconsulting/mokogitea-mcp",
"version": "1.1.0",
"description": "MCP server for Gitea and MokoGitea - 120+ tools for repos, issues, PRs, projects, releases, custom fields, statuses, priorities, and manifests",
"type": "module",
"main": "dist/index.js",
"bin": {
"mokogitea-mcp": "dist/index.js",
"mokogitea-mcp-sse": "dist/sse.js"
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"start": "node dist/index.js",
"start:sse": "node dist/sse.js",
"setup": "node scripts/setup.mjs",
"clean": "rm -rf dist/"
},
"keywords": [
"mcp",
"gitea",
"mokogitea",
"model-context-protocol",
"claude",
"ai",
"git",
"self-hosted",
"api",
"devops"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1",
"zod": "^3.24.4"
},
"devDependencies": {
"@types/node": "^22.15.3",
"typescript": "^5.8.3"
},
"engines": {
"node": ">=20.0.0"
},
"license": "GPL-3.0-or-later",
"author": "Moko Consulting <hello@mokoconsulting.tech>",
"homepage": "https://git.mokoconsulting.tech/MokoConsulting/mcp_mokogitea_api",
"repository": {
"type": "git",
"url": "https://git.mokoconsulting.tech/MokoConsulting/mcp_mokogitea_api.git"
},
"files": [
"dist/",
"config.example.json",
"README.md",
"LICENSE"
],
"publishConfig": {
"access": "public"
}
}
-15
View File
@@ -1,15 +0,0 @@
# mcp_mokogitea_api PowerShell Profile
# Source this with: . ./profile.ps1
$env:MCP_ROOT = $PSScriptRoot
$env:TEMP = 'A:\temp'
$env:TMP = 'A:\temp'
function mcp { Set-Location $PSScriptRoot }
function mcp-src { Set-Location (Join-Path $PSScriptRoot 'src') }
function mcp-build { Set-Location $PSScriptRoot; npm run build }
function mcp-dev { Set-Location $PSScriptRoot; npm run dev }
Write-Host "mcp_mokogitea_api profile loaded" -ForegroundColor Cyan
Write-Host " Commands: mcp-build, mcp-dev" -ForegroundColor DarkGray
Write-Host " Navigate: mcp, mcp-src" -ForegroundColor DarkGray
-40
View File
@@ -1,40 +0,0 @@
#!/usr/bin/env node
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* BRIEF: Interactive setup — prompts for Gitea connection details
*/
import { createInterface } from 'node:readline/promises';
import { readFile, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { homedir } from 'node:os';
const CONFIG_PATH = resolve(homedir(), '.gitea-api-mcp.json');
const rl = createInterface({ input: process.stdin, output: process.stdout });
async function prompt(q, d) { const a = await rl.question(`${q}${d ? ` [${d}]` : ''}: `); return a.trim() || d || ''; }
async function promptRequired(q) { let a = ''; while (!a) { a = (await rl.question(`${q}: `)).trim(); if (!a) console.log(' Required.'); } return a; }
async function main() {
console.log('\n=== gitea-api-mcp Setup ===\n');
let existing = null;
try { existing = JSON.parse(await readFile(CONFIG_PATH, 'utf-8')); console.log(`Existing: ${Object.keys(existing.connections).join(', ')}\n`); } catch {}
const name = await prompt('Connection name', 'moko');
const baseUrl = await promptRequired('Gitea URL (e.g. https://git.mokoconsulting.tech)');
const token = await promptRequired('Access token (Settings > Applications > Generate Token)');
const insecure = (await prompt('Skip TLS verification? (y/N)', 'N')).toLowerCase() === 'y';
const conn = { baseUrl: baseUrl.replace(/\/+$/, ''), token };
if (insecure) conn.insecure = true;
const config = existing ?? { defaultConnection: name, connections: {} };
config.connections[name] = conn;
if (!existing) config.defaultConnection = name;
else if ((await prompt(`Set "${name}" as default? (y/N)`, 'N')).toLowerCase() === 'y') config.defaultConnection = name;
await writeFile(CONFIG_PATH, JSON.stringify(config, null, '\t') + '\n', 'utf-8');
console.log(`\nConfig written to ${CONFIG_PATH}\n`);
rl.close();
}
main().catch(e => { console.error(e.message); rl.close(); process.exit(1); });
-120
View File
@@ -1,120 +0,0 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: gitea-api-mcp.Client
* INGROUP: gitea-api-mcp
* REPO: https://git.mokoconsulting.tech/MokoConsulting/gitea-api-mcp
* PATH: /src/client.ts
* VERSION: 01.00.00
* BRIEF: HTTP client for Gitea REST API v1
*/
import * as https from 'node:https';
import * as http from 'node:http';
import type { GiteaConnection, ApiResponse } from './types.js';
const API_PREFIX = '/api/v1';
const TIMEOUT_MS = 30_000;
export class GiteaClient {
private readonly base_url: string;
private readonly headers: Record<string, string>;
private readonly insecure: boolean;
constructor(conn: GiteaConnection) {
this.base_url = conn.baseUrl.replace(/\/+$/, '') + API_PREFIX;
this.headers = {
'Authorization': `token ${conn.token}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
};
this.insecure = conn.insecure ?? false;
}
async get(endpoint: string, params?: Record<string, string>): Promise<ApiResponse> {
return this.request(this.buildUrl(endpoint, params), 'GET');
}
async post(endpoint: string, body?: unknown): Promise<ApiResponse> {
return this.request(this.buildUrl(endpoint), 'POST', body);
}
async patch(endpoint: string, body: unknown): Promise<ApiResponse> {
return this.request(this.buildUrl(endpoint), 'PATCH', body);
}
async put(endpoint: string, body: unknown): Promise<ApiResponse> {
return this.request(this.buildUrl(endpoint), 'PUT', body);
}
async delete(endpoint: string): Promise<ApiResponse> {
return this.request(this.buildUrl(endpoint), 'DELETE');
}
private buildUrl(endpoint: string, params?: Record<string, string>): string {
const path = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
const url = new URL(`${this.base_url}${path}`);
if (params) {
for (const [key, value] of Object.entries(params)) {
url.searchParams.set(key, value);
}
}
return url.toString();
}
private request(url: string, method: string, body?: unknown): Promise<ApiResponse> {
return new Promise((resolve, reject) => {
const parsed = new URL(url);
const is_https = parsed.protocol === 'https:';
const transport = is_https ? https : http;
const options: https.RequestOptions = {
hostname: parsed.hostname,
port: parsed.port || (is_https ? 443 : 80),
path: parsed.pathname + parsed.search,
method,
headers: { ...this.headers },
timeout: TIMEOUT_MS,
};
if (this.insecure && is_https) {
options.rejectUnauthorized = false;
}
const payload = body !== undefined ? JSON.stringify(body) : undefined;
if (payload) {
(options.headers as Record<string, string>)['Content-Length'] = Buffer.byteLength(payload).toString();
}
const req = transport.request(options, (res) => {
const chunks: Buffer[] = [];
res.on('data', (chunk: Buffer) => chunks.push(chunk));
res.on('end', () => {
const raw = Buffer.concat(chunks).toString('utf-8');
let data: unknown;
try {
data = JSON.parse(raw);
} catch {
data = raw;
}
resolve({ status: res.statusCode ?? 0, data });
});
});
req.on('error', (err) => reject(err));
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timed out'));
});
if (payload) {
req.write(payload);
}
req.end();
});
}
}
-61
View File
@@ -1,61 +0,0 @@
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { homedir } from 'node:os';
import type { GiteaConfig, GiteaConnection } from './types.js';
const CONFIG_FILENAME = '.mcp_mokogitea.json';
export async function loadConfig(): Promise<GiteaConfig> {
// Priority 1: Environment variables (zero-config single instance)
if (process.env.GITEA_URL && process.env.GITEA_TOKEN) {
const conn: GiteaConnection = {
baseUrl: process.env.GITEA_URL,
token: process.env.GITEA_TOKEN,
insecure: process.env.GITEA_INSECURE === 'true',
};
return {
connections: { default: conn },
defaultConnection: 'default',
};
}
// Priority 2: Config file
const config_path = process.env.GITEA_API_MCP_CONFIG
? resolve(process.env.GITEA_API_MCP_CONFIG)
: resolve(homedir(), CONFIG_FILENAME);
try {
const raw = await readFile(config_path, 'utf-8');
const parsed = JSON.parse(raw) as Partial<GiteaConfig>;
if (!parsed.connections || Object.keys(parsed.connections).length === 0) {
throw new Error('No connections defined in config');
}
return {
connections: parsed.connections,
defaultConnection: parsed.defaultConnection ?? Object.keys(parsed.connections)[0],
};
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
throw new Error(
`Failed to load config from ${config_path}: ${message}\n` +
`Option 1: Set GITEA_URL and GITEA_TOKEN environment variables\n` +
`Option 2: Create ${config_path} - see config.example.json for format`,
);
}
}
export function getConnection(config: GiteaConfig, name?: string): GiteaConnection {
const key = name ?? config.defaultConnection;
const conn = config.connections[key];
if (!conn) {
throw new Error(
`Connection "${key}" not found. Available: ${Object.keys(config.connections).join(', ')}`,
);
}
return conn;
}
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Creates a configured MCP server instance for use by both stdio and SSE transports.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import type { GiteaConfig } from './types.js';
// Import index.ts to register all tools on its exported `server` singleton,
// then re-export a factory that initializes config and returns the server.
import { server, initConfig } from './index.js';
export function createMcpServer(cfg: GiteaConfig): McpServer {
initConfig(cfg);
return server;
}
-100
View File
@@ -1,100 +0,0 @@
// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SSE transport entry point for MokoGitea MCP server.
// Run with: node dist/sse.js
// Or: GITEA_URL=https://gitea.example.com GITEA_TOKEN=xxx node dist/sse.js
//
// Listens on PORT (default 3100) and serves SSE at /sse with POST at /message.
import { createServer } from 'node:http';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import { createMcpServer } from './server.js';
import { loadConfig } from './config.js';
const PORT = parseInt(process.env.PORT ?? '3100', 10);
async function main(): Promise<void> {
const config = await loadConfig();
const transports = new Map<string, SSEServerTransport>();
const httpServer = createServer(async (req, res) => {
// CORS headers for browser clients
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
// Health check
if (req.url === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok', tools: 120 }));
return;
}
// SSE endpoint - client connects here
if (req.url === '/sse' && req.method === 'GET') {
const transport = new SSEServerTransport('/message', res);
const sessionId = transport.sessionId;
transports.set(sessionId, transport);
const server = createMcpServer(config);
await server.connect(transport);
req.on('close', () => {
transports.delete(sessionId);
});
return;
}
// Message endpoint - client sends tool calls here
if (req.url?.startsWith('/message') && req.method === 'POST') {
const url = new URL(req.url, `http://${req.headers.host}`);
const sessionId = url.searchParams.get('sessionId');
if (!sessionId || !transports.has(sessionId)) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Invalid or missing sessionId' }));
return;
}
const transport = transports.get(sessionId)!;
await transport.handlePostMessage(req, res);
return;
}
// Root - info page
if (req.url === '/' || req.url === '') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
name: '@mokoconsulting/mokogitea-mcp',
version: '1.1.0',
description: 'MCP server for Gitea and MokoGitea - 120+ tools',
endpoints: {
sse: '/sse',
message: '/message',
health: '/health',
},
docs: 'https://git.mokoconsulting.tech/MokoConsulting/mcp_mokogitea_api',
}));
return;
}
res.writeHead(404);
res.end('Not found');
});
httpServer.listen(PORT, () => {
process.stderr.write(`MokoGitea MCP SSE server listening on port ${PORT}\n`);
process.stderr.write(` SSE: http://localhost:${PORT}/sse\n`);
process.stderr.write(` Health: http://localhost:${PORT}/health\n`);
});
}
main().catch((err) => {
process.stderr.write(`Fatal: ${err}\n`);
process.exit(1);
});
-37
View File
@@ -1,37 +0,0 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: gitea-api-mcp.Types
* INGROUP: gitea-api-mcp
* REPO: https://git.mokoconsulting.tech/MokoConsulting/gitea-api-mcp
* PATH: /src/types.ts
* VERSION: 01.00.00
* BRIEF: TypeScript type definitions for Gitea API MCP server
*/
export interface GiteaConnection {
baseUrl: string;
token: string;
/** Skip TLS certificate verification (self-signed certs) */
insecure?: boolean;
}
export interface GitHubBackupConfig {
token: string;
org: string;
}
export interface GiteaConfig {
connections: Record<string, GiteaConnection>;
defaultConnection: string;
github?: GitHubBackupConfig;
}
export interface ApiResponse {
status: number;
data: unknown;
}
-19
View File
@@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
-66
View File
@@ -1,66 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.02.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
name: "Universal: Auto Version Bump"
on:
push:
branches:
- dev
- rc
- 'feature/**'
- 'patch/**'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
jobs:
bump:
name: Version Bump
runs-on: release
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip bump]') &&
!startsWith(github.event.head_commit.message, 'Merge pull request')
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
run: |
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
if [ -d "/opt/moko-platform/cli" ]; then
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
else
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
-341
View File
@@ -1,341 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/universal/auto-release.yml.template
# VERSION: 05.00.00
# BRIEF: Universal build & release detects platform from manifest.xml
#
# +========================================================================+
# | UNIVERSAL BUILD & RELEASE PIPELINE |
# +========================================================================+
# | |
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
# | |
# | Platform-specific: |
# | joomla: XML manifest, type-prefixed packages |
# | dolibarr: mod*.class.php, update.txt, dev version reset |
# | generic: README-only, no update stream |
# | |
# +========================================================================+
name: "Universal: Build & Release"
on:
pull_request:
types: [opened, closed]
branches:
- main
workflow_dispatch:
inputs:
action:
description: 'Action to perform'
required: false
type: choice
default: release
options:
- release
- promote-rc
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
permissions:
contents: write
jobs:
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────
promote-rc:
name: Promote to RC
runs-on: release
if: >-
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
echo Using pre-installed /opt/moko-platform
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
else
echo Falling back to fresh clone
if ! command -v composer > /dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
fi
- name: Rename branch to rc
run: |
php ${MOKO_CLI}/branch_rename.php \
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
--pr "${{ github.event.pull_request.number }}"
- name: Checkout rc and configure git
run: |
git fetch origin rc
git checkout rc
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Publish RC release
run: |
php ${MOKO_CLI}/release_publish.php \
--path . --stability rc --bump minor --branch rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}"
- name: Summary
if: always()
run: |
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
release:
name: Build & Release Pipeline
runs-on: release
if: >-
github.event.pull_request.merged == true ||
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0
- name: Configure git for bot pushes
run: |
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Check for merge conflict markers
run: |
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
if [ -n "$CONFLICTS" ]; then
echo "::error::Merge conflict markers found — aborting release"
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "No conflict markers found"
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: |
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
echo Using pre-installed /opt/moko-platform
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
else
echo Falling back to fresh clone
if ! command -v composer > /dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/moko-platform-api/cli >> $GITHUB_ENV
fi
- name: "Determine version bump level"
id: bump
run: |
# Fix/patch branches: version was already bumped by pre-release, just strip suffix
# Feature/dev branches: bump minor for the new stable release
HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
case "$HEAD_REF" in
fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
*) BUMP="minor" ;;
esac
echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
- name: "Publish stable release"
run: |
BUMP_FLAG=""
if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
fi
php ${MOKO_CLI}/release_publish.php \
--path . --stability stable ${BUMP_FLAG} --branch main \
--token "${{ secrets.MOKOGITEA_TOKEN }}"
- name: Update release notes from CHANGELOG.md
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Extract [Unreleased] section from changelog
if [ -f "CHANGELOG.md" ]; then
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
[ -z "$NOTES" ] && NOTES="Stable release"
else
NOTES="Stable release"
fi
# Update release body via API
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API_BASE}/releases/tags/stable" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ]; then
python3 -c "
import json, urllib.request
body = open('/dev/stdin').read()
payload = json.dumps({'body': body}).encode()
req = urllib.request.Request(
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
" <<< "$NOTES"
echo "Release notes updated from CHANGELOG.md"
fi
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/release_mirror.php \
--version "$VERSION" --tag "$RELEASE_TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
--branch main 2>&1 || true
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
- name: "Step 10: Push main to GitHub mirror"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
git fetch origin main --depth=1
git push github origin/main:refs/heads/main --force 2>/dev/null \
&& echo "main branch pushed to GitHub mirror" \
|| echo "WARNING: GitHub mirror push failed"
- name: "Step 11: Delete rc branch and recreate dev from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Delete rc branch (ephemeral — created by promote-rc)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/rc" 2>/dev/null \
&& echo "Deleted rc branch" || echo "rc branch not found"
# Delete dev branch
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
# Recreate dev from main (now includes version bump + changelog promotion)
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/branches" \
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
- name: "Step 12: Create version branch from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
BRANCH_NAME="version/${VERSION}"
MAIN_SHA=$(git rev-parse HEAD)
# Delete old version branch if it exists (same version re-release)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
# Create version/XX.YY.ZZ from main
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
# -- Dolibarr post-release: Reset dev version -----------------------------
- name: "Post-release: Reset dev version"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/version_reset_dev.php \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
--branch dev --path . 2>&1 || true
# -- Summary --------------------------------------------------------------
- name: Pipeline Summary
if: always()
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
fi
-48
View File
@@ -1,48 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/branch-cleanup.yml
# VERSION: 01.00.00
# BRIEF: Delete feature branches after PR merge
name: "Branch Cleanup"
on:
pull_request:
types: [closed]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
cleanup:
name: Delete merged branch
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == true &&
github.event.pull_request.head.ref != 'dev' &&
github.event.pull_request.head.ref != 'main'
steps:
- name: Delete source branch
run: |
BRANCH="${{ github.event.pull_request.head.ref }}"
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API}/${ENCODED}" 2>/dev/null || true)
if [ "$STATUS" = "204" ]; then
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
elif [ "$STATUS" = "404" ]; then
echo "Branch already deleted: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
else
echo "::warning::Failed to delete branch ${BRANCH} (HTTP ${STATUS})"
fi
-10
View File
@@ -1,10 +0,0 @@
# DISABLED — auto-release Step 11 recreates dev from main after every release.
# Cascade-dev is redundant and causes version conflicts when both main and dev
# have different version numbers in templateDetails.xml / manifest.xml.
name: "Cascade Main → Dev (DISABLED)"
on: workflow_dispatch
jobs:
noop:
runs-on: ubuntu-latest
steps:
- run: echo "Cascade disabled — auto-release handles dev recreation"
-204
View File
@@ -1,204 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
# PATH: /.gitea/workflows/ci-generic.yml
# VERSION: 01.00.00
# BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js)
name: "Generic: Project CI"
on:
push:
branches:
- main
- dev
- dev/**
- rc/**
- version/**
pull_request:
branches:
- main
- dev
- dev/**
- rc/**
workflow_dispatch:
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ── Lint & Validate ───────────────────────────────────────────────────
lint:
name: Lint & Validate
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect toolchain
id: detect
run: |
HAS_PHP=false
HAS_NODE=false
[ -f "composer.json" ] && HAS_PHP=true
[ -f "package.json" ] && HAS_NODE=true
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
echo "Toolchain: PHP=$HAS_PHP Node=$HAS_NODE"
- name: Setup PHP
if: steps.detect.outputs.has_php == 'true'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
php -v
- name: Setup Node.js
if: steps.detect.outputs.has_node == 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PHP dependencies
if: steps.detect.outputs.has_php == 'true'
run: |
if [ -f "composer.json" ]; then
composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
fi
- name: Install Node.js dependencies
if: steps.detect.outputs.has_node == 'true'
run: |
if [ -f "package.json" ]; then
npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true
fi
- name: PHP syntax check
if: steps.detect.outputs.has_php == 'true'
run: |
ERRORS=0
while IFS= read -r -d '' file; do
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
echo "::error file=${file}::PHP syntax error"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -not -path "./node_modules/*" -print0)
echo "## PHP Lint" >> $GITHUB_STEP_SUMMARY
if [ "$ERRORS" -eq 0 ]; then
echo "All PHP files passed syntax check." >> $GITHUB_STEP_SUMMARY
else
echo "${ERRORS} file(s) with syntax errors." >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: TypeScript/JavaScript lint
if: steps.detect.outputs.has_node == 'true'
run: |
if [ -f "node_modules/.bin/eslint" ]; then
npx eslint src/ --quiet 2>&1 || { echo "::error::ESLint errors found"; exit 1; }
echo "## ESLint" >> $GITHUB_STEP_SUMMARY
echo "All files passed ESLint." >> $GITHUB_STEP_SUMMARY
elif [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
echo "::warning::ESLint config found but eslint not installed"
else
echo "No ESLint configured — skipping"
fi
- name: TypeScript compile check
if: steps.detect.outputs.has_node == 'true'
run: |
if [ -f "tsconfig.json" ] && [ -f "node_modules/.bin/tsc" ]; then
npx tsc --noEmit 2>&1 || { echo "::error::TypeScript compilation errors"; exit 1; }
echo "## TypeScript" >> $GITHUB_STEP_SUMMARY
echo "TypeScript compilation passed." >> $GITHUB_STEP_SUMMARY
fi
- name: PHPStan static analysis
if: steps.detect.outputs.has_php == 'true'
run: |
if [ -f "phpstan.neon" ] && [ -f "vendor/bin/phpstan" ]; then
vendor/bin/phpstan analyse --no-progress 2>&1 || { echo "::warning::PHPStan found issues"; }
fi
# ── Tests ─────────────────────────────────────────────────────────────
test:
name: Tests
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect toolchain
id: detect
run: |
HAS_PHP=false
HAS_NODE=false
[ -f "composer.json" ] && HAS_PHP=true
[ -f "package.json" ] && HAS_NODE=true
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
- name: Setup PHP
if: steps.detect.outputs.has_php == 'true'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
- name: Setup Node.js
if: steps.detect.outputs.has_node == 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
[ -f "composer.json" ] && composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
[ -f "package.json" ] && { npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true; }
- name: Run PHP tests
if: steps.detect.outputs.has_php == 'true'
run: |
if [ -f "vendor/bin/phpunit" ]; then
vendor/bin/phpunit --testdox 2>&1
echo "## PHPUnit" >> $GITHUB_STEP_SUMMARY
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
elif [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ]; then
echo "::warning::PHPUnit config found but phpunit not installed"
else
echo "No PHPUnit configured — skipping"
fi
- name: Run Node.js tests
if: steps.detect.outputs.has_node == 'true'
run: |
if jq -e '.scripts.test' package.json > /dev/null 2>&1; then
npm test 2>&1
echo "## Node.js Tests" >> $GITHUB_STEP_SUMMARY
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
else
echo "No test script in package.json — skipping"
fi
- name: Build check
run: |
if [ -f "Makefile" ]; then
make build 2>&1 || echo "::warning::Build failed or not configured"
elif [ -f "package.json" ] && jq -e '.scripts.build' package.json > /dev/null 2>&1; then
npm run build 2>&1 || echo "::warning::Build failed"
fi
-87
View File
@@ -1,87 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Maintenance
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.gitea/workflows/cleanup.yml
# VERSION: 01.00.00
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
name: "Universal: Repository Cleanup"
on:
schedule:
- cron: '0 3 * * 0' # Weekly on Sunday at 03:00 UTC
workflow_dispatch:
permissions:
contents: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
jobs:
cleanup:
name: Clean Merged Branches
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GA_TOKEN }}
- name: Delete merged branches
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
echo "=== Merged Branch Cleanup ==="
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
# List branches via API
BRANCHES=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
"${API}/branches?limit=50" | jq -r '.[].name')
DELETED=0
for BRANCH in $BRANCHES; do
# Skip protected branches
case "$BRANCH" in
main|master|develop|release/*|hotfix/*) continue ;;
esac
# Check if branch is merged into main
if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then
echo " Deleting merged branch: ${BRANCH}"
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
"${API}/branches/${BRANCH}" 2>/dev/null || true
DELETED=$((DELETED + 1))
fi
done
echo "Deleted ${DELETED} merged branch(es)"
- name: Clean old workflow runs
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
echo "=== Workflow Run Cleanup ==="
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
# Get old completed runs
RUNS=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
"${API}/actions/runs?status=completed&limit=50" | \
jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null)
DELETED=0
for RUN_ID in $RUNS; do
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
DELETED=$((DELETED + 1))
done
echo "Deleted ${DELETED} old workflow run(s)"
-126
View File
@@ -1,126 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Deploy
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
# VERSION: 04.07.00
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
name: "Universal: Deploy to Dev (Manual)"
on:
workflow_dispatch:
inputs:
clear_remote:
description: 'Delete all remote files before uploading'
required: false
default: 'false'
type: boolean
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
jobs:
deploy:
name: SFTP Deploy to Dev
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup PHP
run: |
php -v && composer --version
- name: Setup MokoStandards tools
env:
GA_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
MOKO_CLONE_HOST: ${{ secrets.GA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
run: |
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
/tmp/mokostandards-api 2>/dev/null || true
if [ -d "/tmp/mokostandards-api" ] && [ -f "/tmp/mokostandards-api/composer.json" ]; then
cd /tmp/mokostandards-api && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
fi
- name: Check FTP configuration
id: check
env:
HOST: ${{ vars.DEV_FTP_HOST }}
PATH_VAR: ${{ vars.DEV_FTP_PATH }}
PORT: ${{ vars.DEV_FTP_PORT }}
run: |
if [ -z "$HOST" ] || [ -z "$PATH_VAR" ]; then
echo "DEV_FTP_HOST or DEV_FTP_PATH not configured -- cannot deploy"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "host=$HOST" >> "$GITHUB_OUTPUT"
REMOTE="${PATH_VAR%/}"
echo "remote=$REMOTE" >> "$GITHUB_OUTPUT"
[ -z "$PORT" ] && PORT="22"
echo "port=$PORT" >> "$GITHUB_OUTPUT"
- name: Deploy via SFTP
if: steps.check.outputs.skip != 'true'
env:
SFTP_KEY: ${{ secrets.DEV_FTP_KEY }}
SFTP_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
SFTP_USER: ${{ vars.DEV_FTP_USERNAME }}
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ -- nothing to deploy"; exit 0; }
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
"${{ steps.check.outputs.host }}" "${{ steps.check.outputs.port }}" "$SFTP_USER" "${{ steps.check.outputs.remote }}" \
> /tmp/sftp-config.json
if [ -n "$SFTP_KEY" ]; then
echo "$SFTP_KEY" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
else
printf ',"password":"%s"}' "$SFTP_PASS" >> /tmp/sftp-config.json
fi
DEPLOY_ARGS=(--path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json)
[ "${{ inputs.clear_remote }}" = "true" ] && DEPLOY_ARGS+=(--clear-remote)
PLATFORM=$(php /tmp/mokostandards-api/cli/platform_detect.php --path . 2>/dev/null || true)
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then
php /tmp/mokostandards-api/deploy/deploy-joomla.php "${DEPLOY_ARGS[@]}"
else
php /tmp/mokostandards-api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}"
fi
rm -f /tmp/deploy_key /tmp/sftp-config.json
- name: Summary
if: always()
run: |
if [ "${{ steps.check.outputs.skip }}" = "true" ]; then
echo "### Deploy Skipped -- FTP not configured" >> $GITHUB_STEP_SUMMARY
else
echo "### Manual Dev Deploy Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Host | \`${{ steps.check.outputs.host }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Remote | \`${{ steps.check.outputs.remote }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Clear | ${{ inputs.clear_remote }} |" >> $GITHUB_STEP_SUMMARY
fi
-273
View File
@@ -1,273 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Build MokoGitea Docker image, push to registry, and deploy
name: Deploy MokoGitea
on:
push:
branches:
- main
workflow_dispatch:
inputs:
version:
description: 'Version tag (e.g. v1.26.1+MOKO06.12.00)'
required: true
default: 'latest'
environment:
description: 'Target environment'
required: true
default: 'dev'
type: choice
options:
- dev
- production
concurrency:
group: deploy-mokogitea
cancel-in-progress: false
env:
REGISTRY: code.mokoconsulting.tech
IMAGE: mokoconsulting/mokogitea
DEPLOY_HOST: code.mokoconsulting.tech
DEPLOY_PORT: 2918
DEPLOY_USER: mokoconsulting
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source (for version detection)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine settings
id: config
run: |
# On push to main, auto-deploy to production with git-derived version.
# On workflow_dispatch, use the provided inputs.
if [ "${{ github.event_name }}" = "push" ]; then
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev-$(git rev-parse --short HEAD)")
ENV="production"
else
VERSION="${{ github.event.inputs.version }}"
ENV="${{ github.event.inputs.environment }}"
fi
if [ "$ENV" = "production" ]; then
echo "compose_dir=/opt/gitea" >> $GITHUB_OUTPUT
echo "container=mokogitea" >> $GITHUB_OUTPUT
echo "source_dir=/opt/gitea/source" >> $GITHUB_OUTPUT
echo "branch=main" >> $GITHUB_OUTPUT
echo "tag=${VERSION}" >> $GITHUB_OUTPUT
echo "instance_url=https://code.mokoconsulting.tech" >> $GITHUB_OUTPUT
else
echo "compose_dir=/opt/gitea-dev" >> $GITHUB_OUTPUT
echo "container=mokogitea-dev" >> $GITHUB_OUTPUT
echo "source_dir=/opt/gitea-dev/source" >> $GITHUB_OUTPUT
echo "branch=dev" >> $GITHUB_OUTPUT
echo "tag=${VERSION}-dev" >> $GITHUB_OUTPUT
echo "instance_url=https://git.dev.mokoconsulting.tech" >> $GITHUB_OUTPUT
fi
- name: Enable maintenance mode
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
INSTANCE_URL: ${{ steps.config.outputs.instance_url }}
run: |
echo "Enabling maintenance mode on ${INSTANCE_URL}..."
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/x-www-form-urlencoded" \
"${INSTANCE_URL}/-/admin/config" \
-d 'key=instance.maintenance_mode&value={"AdminWebAccessOnly":true}' \
|| echo "WARNING: Could not enable maintenance mode (instance may be down)"
- name: Build and deploy via SSH
env:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
TAG: ${{ steps.config.outputs.tag }}
BRANCH: ${{ steps.config.outputs.branch }}
SOURCE_DIR: ${{ steps.config.outputs.source_dir }}
COMPOSE_DIR: ${{ steps.config.outputs.compose_dir }}
CONTAINER: ${{ steps.config.outputs.container }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
SSH_CMD="ssh -i ~/.ssh/deploy_key -p ${{ env.DEPLOY_PORT }} -o ConnectTimeout=30 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}"
$SSH_CMD "echo 'SSH connected'"
# Pre-deploy cleanup: free disk and memory for the build
$SSH_CMD "
echo 'Cleaning Docker build cache and unused images...'
docker builder prune -af 2>/dev/null || true
docker image prune -af 2>/dev/null || true
echo 'Clearing swap...'
sudo swapoff -a && sudo swapon -a 2>/dev/null || true
echo 'Cleanup complete'
free -m | head -3
"
# Pull latest source
$SSH_CMD "
set -e
if [ ! -d ${SOURCE_DIR}/.git ]; then
git clone -b ${BRANCH} https://code.mokoconsulting.tech/MokoConsulting/MokoGitea.git ${SOURCE_DIR}
fi
cd ${SOURCE_DIR}
git fetch origin ${BRANCH}
git reset --hard origin/${BRANCH}
"
# Build Docker image
$SSH_CMD "
set -e
cd ${SOURCE_DIR}
docker build --no-cache --build-arg GOFLAGS='-p 1' \
--tag ${{ env.REGISTRY }}/${{ env.IMAGE }}:${TAG} \
--tag ${{ env.REGISTRY }}/${{ env.IMAGE }}:latest \
-f Dockerfile .
"
# Push to container registry
$SSH_CMD "
set -e
docker push ${{ env.REGISTRY }}/${{ env.IMAGE }}:${TAG}
docker push ${{ env.REGISTRY }}/${{ env.IMAGE }}:latest
"
# Update compose and restart
$SSH_CMD "
set -e
cd ${COMPOSE_DIR}
sed -i 's|${{ env.IMAGE }}:[^ ]*|${{ env.IMAGE }}:${TAG}|' docker-compose.yml
docker compose up -d ${CONTAINER}
"
# Health check
$SSH_CMD "
for i in 1 2 3 4 5 6 7 8; do
sleep 15
if docker inspect --format='{{.State.Health.Status}}' ${CONTAINER} 2>/dev/null | grep -q healthy; then
echo 'Container healthy!'
docker inspect --format='Image: {{.Config.Image}}' ${CONTAINER}
exit 0
fi
echo \"Waiting... (attempt \$i/8)\"
done
echo 'Health check failed'
docker logs ${CONTAINER} --tail 20
exit 1
"
- name: Update updates.xml
if: success()
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
TAG: ${{ steps.config.outputs.tag }}
INSTANCE_URL: ${{ steps.config.outputs.instance_url }}
DEPLOY_ENV: ${{ github.event.inputs.environment || 'production' }}
run: |
# Only update updates.xml for production stable releases
if [ "$DEPLOY_ENV" != "production" ]; then
echo "Skipping updates.xml — dev deployments don't update stable channel"
exit 0
fi
# Extract project version by stripping the version prefix from the tag.
# Reads prefix from manifest API (e.g. "v1.26.1+MOKO"), falls back to legacy pattern.
API_BASE="https://${REGISTRY}/api/v1/repos/MokoConsulting/MokoGitea"
PREFIX=$(curl -sf -H "Authorization: token ${GITEA_TOKEN}" \
"${API_BASE}/manifest" | python3 -c "import json,sys; print(json.load(sys.stdin).get('version_prefix',''))" 2>/dev/null || true)
if [ -n "$PREFIX" ]; then
MOKO_VER="${TAG#$PREFIX}"
else
# Legacy fallback: strip everything up to and including "-moko."
MOKO_VER=$(echo "$TAG" | sed -n 's/.*-moko\.\(.*\)/\1/p')
fi
if [ -z "$MOKO_VER" ]; then
echo "Could not extract version from tag: $TAG (prefix: ${PREFIX:-none})"
exit 0
fi
RELEASE_URL="https://${REGISTRY}/MokoConsulting/MokoGitea/releases/tag/${TAG}"
DOCKER_IMG="${REGISTRY}/${IMAGE}:${TAG}"
python3 << PYEOF
import json, os, re, base64, urllib.request
token = os.environ["GITEA_TOKEN"]
registry = os.environ["REGISTRY"]
tag = os.environ["TAG"]
moko_ver = os.environ["MOKO_VER"]
release_url = os.environ["RELEASE_URL"]
docker_img = os.environ["DOCKER_IMG"]
api = f"https://{registry}/api/v1/repos/MokoConsulting/MokoGitea"
# Fetch current updates.xml
req = urllib.request.Request(f"{api}/contents/updates.xml?ref=main",
headers={"Authorization": f"token {token}"})
with urllib.request.urlopen(req) as resp:
data = json.loads(resp.read())
sha = data["sha"]
content = base64.b64decode(data["content"]).decode("utf-8")
# Update stable channel — match the <update> block containing <tag>stable</tag>
def replace_channel(xml, channel, ver, url, docker):
pattern = rf"(<update>\s*<name>MokoGitea</name>[\s\S]*?<tags><tag>{channel}</tag></tags>[\s\S]*?</update>)"
def replacer(m):
block = m.group(1)
block = re.sub(r"<version>[^<]*</version>", f"<version>{ver}</version>", block)
block = re.sub(r"(<infourl[^>]*>)[^<]*(</infourl>)", rf"\1{url}\2", block)
block = re.sub(r"(<downloadurl[^>]*>)[^<]*(</downloadurl>)", rf"\1{docker}\2", block)
return block
return re.sub(pattern, replacer, xml)
content = replace_channel(content, "stable", moko_ver, release_url, docker_img)
content = re.sub(r"VERSION: [^\n]*", f"VERSION: {moko_ver}", content)
# Push updated file
encoded = base64.b64encode(content.encode()).decode()
payload = json.dumps({
"message": f"chore(ci): update updates.xml to {moko_ver}",
"content": encoded,
"sha": sha,
"branch": "main",
}).encode()
req = urllib.request.Request(f"{api}/contents/updates.xml",
data=payload, method="PUT",
headers={"Authorization": f"token {token}", "Content-Type": "application/json"})
with urllib.request.urlopen(req) as resp:
print(f"updates.xml updated to {moko_ver}")
PYEOF
- name: Disable maintenance mode
if: always()
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
INSTANCE_URL: ${{ steps.config.outputs.instance_url }}
run: |
echo "Disabling maintenance mode on ${INSTANCE_URL}..."
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/x-www-form-urlencoded" \
"${INSTANCE_URL}/-/admin/config" \
-d 'key=instance.maintenance_mode&value={"AdminWebAccessOnly":false}' \
|| echo "WARNING: Could not disable maintenance mode"
- name: Verify
run: |
sleep 5
curl -sf https://${{ env.DEPLOY_HOST }}/api/healthz && echo " — API healthy"
- name: Notify on failure
if: failure()
run: echo "::error::Deploy failed for ${{ steps.config.outputs.tag }}"
-96
View File
@@ -1,96 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# PATH: /templates/workflows/gitleaks.yml.template
# VERSION: 01.00.00
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
#
# +========================================================================+
# | SECRET SCANNING |
# +========================================================================+
# | |
# | Scans commits for leaked secrets using Gitleaks. |
# | |
# | - PR scan: only new commits in the PR |
# | - Scheduled: full repo scan weekly |
# | - Alerts via ntfy on findings |
# | |
# +========================================================================+
name: "Universal: Secret Scanning"
on:
pull_request:
branches:
- main
- 'dev/**'
schedule:
- cron: '0 5 * * 1' # Weekly Monday 05:00 UTC
workflow_dispatch:
permissions:
contents: read
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
jobs:
gitleaks:
name: Gitleaks Secret Scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Gitleaks
run: |
GITLEAKS_VERSION="8.21.2"
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xz -C /usr/local/bin gitleaks
gitleaks version
- name: Scan for secrets
id: scan
run: |
echo "### Secret Scanning" >> $GITHUB_STEP_SUMMARY
ARGS="--source . --verbose --report-format json --report-path /tmp/gitleaks-report.json"
if [ "${{ github.event_name }}" = "pull_request" ]; then
# Scan only PR commits
ARGS="$ARGS --log-opts=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}"
echo "Scanning PR commits only" >> $GITHUB_STEP_SUMMARY
else
echo "Full repository scan" >> $GITHUB_STEP_SUMMARY
fi
if gitleaks detect $ARGS 2>&1; then
echo "result=clean" >> "$GITHUB_OUTPUT"
echo "**No secrets detected.**" >> $GITHUB_STEP_SUMMARY
else
echo "result=found" >> "$GITHUB_OUTPUT"
FINDINGS=$(jq length /tmp/gitleaks-report.json 2>/dev/null || echo "unknown")
echo "**${FINDINGS} potential secret(s) detected.**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Review the findings and rotate any exposed credentials immediately." >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: Notify on findings
if: failure() && steps.scan.outputs.result == 'found'
run: |
REPO="${{ github.event.repository.name }}"
curl -sS \
-H "Title: ${REPO} — secrets detected in code" \
-H "Tags: rotating_light,key" \
-H "Priority: urgent" \
-d "Gitleaks found potential secrets. Review and rotate credentials immediately." \
"${NTFY_URL}/${NTFY_TOPIC}" || true
-73
View File
@@ -1,73 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: mokoplatform.Automation
# VERSION: 06.13.00
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
on:
issues:
types: [opened]
permissions:
contents: write
issues: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://code.mokoconsulting.tech' }}
jobs:
create-branch:
name: Create feature branch
runs-on: ubuntu-latest
steps:
- name: Create branch and comment
run: |
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
ISSUE_NUM="${{ github.event.issue.number }}"
ISSUE_TITLE="${{ github.event.issue.title }}"
# Build slug from title: lowercase, replace non-alnum with dash, trim
SLUG=$(echo "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
BRANCH="feature/${ISSUE_NUM}-${SLUG}"
# Check dev branch exists
DEV_EXISTS=$(curl -sf -o /dev/null -w '%{http_code}' \
-H "Authorization: token ${TOKEN}" \
"${API}/branches/dev" 2>/dev/null || echo "000")
if [ "${DEV_EXISTS}" != "200" ]; then
echo "No dev branch -- skipping"
exit 0
fi
# Create branch from dev
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/branches" \
-d "{\"new_branch_name\":\"${BRANCH}\",\"old_branch_name\":\"dev\"}" 2>/dev/null || echo "000")
if [ "${HTTP}" = "201" ]; then
echo "Created branch: ${BRANCH}"
# Comment on issue with branch link
REPO_URL="${GITEA_URL}/${{ github.repository }}"
BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`"
curl -sf -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${ISSUE_NUM}/comments" \
-d "{\"body\":\"${BODY}\"}" > /dev/null 2>&1
echo "Commented on issue #${ISSUE_NUM}"
else
echo "Failed to create branch (HTTP ${HTTP}) -- may already exist"
fi
-70
View File
@@ -1,70 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Notifications
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.gitea/workflows/notify.yml
# VERSION: 01.00.00
# BRIEF: Push notifications via ntfy on release success or workflow failure
name: "Universal: Notifications"
on:
workflow_run:
workflows:
- "Joomla Build & Release"
- "Joomla Extension CI"
- "Deploy"
types:
- completed
permissions:
contents: read
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-releases' }}
jobs:
notify:
name: Send Notification
runs-on: ubuntu-latest
if: >-
github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure'
steps:
- name: Notify on success (releases only)
if: >-
github.event.workflow_run.conclusion == 'success' &&
contains(github.event.workflow_run.name, 'Release')
run: |
REPO="${{ github.event.repository.name }}"
WORKFLOW="${{ github.event.workflow_run.name }}"
URL="${{ github.event.workflow_run.html_url }}"
curl -sS \
-H "Title: ${REPO} released" \
-H "Tags: white_check_mark,package" \
-H "Priority: default" \
-H "Click: ${URL}" \
-d "${WORKFLOW} completed successfully." \
"${NTFY_URL}/${NTFY_TOPIC}"
- name: Notify on failure
if: github.event.workflow_run.conclusion == 'failure'
run: |
REPO="${{ github.event.repository.name }}"
WORKFLOW="${{ github.event.workflow_run.name }}"
URL="${{ github.event.workflow_run.html_url }}"
curl -sS \
-H "Title: ${REPO} workflow failed" \
-H "Tags: x,warning" \
-H "Priority: high" \
-H "Click: ${URL}" \
-d "${WORKFLOW} failed. Check the run for details." \
"${NTFY_URL}/${NTFY_TOPIC}"
-51
View File
@@ -1,51 +0,0 @@
name: Publish MCP to npm
on:
push:
branches: [main]
paths:
- '.mokogitea/mcp/**'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install and build
working-directory: .mokogitea/mcp
run: |
npm ci
npx tsc
- name: Check version change
id: version
working-directory: .mokogitea/mcp
run: |
LOCAL_VERSION=$(node -p "require('./package.json').version")
NPM_VERSION=$(npm view @mokoconsulting/mokogitea-mcp version 2>/dev/null || echo "0.0.0")
if [ "$LOCAL_VERSION" != "$NPM_VERSION" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "Version changed: $NPM_VERSION -> $LOCAL_VERSION"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "Version unchanged: $LOCAL_VERSION"
fi
- name: Publish to npm
if: steps.version.outputs.changed == 'true'
working-directory: .mokogitea/mcp
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish to Gitea registry
if: steps.version.outputs.changed == 'true'
working-directory: .mokogitea/mcp
run: |
npm publish --registry ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/npm/ \
--//$(echo "${{ github.server_url }}" | sed 's|https://||')/api/packages/${{ github.repository_owner }}/npm/:_authToken=${{ secrets.GITEA_TOKEN }}
-90
View File
@@ -1,90 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Enforces branch merge policy:
# feature/* → dev only
# fix/* → dev only
# hotfix/* → dev or main (emergency)
# dev → main only
# alpha/* → dev only
# beta/* → dev only
# rc/* → main only
name: Branch Policy Check
on:
pull_request:
types: [opened, synchronize, reopened, edited]
jobs:
check-target:
name: Verify merge target
runs-on: ubuntu-latest
steps:
- name: Check branch policy
run: |
HEAD="${{ github.head_ref }}"
BASE="${{ github.base_ref }}"
echo "PR: ${HEAD} → ${BASE}"
ALLOWED=true
REASON=""
case "$HEAD" in
feature/*|feat/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Feature branches must target 'dev', not '${BASE}'"
fi
;;
fix/*|bugfix/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Fix branches must target 'dev', not '${BASE}'"
fi
;;
hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi
;;
alpha/*|beta/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Pre-release branches must target 'dev', not '${BASE}'"
fi
;;
rc/*)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Release candidate branches must target 'main', not '${BASE}'"
fi
;;
dev)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Dev branch can only merge into 'main', not '${BASE}'"
fi
;;
esac
if [ "$ALLOWED" = false ]; then
echo "::error::${REASON}"
echo ""
echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "${REASON}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
-508
View File
@@ -1,508 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 09.23.00
# BRIEF: PR gate — branch policy + code validation before merge
name: "Universal: PR Check"
on:
pull_request:
types: [opened, synchronize, reopened, edited]
permissions:
contents: read
pull-requests: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ── Branch Policy ──────────────────────────────────────────────────────
branch-policy:
name: Branch Policy
runs-on: ubuntu-latest
steps:
- name: Check branch merge target
run: |
HEAD="${{ github.head_ref }}"
BASE="${{ github.base_ref }}"
echo "PR: ${HEAD} → ${BASE}"
ALLOWED=true
REASON=""
case "$HEAD" in
feature/*|feat/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Feature branches must target 'dev', not '${BASE}'"
fi
;;
fix/*|bugfix/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Fix branches must target 'dev', not '${BASE}'"
fi
;;
patch/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ]; then
ALLOWED=false
REASON="Patch branches must target 'dev' or 'rc', not '${BASE}'"
fi
;;
hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi
;;
rc)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="RC branch can only merge into 'main', not '${BASE}'"
fi
;;
dev)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Dev branch can only merge into 'main', not '${BASE}'"
fi
;;
esac
if [ "$ALLOWED" = false ]; then
echo "::error::${REASON}"
echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "${REASON}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
# ── Code Validation ────────────────────────────────────────────────────
validate:
name: Validate PR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check for merge conflict markers
run: |
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
if [ -n "$CONFLICTS" ]; then
echo "::error::Merge conflict markers found in source files"
echo "## Conflict Markers Found" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "No conflict markers found"
- name: Detect platform
id: platform
run: |
# Read platform from XML manifest (<platform> tag) or plain text fallback
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1)
[ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]')
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
- name: Setup PHP
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
- name: PHP syntax check
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
run: |
ERRORS=0
while IFS= read -r -d '' file; do
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -print0)
echo "PHP lint: ${ERRORS} error(s)"
[ "$ERRORS" -eq 0 ] || { echo "::error::PHP syntax errors found"; exit 1; }
- name: Joomla JEXEC guard check
if: steps.platform.outputs.platform == 'joomla'
run: |
ERRORS=0
while IFS= read -r -d '' file; do
# Skip vendor, node_modules, and index.html stub files
case "$file" in ./vendor/*|./node_modules/*) continue ;; esac
# Check first 10 lines for JEXEC or JPATH guard
if ! head -20 "$file" | grep -qE "defined\s*\(\s*['\"](_JEXEC|JPATH_BASE|\\\\JPATH_PLATFORM)['\"]"; then
echo "::error file=${file}::Missing JEXEC guard: ${file}"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.php" -path "*/src/*" -not -path "./.git/*" -not -path "./vendor/*" -print0)
if [ "$ERRORS" -gt 0 ]; then
echo "::error::${ERRORS} PHP file(s) missing defined('_JEXEC') or die guard"
echo "## JEXEC Guard Check: Failed" >> $GITHUB_STEP_SUMMARY
echo "${ERRORS} file(s) in src/ are missing the Joomla execution guard." >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "JEXEC guard: OK"
- name: Joomla directory listing protection
if: steps.platform.outputs.platform == 'joomla'
run: |
MISSING=0
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && exit 0
while IFS= read -r dir; do
if [ ! -f "${dir}/index.html" ]; then
echo "::warning::Missing index.html in ${dir} (directory listing protection)"
MISSING=$((MISSING + 1))
fi
done < <(find "$SOURCE_DIR" -type d -not -path "./.git/*" -not -path "*/vendor/*" -not -path "*/node_modules/*")
if [ "$MISSING" -gt 0 ]; then
echo "## Directory Protection" >> $GITHUB_STEP_SUMMARY
echo "${MISSING} director(ies) missing index.html" >> $GITHUB_STEP_SUMMARY
fi
echo "Directory protection: ${MISSING} missing (advisory)"
- name: Joomla script file and asset checks
if: steps.platform.outputs.platform == 'joomla'
run: |
ERRORS=0
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
[ -z "$MANIFEST" ] && exit 0
MANIFEST_DIR=$(dirname "$MANIFEST")
# Check scriptfile exists if declared
SCRIPTFILE=$(sed -n 's/.*<scriptfile>\([^<]*\)<\/scriptfile>.*/\1/p' "$MANIFEST" 2>/dev/null)
if [ -n "$SCRIPTFILE" ]; then
if [ ! -f "${MANIFEST_DIR}/${SCRIPTFILE}" ]; then
echo "::error::Manifest declares <scriptfile>${SCRIPTFILE}</scriptfile> but file not found at ${MANIFEST_DIR}/${SCRIPTFILE}"
ERRORS=$((ERRORS + 1))
else
echo "Script file: ${MANIFEST_DIR}/${SCRIPTFILE} (OK)"
fi
fi
# Require joomla.asset.json and validate it
ASSET_JSON=$(find "$MANIFEST_DIR" -name "joomla.asset.json" -not -path "./.git/*" 2>/dev/null | head -1)
if [ -z "$ASSET_JSON" ]; then
echo "::error::joomla.asset.json not found — Joomla asset system is required"
ERRORS=$((ERRORS + 1))
else
if command -v php &> /dev/null; then
php -r "json_decode(file_get_contents('$ASSET_JSON')); if(json_last_error()!==JSON_ERROR_NONE){echo json_last_error_msg();exit(1);}" 2>&1 || {
echo "::error::joomla.asset.json is not valid JSON"
ERRORS=$((ERRORS + 1))
}
fi
echo "joomla.asset.json: valid"
fi
# Validate all XML files in src/ are well-formed
XML_ERRORS=0
if command -v php &> /dev/null; then
while IFS= read -r -d '' xmlfile; do
if ! php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('$xmlfile'); if(!\$x){foreach(libxml_get_errors() as \$e) echo trim(\$e->message) . ' in $xmlfile'; exit(1);}" 2>&1; then
XML_ERRORS=$((XML_ERRORS + 1))
fi
done < <(find "$MANIFEST_DIR" -name "*.xml" -not -path "./.git/*" -print0)
fi
if [ "$XML_ERRORS" -gt 0 ]; then
echo "::error::${XML_ERRORS} XML file(s) are malformed"
ERRORS=$((ERRORS + 1))
else
echo "XML well-formedness: OK"
fi
[ "$ERRORS" -gt 0 ] && exit 1
echo "Joomla asset checks: OK"
- name: Validate platform manifest
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
joomla)
MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '<extension' {} \; 2>/dev/null | head -1)
if [ -z "$MANIFEST" ]; then
echo "::warning::No Joomla manifest found (WaaS site)"
exit 0
fi
echo "Manifest: ${MANIFEST}"
if command -v php &> /dev/null; then
php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('$MANIFEST'); if(!\$x){foreach(libxml_get_errors() as \$e) echo \$e->message; exit(1);}" || { echo "::error::Manifest XML is malformed"; exit 1; }
fi
for ELEMENT in name version description; do
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
done
# Block legacy raw/branch update server URLs on MokoGitea
RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogitea\|git\.mokoconsulting\.tech' || true)
if [ -n "$RAW_URLS" ]; then
echo "::error::Manifest contains legacy raw/branch update server URL on MokoGitea. Use the Gitea Pages URL instead (e.g. /{REPO}/updates.xml not /{REPO}/raw/branch/main/updates.xml)"
echo "$RAW_URLS"
exit 1
fi
echo "Joomla manifest valid"
;;
dolibarr)
MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1)
if [ -z "$MOD_FILE" ]; then
echo "::error::No mod*.class.php found"
exit 1
fi
echo "Dolibarr module: ${MOD_FILE}"
;;
*)
echo "Generic platform — no manifest validation"
;;
esac
- name: Check update stream format
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
case "$PLATFORM" in
joomla)
if [ -f "updates.xml" ]; then
if command -v php &> /dev/null; then
php -r "libxml_use_internal_errors(true); \$x = simplexml_load_file('updates.xml'); if(!\$x){foreach(libxml_get_errors() as \$e) echo \$e->message; exit(1);}" || { echo "::error::updates.xml is malformed"; exit 1; }
fi
echo "updates.xml valid"
fi
;;
dolibarr)
[ -f "update.txt" ] && echo "update.txt present" || echo "::warning::No update.txt"
;;
esac
- name: Validate Joomla language files
if: steps.platform.outputs.platform == 'joomla'
run: |
ERRORS=0
WARNINGS=0
# Require both en-GB and en-US language directories
LANG_ROOT=$(find . -path "*/language" -type d -not -path "./.git/*" 2>/dev/null | head -1)
if [ -z "$LANG_ROOT" ]; then
echo "No language/ directory found — skipping"
exit 0
fi
if [ ! -d "$LANG_ROOT/en-GB" ]; then
echo "::error::Missing en-GB language directory (${LANG_ROOT}/en-GB)"
ERRORS=$((ERRORS + 1))
fi
if [ ! -d "$LANG_ROOT/en-US" ]; then
echo "::error::Missing en-US language directory (${LANG_ROOT}/en-US)"
ERRORS=$((ERRORS + 1))
fi
# Check that en-GB and en-US have matching .ini files
if [ -d "$LANG_ROOT/en-GB" ] && [ -d "$LANG_ROOT/en-US" ]; then
for GB_INI in "$LANG_ROOT/en-GB"/*.ini; do
[ ! -f "$GB_INI" ] && continue
US_INI="$LANG_ROOT/en-US/$(basename "$GB_INI")"
if [ ! -f "$US_INI" ]; then
echo "::error::$(basename "$GB_INI") exists in en-GB but missing from en-US"
ERRORS=$((ERRORS + 1))
fi
done
for US_INI in "$LANG_ROOT/en-US"/*.ini; do
[ ! -f "$US_INI" ] && continue
GB_INI="$LANG_ROOT/en-GB/$(basename "$US_INI")"
if [ ! -f "$GB_INI" ]; then
echo "::error::$(basename "$US_INI") exists in en-US but missing from en-GB"
ERRORS=$((ERRORS + 1))
fi
done
fi
# Find all .ini language files
INI_FILES=$(find . -path "*/language/*/*.ini" -not -path "./.git/*" 2>/dev/null)
if [ -z "$INI_FILES" ]; then
echo "No .ini language files found"
[ "$ERRORS" -gt 0 ] && exit 1
exit 0
fi
echo "Found $(echo "$INI_FILES" | wc -l) language file(s)"
for FILE in $INI_FILES; do
FNAME=$(basename "$FILE")
LINENUM=0
SEEN_KEYS=""
while IFS= read -r line || [ -n "$line" ]; do
LINENUM=$((LINENUM + 1))
# Skip empty lines and comments
[ -z "$line" ] && continue
echo "$line" | grep -qE '^\s*;' && continue
echo "$line" | grep -qE '^\s*$' && continue
# Must match KEY="VALUE" format
if ! echo "$line" | grep -qE '^[A-Z_][A-Z0-9_]*=".*"$'; then
echo "::error file=${FILE},line=${LINENUM}::Malformed line: ${line}"
ERRORS=$((ERRORS + 1))
continue
fi
# Extract key and check for duplicates
KEY=$(echo "$line" | sed 's/=.*//')
if echo "$SEEN_KEYS" | grep -qx "$KEY"; then
echo "::error file=${FILE},line=${LINENUM}::Duplicate key: ${KEY}"
ERRORS=$((ERRORS + 1))
fi
SEEN_KEYS="${SEEN_KEYS}
${KEY}"
done < "$FILE"
echo " ${FILE}: checked ${LINENUM} lines"
done
# Cross-check en-GB vs en-US key consistency
GB_DIR=$(find . -path "*/language/en-GB" -type d -not -path "./.git/*" 2>/dev/null | head -1)
US_DIR=$(find . -path "*/language/en-US" -type d -not -path "./.git/*" 2>/dev/null | head -1)
if [ -n "$GB_DIR" ] && [ -n "$US_DIR" ]; then
for GB_FILE in "$GB_DIR"/*.ini; do
[ ! -f "$GB_FILE" ] && continue
FNAME=$(basename "$GB_FILE")
US_FILE="$US_DIR/$FNAME"
[ ! -f "$US_FILE" ] && continue
GB_KEYS=$(grep -oP '^[A-Z_][A-Z0-9_]*(?==)' "$GB_FILE" 2>/dev/null | sort)
US_KEYS=$(grep -oP '^[A-Z_][A-Z0-9_]*(?==)' "$US_FILE" 2>/dev/null | sort)
# Keys in en-GB but not en-US
MISSING_US=$(comm -23 <(echo "$GB_KEYS") <(echo "$US_KEYS"))
if [ -n "$MISSING_US" ]; then
echo "::warning::Keys in en-GB/$FNAME but missing from en-US/$FNAME:"
echo "$MISSING_US" | while read -r k; do echo " - $k"; done
WARNINGS=$((WARNINGS + 1))
fi
# Keys in en-US but not en-GB
MISSING_GB=$(comm -13 <(echo "$GB_KEYS") <(echo "$US_KEYS"))
if [ -n "$MISSING_GB" ]; then
echo "::warning::Keys in en-US/$FNAME but missing from en-GB/$FNAME:"
echo "$MISSING_GB" | while read -r k; do echo " - $k"; done
WARNINGS=$((WARNINGS + 1))
fi
done
fi
{
echo "### Language File Validation"
echo "| Metric | Count |"
echo "|---|---|"
echo "| Files checked | $(echo "$INI_FILES" | wc -l) |"
echo "| Errors | ${ERRORS} |"
echo "| Warnings | ${WARNINGS} |"
} >> $GITHUB_STEP_SUMMARY
if [ "$ERRORS" -gt 0 ]; then
echo "::error::Language validation failed with ${ERRORS} error(s)"
exit 1
fi
echo "Language files: OK (${WARNINGS} warning(s))"
- name: Check changelog has unreleased entry
run: |
if [ ! -f "CHANGELOG.md" ]; then
echo "::warning::No CHANGELOG.md found"
exit 0
fi
# Check for content under [Unreleased] section
if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then
echo "::error::CHANGELOG.md missing [Unreleased] section"
exit 1
fi
# Check there's at least one entry (Added/Changed/Fixed/Removed) under Unreleased
UNRELEASED_CONTENT=$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | grep -cE '^\s*-\s' || true)
if [ "$UNRELEASED_CONTENT" -eq 0 ]; then
echo "::error::CHANGELOG.md [Unreleased] section has no entries. Add a changelog entry describing your changes."
echo "## Changelog Check: Failed" >> $GITHUB_STEP_SUMMARY
echo "The \`[Unreleased]\` section in CHANGELOG.md has no entries." >> $GITHUB_STEP_SUMMARY
echo "Add a line like \`- Description of your change\` under a heading (\`### Added\`, \`### Changed\`, \`### Fixed\`, etc.)" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Changelog: ${UNRELEASED_CONTENT} entry/entries in [Unreleased]"
- name: Verify package source
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
if [ ! -d "$SOURCE_DIR" ]; then
echo "::warning::No src/ or htdocs/ directory"
exit 0
fi
FILE_COUNT=$(find "$SOURCE_DIR" -type f | wc -l)
echo "Source: ${FILE_COUNT} files"
[ "$FILE_COUNT" -gt 0 ] || { echo "::error::Source directory is empty"; exit 1; }
# ── Pre-Release RC Build ─────────────────────────────────────────────────
pre-release:
name: Build RC Package
runs-on: ubuntu-latest
needs: [branch-policy, validate]
steps:
- name: Trigger RC pre-release
env:
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: ${{ github.head_ref }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
# ── Issue Reporter ──────────────────────────────────────────────────────
report-issues:
name: Report Issues
runs-on: ubuntu-latest
needs: [branch-policy, validate]
if: >-
always() &&
needs.validate.result == 'failure'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
- name: "File issue for PR validation failure"
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
./automation/ci-issue-reporter.sh \
--gate "PR Validation" \
--workflow "PR Check" \
--severity error \
--details "PR validation failed (syntax, manifest, changelog, or source checks). See the CI run for the specific check that failed."
-170
View File
@@ -1,170 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Auto-build RC release on PR to main, update RC update stream
name: "PR RC Release"
on:
pull_request:
types: [opened, synchronize]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
REGISTRY: code.mokoconsulting.tech
IMAGE: mokoconsulting/mokogitea
permissions:
contents: write
jobs:
rc-release:
name: Build RC Release
runs-on: ubuntu-latest
steps:
- name: Check target branch
id: guard
env:
BASE_BRANCH: ${{ github.base_ref }}
run: |
echo "PR target: ${BASE_BRANCH}"
if [ "$BASE_BRANCH" != "main" ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Skipping RC — only for PRs targeting main"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Checkout PR branch
if: steps.guard.outputs.skip != 'true'
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Determine RC version
if: steps.guard.outputs.skip != 'true'
id: version
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
BASE_VERSION=$(sed -n 's/.*<version>\(.*\)<\/version>.*/\1/p' updates.xml | head -1)
[ -z "$BASE_VERSION" ] && BASE_VERSION="04.00.00"
RC_VERSION="${BASE_VERSION}-rc.${PR_NUMBER}"
RC_TAG="v1.26.1-moko.${RC_VERSION}"
echo "version=$RC_VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$RC_TAG" >> "$GITHUB_OUTPUT"
echo "RC version: $RC_VERSION (tag: $RC_TAG)"
- name: Update updates.xml RC channel
if: steps.guard.outputs.skip != 'true'
env:
RC_VERSION: ${{ steps.version.outputs.version }}
RC_TAG: ${{ steps.version.outputs.tag }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_NUM: ${{ github.event.pull_request.number }}
run: |
DOCKER_TAG="${REGISTRY}/${IMAGE}:${RC_TAG}"
python3 << 'PYEOF'
import os, re
rc_version = os.environ["RC_VERSION"]
rc_tag = os.environ["RC_TAG"]
pr_url = os.environ["PR_URL"]
pr_num = os.environ["PR_NUM"]
docker_tag = os.environ["REGISTRY"] + "/" + os.environ["IMAGE"] + ":" + rc_tag
entry = f""" <update>
<name>MokoGitea</name>
<description>MokoGitea RC from PR #{pr_num}</description>
<element>mokogitea</element>
<type>application</type>
<version>{rc_version}</version>
<client>server</client>
<tags><tag>rc</tag></tags>
<infourl title="MokoGitea RC">{pr_url}</infourl>
<downloads>
<downloadurl type="full" format="docker">{docker_tag}</downloadurl>
</downloads>
<sha256></sha256>
<targetplatform name="mokogitea" version="((1\\.25\\.)|(1\\.26\\.))" />
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
</update>"""
content = open("updates.xml").read()
# Remove existing RC entry
content = re.sub(
r"\s*<update>[\s\S]*?<tag>rc</tag>[\s\S]*?</update>",
"",
content,
)
# Insert before </updates>
content = content.replace("</updates>", entry + "\n</updates>")
open("updates.xml", "w").write(content)
print(f"Updated updates.xml with RC entry: {rc_version}")
PYEOF
- name: Create RC release
if: steps.guard.outputs.skip != 'true'
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
RC_TAG: ${{ steps.version.outputs.tag }}
RC_VERSION: ${{ steps.version.outputs.version }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
API_BASE: https://${{ env.REGISTRY }}/api/v1/repos/${{ github.repository }}
run: |
# Delete existing RC release/tag if present
curl -s -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
"${API_BASE}/releases/tags/${RC_TAG}" 2>/dev/null || true
curl -s -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
"${API_BASE}/tags/${RC_TAG}" 2>/dev/null || true
# Create prerelease
python3 << PYEOF
import json, os, urllib.request
api = os.environ["API_BASE"]
token = os.environ["GITEA_TOKEN"]
payload = json.dumps({
"tag_name": os.environ["RC_TAG"],
"target_commitish": os.environ["HEAD_SHA"],
"name": f"RC: {os.environ['PR_TITLE']}",
"body": f"Release candidate from PR #{os.environ['PR_NUMBER']}\n\nPR: {os.environ['PR_URL']}\nDocker: docker pull {os.environ['REGISTRY']}/{os.environ['IMAGE']}:{os.environ['RC_TAG']}",
"draft": False,
"prerelease": True,
}).encode()
req = urllib.request.Request(
f"{api}/releases",
data=payload,
headers={
"Authorization": f"token {token}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
result = json.loads(resp.read())
print(f"Created RC release: {result.get('tag_name')}")
PYEOF
- name: Commit updates.xml
if: steps.guard.outputs.skip != 'true'
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_NUM: ${{ github.event.pull_request.number }}
run: |
git config user.name "MokoGitea Bot"
git config user.email "deploy@mokoconsulting.tech"
git add updates.xml
if git diff --cached --quiet; then
echo "No changes to updates.xml"
else
git commit -m "chore(ci): update RC stream for PR #${PR_NUM}"
git push origin "HEAD:${HEAD_REF}" || echo "Push failed"
fi
-11
View File
@@ -1,11 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.01.00
# BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches
-66
View File
@@ -1,66 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoPlatform.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokoplatform
# PATH: /.mokogitea/workflows/rc-revert.yml
# VERSION: 09.23.00
# BRIEF: Rename rc/ branch back to dev/ when PR is closed without merge
name: "RC Revert"
on:
pull_request:
types: [closed]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
revert:
name: Rename rc/ back to dev/
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == false &&
startsWith(github.event.pull_request.head.ref, 'rc/')
steps:
- name: Rename branch
run: |
BRANCH="${{ github.event.pull_request.head.ref }}"
SUFFIX="${BRANCH#rc/}"
DEV_BRANCH="dev/${SUFFIX}"
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Create dev/ branch from rc/ branch
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"new_branch_name\": \"${DEV_BRANCH}\", \"old_branch_name\": \"${BRANCH}\"}" \
"${API}" 2>/dev/null || true)
if [ "$STATUS" = "201" ]; then
echo "Created branch: ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY
else
echo "::error::Failed to create ${DEV_BRANCH} from ${BRANCH} (HTTP ${STATUS})"
exit 1
fi
# Delete rc/ branch
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: token ${TOKEN}" \
"${API}/${ENCODED}" 2>/dev/null || true)
if [ "$STATUS" = "204" ]; then
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
else
echo "::warning::Failed to delete ${BRANCH} (HTTP ${STATUS})"
fi
echo "### RC Reverted" >> $GITHUB_STEP_SUMMARY
echo "${BRANCH} → ${DEV_BRANCH}" >> $GITHUB_STEP_SUMMARY
-711
View File
@@ -1,711 +0,0 @@
# ============================================================================
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Validation
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/joomla/repo_health.yml.template
# VERSION: 09.23.00
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
# ============================================================================
name: "Generic: Repo Health"
defaults:
run:
shell: bash
on:
workflow_dispatch:
inputs:
profile:
description: 'Validation profile: all, scripts, or repo'
required: true
default: all
type: choice
options:
- all
- scripts
- repo
pull_request:
push:
permissions:
contents: read
env:
# Scripts governance policy
SCRIPTS_REQUIRED_DIRS:
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
# Repo health policy
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogitea/workflows/
REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/
REPO_DISALLOWED_DIRS:
REPO_DISALLOWED_FILES: TODO.md,todo.md
# Extended checks toggles
EXTENDED_CHECKS: "true"
# File / directory variables
DOCS_INDEX: docs/docs-index.md
SCRIPT_DIR: scripts
WORKFLOWS_DIR: .mokogitea/workflows
SHELLCHECK_PATTERN: '*.sh'
SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml'
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
access_check:
name: Access control
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
outputs:
allowed: ${{ steps.perm.outputs.allowed }}
permission: ${{ steps.perm.outputs.permission }}
steps:
- name: Check actor permission (admin only)
id: perm
env:
TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
REPO: ${{ github.repository }}
ACTOR: ${{ github.actor }}
run: |
set -euo pipefail
ALLOWED=false
PERMISSION=unknown
METHOD=""
# Hardcoded authorized users — always allowed
case "$ACTOR" in
jmiller|gitea-actions[bot])
ALLOWED=true
PERMISSION=admin
METHOD="hardcoded allowlist"
;;
*)
# Detect platform and check permissions via API
API_BASE="${GITHUB_API_URL:-${GITEA_API_URL:-https://api.github.com}}"
RESP=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/repos/${REPO}/collaborators/${ACTOR}/permission" 2>/dev/null || echo '{}')
PERMISSION=$(echo "$RESP" | grep -oP '"permission"\s*:\s*"\K[^"]+' || echo "unknown")
if [ "$PERMISSION" = "admin" ] || [ "$PERMISSION" = "maintain" ] || [ "$PERMISSION" = "owner" ]; then
ALLOWED=true
fi
METHOD="collaborator API"
;;
esac
echo "permission=${PERMISSION}" >> "$GITHUB_OUTPUT"
echo "allowed=${ALLOWED}" >> "$GITHUB_OUTPUT"
{
echo "## Access Authorization"
echo ""
echo "| Field | Value |"
echo "|-------|-------|"
echo "| **Actor** | \`${ACTOR}\` |"
echo "| **Repository** | \`${REPO}\` |"
echo "| **Permission** | \`${PERMISSION}\` |"
echo "| **Method** | ${METHOD} |"
echo "| **Authorized** | ${ALLOWED} |"
echo ""
if [ "$ALLOWED" = "true" ]; then
echo "${ACTOR} authorized (${METHOD})"
else
echo "${ACTOR} is NOT authorized. Requires admin or maintain role."
fi
} >> "${GITHUB_STEP_SUMMARY}"
- name: Deny execution when not permitted
if: ${{ steps.perm.outputs.allowed != 'true' }}
run: |
set -euo pipefail
printf '%s\n' 'ERROR: Access denied. Admin permission required.' >> "${GITHUB_STEP_SUMMARY}"
exit 1
scripts_governance:
name: Scripts governance
needs: access_check
if: ${{ needs.access_check.outputs.allowed == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Scripts folder checks
env:
PROFILE_RAW: ${{ github.event.inputs.profile }}
run: |
set -euo pipefail
profile="${PROFILE_RAW:-all}"
case "${profile}" in
all|scripts|repo) ;;
*)
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
;;
esac
if [ "${profile}" = 'repo' ]; then
{
printf '%s\n' '### Scripts governance'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' 'Status: SKIPPED'
printf '%s\n' 'Reason: profile excludes scripts governance'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
if [ ! -d "${SCRIPT_DIR}" ]; then
{
printf '%s\n' '### Scripts governance'
printf '%s\n' 'Status: OK (advisory)'
printf '%s\n' 'scripts/ directory not present. No scripts governance enforced.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
if [ -n "${SCRIPTS_REQUIRED_DIRS:-}" ]; then IFS=',' read -r -a required_dirs <<< "${SCRIPTS_REQUIRED_DIRS}"; else required_dirs=(); fi
IFS=',' read -r -a allowed_dirs <<< "${SCRIPTS_ALLOWED_DIRS}"
missing_dirs=()
unapproved_dirs=()
for d in "${required_dirs[@]}"; do
req="${d%/}"
[ ! -d "${req}" ] && missing_dirs+=("${req}/")
done
while IFS= read -r d; do
allowed=false
for a in "${allowed_dirs[@]}"; do
a_norm="${a%/}"
[ "${d%/}" = "${a_norm}" ] && allowed=true
done
[ "${allowed}" = false ] && unapproved_dirs+=("${d%/}/")
done < <(find "${SCRIPT_DIR}" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sed 's#^\./##')
{
printf '%s\n' '### Scripts governance'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' '| Area | Status | Notes |'
printf '%s\n' '|---|---|---|'
if [ "${#missing_dirs[@]}" -gt 0 ]; then
printf '%s\n' '| Required directories | Warning | Missing required subfolders |'
else
printf '%s\n' '| Required directories | OK | All required subfolders present |'
fi
if [ "${#unapproved_dirs[@]}" -gt 0 ]; then
printf '%s\n' '| Directory policy | Warning | Unapproved directories detected |'
else
printf '%s\n' '| Directory policy | OK | No unapproved directories |'
fi
printf '%s\n' '| Enforcement mode | Advisory | scripts folder is optional |'
printf '\n'
if [ "${#missing_dirs[@]}" -gt 0 ]; then
printf '%s\n' 'Missing required script directories:'
for m in "${missing_dirs[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
else
printf '%s\n' 'Missing required script directories: none.'
printf '\n'
fi
if [ "${#unapproved_dirs[@]}" -gt 0 ]; then
printf '%s\n' 'Unapproved script directories detected:'
for m in "${unapproved_dirs[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
else
printf '%s\n' 'Unapproved script directories detected: none.'
printf '\n'
fi
printf '%s\n' 'Scripts governance completed in advisory mode.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
repo_health:
name: Repository health
needs: access_check
if: ${{ needs.access_check.outputs.allowed == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Repository health checks
env:
PROFILE_RAW: ${{ github.event.inputs.profile }}
run: |
set -euo pipefail
profile="${PROFILE_RAW:-all}"
case "${profile}" in
all|scripts|repo) ;;
*)
printf '%s\n' "ERROR: Unknown profile: ${profile}" >> "${GITHUB_STEP_SUMMARY}"
exit 1
;;
esac
if [ "${profile}" = 'scripts' ]; then
{
printf '%s\n' '### Repository health'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' 'Status: SKIPPED'
printf '%s\n' 'Reason: profile excludes repository health'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
IFS=',' read -r -a required_artifacts <<< "${REPO_REQUIRED_ARTIFACTS}"
IFS=',' read -r -a optional_files <<< "${REPO_OPTIONAL_FILES}"
if [ -n "${REPO_DISALLOWED_DIRS:-}" ]; then IFS=',' read -r -a disallowed_dirs <<< "${REPO_DISALLOWED_DIRS}"; else disallowed_dirs=(); fi
IFS=',' read -r -a disallowed_files <<< "${REPO_DISALLOWED_FILES:-}"
missing_required=()
missing_optional=()
# Source directory: src/ or htdocs/ (either is valid for extension repos)
SOURCE_DIR=""
if [ -d "src" ]; then
SOURCE_DIR="src"
elif [ -d "htdocs" ]; then
SOURCE_DIR="htdocs"
elif [ -d "deploy" ] || [ -d "cli" ] || [ -d "monitoring" ]; then
# Platform/tooling repos don't need src/
SOURCE_DIR=""
else
missing_required+=("src/ or htdocs/ (source directory required)")
fi
for item in "${required_artifacts[@]}"; do
if printf '%s' "${item}" | grep -q '/$'; then
d="${item%/}"
[ ! -d "${d}" ] && missing_required+=("${item}")
else
[ ! -f "${item}" ] && missing_required+=("${item}")
fi
done
for f in "${optional_files[@]}"; do
if printf '%s' "${f}" | grep -q '/$'; then
d="${f%/}"
[ ! -d "${d}" ] && missing_optional+=("${f}")
else
[ ! -f "${f}" ] && missing_optional+=("${f}")
fi
done
for d in "${disallowed_dirs[@]}"; do
d_norm="${d%/}"
[ -d "${d_norm}" ] && missing_required+=("${d_norm}/ (disallowed)")
done
for f in "${disallowed_files[@]}"; do
[ -f "${f}" ] && missing_required+=("${f} (disallowed)")
done
git fetch origin --prune
dev_paths=()
dev_branches=()
while IFS= read -r b; do
name="${b#origin/}"
if [ "${name}" = 'dev' ]; then
dev_branches+=("${name}")
else
dev_paths+=("${name}")
fi
done < <(git branch -r --list 'origin/dev*' | sed 's/^ *//')
if [ "${#dev_paths[@]}" -eq 0 ] && [ "${#dev_branches[@]}" -eq 0 ]; then
missing_required+=("dev or dev/* branch")
fi
content_warnings=()
if [ -f 'CHANGELOG.md' ] && ! grep -Eq '^# Changelog' CHANGELOG.md; then
content_warnings+=("CHANGELOG.md missing '# Changelog' header")
fi
if [ -f 'CHANGELOG.md' ] && grep -Eq '^[# ]*Unreleased' CHANGELOG.md; then
content_warnings+=("CHANGELOG.md contains Unreleased section (review release readiness)")
fi
if [ -f 'LICENSE' ] && ! grep -qiE 'GNU GENERAL PUBLIC LICENSE|GPL' LICENSE; then
content_warnings+=("LICENSE does not look like a GPL text")
fi
if [ -f 'README.md' ] && ! grep -qiE 'moko|Moko' README.md; then
content_warnings+=("README.md missing expected brand keyword")
fi
export PROFILE_RAW="${profile}"
export MISSING_REQUIRED="$(printf '%s\n' "${missing_required[@]:-}")"
export MISSING_OPTIONAL="$(printf '%s\n' "${missing_optional[@]:-}")"
export CONTENT_WARNINGS="$(printf '%s\n' "${content_warnings[@]:-}")"
report_json=$(printf '{"profile":"%s","missing_required":%d,"missing_optional":%d,"content_warnings":%d}' "$profile" "${#missing_required[@]}" "${#missing_optional[@]}" "${#content_warnings[@]}")
{
printf '%s\n' '### Repository health'
printf '%s\n' "Profile: ${profile}"
printf '%s\n' '| Metric | Value |'
printf '%s\n' '|---|---|'
printf '%s\n' "| Missing required | ${#missing_required[@]} |"
printf '%s\n' "| Missing optional | ${#missing_optional[@]} |"
printf '%s\n' "| Content warnings | ${#content_warnings[@]} |"
printf '\n'
printf '%s\n' '### Guardrails report (JSON)'
printf '%s\n' '```json'
printf '%s\n' "${report_json}"
printf '%s\n' '```'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
if [ "${#missing_required[@]}" -gt 0 ]; then
{
printf '%s\n' '### Missing required repo artifacts'
for m in "${missing_required[@]}"; do printf '%s\n' "- ${m}"; done
printf '%s\n' 'ERROR: Guardrails failed. Missing required repository artifacts.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
exit 1
fi
if [ "${#missing_optional[@]}" -gt 0 ]; then
{
printf '%s\n' '### Missing optional repo artifacts'
for m in "${missing_optional[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
if [ "${#content_warnings[@]}" -gt 0 ]; then
{
printf '%s\n' '### Repo content warnings'
for m in "${content_warnings[@]}"; do printf '%s\n' "- ${m}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
# -- Joomla-specific checks --
joomla_findings=()
MANIFEST="$(find . -maxdepth 2 -name '*.xml' -exec grep -l '<extension' {} \; 2>/dev/null | head -1 || true)"
if [ -z "${MANIFEST}" ]; then
joomla_findings+=("Joomla XML manifest not found (no *.xml with <extension> tag)")
else
if ! grep -qP '<version>' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <version> tag missing")
fi
if ! grep -qP 'type="(component|module|plugin|library|package|template|language)"' "${MANIFEST}"; then
joomla_findings+=("XML manifest: type attribute missing or invalid")
fi
if ! grep -qP '<name>' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <name> tag missing")
fi
if ! grep -qP '<author>' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <author> tag missing")
fi
if ! grep -qP '<namespace' "${MANIFEST}"; then
joomla_findings+=("XML manifest: <namespace> missing (required for Joomla 5+)")
fi
fi
INI_COUNT="$(find . -name '*.ini' -type f 2>/dev/null | wc -l)"
if [ "${INI_COUNT}" -eq 0 ]; then
joomla_findings+=("No .ini language files found")
fi
if [ ! -f 'updates.xml' ]; then
joomla_findings+=("updates.xml missing in root (required for Joomla update server)")
fi
if [ -n "${SOURCE_DIR}" ]; then
INDEX_DIRS=("${SOURCE_DIR}" "${SOURCE_DIR}/admin" "${SOURCE_DIR}/site")
for dir in "${INDEX_DIRS[@]}"; do
if [ -d "${dir}" ] && [ ! -f "${dir}/index.html" ]; then
joomla_findings+=("${dir}/index.html missing (directory listing protection)")
fi
done
fi
if [ "${#joomla_findings[@]}" -gt 0 ]; then
{
printf '%s\n' '### Joomla extension checks'
printf '%s\n' '| Check | Status |'
printf '%s\n' '|---|---|'
for f in "${joomla_findings[@]}"; do
printf '%s\n' "| ${f} | Warning |"
done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
else
{
printf '%s\n' '### Joomla extension checks'
printf '%s\n' 'All Joomla-specific checks passed.'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
extended_enabled="${EXTENDED_CHECKS:-true}"
extended_findings=()
if [ "${extended_enabled}" = 'true' ]; then
if [ -f '.github/CODEOWNERS' ] || [ -f 'CODEOWNERS' ] || [ -f 'docs/CODEOWNERS' ]; then
:
else
extended_findings+=("CODEOWNERS not found (.github/CODEOWNERS preferred)")
fi
if ls "${WORKFLOWS_DIR}"/*.yml >/dev/null 2>&1 || ls "${WORKFLOWS_DIR}"/*.yaml >/dev/null 2>&1; then
bad_refs="$(grep -RIn --include='*.yml' --include='*.yaml' -E '^[[:space:]]*uses:[[:space:]]*[^#]+@(main|master)\b' "${WORKFLOWS_DIR}" 2>/dev/null || true)"
if [ -n "${bad_refs}" ]; then
extended_findings+=("Workflows reference actions @main/@master (pin versions): see log excerpt")
{
printf '%s\n' '### Workflow pinning advisory'
printf '%s\n' 'Found uses: entries pinned to main/master:'
printf '%s\n' '```'
printf '%s\n' "${bad_refs}"
printf '%s\n' '```'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
if [ -f "${DOCS_INDEX}" ]; then
missing_links=""
while IFS= read -r docline; do
for link in $(echo "$docline" | grep -oE '\]\([^)]+\)' | sed 's/\](//' | sed 's/)$//' || true); do
case "$link" in http://*|https://*|"#"*|mailto:*) continue ;; esac
linkpath="${link%%#*}"
linkpath="${linkpath%%\?*}"
[ -z "$linkpath" ] && continue
if [ "${linkpath:0:1}" = "/" ]; then
testpath="${linkpath#/}"
else
testpath="$(dirname "${DOCS_INDEX}")/${linkpath}"
fi
[ ! -e "$testpath" ] && missing_links="${missing_links}${testpath} "
done
done < "${DOCS_INDEX}"
if [ -n "${missing_links}" ]; then
extended_findings+=("docs/docs-index.md contains broken relative links")
{
printf '%s\n' '### Docs index link integrity'
printf '%s\n' 'Broken relative links:'
for bl in ${missing_links}; do
printf '%s\n' "- ${bl}"
done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
if [ -d "${SCRIPT_DIR}" ]; then
if ! command -v shellcheck >/dev/null 2>&1; then
sudo apt-get update -qq
sudo apt-get install -y shellcheck >/dev/null
fi
sc_out=''
while IFS= read -r shf; do
[ -z "${shf}" ] && continue
out_one="$(shellcheck -S warning -x "${shf}" 2>/dev/null || true)"
if [ -n "${out_one}" ]; then
sc_out="${sc_out}${out_one}\n"
fi
done < <(find "${SCRIPT_DIR}" -type f -name "${SHELLCHECK_PATTERN}" 2>/dev/null | sort)
if [ -n "${sc_out}" ]; then
extended_findings+=("ShellCheck warnings detected (advisory)")
sc_head="$(printf '%s' "${sc_out}" | head -n 200)"
{
printf '%s\n' '### ShellCheck (advisory)'
printf '%s\n' '```'
printf '%s\n' "${sc_head}"
printf '%s\n' '```'
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
spdx_missing=()
IFS=',' read -r -a spdx_globs <<< "${SPDX_FILE_GLOBS}"
spdx_args=()
for g in "${spdx_globs[@]}"; do spdx_args+=("${g}"); done
while IFS= read -r f; do
[ -z "${f}" ] && continue
if ! head -n 40 "${f}" | grep -q 'SPDX-License-Identifier:'; then
spdx_missing+=("${f}")
fi
done < <(git ls-files "${spdx_args[@]}" 2>/dev/null || true)
if [ "${#spdx_missing[@]}" -gt 0 ]; then
extended_findings+=("SPDX header missing in some tracked files (advisory)")
{
printf '%s\n' '### SPDX header advisory'
printf '%s\n' 'Files missing SPDX-License-Identifier (first 40 lines scan):'
for f in "${spdx_missing[@]}"; do printf '%s\n' "- ${f}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
stale_cutoff_days=180
stale_branches="$(git for-each-ref --format='%(refname:short) %(committerdate:unix)' refs/remotes/origin 2>/dev/null | awk -v now="$(date +%s)" -v days="${stale_cutoff_days}" '{if (now-$2 > days*86400) print $1}' | head -50)"
if [ -n "${stale_branches}" ]; then
extended_findings+=("Stale remote branches detected (advisory)")
{
printf '%s\n' '### Git hygiene advisory'
printf '%s\n' "Branches with last commit older than ${stale_cutoff_days} days (sample up to 50):"
while IFS= read -r b; do [ -n "${b}" ] && printf '%s\n' "- ${b}"; done <<< "${stale_branches}"
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
fi
{
printf '%s\n' '### Guardrails coverage matrix'
printf '%s\n' '| Domain | Status | Notes |'
printf '%s\n' '|---|---|---|'
printf '%s\n' '| Access control | OK | Admin-only execution gate |'
printf '%s\n' '| Release policy | N/A | Releases handled by MokoGitea |'
printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |'
printf '%s\n' '| Repo required artifacts | OK | Required, optional, disallowed enforcement |'
printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
if [ "${extended_enabled}" = 'true' ]; then
if [ "${#extended_findings[@]}" -gt 0 ]; then
printf '%s\n' '| Extended checks | Warning | See extended findings below |'
else
printf '%s\n' '| Extended checks | OK | No findings |'
fi
else
printf '%s\n' '| Extended checks | SKIPPED | EXTENDED_CHECKS disabled |'
fi
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
if [ "${extended_enabled}" = 'true' ] && [ "${#extended_findings[@]}" -gt 0 ]; then
{
printf '%s\n' '### Extended findings (advisory)'
for f in "${extended_findings[@]}"; do printf '%s\n' "- ${f}"; done
printf '\n'
} >> "${GITHUB_STEP_SUMMARY}"
fi
printf '%s\n' 'Repository health guardrails passed.' >> "${GITHUB_STEP_SUMMARY}"
site-health:
name: Site Health
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
- name: Uptime check
if: env.URLS != ''
run: |
echo "$URLS" > /tmp/urls.txt
php monitoring/uptime-probe.php --urls /tmp/urls.txt --timeout 15 || echo "::warning::Some sites are down"
rm -f /tmp/urls.txt
env:
URLS: ${{ vars.MONITORED_URLS }}
- name: SSL certificate check
if: env.DOMAINS != ''
run: |
echo "$DOMAINS" > /tmp/domains.txt
php monitoring/ssl-check.php --domains /tmp/domains.txt --warn-days 30 || echo "::warning::SSL certificates expiring soon"
rm -f /tmp/domains.txt
env:
DOMAINS: ${{ vars.MONITORED_DOMAINS }}
- name: Summary
if: always()
run: |
echo "### Site Health" >> $GITHUB_STEP_SUMMARY
echo "Uptime and SSL checks completed." >> $GITHUB_STEP_SUMMARY
# ═══════════════════════════════════════════════════════════════════════
# Issue Reporter — file issues for failed gates
# ═══════════════════════════════════════════════════════════════════════
report-issues:
name: "Report Issues"
runs-on: ubuntu-latest
needs: [access_check, scripts_governance, repo_health]
if: >-
always() &&
(needs.scripts_governance.result == 'failure' ||
needs.repo_health.result == 'failure')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
- name: "File issues for failed gates"
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
REPORTER="./automation/ci-issue-reporter.sh"
WF="Repo Health"
report_gate() {
local gate="$1" result="$2" details="$3"
if [ "$result" = "failure" ]; then
"$REPORTER" --gate "$gate" --details "$details" --workflow "$WF" --severity error
fi
}
report_gate "Scripts Governance" \
"${{ needs.scripts_governance.result }}" \
"Scripts directory policy violations detected. Review required and allowed directories."
report_gate "Repository Health" \
"${{ needs.repo_health.result }}" \
"Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
-82
View File
@@ -1,82 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.gitea/workflows/security-audit.yml
# VERSION: 01.00.00
# BRIEF: Dependency vulnerability scanning for composer and npm packages
name: "Universal: Security Audit"
on:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday at 06:00 UTC
pull_request:
branches:
- main
paths:
- 'composer.json'
- 'composer.lock'
- 'package.json'
- 'package-lock.json'
workflow_dispatch:
permissions:
contents: read
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
jobs:
audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Composer audit
if: hashFiles('composer.lock') != ''
run: |
echo "=== Composer Security Audit ==="
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli composer >/dev/null 2>&1
fi
composer audit --format=plain 2>&1 | tee /tmp/composer-audit.txt
RESULT=$?
if [ $RESULT -ne 0 ]; then
echo "::warning::Composer vulnerabilities found"
echo "composer_vulnerable=true" >> "$GITHUB_ENV"
else
echo "No known vulnerabilities in composer dependencies"
fi
- name: NPM audit
if: hashFiles('package-lock.json') != ''
run: |
echo "=== NPM Security Audit ==="
npm audit --production 2>&1 | tee /tmp/npm-audit.txt || true
if npm audit --production 2>&1 | grep -q "found 0 vulnerabilities"; then
echo "No known vulnerabilities in npm dependencies"
else
echo "::warning::NPM vulnerabilities found"
echo "npm_vulnerable=true" >> "$GITHUB_ENV"
fi
- name: Notify on vulnerabilities
if: env.composer_vulnerable == 'true' || env.npm_vulnerable == 'true'
run: |
REPO="${{ github.event.repository.name }}"
curl -sS \
-H "Title: ${REPO} has vulnerable dependencies" \
-H "Tags: lock,warning" \
-H "Priority: high" \
-d "Security audit found vulnerabilities. Review dependency updates." \
"${NTFY_URL}/${NTFY_TOPIC}" || true
-12
View File
@@ -1,12 +0,0 @@
# Test workflow to verify .mokogitea/ directory is discovered
name: Test .mokogitea workflows
on:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Verify .mokogitea
run: echo "This workflow ran from .mokogitea/workflows/ — feature works!"
-167
View File
@@ -1,167 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# BRIEF: Sync upstream Gitea bug fixes into MokoGitea issue tracker
name: Upstream Bug Sync
on:
schedule:
- cron: '0 8 * * *' # daily at 08:00 UTC
workflow_dispatch:
inputs:
days_back:
description: 'How many days back to scan (default: 7)'
required: false
default: '7'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Sync upstream bugs
env:
GH_TOKEN: ${{ secrets.GH_MIRROR_TOKEN }}
MOKOGITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
MOKOGITEA_URL: https://code.mokoconsulting.tech
MOKOGITEA_REPO: MokoConsulting/MokoGitea
UPSTREAM_BRANCH: release/v1.26
DAYS_BACK: ${{ github.event.inputs.days_back || '7' }}
run: |
python3 << 'PYEOF'
import json, os, re, sys, urllib.parse, urllib.request
from datetime import datetime, timedelta, timezone
GH_TOKEN = os.environ["GH_TOKEN"]
MOKO_TOKEN = os.environ["MOKOGITEA_TOKEN"]
MOKO_URL = os.environ["MOKOGITEA_URL"]
MOKO_REPO = os.environ["MOKOGITEA_REPO"]
BRANCH = os.environ["UPSTREAM_BRANCH"]
DAYS = int(os.environ.get("DAYS_BACK", "7"))
# Label IDs in MokoGitea
LABELS = {
"type_bug": 5757, "upstream": 5758, "security": 5032,
"critical": 5018, "high": 5019, "medium": 5020, "low": 5021,
}
def gh_get(url):
req = urllib.request.Request(url, headers={
"Authorization": f"token {GH_TOKEN}",
"Accept": "application/vnd.github.v3+json",
})
with urllib.request.urlopen(req) as r:
return json.loads(r.read())
def moko_get(path):
req = urllib.request.Request(f"{MOKO_URL}/api/v1/{path}", headers={
"Authorization": f"token {MOKO_TOKEN}",
})
with urllib.request.urlopen(req) as r:
return json.loads(r.read())
def moko_post(path, data):
payload = json.dumps(data).encode()
req = urllib.request.Request(f"{MOKO_URL}/api/v1/{path}",
data=payload, method="POST", headers={
"Authorization": f"token {MOKO_TOKEN}",
"Content-Type": "application/json",
})
with urllib.request.urlopen(req) as r:
return json.loads(r.read())
# ── Step 1: Find recently merged upstream PRs ──
since = (datetime.now(timezone.utc) - timedelta(days=DAYS)).strftime("%Y-%m-%dT%H:%M:%SZ")
query = f"repo:go-gitea/gitea is:pr is:merged base:{BRANCH} merged:>={since}"
encoded = urllib.parse.quote(query)
print(f"Scanning: {query}")
result = gh_get(f"https://api.github.com/search/issues?q={encoded}&per_page=100&sort=updated&order=desc")
total = result["total_count"]
print(f"Found {total} merged PRs in the last {DAYS} days")
if total == 0:
print("Nothing to sync.")
sys.exit(0)
# ── Step 2: Filter for bug/security fixes ──
bugs = []
for pr in result["items"]:
title = pr["title"]
label_names = [l["name"].lower() for l in pr.get("labels", [])]
is_fix = title.lower().startswith("fix")
is_security = any("security" in l for l in label_names) or "[security]" in title.lower()
is_bug = any("bug" in l for l in label_names)
if not (is_fix or is_security or is_bug):
continue
refs = re.findall(r"#(\d+)", title)
severity = "critical" if is_security and "[security]" in title.lower() else \
"high" if is_security else "medium"
bugs.append({
"number": pr["number"], "title": title, "url": pr["html_url"],
"severity": severity, "is_security": is_security, "refs": refs,
"merged": pr.get("pull_request", {}).get("merged_at", "")[:10],
})
print(f"Filtered to {len(bugs)} bug/security fixes")
if not bugs:
sys.exit(0)
# ── Step 3: Collect already-tracked PR numbers ──
tracked = set()
for state in ["open", "closed"]:
try:
issues = moko_get(f"repos/{MOKO_REPO}/issues?state={state}&type=issues&limit=50&labels=upstream")
for iss in issues:
text = (iss.get("body") or "") + " " + (iss.get("title") or "")
tracked.update(re.findall(r"(?:#|/pull/)(\d{4,})", text))
except Exception:
pass
print(f"Already tracked: {len(tracked)} upstream PRs")
# ── Step 4: Create issues for new bugs ──
created = skipped = errors = 0
for bug in bugs:
if any(r in tracked for r in bug["refs"]):
print(f" SKIP #{bug['number']}: {bug['title'][:55]} (tracked)")
skipped += 1
continue
labels = [LABELS["type_bug"], LABELS["upstream"], LABELS[bug["severity"]]]
if bug["is_security"]:
labels.append(LABELS["security"])
body = (
f"## Summary\n\n"
f"Upstream bug fix merged into `{BRANCH}`.\n\n"
f"## Upstream Reference\n\n"
f"- PR: {bug['url']}\n"
f"- Merged: {bug['merged']}\n"
f"- Branch: {BRANCH}\n\n"
f"## Severity: {bug['severity'].title()}"
f"{' (security)' if bug['is_security'] else ''}\n\n"
f"## Action\n\n"
f"Cherry-pick from upstream `{BRANCH}` branch.\n\n"
f"---\n"
f"*Auto-created by upstream-bug-sync workflow*\n"
f"*Authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>*"
)
try:
iss = moko_post(f"repos/{MOKO_REPO}/issues", {
"title": bug["title"], "body": body, "labels": labels,
})
print(f" CREATED #{iss['number']}: {bug['title'][:55]}")
created += 1
except Exception as e:
print(f" ERROR #{bug['number']}: {e}")
errors += 1
print(f"\n=== Done: {created} created, {skipped} skipped, {errors} errors ===")
PYEOF
+1 -4
View File
@@ -1,7 +1,4 @@
audit=false
fund=false
update-notifier=false
package-lock=true
save-exact=true
auto-install-peers=true
dedupe-peer-dependents=false
enable-pre-post-scripts=true
+25
View File
@@ -0,0 +1,25 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 1
warningCode = 1
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
-12
View File
@@ -1,12 +0,0 @@
extends: [[spectral:oas, all]]
rules:
info-contact: off
oas2-api-host: off
oas2-parameter-description: off
oas2-schema: off
oas2-valid-schema-example: off
openapi-tags: off
operation-description: off
operation-singular-tag: off
operation-tag-defined: off
+15
View File
@@ -0,0 +1,15 @@
extends: stylelint-config-standard
rules:
at-rule-empty-line-before: null
block-closing-brace-empty-line-before: null
color-hex-length: null
comment-empty-line-before: null
declaration-block-single-line-max-declarations: null
declaration-empty-line-before: null
indentation: 2
no-descending-specificity: null
number-leading-zero: never
rule-empty-line-before: null
selector-pseudo-element-colon-notation: double
shorthand-property-no-redundant-values: true
-42
View File
@@ -1,42 +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: disable
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
+13 -20
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
File diff suppressed because it is too large Load Diff

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