Compare commits

...

7 Commits

Author SHA1 Message Date
Jack Hay
e60c4c7078
Merge 8d71b733ad44bdeaaa01380906bd00151ed4bde6 into 40faa6dc78a5b5730a1609ba39daefddac08aa63 2025-02-19 15:03:27 -05:00
ericLemanissier
40faa6dc78
git graph: don't show detached commits (#33645)
Some checks failed
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-docker-rootful (push) Has been cancelled
release-nightly / nightly-docker-rootless (push) Has been cancelled
Current git graph is not usable for mirrors of repos having a lot of
PRs, as can be seen at
https://demo.gitea.com/ericLemanissier/conan-center-index/graph

![image](https://github.com/user-attachments/assets/ace40dd2-3eea-4d69-8e19-10fb7224e326)


Manually running `git log --graph --date-order --all` on such a repo
indeed shows:
```
*   commit c4a34bd39d7977c8630177c5f88507000ea3e943
|\  Merge: a4bbd3ad6b 35a102c77c
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 08:36:41 2025 +0000
| |
| |     Merge 35a102c77cbc38d84baca0ca63466fb410336ea8 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| |
| * commit 35a102c77cbc38d84baca0ca63466fb410336ea8
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 17:36:35 2025 +0900
| |
| |     update 4.4.2
| |
| | * commit 5d610f4fd3c0428731e402a2f618fad9ce055875
| |/| Merge: a4bbd3ad6b fe916fb70a
|/| | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:30 2025 +0000
| | |
| | |     Merge fe916fb70a8bf49503cce70a5c7124bcc4314ddc into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | |
| | * commit fe916fb70a8bf49503cce70a5c7124bcc4314ddc
| | | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:18 2025 +0000
| | |
| | |     Remove parquet cmakelist patch
| | |
| | | * commit 9f6d2759d650ec3c86d01bb940e829e7e14220c2
| |_|/| Merge: a4bbd3ad6b f0963429b0
|/| | | Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
| | | | Date:   Wed Feb 19 08:03:08 2025 +0100
| | | |
| | | |     Merge f0963429b0952499da0da7e559f8d53387097307 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | | |
| | | * commit f0963429b0952499da0da7e559f8d53387097307
| |_|/  Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
|/| |   Date:   Wed Feb 19 08:01:43 2025 +0100
| | |
| | |       added cwt-cucumber 2.5
| | |
```

On the other hand, running `git log --graph --date-order --branches
--tags` returns the expected:
```
* commit a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98 (HEAD -> master)
| Author: Dan <mstr.danila@gmail.com>
| Date:   Fri Feb 14 18:46:11 2025 +0200
|
|     grpc: add version 1.69.0 (#26446)
|
|     * grpc: add version 1.69.0
|
|     * add cmake tool requires
|
|     ---------
|
|     Co-authored-by: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
|
* commit a7868807cb2e21206ebf95278cb588f29a3e2205
| Author: Guillaume Egles <gegles@users.noreply.github.com>
| Date:   Thu Feb 13 05:44:35 2025 -0800
|
|     openssl: add versions `3.0.16`, `3.1.8`, `3.2.4`, `3.3.3`, `3.4.1`, stop publishing revisions for version `3.0.15` (#26578)
|
* commit 86057d3e63ac71e2fe48c07bb301f2d54187044d
| Author: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
| Date:   Thu Feb 13 13:34:41 2025 +0000
|
|     android-ndk: dont set LD and AS variables (#26581)
|
|     * android-ndk: dont set LD and AS variables
|
|     * android-ndk: refactor test package
|
* commit 123e382fafd2f5e811e10faac02efc275c45ec2a
| Author: Nikita <root.kidik@gmail.com>
| Date:   Thu Feb 13 12:29:39 2025 +0300
|
|     libffi: fix conditionals when building on Windows (#26500)
|
|     * fix: add missing or `clang`
|
|     * fix: libffi - always require as tool `automake`
```
2025-02-19 10:35:08 -08:00
wxiaoguang
c2e23d3301
Fix PR web route permission check (#33636)
Some checks are pending
release-nightly / nightly-binary (push) Waiting to run
release-nightly / nightly-docker-rootful (push) Waiting to run
release-nightly / nightly-docker-rootless (push) Waiting to run
See the FIXME comment in code. Otherwise, if a repo's issue unit is
disabled, then the PRs can't be edited anymore.

By the way, make the permission log output look slightly better.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: metiftikci <metiftikci@hotmail.com>
2025-02-19 00:55:19 +00:00
metiftikci
84d2159ef6
fix: add missing locale (#33641)
this removed in #23113 but still using in `head_navbar.tmpl`
2025-02-18 16:29:17 -08:00
jackHay22
8d71b733ad fix lints 2025-01-17 13:50:11 -05:00
jackHay22
12e3e0b3ad fixes 2025-01-17 13:14:37 -05:00
jackHay22
a5035eadba warn if release uses old tag 2025-01-17 10:47:18 -05:00
10 changed files with 152 additions and 23 deletions

View File

@ -152,7 +152,7 @@ func (p *Permission) ReadableUnitTypes() []unit.Type {
} }
func (p *Permission) LogString() string { func (p *Permission) LogString() string {
format := "<Permission AccessMode=%s, %d Units, %d UnitsMode(s): [ " format := "<Permission AccessMode=%s, %d Units, %d UnitsMode(s): ["
args := []any{p.AccessMode.ToString(), len(p.units), len(p.unitsMode)} args := []any{p.AccessMode.ToString(), len(p.units), len(p.unitsMode)}
for i, u := range p.units { for i, u := range p.units {
@ -164,14 +164,16 @@ func (p *Permission) LogString() string {
config = err.Error() config = err.Error()
} }
} }
format += "\nUnits[%d]: ID: %d RepoID: %d Type: %s Config: %s" format += "\n\tunits[%d]: ID=%d RepoID=%d Type=%s Config=%s"
args = append(args, i, u.ID, u.RepoID, u.Type.LogString(), config) args = append(args, i, u.ID, u.RepoID, u.Type.LogString(), config)
} }
for key, value := range p.unitsMode { for key, value := range p.unitsMode {
format += "\nUnitMode[%-v]: %-v" format += "\n\tunitsMode[%-v]: %-v"
args = append(args, key.LogString(), value.LogString()) args = append(args, key.LogString(), value.LogString())
} }
format += " ]>" format += "\n\teveryoneAccessMode: %-v"
args = append(args, p.everyoneAccessMode)
format += "\n\t]>"
return fmt.Sprintf(format, args...) return fmt.Sprintf(format, args...)
} }

View File

@ -298,6 +298,26 @@ func GetTagNamesByRepoID(ctx context.Context, repoID int64) ([]string, error) {
return tags, sess.Find(&tags) return tags, sess.Find(&tags)
} }
// GetTagMappingsByRepoID returns a mapping from tag name to commit SHA by repo id
func GetTagMappingsByRepoID(ctx context.Context, repoID int64) (map[string]string, error) {
mapping := make(map[string]string)
rels := make([]*Release, 0)
if err := db.GetEngine(ctx).
Desc("created_unix").
Find(&rels, Release{RepoID: repoID}); err != nil {
return mapping, err
}
for _, r := range rels {
mapping[r.TagName] = r.Sha1
}
return mapping, nil
}
// CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID.
func CountReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) {
return db.GetEngine(ctx).Where(opts.ToConds()).Count(new(Release))
}
// GetLatestReleaseByRepoID returns the latest release for a repository // GetLatestReleaseByRepoID returns the latest release for a repository
func GetLatestReleaseByRepoID(ctx context.Context, repoID int64) (*Release, error) { func GetLatestReleaseByRepoID(ctx context.Context, repoID int64) (*Release, error) {
cond := builder.NewCond(). cond := builder.NewCond().

View File

@ -5,6 +5,7 @@ package log
import ( import (
"context" "context"
"reflect"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
@ -175,6 +176,20 @@ func (l *LoggerImpl) IsEnabled() bool {
return l.level.Load() < int32(FATAL) && len(l.eventWriters) > 0 return l.level.Load() < int32(FATAL) && len(l.eventWriters) > 0
} }
func asLogStringer(v any) LogStringer {
if s, ok := v.(LogStringer); ok {
return s
} else if a := reflect.ValueOf(v); a.Kind() == reflect.Struct {
// in case the receiver is a pointer, but the value is a struct
vp := reflect.New(a.Type())
vp.Elem().Set(a)
if s, ok := vp.Interface().(LogStringer); ok {
return s
}
}
return nil
}
// Log prepares the log event, if the level matches, the event will be sent to the writers // Log prepares the log event, if the level matches, the event will be sent to the writers
func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) { func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) {
if Level(l.level.Load()) > level { if Level(l.level.Load()) > level {
@ -207,11 +222,11 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) {
// handle LogStringer values // handle LogStringer values
for i, v := range msgArgs { for i, v := range msgArgs {
if cv, ok := v.(*ColoredValue); ok { if cv, ok := v.(*ColoredValue); ok {
if s, ok := cv.v.(LogStringer); ok { if ls := asLogStringer(cv.v); ls != nil {
cv.v = logStringFormatter{v: s} cv.v = logStringFormatter{v: ls}
} }
} else if s, ok := v.(LogStringer); ok { } else if ls := asLogStringer(v); ls != nil {
msgArgs[i] = logStringFormatter{v: s} msgArgs[i] = logStringFormatter{v: ls}
} }
} }

View File

@ -116,6 +116,14 @@ func (t testLogString) LogString() string {
return "log-string" return "log-string"
} }
type testLogStringPtrReceiver struct {
Field string
}
func (t *testLogStringPtrReceiver) LogString() string {
return "log-string-ptr-receiver"
}
func TestLoggerLogString(t *testing.T) { func TestLoggerLogString(t *testing.T) {
logger := NewLoggerWithWriters(context.Background(), "test") logger := NewLoggerWithWriters(context.Background(), "test")
@ -124,9 +132,13 @@ func TestLoggerLogString(t *testing.T) {
logger.AddWriters(w1) logger.AddWriters(w1)
logger.Info("%s %s %#v %v", testLogString{}, &testLogString{}, testLogString{Field: "detail"}, NewColoredValue(testLogString{}, FgRed)) logger.Info("%s %s %#v %v", testLogString{}, &testLogString{}, testLogString{Field: "detail"}, NewColoredValue(testLogString{}, FgRed))
logger.Info("%s %s %#v %v", testLogStringPtrReceiver{}, &testLogStringPtrReceiver{}, testLogStringPtrReceiver{Field: "detail"}, NewColoredValue(testLogStringPtrReceiver{}, FgRed))
logger.Close() logger.Close()
assert.Equal(t, []string{"log-string log-string log.testLogString{Field:\"detail\"} \x1b[31mlog-string\x1b[0m\n"}, w1.GetLogs()) assert.Equal(t, []string{
"log-string log-string log.testLogString{Field:\"detail\"} \x1b[31mlog-string\x1b[0m\n",
"log-string-ptr-receiver log-string-ptr-receiver &log.testLogStringPtrReceiver{Field:\"detail\"} \x1b[31mlog-string-ptr-receiver\x1b[0m\n",
}, w1.GetLogs())
} }
func TestLoggerExpressionFilter(t *testing.T) { func TestLoggerExpressionFilter(t *testing.T) {

View File

@ -1702,7 +1702,9 @@ issues.time_estimate_invalid = Time estimate format is invalid
issues.start_tracking_history = started working %s issues.start_tracking_history = started working %s
issues.tracker_auto_close = Timer will be stopped automatically when this issue gets closed issues.tracker_auto_close = Timer will be stopped automatically when this issue gets closed
issues.tracking_already_started = `You have already started time tracking on <a href="%s">another issue</a>!` issues.tracking_already_started = `You have already started time tracking on <a href="%s">another issue</a>!`
issues.stop_tracking = Stop Timer
issues.stop_tracking_history = worked for <b>%[1]s</b> %[2]s issues.stop_tracking_history = worked for <b>%[1]s</b> %[2]s
issues.cancel_tracking = Discard
issues.cancel_tracking_history = `canceled time tracking %s` issues.cancel_tracking_history = `canceled time tracking %s`
issues.del_time = Delete this time log issues.del_time = Delete this time log
issues.add_time_history = added spent time <b>%[1]s</b> %[2]s issues.add_time_history = added spent time <b>%[1]s</b> %[2]s
@ -2692,6 +2694,12 @@ release.add_tag_msg = Use the title and content of release as tag message.
release.add_tag = Create Tag Only release.add_tag = Create Tag Only
release.releases_for = Releases for %s release.releases_for = Releases for %s
release.tags_for = Tags for %s release.tags_for = Tags for %s
release.existing_tag_header = New release with an old tag
release.existing_tag_draft_header = Draft release with an old tag
release.existing_tag = You are about to create a new release with an <b>existing tag</b>. Make sure that the tag is pointing to the right commit.
release.existing_draft_tag = You are about to create a draft release with an <b>existing tag</b>. Make sure that the tag is pointing to the right commit.
release.create_confirmation = Do you want to continue with the release creation?
release.create_draft_confirmation = Do you want to continue with the release draft creation?
branch.name = Branch Name branch.name = Branch Name
branch.already_exists = A branch named "%s" already exists. branch.already_exists = A branch named "%s" already exists.

View File

@ -330,9 +330,9 @@ func newReleaseCommon(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.new_release") ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["PageIsReleaseList"] = true ctx.Data["PageIsReleaseList"] = true
tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) tags, err := repo_model.GetTagMappingsByRepoID(ctx, ctx.Repo.Repository.ID)
if err != nil { if err != nil {
ctx.ServerError("GetTagNamesByRepoID", err) ctx.ServerError("GetTagMappingsByRepoID", err)
return return
} }
ctx.Data["Tags"] = tags ctx.Data["Tags"] = tags

View File

@ -1196,6 +1196,10 @@ func registerRoutes(m *web.Router) {
}) })
}) })
} }
// FIXME: many "pulls" requests are sent to "issues" endpoints correctly, so the issue endpoints have to tolerate pull request permissions at the moment
m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests))
m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader)
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
m.Get("/comments/{id}/attachments", repo.GetCommentAttachments) m.Get("/comments/{id}/attachments", repo.GetCommentAttachments)
m.Get("/labels", repo.RetrieveLabelsForList, repo.Labels) m.Get("/labels", repo.RetrieveLabelsForList, repo.Labels)
@ -1203,9 +1207,6 @@ func registerRoutes(m *web.Router) {
m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls) m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls)
m.Get("/issues/suggestions", repo.IssueSuggestions) m.Get("/issues/suggestions", repo.IssueSuggestions)
}, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones }, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones
m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitIssuesReader)
m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader)
// end "/{username}/{reponame}": view milestone, label, issue, pull, etc // end "/{username}/{reponame}": view milestone, label, issue, pull, etc
m.Group("/{username}/{reponame}/{type:issues}", func() { m.Group("/{username}/{reponame}/{type:issues}", func() {
@ -1224,7 +1225,7 @@ func registerRoutes(m *web.Router) {
m.Get("/search", repo.SearchRepoIssuesJSON) m.Get("/search", repo.SearchRepoIssuesJSON)
}, reqUnitIssuesReader) }, reqUnitIssuesReader)
addIssuesPullsRoutes := func() { addIssuesPullsUpdateRoutes := func() {
// for "/{username}/{reponame}/issues" or "/{username}/{reponame}/pulls" // for "/{username}/{reponame}/issues" or "/{username}/{reponame}/pulls"
m.Group("/{index}", func() { m.Group("/{index}", func() {
m.Post("/title", repo.UpdateIssueTitle) m.Post("/title", repo.UpdateIssueTitle)
@ -1267,8 +1268,9 @@ func registerRoutes(m *web.Router) {
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin) m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove) m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
} }
m.Group("/{type:issues}", addIssuesPullsRoutes, reqUnitIssuesReader, context.RepoMustNotBeArchived()) // FIXME: many "pulls" requests are sent to "issues" endpoints incorrectly, so the issue endpoints have to tolerate pull request permissions at the moment
m.Group("/{type:pulls}", addIssuesPullsRoutes, reqUnitPullsReader, context.RepoMustNotBeArchived()) m.Group("/{type:issues}", addIssuesPullsUpdateRoutes, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests), context.RepoMustNotBeArchived())
m.Group("/{type:pulls}", addIssuesPullsUpdateRoutes, reqUnitPullsReader, context.RepoMustNotBeArchived())
m.Group("/comments/{id}", func() { m.Group("/comments/{id}", func() {
m.Post("", repo.UpdateCommentContent) m.Post("", repo.UpdateCommentContent)
@ -1292,7 +1294,7 @@ func registerRoutes(m *web.Router) {
m.Post("/delete", repo.DeleteMilestone) m.Post("/delete", repo.DeleteMilestone)
}, reqRepoIssuesOrPullsWriter, context.RepoRef()) }, reqRepoIssuesOrPullsWriter, context.RepoRef())
// FIXME: need to move these routes to the proper place // FIXME: many "pulls" requests are sent to "issues" endpoints incorrectly, need to move these routes to the proper place
m.Group("/issues", func() { m.Group("/issues", func() {
m.Post("/request_review", repo.UpdatePullReviewRequest) m.Post("/request_review", repo.UpdatePullReviewRequest)
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview) m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)

View File

@ -29,7 +29,7 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
} }
if len(branches) == 0 { if len(branches) == 0 {
graphCmd.AddArguments("--all") graphCmd.AddArguments("--tags", "--branches")
} }
graphCmd.AddArguments("-C", "-M", "--date=iso-strict"). graphCmd.AddArguments("-C", "-M", "--date=iso-strict").

View File

@ -38,6 +38,9 @@
</div> </div>
</div> </div>
</div> </div>
<div id="tag-warning" class="gt-dib gt-hidden" data-commit-url-stub="{{.RepoLink}}/commit">
{{svg "octicon-alert-fill" 16}} Existing tag referencing <span class="gt-px-3">{{svg "octicon-git-commit" 16}} <a target="_blank" rel="noopener noreferrer" class="tag-warning-detail"></a></span>
</div>
<div> <div>
<span id="tag-helper" class="help tw-mt-2 tw-pb-0">{{ctx.Locale.Tr "repo.release.tag_helper"}}</span> <span id="tag-helper" class="help tw-mt-2 tw-pb-0">{{ctx.Locale.Tr "repo.release.tag_helper"}}</span>
</div> </div>
@ -118,8 +121,8 @@
{{if .ShowCreateTagOnlyButton}} {{if .ShowCreateTagOnlyButton}}
<button class="ui small button" name="tag_only" value="1">{{ctx.Locale.Tr "repo.release.add_tag"}}</button> <button class="ui small button" name="tag_only" value="1">{{ctx.Locale.Tr "repo.release.add_tag"}}</button>
{{end}} {{end}}
<button class="ui small button" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button> <button class="ui small button tag-confirm tag-draft" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
<button class="ui small primary button">{{ctx.Locale.Tr "repo.release.publish"}}</button> <button class="ui small primary button tag-confirm">{{ctx.Locale.Tr "repo.release.publish"}}</button>
{{end}} {{end}}
</div> </div>
</div> </div>
@ -128,6 +131,29 @@
</div> </div>
</div> </div>
<div id="tag-confirm-modal" class="ui g-modal-confirm modal">
<div class="header">
{{ctx.Locale.Tr "repo.release.existing_tag_header"}}
</div>
<div class="content">
<p>{{svg "octicon-alert-fill" 16}} Existing tag referencing <span class="gt-px-3">{{svg "octicon-git-commit" 16}} <a target="_blank" rel="noopener noreferrer" class="tag-warning-detail"></a></span></p>
<p>{{ctx.Locale.Tr "repo.release.existing_tag"}}</p>
<p>{{ctx.Locale.Tr "repo.release.create_confirmation"}}</p>
</div>
{{template "base/modal_actions_confirm" .}}
</div>
<div id="tag-confirm-draft-modal" class="ui g-modal-confirm modal">
<div class="header">
{{ctx.Locale.Tr "repo.release.existing_tag_draft_header"}}
</div>
<div class="content">
<p>{{svg "octicon-alert-fill" 16}} Existing tag referencing <span class="gt-px-3">{{svg "octicon-git-commit" 16}} <a target="_blank" rel="noopener noreferrer" class="tag-warning-detail"></a></span></p>
<p>{{ctx.Locale.Tr "repo.release.existing_draft_tag"}}</p>
<p>{{ctx.Locale.Tr "repo.release.create_draft_confirmation"}}</p>
</div>
{{template "base/modal_actions_confirm" .}}
</div>
{{if .PageIsEditRelease}} {{if .PageIsEditRelease}}
<div class="ui g-modal-confirm delete modal"> <div class="ui g-modal-confirm delete modal">
<div class="header"> <div class="header">

View File

@ -1,4 +1,6 @@
import $ from 'jquery';
import {hideElem, showElem, type DOMEvent} from '../utils/dom.ts'; import {hideElem, showElem, type DOMEvent} from '../utils/dom.ts';
import {fomanticQuery} from '../modules/fomantic/base.ts';
export function initRepoRelease() { export function initRepoRelease() {
document.addEventListener('click', (e: DOMEvent<MouseEvent>) => { document.addEventListener('click', (e: DOMEvent<MouseEvent>) => {
@ -21,24 +23,66 @@ function initTagNameEditor() {
const el = document.querySelector('#tag-name-editor'); const el = document.querySelector('#tag-name-editor');
if (!el) return; if (!el) return;
const tagWarning = document.querySelector('#tag-warning');
const tagWarningDetailLinks = Array.from(document.querySelectorAll('.tag-warning-detail'));
const existingTags = JSON.parse(el.getAttribute('data-existing-tags')); const existingTags = JSON.parse(el.getAttribute('data-existing-tags'));
if (!Array.isArray(existingTags)) return;
const defaultTagHelperText = el.getAttribute('data-tag-helper'); const defaultTagHelperText = el.getAttribute('data-tag-helper');
const newTagHelperText = el.getAttribute('data-tag-helper-new'); const newTagHelperText = el.getAttribute('data-tag-helper-new');
const existingTagHelperText = el.getAttribute('data-tag-helper-existing'); const existingTagHelperText = el.getAttribute('data-tag-helper-existing');
const tagURLStub = tagWarning.getAttribute('data-commit-url-stub');
const tagConfirmDraftModal = document.querySelector('#tag-confirm-draft-modal');
const tagConfirmModal = document.querySelector('#tag-confirm-modal');
// show the confirmation modal if release is using an existing tag
let requiresConfirmation = false;
$('.tag-confirm').on('click', (event) => {
if (requiresConfirmation) {
event.preventDefault();
const form = event.target.closest('form');
if (event.target.classList.contains('tag-draft')) {
fomanticQuery(tagConfirmDraftModal).modal({
onApprove() {
// need to add hidden input with draft form value
// (triggering form submission doesn't include the button data)
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'draft';
input.value = '1';
form.append(input);
$(form).trigger('submit');
},
}).modal('show');
} else {
fomanticQuery(tagConfirmModal).modal({
onApprove() {
$(form).trigger('submit');
},
}).modal('show');
}
}
});
const tagNameInput = document.querySelector<HTMLInputElement>('#tag-name'); const tagNameInput = document.querySelector<HTMLInputElement>('#tag-name');
const hideTargetInput = function(tagNameInput: HTMLInputElement) { const hideTargetInput = function(tagNameInput: HTMLInputElement) {
const value = tagNameInput.value; const value = tagNameInput.value;
const tagHelper = document.querySelector('#tag-helper'); const tagHelper = document.querySelector('#tag-helper');
if (existingTags.includes(value)) { if (value in existingTags) {
// If the tag already exists, hide the target branch selector. // If the tag already exists, hide the target branch selector.
hideElem('#tag-target-selector'); hideElem('#tag-target-selector');
tagHelper.textContent = existingTagHelperText; tagHelper.textContent = existingTagHelperText;
showElem('#tag-warning');
for (const detail of tagWarningDetailLinks) {
const anchor = detail as HTMLAnchorElement;
anchor.href = `${tagURLStub}/${existingTags[value]}`;
anchor.textContent = existingTags[value].substring(0, 10);
}
requiresConfirmation = true;
} else { } else {
showElem('#tag-target-selector'); showElem('#tag-target-selector');
tagHelper.textContent = value ? newTagHelperText : defaultTagHelperText; tagHelper.textContent = value ? newTagHelperText : defaultTagHelperText;
hideElem('#tag-warning');
requiresConfirmation = false;
} }
}; };
hideTargetInput(tagNameInput); // update on page load because the input may have a value hideTargetInput(tagNameInput); // update on page load because the input may have a value