mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-29 14:21:25 +00:00
fix(actions): address workflow status badge review feedback (#38241)
Follow https://github.com/go-gitea/gitea/pull/38196#discussion_r3487219492 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
@@ -3863,8 +3863,6 @@
|
||||
"actions.workflow.create_status_badge": "Create status badge",
|
||||
"actions.workflow.status_badge": "Status Badge",
|
||||
"actions.workflow.status_badge_url": "Badge URL",
|
||||
"actions.workflow.status_badge_markdown": "Markdown",
|
||||
"actions.workflow.status_badge_html": "HTML",
|
||||
"actions.workflow.not_found": "Workflow '%s' not found.",
|
||||
"actions.workflow.run_success": "Workflow '%s' run successfully.",
|
||||
"actions.workflow.from_ref": "Use workflow from",
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
stdCtx "context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
@@ -49,12 +48,9 @@ type WorkflowInfo struct {
|
||||
}
|
||||
|
||||
type workflowBadge struct {
|
||||
URL string
|
||||
WorkflowURL string
|
||||
Markdown string
|
||||
MarkdownAltText string
|
||||
HTML string
|
||||
HTMLAltText string
|
||||
DisplayName string
|
||||
BadgeURL string
|
||||
WorkflowURL string
|
||||
}
|
||||
|
||||
// DisplayName returns the workflow name from the YAML file if present, otherwise the filename.
|
||||
@@ -616,28 +612,19 @@ func prepareWorkflowBadgeTemplate(ctx *context.Context, workflowID, displayName
|
||||
if workflowID == "" {
|
||||
return
|
||||
}
|
||||
if displayName == "" {
|
||||
displayName = workflowID
|
||||
}
|
||||
displayName = util.IfZero(displayName, workflowID)
|
||||
|
||||
repoURL := ctx.Repo.Repository.HTMLURL(ctx)
|
||||
badgeURL := fmt.Sprintf("%s/actions/workflows/%s/badge.svg?branch=%s", repoURL, util.PathEscapeSegments(workflowID), url.QueryEscape(ctx.Repo.Repository.DefaultBranch))
|
||||
workflowURL := fmt.Sprintf("%s/actions?workflow=%s", repoURL, url.QueryEscape(workflowID))
|
||||
|
||||
ctx.Data["WorkflowBadge"] = workflowBadge{
|
||||
URL: badgeURL,
|
||||
WorkflowURL: workflowURL,
|
||||
Markdown: fmt.Sprintf("[](%s)", escapeMarkdownImageAltText(displayName), badgeURL, workflowURL),
|
||||
MarkdownAltText: escapeMarkdownImageAltText(displayName),
|
||||
HTML: fmt.Sprintf(`<a href="%s"><img src="%s" alt="%s"></a>`, html.EscapeString(workflowURL), html.EscapeString(badgeURL), html.EscapeString(displayName)),
|
||||
HTMLAltText: displayName,
|
||||
BadgeURL: badgeURL,
|
||||
WorkflowURL: workflowURL,
|
||||
DisplayName: displayName,
|
||||
}
|
||||
}
|
||||
|
||||
func escapeMarkdownImageAltText(s string) string {
|
||||
return strings.NewReplacer(`\`, `\\`, `[`, `\[`, `]`, `\]`).Replace(s)
|
||||
}
|
||||
|
||||
// loadIsRefDeleted loads the IsRefDeleted field for each run in the list.
|
||||
// TODO: move this function to models/actions/run_list.go but now it will result in a circular import.
|
||||
func loadIsRefDeleted(ctx stdCtx.Context, repoID int64, runs actions_model.RunList) error {
|
||||
|
||||
@@ -184,10 +184,7 @@ func Test_loadIsRefDeleted(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrepareWorkflowBadgeTemplate(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.IsInTesting, true)()
|
||||
defer test.MockVariableValue(&setting.AppURL, "https://gitea.example.com/")()
|
||||
defer test.MockVariableValue(&setting.AppSubURL, "")()
|
||||
defer test.MockVariableValue(&setting.PublicURLDetection, setting.PublicURLNever)()
|
||||
|
||||
t.Run("no workflow selected", func(t *testing.T) {
|
||||
ctx := newWorkflowBadgeTestContext(t)
|
||||
@@ -203,13 +200,9 @@ func TestPrepareWorkflowBadgeTemplate(t *testing.T) {
|
||||
prepareWorkflowBadgeTemplate(ctx, "build/test workflow.yml", `CI [prod]\build "fast" <ok>`)
|
||||
|
||||
assert.Equal(t, workflowBadge{
|
||||
URL: "https://gitea.example.com/user1/repo1/actions/workflows/build/test%20workflow.yml/badge.svg?branch=release%2F1.0+%26+hotfix",
|
||||
BadgeURL: "https://gitea.example.com/user1/repo1/actions/workflows/build/test%20workflow.yml/badge.svg?branch=release%2F1.0+%26+hotfix",
|
||||
WorkflowURL: "https://gitea.example.com/user1/repo1/actions?workflow=build%2Ftest+workflow.yml",
|
||||
Markdown: `[![CI \[prod\]\\build "fast" <ok>](https://gitea.example.com/user1/repo1/actions/workflows/build/test%20workflow.yml/badge.svg?branch=release%2F1.0+%26+hotfix)]` +
|
||||
`(https://gitea.example.com/user1/repo1/actions?workflow=build%2Ftest+workflow.yml)`,
|
||||
MarkdownAltText: `CI \[prod\]\\build "fast" <ok>`,
|
||||
HTML: `<a href="https://gitea.example.com/user1/repo1/actions?workflow=build%2Ftest+workflow.yml"><img src="https://gitea.example.com/user1/repo1/actions/workflows/build/test%20workflow.yml/badge.svg?branch=release%2F1.0+%26+hotfix" alt="CI [prod]\build "fast" <ok>"></a>`,
|
||||
HTMLAltText: `CI [prod]\build "fast" <ok>`,
|
||||
DisplayName: `CI [prod]\build "fast" <ok>`,
|
||||
}, ctx.Data["WorkflowBadge"])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{{template "base/head" .}}
|
||||
|
||||
{{$showCreateWorkflowBadge := Iif .WorkflowBadge true false}}
|
||||
{{$showEnableDisableWorkflow := and .AllowDisableOrEnableWorkflow .CurWorkflowIsListed $.CurWorkflow}}
|
||||
|
||||
<div class="page-content repository actions">
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container">
|
||||
@@ -124,16 +128,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if or .WorkflowBadge (and .AllowDisableOrEnableWorkflow .CurWorkflowIsListed $.CurWorkflow)}}
|
||||
{{if or $showCreateWorkflowBadge $showEnableDisableWorkflow}}
|
||||
<button class="ui jump dropdown btn interact-bg tw-p-2">
|
||||
{{svg "octicon-kebab-horizontal"}}
|
||||
<div class="menu">
|
||||
{{if .WorkflowBadge}}
|
||||
{{if $showCreateWorkflowBadge}}
|
||||
<div class="item show-modal" data-modal="#workflow-status-badge-modal">
|
||||
{{ctx.Locale.Tr "actions.workflow.create_status_badge"}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if and .AllowDisableOrEnableWorkflow .CurWorkflowIsListed $.CurWorkflow}}
|
||||
{{if $showEnableDisableWorkflow}}
|
||||
<a class="item {{if .CurWorkflowRequired}}disabled{{else}}link-action{{end}}"{{if not .CurWorkflowRequired}} data-url="{{$.Link}}/{{if .CurWorkflowDisabled}}enable{{else}}disable{{end}}?workflow={{$.CurWorkflow}}&scoped_workflow_source_repo_id={{$.CurWorkflowRepoID}}&actor={{.CurActor}}&status={{$.CurStatus}}&branch={{$.CurBranch}}"{{end}}>
|
||||
{{if .CurWorkflowRequired}}{{ctx.Locale.Tr "actions.workflow.disable"}}{{else if .CurWorkflowDisabled}}{{ctx.Locale.Tr "actions.workflow.enable"}}{{else}}{{ctx.Locale.Tr "actions.workflow.disable"}}{{end}}
|
||||
</a>
|
||||
@@ -151,49 +155,6 @@
|
||||
<div class="ui attached segment">
|
||||
{{template "repo/actions/runs_list" .}}
|
||||
</div>
|
||||
{{if .WorkflowBadge}}
|
||||
<div id="workflow-status-badge-modal" class="ui tiny modal">
|
||||
<div class="header">{{ctx.Locale.Tr "actions.workflow.status_badge"}}</div>
|
||||
<div class="content">
|
||||
<div class="ui form" data-workflow-badge-form data-badge-url="{{.WorkflowBadge.URL}}" data-workflow-url="{{.WorkflowBadge.WorkflowURL}}" data-markdown-alt-text="{{.WorkflowBadge.MarkdownAltText}}" data-html-alt-text="{{.WorkflowBadge.HTMLAltText}}">
|
||||
<div class="field">
|
||||
<img data-workflow-badge-image src="{{.WorkflowBadge.URL}}" alt="{{.CurWorkflow}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "actions.runs.branch"}}</label>
|
||||
<div class="ui selection dropdown">
|
||||
<input type="hidden" data-workflow-badge-branch value="{{.Repository.DefaultBranch}}">
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="text">{{.Repository.DefaultBranch}}</div>
|
||||
<div class="menu">
|
||||
<div class="item selected" data-value="{{.Repository.DefaultBranch}}">{{.Repository.DefaultBranch}}</div>
|
||||
{{range .RunBranches}}
|
||||
{{if ne . $.Repository.DefaultBranch}}
|
||||
<div class="item" data-value="{{.}}">{{.}}</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "actions.workflow.status_badge_url"}}</label>
|
||||
<div class="ui action input">
|
||||
<input id="workflow-badge-url" readonly autofocus value="{{.WorkflowBadge.URL}}">
|
||||
<button class="ui icon button" data-tooltip-content="{{ctx.Locale.Tr "copy"}}" data-clipboard-target="#workflow-badge-url">{{svg "octicon-copy" 14}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "actions.workflow.status_badge_markdown"}}</label>
|
||||
<textarea id="workflow-badge-markdown" rows="2" readonly>{{.WorkflowBadge.Markdown}}</textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "actions.workflow.status_badge_html"}}</label>
|
||||
<textarea id="workflow-badge-html" rows="2" readonly>{{.WorkflowBadge.HTML}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
@@ -201,4 +162,53 @@
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if $showCreateWorkflowBadge}}
|
||||
<div id="workflow-status-badge-modal" class="ui tiny modal">
|
||||
<div class="header">{{ctx.Locale.Tr "actions.workflow.status_badge"}}</div>
|
||||
<div class="content">
|
||||
<div class="ui form" data-global-init="initWorkflowBadgeForm"
|
||||
data-badge-url="{{.WorkflowBadge.BadgeURL}}"
|
||||
data-workflow-url="{{.WorkflowBadge.WorkflowURL}}"
|
||||
data-workflow-display-name="{{.WorkflowBadge.DisplayName}}"
|
||||
>
|
||||
<div class="field">
|
||||
<img data-workflow-badge-image src="{{.WorkflowBadge.BadgeURL}}" alt="{{.CurWorkflow}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "actions.runs.branch"}}</label>
|
||||
<div class="ui selection dropdown">
|
||||
<input type="hidden" data-workflow-badge-branch value="{{.Repository.DefaultBranch}}">
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="text">{{.Repository.DefaultBranch}}</div>
|
||||
<div class="menu">
|
||||
<div class="item selected" data-value="{{.Repository.DefaultBranch}}">{{.Repository.DefaultBranch}}</div>
|
||||
{{range $branchName := .RunBranches}}
|
||||
{{if ne $branchName $.Repository.DefaultBranch}}
|
||||
<div class="item" data-value="{{$branchName}}">{{$branchName}}</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "actions.workflow.status_badge_url"}}</label>
|
||||
<div class="ui action input">
|
||||
<input id="workflow-badge-url" readonly autofocus>
|
||||
<button class="ui icon button" data-tooltip-content="{{ctx.Locale.Tr "copy"}}" data-clipboard-target="#workflow-badge-url">{{svg "octicon-copy" 14}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Markdown</label>
|
||||
<textarea id="workflow-badge-markdown" rows="2" readonly></textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>HTML</label>
|
||||
<textarea id="workflow-badge-html" rows="2" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{template "base/footer" .}}
|
||||
|
||||
@@ -5,8 +5,7 @@ test('updateWorkflowBadgeFields updates badge snippets for selected branch', ()
|
||||
<div
|
||||
data-badge-url="https://gitea.example.com/user1/repo1/actions/workflows/build/test%20workflow.yml/badge.svg?branch=main"
|
||||
data-workflow-url="https://gitea.example.com/user1/repo1/actions?workflow=build%2Ftest+workflow.yml"
|
||||
data-markdown-alt-text="CI \\[prod\\]\\\\build "fast" <ok>"
|
||||
data-html-alt-text="CI [prod]\\build "fast" <ok>"
|
||||
data-workflow-display-name="CI [prod]\\build "fast" <ok>"
|
||||
>
|
||||
<img data-workflow-badge-image src="">
|
||||
<input id="workflow-badge-url" readonly>
|
||||
|
||||
@@ -1,36 +1,35 @@
|
||||
import {createApp} from 'vue';
|
||||
import RepoActionView from '../components/RepoActionView.vue';
|
||||
import {queryElems} from '../utils/dom.ts';
|
||||
|
||||
function escapeHTMLAttribute(value: string): string {
|
||||
return value.replaceAll('&', '&').replaceAll('"', '"').replaceAll('<', '<').replaceAll('>', '>');
|
||||
}
|
||||
import {registerGlobalInitFunc} from '../modules/observer.ts';
|
||||
import {html} from '../utils/html.ts';
|
||||
|
||||
export function updateWorkflowBadgeFields(form: HTMLElement, branch: string): void {
|
||||
const badgeURL = new URL(form.getAttribute('data-badge-url')!);
|
||||
badgeURL.searchParams.set('branch', branch);
|
||||
const badgeURLParsed = new URL(form.getAttribute('data-badge-url')!);
|
||||
badgeURLParsed.searchParams.set('branch', branch);
|
||||
|
||||
const badgeURLString = badgeURL.href;
|
||||
const badgeURL = badgeURLParsed.href;
|
||||
const workflowURL = form.getAttribute('data-workflow-url')!;
|
||||
const markdownAltText = form.getAttribute('data-markdown-alt-text')!;
|
||||
const htmlAltText = form.getAttribute('data-html-alt-text')!;
|
||||
const displayName = form.getAttribute('data-workflow-display-name')!;
|
||||
const markdownAltText = displayName.replaceAll(/[\\[\]]/g, (c) => `\\${c}`);
|
||||
|
||||
form.querySelector<HTMLImageElement>('[data-workflow-badge-image]')!.src = badgeURLString;
|
||||
form.querySelector<HTMLInputElement>('#workflow-badge-url')!.value = badgeURLString;
|
||||
form.querySelector<HTMLTextAreaElement>('#workflow-badge-markdown')!.value = `[](${workflowURL})`;
|
||||
form.querySelector<HTMLTextAreaElement>('#workflow-badge-html')!.value = `<a href="${escapeHTMLAttribute(workflowURL)}"><img src="${escapeHTMLAttribute(badgeURLString)}" alt="${escapeHTMLAttribute(htmlAltText)}"></a>`;
|
||||
form.querySelector<HTMLImageElement>('[data-workflow-badge-image]')!.src = badgeURL;
|
||||
form.querySelector<HTMLInputElement>('#workflow-badge-url')!.value = badgeURL;
|
||||
form.querySelector<HTMLTextAreaElement>('#workflow-badge-markdown')!.value = `[](${workflowURL})`;
|
||||
form.querySelector<HTMLTextAreaElement>('#workflow-badge-html')!.value = html`<a href="${workflowURL}"><img src="${badgeURL}" alt="${displayName}"></a>`;
|
||||
}
|
||||
|
||||
function initWorkflowBadgeBranchSelection(): void {
|
||||
queryElems(document, '[data-workflow-badge-form]', (form) => {
|
||||
const branchInput = form.querySelector<HTMLInputElement>('[data-workflow-badge-branch]')!;
|
||||
branchInput.addEventListener('change', () => updateWorkflowBadgeFields(form, branchInput.value));
|
||||
});
|
||||
function initWorkflowBadgeForm(form: HTMLElement): void {
|
||||
const branchInput = form.querySelector<HTMLInputElement>('[data-workflow-badge-branch]')!;
|
||||
branchInput.addEventListener('change', () => updateWorkflowBadgeFields(form, branchInput.value));
|
||||
updateWorkflowBadgeFields(form, branchInput.value);
|
||||
}
|
||||
|
||||
export function initRepositoryActionView() {
|
||||
initWorkflowBadgeBranchSelection();
|
||||
export function initRepositoryActions() {
|
||||
registerGlobalInitFunc('initWorkflowBadgeForm', initWorkflowBadgeForm);
|
||||
initRepositoryActionsView();
|
||||
}
|
||||
|
||||
function initRepositoryActionsView() {
|
||||
const el = document.querySelector('#repo-action-view');
|
||||
if (!el) return;
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import {initCommonOrganization} from './features/common-organization.ts';
|
||||
import {initRepoWikiForm} from './features/repo-wiki.ts';
|
||||
import {initRepository, initBranchSelectorTabs} from './features/repo-legacy.ts';
|
||||
import {initCaptcha} from './features/captcha.ts';
|
||||
import {initRepositoryActionView} from './features/repo-actions.ts';
|
||||
import {initRepositoryActions} from './features/repo-actions.ts';
|
||||
import {initGlobalTooltips} from './modules/tippy.ts';
|
||||
import {initGiteaFomantic} from './modules/fomantic.ts';
|
||||
import {initRepoIssueList} from './features/repo-issue-list.ts';
|
||||
@@ -138,7 +138,7 @@ const initPerformanceTracer = callInitFunctions([
|
||||
initRepoViewFileTree,
|
||||
initRepoWikiForm,
|
||||
initRepository,
|
||||
initRepositoryActionView,
|
||||
initRepositoryActions,
|
||||
initRepositorySearch,
|
||||
initRepoContributors,
|
||||
initRepoCodeFrequency,
|
||||
|
||||
Reference in New Issue
Block a user