Skip to content

Commit a5035ea

Browse files
author
jackHay22
committed
warn if release uses old tag
1 parent 3b839f8 commit a5035ea

File tree

5 files changed

+99
-5
lines changed

5 files changed

+99
-5
lines changed

models/repo/release.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,26 @@ func GetTagNamesByRepoID(ctx context.Context, repoID int64) ([]string, error) {
298298
return tags, sess.Find(&tags)
299299
}
300300

301+
// GetTagMappingsByRepoID returns a mapping from tag name to commit SHA by repo id
302+
func GetTagMappingsByRepoID(ctx context.Context, repoID int64) (map[string]string, error) {
303+
mapping := make(map[string]string)
304+
rels := make([]*Release, 0)
305+
if err := db.GetEngine(ctx).
306+
Desc("created_unix").
307+
Find(&rels, Release{RepoID: repoID}); err != nil {
308+
return mapping, err
309+
}
310+
for _, r := range rels {
311+
mapping[r.TagName] = r.Sha1
312+
}
313+
return mapping, nil
314+
}
315+
316+
// CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID.
317+
func CountReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) {
318+
return db.GetEngine(ctx).Where(opts.ToConds()).Count(new(Release))
319+
}
320+
301321
// GetLatestReleaseByRepoID returns the latest release for a repository
302322
func GetLatestReleaseByRepoID(ctx context.Context, repoID int64) (*Release, error) {
303323
cond := builder.NewCond().

options/locale/locale_en-US.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,6 +2679,12 @@ release.add_tag_msg = Use the title and content of release as tag message.
26792679
release.add_tag = Create Tag Only
26802680
release.releases_for = Releases for %s
26812681
release.tags_for = Tags for %s
2682+
release.existing_tag_header = New release with an old tag
2683+
release.existing_tag_draft_header = Draft release with an old tag
2684+
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.
2685+
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.
2686+
release.create_confirmation = Do you want to continue with the release creation?
2687+
release.create_draft_confirmation = Do you want to continue with the release draft creation?
26822688
26832689
branch.name = Branch Name
26842690
branch.already_exists = A branch named "%s" already exists.

routers/web/repo/release.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,9 @@ func newReleaseCommon(ctx *context.Context) {
330330
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
331331
ctx.Data["PageIsReleaseList"] = true
332332

333-
tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
333+
tags, err := repo_model.GetTagMappingsByRepoID(ctx, ctx.Repo.Repository.ID)
334334
if err != nil {
335-
ctx.ServerError("GetTagNamesByRepoID", err)
335+
ctx.ServerError("GetTagMappingsByRepoID", err)
336336
return
337337
}
338338
ctx.Data["Tags"] = tags

templates/repo/release/new.tmpl

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
</div>
3939
</div>
4040
</div>
41+
<div id="tag-warning" class="gt-dib gt-hidden" data-commit-url-stub="{{.RepoLink}}/commit">
42+
{{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>
43+
</div>
4144
<div>
4245
<span id="tag-helper" class="help tw-mt-2 tw-pb-0">{{ctx.Locale.Tr "repo.release.tag_helper"}}</span>
4346
</div>
@@ -118,8 +121,8 @@
118121
{{if .ShowCreateTagOnlyButton}}
119122
<button class="ui small button" name="tag_only" value="1">{{ctx.Locale.Tr "repo.release.add_tag"}}</button>
120123
{{end}}
121-
<button class="ui small button" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
122-
<button class="ui small primary button">{{ctx.Locale.Tr "repo.release.publish"}}</button>
124+
<button class="ui small button tag-confirm tag-draft" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
125+
<button class="ui small primary button tag-confirm">{{ctx.Locale.Tr "repo.release.publish"}}</button>
123126
{{end}}
124127
</div>
125128
</div>
@@ -128,6 +131,29 @@
128131
</div>
129132
</div>
130133

134+
<div id="tag-confirm-modal" class="ui g-modal-confirm modal">
135+
<div class="header">
136+
{{ctx.Locale.Tr "repo.release.existing_tag_header"}}
137+
</div>
138+
<div class="content">
139+
<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>
140+
<p>{{ctx.Locale.Tr "repo.release.existing_tag"}}</p>
141+
<p>{{ctx.Locale.Tr "repo.release.create_confirmation"}}</p>
142+
</div>
143+
{{template "base/modal_actions_confirm" .}}
144+
</div>
145+
<div id="tag-confirm-draft-modal" class="ui g-modal-confirm modal">
146+
<div class="header">
147+
{{ctx.Locale.Tr "repo.release.existing_tag_draft_header"}}
148+
</div>
149+
<div class="content">
150+
<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>
151+
<p>{{ctx.Locale.Tr "repo.release.existing_draft_tag"}}</p>
152+
<p>{{ctx.Locale.Tr "repo.release.create_draft_confirmation"}}</p>
153+
</div>
154+
{{template "base/modal_actions_confirm" .}}
155+
</div>
156+
131157
{{if .PageIsEditRelease}}
132158
<div class="ui g-modal-confirm delete modal">
133159
<div class="header">

web_src/js/features/repo-release.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {hideElem, showElem, type DOMEvent} from '../utils/dom.ts';
2+
import {fomanticQuery} from "../modules/fomantic/base";
23

34
export function initRepoRelease() {
45
document.addEventListener('click', (e: DOMEvent<MouseEvent>) => {
@@ -21,24 +22,65 @@ function initTagNameEditor() {
2122
const el = document.querySelector('#tag-name-editor');
2223
if (!el) return;
2324

25+
const tagWarning = document.querySelector('#tag-warning');
26+
const tagWarningDetailLinks = Array.from(document.getElementsByClassName('tag-warning-detail'));
2427
const existingTags = JSON.parse(el.getAttribute('data-existing-tags'));
2528
if (!Array.isArray(existingTags)) return;
2629

2730
const defaultTagHelperText = el.getAttribute('data-tag-helper');
2831
const newTagHelperText = el.getAttribute('data-tag-helper-new');
2932
const existingTagHelperText = el.getAttribute('data-tag-helper-existing');
33+
const tagURLStub = tagWarning.getAttribute('data-commit-url-stub');
34+
const tagConfirmDraftModal = document.querySelector('#tag-confirm-draft-modal');
35+
const tagConfirmModal = document.querySelector('#tag-confirm-modal');
36+
37+
// show the confirmation modal if release is using an existing tag
38+
let requiresConfirmation = false;
39+
$('.tag-confirm').on('click', (event) => {
40+
if (requiresConfirmation) {
41+
event.preventDefault();
42+
if ($(event.target).hasClass('tag-draft')) {
43+
fomanticQuery(tagConfirmDraftModal).modal({
44+
onApprove() {
45+
// need to add hidden input with draft form value
46+
// (triggering form submission doesn't include the button data)
47+
$('<input>').attr({
48+
type: 'hidden',
49+
name: 'draft',
50+
value: '1'
51+
}).appendTo(event.target.form);
52+
$(event.target.form).trigger('submit');
53+
},
54+
}).modal('show');
55+
} else {
56+
fomanticQuery(tagConfirmModal).modal({
57+
onApprove() {
58+
$(event.target.form).trigger('submit');
59+
},
60+
}).modal('show');
61+
}
62+
}
63+
});
3064

3165
const tagNameInput = document.querySelector<HTMLInputElement>('#tag-name');
3266
const hideTargetInput = function(tagNameInput: HTMLInputElement) {
3367
const value = tagNameInput.value;
3468
const tagHelper = document.querySelector('#tag-helper');
35-
if (existingTags.includes(value)) {
69+
if (value in existingTags) {
3670
// If the tag already exists, hide the target branch selector.
3771
hideElem('#tag-target-selector');
3872
tagHelper.textContent = existingTagHelperText;
73+
showElem('#tag-warning');
74+
for (const detail of tagWarningDetailLinks) {
75+
detail.href = `${tagURLStub}/${existingTags[value]}`;
76+
detail.textContent = existingTags[value].substring(0, 10);
77+
}
78+
requiresConfirmation = true;
3979
} else {
4080
showElem('#tag-target-selector');
4181
tagHelper.textContent = value ? newTagHelperText : defaultTagHelperText;
82+
hideElem('#tag-warning');
83+
requiresConfirmation = false;
4284
}
4385
};
4486
hideTargetInput(tagNameInput); // update on page load because the input may have a value

0 commit comments

Comments
 (0)