diff --git a/.deadcode-out b/.deadcode-out index 2c54b37490..ae0d358b51 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -15,7 +15,6 @@ code.gitea.io/gitea/models ErrUpdateTaskNotExist.Unwrap IsErrSHANotFound IsErrMergeDivergingFastForwardOnly - GetYamlFixturesAccess code.gitea.io/gitea/models/actions ScheduleList.GetUserIDs diff --git a/contrib/fixtures/fixture_generation.go b/contrib/fixtures/fixture_generation.go deleted file mode 100644 index 31797cc800..0000000000 --- a/contrib/fixtures/fixture_generation.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//nolint:forbidigo -package main - -import ( - "context" - "fmt" - "os" - "path/filepath" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/unittest" -) - -// To generate derivative fixtures, execute the following from Gitea's repository base dir: -// go run -tags 'sqlite sqlite_unlock_notify' contrib/fixtures/fixture_generation.go [fixture...] - -var ( - generators = []struct { - gen func(ctx context.Context) (string, error) - name string - }{ - { - models.GetYamlFixturesAccess, "access", - }, - } - fixturesDir string -) - -func main() { - pathToGiteaRoot := "." - fixturesDir = filepath.Join(pathToGiteaRoot, "models", "fixtures") - if err := unittest.CreateTestEngine(unittest.FixturesOptions{ - Dir: fixturesDir, - }); err != nil { - fmt.Printf("CreateTestEngine: %+v", err) - os.Exit(1) - } - if err := unittest.PrepareTestDatabase(); err != nil { - fmt.Printf("PrepareTestDatabase: %+v\n", err) - os.Exit(1) - } - ctx := context.Background() - if len(os.Args) == 0 { - for _, r := range os.Args { - if err := generate(ctx, r); err != nil { - fmt.Printf("generate '%s': %+v\n", r, err) - os.Exit(1) - } - } - } else { - for _, g := range generators { - if err := generate(ctx, g.name); err != nil { - fmt.Printf("generate '%s': %+v\n", g.name, err) - os.Exit(1) - } - } - } -} - -func generate(ctx context.Context, name string) error { - for _, g := range generators { - if g.name == name { - data, err := g.gen(ctx) - if err != nil { - return err - } - path := filepath.Join(fixturesDir, name+".yml") - if err := os.WriteFile(path, []byte(data), 0o644); err != nil { - return fmt.Errorf("%s: %+v", path, err) - } - fmt.Printf("%s created.\n", path) - return nil - } - } - - return fmt.Errorf("generator not found") -} diff --git a/models/fixture_generation.go b/models/fixture_generation.go deleted file mode 100644 index 6234caefad..0000000000 --- a/models/fixture_generation.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package models - -import ( - "context" - "fmt" - "strings" - - "code.gitea.io/gitea/models/db" - access_model "code.gitea.io/gitea/models/perm/access" - repo_model "code.gitea.io/gitea/models/repo" -) - -// GetYamlFixturesAccess returns a string containing the contents -// for the access table, as recalculated using repo.RecalculateAccesses() -func GetYamlFixturesAccess(ctx context.Context) (string, error) { - repos := make([]*repo_model.Repository, 0, 50) - if err := db.GetEngine(ctx).Find(&repos); err != nil { - return "", err - } - - for _, repo := range repos { - repo.MustOwner(ctx) - if err := access_model.RecalculateAccesses(ctx, repo); err != nil { - return "", err - } - } - - var b strings.Builder - - accesses := make([]*access_model.Access, 0, 200) - if err := db.GetEngine(ctx).OrderBy("user_id, repo_id").Find(&accesses); err != nil { - return "", err - } - - for i, a := range accesses { - fmt.Fprintf(&b, "-\n") - fmt.Fprintf(&b, " id: %d\n", i+1) - fmt.Fprintf(&b, " user_id: %d\n", a.UserID) - fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID) - fmt.Fprintf(&b, " mode: %d\n", a.Mode) - if i < len(accesses)-1 { - fmt.Fprintf(&b, "\n") - } - } - - return b.String(), nil -} diff --git a/models/fixture_test.go b/models/fixture_test.go deleted file mode 100644 index 33429c8c2d..0000000000 --- a/models/fixture_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package models - -import ( - "context" - "os" - "path/filepath" - "testing" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/util" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestFixtureGeneration(t *testing.T) { - require.NoError(t, unittest.PrepareTestDatabase()) - - test := func(ctx context.Context, gen func(ctx context.Context) (string, error), name string) { - expected, err := gen(ctx) - require.NoError(t, err) - - p := filepath.Join(unittest.FixturesDir(), name+".yml") - bytes, err := os.ReadFile(p) - require.NoError(t, err) - - data := string(util.NormalizeEOL(bytes)) - assert.EqualValues(t, expected, data, "Differences detected for %s", p) - } - - test(db.DefaultContext, GetYamlFixturesAccess, "access") -} diff --git a/release-notes/6200.md b/release-notes/6200.md new file mode 100644 index 0000000000..f7cf8de471 --- /dev/null +++ b/release-notes/6200.md @@ -0,0 +1 @@ +feat: [commit](https://codeberg.org/forgejo/forgejo/commit/0786ddc5de37a01d1c3e3bf99b794665341b3c12) Add Swift login endpoint diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index b6666c9269..781bfc7f90 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -637,40 +637,46 @@ func CommonRoutes() *web.Route { }, reqPackageAccess(perm.AccessModeWrite)) }, reqPackageAccess(perm.AccessModeRead)) r.Group("/swift", func() { - r.Group("/{scope}/{name}", func() { - r.Group("", func() { - r.Get("", swift.EnumeratePackageVersions) - r.Get(".json", swift.EnumeratePackageVersions) - }, swift.CheckAcceptMediaType(swift.AcceptJSON)) - r.Group("/{version}", func() { - r.Get("/Package.swift", swift.CheckAcceptMediaType(swift.AcceptSwift), swift.DownloadManifest) - r.Put("", reqPackageAccess(perm.AccessModeWrite), swift.CheckAcceptMediaType(swift.AcceptJSON), enforcePackagesQuota(), swift.UploadPackageFile) - r.Get("", func(ctx *context.Context) { - // Can't use normal routes here: https://github.com/go-chi/chi/issues/781 + r.Group("", func() { // Needs to be unauthenticated. + r.Post("", swift.CheckAuthenticate) + r.Post("/login", swift.CheckAuthenticate) + }) + r.Group("", func() { + r.Group("/{scope}/{name}", func() { + r.Group("", func() { + r.Get("", swift.EnumeratePackageVersions) + r.Get(".json", swift.EnumeratePackageVersions) + }, swift.CheckAcceptMediaType(swift.AcceptJSON)) + r.Group("/{version}", func() { + r.Get("/Package.swift", swift.CheckAcceptMediaType(swift.AcceptSwift), swift.DownloadManifest) + r.Put("", reqPackageAccess(perm.AccessModeWrite), swift.CheckAcceptMediaType(swift.AcceptJSON), enforcePackagesQuota(), swift.UploadPackageFile) + r.Get("", func(ctx *context.Context) { + // Can't use normal routes here: https://github.com/go-chi/chi/issues/781 - version := ctx.Params("version") - if strings.HasSuffix(version, ".zip") { - swift.CheckAcceptMediaType(swift.AcceptZip)(ctx) - if ctx.Written() { - return + version := ctx.Params("version") + if strings.HasSuffix(version, ".zip") { + swift.CheckAcceptMediaType(swift.AcceptZip)(ctx) + if ctx.Written() { + return + } + ctx.SetParams("version", version[:len(version)-4]) + swift.DownloadPackageFile(ctx) + } else { + swift.CheckAcceptMediaType(swift.AcceptJSON)(ctx) + if ctx.Written() { + return + } + if strings.HasSuffix(version, ".json") { + ctx.SetParams("version", version[:len(version)-5]) + } + swift.PackageVersionMetadata(ctx) } - ctx.SetParams("version", version[:len(version)-4]) - swift.DownloadPackageFile(ctx) - } else { - swift.CheckAcceptMediaType(swift.AcceptJSON)(ctx) - if ctx.Written() { - return - } - if strings.HasSuffix(version, ".json") { - ctx.SetParams("version", version[:len(version)-5]) - } - swift.PackageVersionMetadata(ctx) - } + }) }) }) - }) - r.Get("/identifiers", swift.CheckAcceptMediaType(swift.AcceptJSON), swift.LookupPackageIdentifiers) - }, reqPackageAccess(perm.AccessModeRead)) + r.Get("/identifiers", swift.CheckAcceptMediaType(swift.AcceptJSON), swift.LookupPackageIdentifiers) + }, reqPackageAccess(perm.AccessModeRead)) + }) r.Group("/vagrant", func() { r.Group("/authenticate", func() { r.Get("", vagrant.CheckAuthenticate) diff --git a/routers/api/packages/swift/swift.go b/routers/api/packages/swift/swift.go index a9da3ea9c2..fce2a36dd6 100644 --- a/routers/api/packages/swift/swift.go +++ b/routers/api/packages/swift/swift.go @@ -27,7 +27,7 @@ import ( "github.com/hashicorp/go-version" ) -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#35-api-versioning +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#35-api-versioning const ( AcceptJSON = "application/vnd.swift.registry.v1+json" AcceptSwift = "application/vnd.swift.registry.v1+swift" @@ -35,9 +35,9 @@ const ( ) var ( - // https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#361-package-scope + // https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#361-package-scope scopePattern = regexp.MustCompile(`\A[a-zA-Z0-9][a-zA-Z0-9-]{0,38}\z`) - // https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#362-package-name + // https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#362-package-name namePattern = regexp.MustCompile(`\A[a-zA-Z0-9][a-zA-Z0-9-_]{0,99}\z`) ) @@ -49,7 +49,7 @@ type headers struct { Link string } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#35-api-versioning +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#35-api-versioning func setResponseHeaders(resp http.ResponseWriter, h *headers) { if h.ContentType != "" { resp.Header().Set("Content-Type", h.ContentType) @@ -69,7 +69,7 @@ func setResponseHeaders(resp http.ResponseWriter, h *headers) { } } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#33-error-handling +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#33-error-handling func apiError(ctx *context.Context, status int, obj any) { // https://www.rfc-editor.org/rfc/rfc7807 type Problem struct { @@ -91,7 +91,7 @@ func apiError(ctx *context.Context, status int, obj any) { }) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#35-api-versioning +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#35-api-versioning func CheckAcceptMediaType(requiredAcceptHeader string) func(ctx *context.Context) { return func(ctx *context.Context) { accept := ctx.Req.Header.Get("Accept") @@ -101,6 +101,16 @@ func CheckAcceptMediaType(requiredAcceptHeader string) func(ctx *context.Context } } +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md#registry-authentication +func CheckAuthenticate(ctx *context.Context) { + if ctx.Doer == nil { + apiError(ctx, http.StatusUnauthorized, nil) + return + } + + ctx.Status(http.StatusOK) +} + func buildPackageID(scope, name string) string { return scope + "." + name } @@ -113,7 +123,7 @@ type EnumeratePackageVersionsResponse struct { Releases map[string]Release `json:"releases"` } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#41-list-package-releases +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#41-list-package-releases func EnumeratePackageVersions(ctx *context.Context) { packageScope := ctx.Params("scope") packageName := ctx.Params("name") @@ -170,7 +180,7 @@ type PackageVersionMetadataResponse struct { Metadata *swift_module.SoftwareSourceCode `json:"metadata"` } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-2 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-2 func PackageVersionMetadata(ctx *context.Context) { id := buildPackageID(ctx.Params("scope"), ctx.Params("name")) @@ -228,7 +238,7 @@ func PackageVersionMetadata(ctx *context.Context) { }) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#43-fetch-manifest-for-a-package-release +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#43-fetch-manifest-for-a-package-release func DownloadManifest(ctx *context.Context) { packageScope := ctx.Params("scope") packageName := ctx.Params("name") @@ -280,7 +290,7 @@ func DownloadManifest(ctx *context.Context) { }) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-6 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-6 func UploadPackageFile(ctx *context.Context) { packageScope := ctx.Params("scope") packageName := ctx.Params("name") @@ -379,7 +389,7 @@ func UploadPackageFile(ctx *context.Context) { ctx.Status(http.StatusCreated) } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-4 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-4 func DownloadPackageFile(ctx *context.Context) { pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeSwift, buildPackageID(ctx.Params("scope"), ctx.Params("name")), ctx.Params("version")) if err != nil { @@ -420,7 +430,7 @@ type LookupPackageIdentifiersResponse struct { Identifiers []string `json:"identifiers"` } -// https://github.com/apple/swift-package-manager/blob/main/Documentation/Registry.md#endpoint-5 +// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#endpoint-5 func LookupPackageIdentifiers(ctx *context.Context) { url := ctx.FormTrim("url") if url == "" { diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index e7dbb6d975..cab37acdd1 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "html/template" "io" "net/http" "net/url" @@ -25,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -108,16 +110,17 @@ type ViewRequest struct { type ViewResponse struct { State struct { Run struct { - Link string `json:"link"` - Title string `json:"title"` - Status string `json:"status"` - CanCancel bool `json:"canCancel"` - CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve - CanRerun bool `json:"canRerun"` - CanDeleteArtifact bool `json:"canDeleteArtifact"` - Done bool `json:"done"` - Jobs []*ViewJob `json:"jobs"` - Commit ViewCommit `json:"commit"` + Link string `json:"link"` + Title string `json:"title"` + TitleHTML template.HTML `json:"titleHTML"` + Status string `json:"status"` + CanCancel bool `json:"canCancel"` + CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve + CanRerun bool `json:"canRerun"` + CanDeleteArtifact bool `json:"canDeleteArtifact"` + Done bool `json:"done"` + Jobs []*ViewJob `json:"jobs"` + Commit ViewCommit `json:"commit"` } `json:"run"` CurrentJob struct { Title string `json:"title"` @@ -194,7 +197,10 @@ func ViewPost(ctx *context_module.Context) { resp := &ViewResponse{} + metas := ctx.Repo.Repository.ComposeMetas(ctx) + resp.State.Run.Title = run.Title + resp.State.Run.TitleHTML = templates.RenderCommitMessage(ctx, run.Title, metas) resp.State.Run.Link = run.Link() resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 878b7ee699..f4b027dae1 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -363,6 +363,7 @@ func ViewProject(ctx *context.Context) { return } + ctx.Data["Title"] = project.Title ctx.Data["IsProjectsPage"] = true ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects) ctx.Data["Project"] = project diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 1fd080021d..3d55afe294 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -6,6 +6,7 @@ package repo import ( "bytes" + gocontext "context" "fmt" "io" "net/http" @@ -598,22 +599,32 @@ func WikiPages(ctx *context.Context) { } }() - entries, err := commit.ListEntries() + treePath := "" // To support list sub folders' pages in the future + tree, err := commit.SubTree(treePath) + if err != nil { + ctx.ServerError("SubTree", err) + return + } + + allEntries, err := tree.ListEntries() if err != nil { ctx.ServerError("ListEntries", err) return } + allEntries.CustomSort(base.NaturalSortLess) + + entries, _, err := allEntries.GetCommitsInfo(gocontext.Context(ctx), commit, treePath) + if err != nil { + ctx.ServerError("GetCommitsInfo", err) + return + } + pages := make([]PageMeta, 0, len(entries)) for _, entry := range entries { - if !entry.IsRegular() { + if !entry.Entry.IsRegular() { continue } - c, err := wikiRepo.GetCommitByPath(entry.Name()) - if err != nil { - ctx.ServerError("GetCommit", err) - return - } - wikiName, err := wiki_service.GitPathToWebPath(entry.Name()) + wikiName, err := wiki_service.GitPathToWebPath(entry.Entry.Name()) if err != nil { if repo_model.IsErrWikiInvalidFileName(err) { continue @@ -625,8 +636,8 @@ func WikiPages(ctx *context.Context) { pages = append(pages, PageMeta{ Name: displayName, SubURL: wiki_service.WebPathToURLPath(wikiName), - GitEntryName: entry.Name(), - UpdatedUnix: timeutil.TimeStamp(c.Author.When.Unix()), + GitEntryName: entry.Entry.Name(), + UpdatedUnix: timeutil.TimeStamp(entry.Commit.Author.When.Unix()), }) } ctx.Data["Pages"] = pages diff --git a/tests/integration/api_packages_swift_test.go b/tests/integration/api_packages_swift_test.go index 5b6229f721..3c2a8b0694 100644 --- a/tests/integration/api_packages_swift_test.go +++ b/tests/integration/api_packages_swift_test.go @@ -43,6 +43,24 @@ func TestPackageSwift(t *testing.T) { url := fmt.Sprintf("/api/packages/%s/swift", user.Name) + t.Run("CheckLogin", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "POST", url, strings.NewReader("")) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequestWithBody(t, "POST", url, strings.NewReader("")). + AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusOK) + + req = NewRequestWithBody(t, "POST", url+"/login", strings.NewReader("")) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequestWithBody(t, "POST", url+"/login", strings.NewReader("")). + AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusOK) + }) + t.Run("CheckAcceptMediaType", func(t *testing.T) { defer tests.PrintCurrentTest(t)() diff --git a/tests/integration/git_clone_wiki_test.go b/tests/integration/wiki_test.go similarity index 66% rename from tests/integration/git_clone_wiki_test.go rename to tests/integration/wiki_test.go index df260258de..3e30b94486 100644 --- a/tests/integration/git_clone_wiki_test.go +++ b/tests/integration/wiki_test.go @@ -6,14 +6,18 @@ package integration import ( "context" "fmt" + "net/http" "net/url" "os" "path/filepath" + "strings" "testing" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/tests" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -47,3 +51,23 @@ func TestRepoCloneWiki(t *testing.T) { }) }) } + +func Test_RepoWikiPages(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + url := "/user2/repo1/wiki/?action=_pages" + req := NewRequest(t, "GET", url) + resp := MakeRequest(t, req, http.StatusOK) + + doc := NewHTMLParser(t, resp.Body) + expectedPagePaths := []string{ + "Home", "Long-Page", "Page-With-Image", "Page-With-Spaced-Name", "Unescaped-File", + } + doc.Find("tr").Each(func(i int, s *goquery.Selection) { + firstAnchor := s.Find("a").First() + href, _ := firstAnchor.Attr("href") + pagePath := strings.TrimPrefix(href, "/user2/repo1/wiki/") + + assert.EqualValues(t, expectedPagePaths[i], pagePath) + }) +} diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index b96d1f7573..941440c6f3 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -42,6 +42,7 @@ const sfc = { run: { link: '', title: '', + titleHTML: '', status: '', canCancel: false, canApprove: false, @@ -424,9 +425,8 @@ export function initRepositoryActionView() {