mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-09-12 22:07:17 +00:00
fix!: use run ID instead of run Index in artifacts download web views
- the run ID used to download artifacts is absolute (ID) instead of being relative to the repository (Index) for compatibility with the url built and returned as `artifact-url` by the the upload-artifact@v4 action. - this is a breaking change because URLs to download artifacts previous saved/bookmarked and not yet expired expired are no longer working, they need to be looked up again by visiting the job web page. - add unit tests for getRunByID(). - RepoActionView.test.js verifies the download URL is built using the run ID. - lAdd integration tests to verify the RunID is set as expected in the template used by RepoActionView.vue. Refs https://code.forgejo.org/forgejo/runner/issues/187
This commit is contained in:
parent
f7b0eb16c8
commit
b047a60a09
9 changed files with 233 additions and 19 deletions
|
@ -215,3 +215,104 @@ test('load multiple steps on a finished action', async () => {
|
|||
expect(wrapper.get('.job-step-section:nth-of-type(2) .job-log-line:nth-of-type(2) .log-msg').text()).toEqual('Step #2 Log #2');
|
||||
expect(wrapper.get('.job-step-section:nth-of-type(2) .job-log-line:nth-of-type(3) .log-msg').text()).toEqual('Step #2 Log #3');
|
||||
});
|
||||
|
||||
test('artifacts download links', async () => {
|
||||
Object.defineProperty(document.documentElement, 'lang', {value: 'en'});
|
||||
vi.spyOn(global, 'fetch').mockImplementation((url, opts) => {
|
||||
if (url.endsWith('/artifacts')) {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: vi.fn().mockResolvedValue(
|
||||
{
|
||||
artifacts: [
|
||||
{name: 'artifactname1', size: 111, status: 'completed'},
|
||||
{name: 'artifactname2', size: 222, status: 'expired'},
|
||||
],
|
||||
},
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const postBody = JSON.parse(opts.body);
|
||||
const stepsLog_value = [];
|
||||
for (const cursor of postBody.logCursors) {
|
||||
if (cursor.expanded) {
|
||||
stepsLog_value.push(
|
||||
{
|
||||
step: cursor.step,
|
||||
cursor: 0,
|
||||
lines: [
|
||||
{index: 1, message: `Step #${cursor.step + 1} Log #1`, timestamp: 0},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
const jobs_value = {
|
||||
state: {
|
||||
run: {
|
||||
status: 'success',
|
||||
commit: {
|
||||
pusher: {},
|
||||
},
|
||||
},
|
||||
currentJob: {
|
||||
steps: [
|
||||
{
|
||||
summary: 'Test Step #1',
|
||||
duration: '1s',
|
||||
status: 'success',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
logs: {
|
||||
stepsLog: opts.body?.includes('"cursor":null') ? stepsLog_value : [],
|
||||
},
|
||||
};
|
||||
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: vi.fn().mockResolvedValue(
|
||||
jobs_value,
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
const wrapper = mount(RepoActionView, {
|
||||
props: {
|
||||
actionsURL: 'https://example.com/example-org/example-repo/actions',
|
||||
runIndex: '10',
|
||||
runID: '1001',
|
||||
jobIndex: '2',
|
||||
locale: {
|
||||
approve: '',
|
||||
cancel: '',
|
||||
rerun: '',
|
||||
artifactsTitle: 'artifactTitleHere',
|
||||
areYouSure: '',
|
||||
confirmDeleteArtifact: '',
|
||||
rerun_all: '',
|
||||
showTimeStamps: '',
|
||||
showLogSeconds: '',
|
||||
showFullScreen: '',
|
||||
downloadLogs: '',
|
||||
status: {
|
||||
unknown: '',
|
||||
waiting: '',
|
||||
running: '',
|
||||
success: '',
|
||||
failure: '',
|
||||
cancelled: '',
|
||||
skipped: '',
|
||||
blocked: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.get('.job-artifacts .job-artifacts-title').text()).toEqual('artifactTitleHere');
|
||||
expect(wrapper.get('.job-artifacts .job-artifacts-item:nth-of-type(1) .job-artifacts-link').attributes('href')).toEqual('https://example.com/example-org/example-repo/actions/runs/1001/artifacts/artifactname1');
|
||||
expect(wrapper.get('.job-artifacts .job-artifacts-item:nth-of-type(2) .job-artifacts-link').attributes('href')).toEqual('https://example.com/example-org/example-repo/actions/runs/1001/artifacts/artifactname2');
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ const sfc = {
|
|||
},
|
||||
props: {
|
||||
runIndex: String,
|
||||
runID: String,
|
||||
jobIndex: String,
|
||||
actionsURL: String,
|
||||
workflowName: String,
|
||||
|
@ -386,6 +387,7 @@ export function initRepositoryActionView() {
|
|||
|
||||
const view = createApp(sfc, {
|
||||
runIndex: el.getAttribute('data-run-index'),
|
||||
runID: el.getAttribute('data-run-id'),
|
||||
jobIndex: el.getAttribute('data-job-index'),
|
||||
actionsURL: el.getAttribute('data-actions-url'),
|
||||
workflowName: el.getAttribute('data-workflow-name'),
|
||||
|
@ -473,7 +475,7 @@ export function initRepositoryActionView() {
|
|||
</div>
|
||||
<ul class="job-artifacts-list">
|
||||
<li class="job-artifacts-item" v-for="artifact in artifacts" :key="artifact.name">
|
||||
<a class="job-artifacts-link" target="_blank" :href="run.link+'/artifacts/'+artifact.name">
|
||||
<a class="job-artifacts-link" target="_blank" :href="actionsURL+'/runs/'+runID+'/artifacts/'+artifact.name">
|
||||
<SvgIcon name="octicon-file" class="ui text black job-artifacts-icon"/>{{ artifact.name }}
|
||||
</a>
|
||||
<a v-if="run.canDeleteArtifact" @click="deleteArtifact(artifact.name)" class="job-artifacts-delete">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue