Implement actions artifacts (#22738)

Implement action artifacts server api.

This change is used for supporting
https://github.com/actions/upload-artifact and
https://github.com/actions/download-artifact in gitea actions. It can
run sample workflow from doc
https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts.
The api design is inspired by
https://github.com/nektos/act/blob/master/pkg/artifacts/server.go and
includes some changes from gitea internal structs and methods.

Actions artifacts contains two parts:

- Gitea server api and storage (this pr implement basic design without
some complex cases supports)
- Runner communicate with gitea server api (in comming)

Old pr https://github.com/go-gitea/gitea/pull/22345 is outdated after
actions merged. I create new pr from main branch.


![897f7694-3e0f-4f7c-bb4b-9936624ead45](https://user-images.githubusercontent.com/2142787/219382371-eb3cf810-e4e0-456b-a8ff-aecc2b1a1032.jpeg)

Add artifacts list in actions workflow page.
This commit is contained in:
FuXiaoHei 2023-05-19 21:37:57 +08:00 committed by GitHub
parent 7985cde84d
commit c757765a9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1127 additions and 6 deletions

View file

@ -42,6 +42,18 @@
</div>
</div>
</div>
<div class="job-artifacts" v-if="artifacts.length > 0">
<div class="job-artifacts-title">
{{ locale.artifactsTitle }}
</div>
<ul class="job-artifacts-list">
<li class="job-artifacts-item" v-for="artifact in artifacts" :key="artifact.id">
<a class="job-artifacts-link" target="_blank" :href="run.link+'/artifacts/'+artifact.id">
<SvgIcon name="octicon-file" class="ui text black job-artifacts-icon" />{{ artifact.name }}
</a>
</li>
</ul>
</div>
</div>
<div class="action-view-right">
@ -102,6 +114,7 @@ const sfc = {
loading: false,
intervalID: null,
currentJobStepsStates: [],
artifacts: [],
// provided by backend
run: {
@ -156,6 +169,15 @@ const sfc = {
this.intervalID = setInterval(this.loadJob, 1000);
},
unmounted() {
// clear the interval timer when the component is unmounted
// even our page is rendered once, not spa style
if (this.intervalID) {
clearInterval(this.intervalID);
this.intervalID = null;
}
},
methods: {
// get the active container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group`
getLogsContainer(idx) {
@ -259,6 +281,11 @@ const sfc = {
try {
this.loading = true;
// refresh artifacts if upload-artifact step done
const resp = await this.fetchPost(`${this.actionsURL}/runs/${this.runIndex}/artifacts`);
const artifacts = await resp.json();
this.artifacts = artifacts['artifacts'] || [];
const response = await this.fetchJob();
// save the state to Vue data, then the UI will be updated
@ -287,6 +314,7 @@ const sfc = {
}
},
fetchPost(url, body) {
return fetch(url, {
method: 'POST',
@ -319,6 +347,7 @@ export function initRepositoryActionView() {
approve: el.getAttribute('data-locale-approve'),
cancel: el.getAttribute('data-locale-cancel'),
rerun: el.getAttribute('data-locale-rerun'),
artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
status: {
unknown: el.getAttribute('data-locale-status-unknown'),
waiting: el.getAttribute('data-locale-status-waiting'),
@ -423,6 +452,27 @@ export function ansiLogToHTML(line) {
padding: 10px;
}
.job-artifacts-title {
font-size: 18px;
margin-top: 16px;
padding: 16px 10px 0px 20px;
border-top: 1px solid var(--color-secondary);
}
.job-artifacts-item {
margin: 5px 0;
padding: 6px;
}
.job-artifacts-list {
padding-left: 12px;
list-style: none;
}
.job-artifacts-icon {
padding-right: 3px;
}
.job-group-section .job-brief-list .job-brief-item {
margin: 5px 0;
padding: 10px;