From 013cc1dee430b45ac06adab1c7a05c6b51c9fe3a Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Mon, 4 Nov 2024 23:13:52 -0800
Subject: [PATCH 1/4] Only query team tables if repository is under org when
 getting assignees (#32414)

It's unnecessary to query the team table if the repository is not under
organization when getting assignees.

(cherry picked from commit 1887c75c35c1d16372b1dbe2b792e374b558ce1f)
---
 models/repo/user_repo.go | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go
index 6790ee1da9..781a75730a 100644
--- a/models/repo/user_repo.go
+++ b/models/repo/user_repo.go
@@ -75,26 +75,28 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
 		return nil, err
 	}
 
-	additionalUserIDs := make([]int64, 0, 10)
-	if err = e.Table("team_user").
-		Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
-		Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
-		Where("`team_repo`.repo_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))",
-			repo.ID, perm.AccessModeWrite, perm.AccessModeRead, unit.TypePullRequests).
-		Distinct("`team_user`.uid").
-		Select("`team_user`.uid").
-		Find(&additionalUserIDs); err != nil {
-		return nil, err
-	}
-
 	uniqueUserIDs := make(container.Set[int64])
 	uniqueUserIDs.AddMultiple(userIDs...)
-	uniqueUserIDs.AddMultiple(additionalUserIDs...)
+
+	if repo.Owner.IsOrganization() {
+		additionalUserIDs := make([]int64, 0, 10)
+		if err = e.Table("team_user").
+			Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
+			Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
+			Where("`team_repo`.repo_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))",
+				repo.ID, perm.AccessModeWrite, perm.AccessModeRead, unit.TypePullRequests).
+			Distinct("`team_user`.uid").
+			Select("`team_user`.uid").
+			Find(&additionalUserIDs); err != nil {
+			return nil, err
+		}
+		uniqueUserIDs.AddMultiple(additionalUserIDs...)
+	}
 
 	// Leave a seat for owner itself to append later, but if owner is an organization
 	// and just waste 1 unit is cheaper than re-allocate memory once.
 	users := make([]*user_model.User, 0, len(uniqueUserIDs)+1)
-	if len(userIDs) > 0 {
+	if len(uniqueUserIDs) > 0 {
 		if err = e.In("id", uniqueUserIDs.Values()).
 			Where(builder.Eq{"`user`.is_active": true}).
 			OrderBy(user_model.GetOrderByName()).

From fc26becba4b08877a726f2e7e453992310245fe5 Mon Sep 17 00:00:00 2001
From: Zettat123 <zettat123@gmail.com>
Date: Fri, 8 Nov 2024 10:53:06 +0800
Subject: [PATCH 2/4] Fix broken releases when re-pushing tags (#32435)

Fix #32427

(cherry picked from commit 35bcd667b23de29a7b0d0bf1090fb10961d3aca3)

Conflicts:
	- tests/integration/repo_tag_test.go
	  Resolved by manually copying the added test, and also manually
	  adjusting the imported Go modules.
---
 services/repository/push.go        | 19 +++++++-----
 tests/integration/repo_tag_test.go | 47 ++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/services/repository/push.go b/services/repository/push.go
index 0f24295e89..a8e7d0f3b6 100644
--- a/services/repository/push.go
+++ b/services/repository/push.go
@@ -307,9 +307,10 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
 	}
 
 	releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
-		RepoID:      repo.ID,
-		TagNames:    tags,
-		IncludeTags: true,
+		RepoID:        repo.ID,
+		TagNames:      tags,
+		IncludeDrafts: true,
+		IncludeTags:   true,
 	})
 	if err != nil {
 		return fmt.Errorf("db.Find[repo_model.Release]: %w", err)
@@ -394,13 +395,17 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
 			}
 			newReleases = append(newReleases, rel)
 		} else {
-			rel.Title = parts[0]
-			rel.Note = note
 			rel.Sha1 = commit.ID.String()
 			rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix())
 			rel.NumCommits = commitsCount
-			if rel.IsTag && author != nil {
-				rel.PublisherID = author.ID
+			if rel.IsTag {
+				rel.Title = parts[0]
+				rel.Note = note
+				if author != nil {
+					rel.PublisherID = author.ID
+				}
+			} else {
+				rel.IsDraft = false
 			}
 			if err = repo_model.UpdateRelease(ctx, rel); err != nil {
 				return fmt.Errorf("Update: %w", err)
diff --git a/tests/integration/repo_tag_test.go b/tests/integration/repo_tag_test.go
index 06b6c30383..cb2d0964f0 100644
--- a/tests/integration/repo_tag_test.go
+++ b/tests/integration/repo_tag_test.go
@@ -5,17 +5,20 @@
 package integration
 
 import (
+	"fmt"
 	"net/http"
 	"net/url"
 	"strings"
 	"testing"
 
 	"code.gitea.io/gitea/models"
+	auth_model "code.gitea.io/gitea/models/auth"
 	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unittest"
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/git"
 	repo_module "code.gitea.io/gitea/modules/repository"
+	api "code.gitea.io/gitea/modules/structs"
 	"code.gitea.io/gitea/services/release"
 	"code.gitea.io/gitea/tests"
 
@@ -159,3 +162,47 @@ func TestSyncRepoTags(t *testing.T) {
 		})
 	})
 }
+
+func TestRepushTag(t *testing.T) {
+	onGiteaRun(t, func(t *testing.T, u *url.URL) {
+		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+		owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+		session := loginUser(t, owner.LowerName)
+		token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+		httpContext := NewAPITestContext(t, owner.Name, repo.Name)
+
+		dstPath := t.TempDir()
+
+		u.Path = httpContext.GitPath()
+		u.User = url.UserPassword(owner.Name, userPassword)
+
+		doGitClone(dstPath, u)(t)
+
+		// create and push a tag
+		_, _, err := git.NewCommand(git.DefaultContext, "tag", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+		require.NoError(t, err)
+		_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "--tags", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+		require.NoError(t, err)
+		// create a release for the tag
+		createdRelease := createNewReleaseUsingAPI(t, token, owner, repo, "v2.0", "", "Release of v2.0", "desc")
+		assert.False(t, createdRelease.IsDraft)
+		// delete the tag
+		_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "--delete", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+		require.NoError(t, err)
+		// query the release by API and it should be a draft
+		req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s", owner.Name, repo.Name, "v2.0"))
+		resp := MakeRequest(t, req, http.StatusOK)
+		var respRelease *api.Release
+		DecodeJSON(t, resp, &respRelease)
+		assert.True(t, respRelease.IsDraft)
+		// re-push the tag
+		_, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "--tags", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+		require.NoError(t, err)
+		// query the release by API and it should not be a draft
+		req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s", owner.Name, repo.Name, "v2.0"))
+		resp = MakeRequest(t, req, http.StatusOK)
+		DecodeJSON(t, resp, &respRelease)
+		assert.False(t, respRelease.IsDraft)
+	})
+}

From 308812a82ec6b0a372e0881bb786d2dc8cff3919 Mon Sep 17 00:00:00 2001
From: silverwind <me@silverwind.io>
Date: Sat, 9 Nov 2024 19:03:55 +0100
Subject: [PATCH 3/4] Fix mermaid diagram height when initially hidden (#32457)

In a hidden iframe, `document.body.clientHeight` is not reliable. Use
`IntersectionObserver` to detect the visibility change and update the
height there.

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

<img width="885" alt="image"
src="https://github.com/user-attachments/assets/a95ef6aa-27e7-443f-9d06-400ef27919ae">

(cherry picked from commit b55a31eb6a894feb5508e350ff5e9548b2531bd6)
---
 web_src/js/markup/mermaid.js | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/web_src/js/markup/mermaid.js b/web_src/js/markup/mermaid.js
index 0549fb3e31..e420ff12a2 100644
--- a/web_src/js/markup/mermaid.js
+++ b/web_src/js/markup/mermaid.js
@@ -56,10 +56,21 @@ export async function renderMermaid() {
       btn.setAttribute('data-clipboard-text', source);
       mermaidBlock.append(btn);
 
+      const updateIframeHeight = () => {
+        iframe.style.height = `${iframe.contentWindow.document.body.clientHeight}px`;
+      };
+
+      // update height when element's visibility state changes, for example when the diagram is inside
+      // a <details> + <summary> block and the <details> block becomes visible upon user interaction, it
+      // would initially set a incorrect height and the correct height is set during this callback.
+      (new IntersectionObserver(() => {
+        updateIframeHeight();
+      }, {root: document.documentElement})).observe(iframe);
+
       iframe.addEventListener('load', () => {
         pre.replaceWith(mermaidBlock);
         mermaidBlock.classList.remove('tw-hidden');
-        iframe.style.height = `${iframe.contentWindow.document.body.clientHeight}px`;
+        updateIframeHeight();
         setTimeout(() => { // avoid flash of iframe background
           mermaidBlock.classList.remove('is-loading');
           iframe.classList.remove('tw-invisible');

From 969a6ab24a800e8446b6222d3fd6466538e11bb5 Mon Sep 17 00:00:00 2001
From: Earl Warren <contact@earl-warren.org>
Date: Sat, 16 Nov 2024 15:25:37 +0100
Subject: [PATCH 4/4] chore(release-notes): notes for the week 2024-46 weekly
 cherry pick

---
 release-notes/5988.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 release-notes/5988.md

diff --git a/release-notes/5988.md b/release-notes/5988.md
new file mode 100644
index 0000000000..52add6347e
--- /dev/null
+++ b/release-notes/5988.md
@@ -0,0 +1 @@
+fix: [commit](https://codeberg.org/forgejo/forgejo/commit/fc26becba4b08877a726f2e7e453992310245fe5) when a tag was removed and a release existed for that tag, it would be broken. The release is no longer broken the tag can be added again.