This commit is contained in:
Akkuman 2023-12-01 16:14:35 +08:00
commit de0122b411
7 changed files with 33833 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Gitea Release action
An action to support publishing release to Gitea.
## Inputs
The following are optional as `step.with` keys
| Name | Type | Description |
| -------------- | ------- | ------------------------------------------------------------------------------------------- |
| `server_url` | String | the base url of the gitea API. Defaults to `github.server_url` |
| `body` | String | Text communicating notable changes in this release |
| `body_path` | String | Path to load text communicating notable changes in this release |
| `draft` | Boolean | Creates a draft release. Defaults to false |
| `prerelease` | Boolean | Indicator of whether or not is a prerelease |
| `files` | String | Newline-delimited globs of paths to assets to upload for release |
| `name` | String | Name of the release. Defaults to tag name |
| `tag_name` | String | Name of a tag. Defaults to `github.ref_name` |
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to `github.repository` |
| `token` | String | Gitea Token. Defaults to `${{ github.token }}` |
## Example usage
```yaml
uses: akkuman/gitea-release-action@v1.0.0
with:
files: |-
bin/**
```
If you want to ignore ssl verify error, you can set env `NODE_TLS_REJECT_UNAUTHORIZED=false`
## References
- [softprops/action-gh-release: 📦 GitHub Action for creating GitHub Releases](https://github.com/softprops/action-gh-release)
- [sigyl-actions/gitea-action-release-asset](https://github.com/sigyl-actions/gitea-action-release-asset)
- [actions/release-action: An action written by Golang to support publishing release to Gitea(not Github Actions compatible) - release-action - Gitea: Git with a cup of tea](https://gitea.com/actions/release-action)

43
action.yml Normal file
View File

@ -0,0 +1,43 @@
---
name: gitea-release-action
description: "An action to support publishing release to Gitea."
author: "Akkuman"
inputs:
server_url:
description: the base url of the gitea API
required: false
default: ${{ github.server_url }}
body:
description: "Note-worthy description of changes in release"
required: false
name:
description: "Gives the release a custom name. Defaults to tag name"
required: false
default: ${{ github.ref_name }}
tag_name:
description: "Gives a tag name. Defaults to github.GITHUB_REF"
required: false
default: ${{ github.ref_name }}
draft:
description: "Creates a draft release. Defaults to false"
required: false
prerelease:
description: "Identify the release as a prerelease. Defaults to false"
required: false
files:
description: "Newline-delimited list of path globs for asset files to upload"
required: false
repository:
description: "Repository to make releases against, in <owner>/<repo> format"
required: false
default: ${{ github.repository }}
token:
description: "Gitea Token"
required: false
default: ${{ github.token }}
runs:
using: "node16"
main: "dist/index.js"
branding:
color: "green"
icon: "package"

33361
dist/index.js vendored Normal file

File diff suppressed because one or more lines are too long

242
package-lock.json generated Normal file
View File

@ -0,0 +1,242 @@
{
"name": "gitea-release-action",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gitea-release-action",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@vercel/ncc": "^0.38.1",
"gitea-api": "^1.17.3-1"
}
},
"node_modules/@actions/core": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
"integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/github": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz",
"integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==",
"dependencies": {
"@actions/http-client": "^2.2.0",
"@octokit/core": "^5.0.1",
"@octokit/plugin-paginate-rest": "^9.0.0",
"@octokit/plugin-rest-endpoint-methods": "^10.0.0"
}
},
"node_modules/@actions/http-client": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz",
"integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==",
"engines": {
"node": ">=14"
}
},
"node_modules/@octokit/auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/core": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.2.tgz",
"integrity": "sha512-cZUy1gUvd4vttMic7C0lwPed8IYXWYp8kHIMatyhY8t8n3Cpw2ILczkV5pGMPqef7v0bLo0pOHrEHarsau2Ydg==",
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.0.0",
"@octokit/request": "^8.0.2",
"@octokit/request-error": "^5.0.0",
"@octokit/types": "^12.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/endpoint": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz",
"integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==",
"dependencies": {
"@octokit/types": "^12.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/graphql": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz",
"integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==",
"dependencies": {
"@octokit/request": "^8.0.1",
"@octokit/types": "^12.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/openapi-types": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz",
"integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw=="
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "9.1.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.4.tgz",
"integrity": "sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==",
"dependencies": {
"@octokit/types": "^12.3.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": ">=5"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.2.0.tgz",
"integrity": "sha512-ePbgBMYtGoRNXDyKGvr9cyHjQ163PbwD0y1MkDJCpkO2YH4OeXX40c4wYHKikHGZcpGPbcRLuy0unPUuafco8Q==",
"dependencies": {
"@octokit/types": "^12.3.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": ">=5"
}
},
"node_modules/@octokit/request": {
"version": "8.1.6",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz",
"integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==",
"dependencies": {
"@octokit/endpoint": "^9.0.0",
"@octokit/request-error": "^5.0.0",
"@octokit/types": "^12.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/request-error": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz",
"integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==",
"dependencies": {
"@octokit/types": "^12.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/types": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.3.0.tgz",
"integrity": "sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==",
"dependencies": {
"@octokit/openapi-types": "^19.0.2"
}
},
"node_modules/@vercel/ncc": {
"version": "0.38.1",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz",
"integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==",
"bin": {
"ncc": "dist/ncc/cli.js"
}
},
"node_modules/before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"node_modules/gitea-api": {
"version": "1.17.3-1",
"resolved": "https://registry.npmjs.org/gitea-api/-/gitea-api-1.17.3-1.tgz",
"integrity": "sha512-Tj2s8feRRXfO4k6MmPyxa0JDDFG+VMifchc6gchzob+puFJErIIWkElQgum8JYT9sLsAFzHE/IFcMUx0ctlAhQ=="
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/undici": {
"version": "5.28.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz",
"integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "gitea-release-action",
"version": "1.0.0",
"description": "",
"main": "src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"package": "ncc build src/main.js -o dist",
"build": "ncc build src/main.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@vercel/ncc": "^0.38.1",
"gitea-api": "^1.17.3-1"
}
}

129
src/main.js Normal file
View File

@ -0,0 +1,129 @@
import fs from "fs";
import { Blob } from "buffer";
import core from "@actions/core";
import gitea from "gitea-api";
import path from 'path'
async function run() {
try {
const server_url = core.getInput("server_url")
const name = core.getInput("name")
const body = core.getInput("body")
const tag_name = core.getInput("tag_name")
const draft = core.getInput("draft")
const prerelease = core.getInput("prerelease")
const files = core.getInput("files")
const repository = core.getInput("repository")
const token = core.getInput("token")
const [owner, repo] = (repository).split("/")
const gitea_client = new gitea.GiteaApi({
BASE: `${server_url}/api/v1`,
WITH_CREDENTIALS: true,
TOKEN: token,
});
const response = await createOrGetRelease(gitea_client, owner, repo, {
body: body,
draft: draft,
name: name,
prerelease: prerelease,
tag_name: tag_name,
})
const file_patterns = files.split('\n')
const all_files = paths(file_patterns);
if (all_files.length == 0) {
console.warn(`${file_patterns} not include valid file.`);
}
await uploadFiles(gitea_client, owner, repo, response.id, all_files)
console.log(`🎉 Release ready at ${response.html_url}`);
} catch (error) {
core.setFailed(error.message);
}
}
/**
*
* @param {gitea.GiteaApi} client
* @param {String} owner
* @param {String} repo
* @param {gitea.CreateReleaseOption} body
* @returns {Promise<gitea.Release>}
*/
async function createOrGetRelease(client, owner, repo, body) {
try {
let release = await client.repository.repoGetReleaseByTag({
owner: owner,
repo: repo,
tag: body.tag_name,
})
return release
} catch (error) {
if (!(error instanceof gitea.ApiError) || error.status !== 404) {
throw error
}
}
let release = await client.repository.repoCreateRelease({
owner: owner,
repo: repo,
body: body,
})
return release
}
/**
*
* @param {Array<String>} patterns
* @returns {Array<String>}
*/
function paths(patterns) {
return patterns.reduce((acc, pattern) => {
return acc.concat(
glob.sync(pattern).filter((path) => statSync(path).isFile())
);
}, []);
};
/**
*
* @param {gitea.GiteaApi} client
* @param {String} owner
* @param {String} repo
* @param {Number} release_id
* @param {Array<String>} all_files
*/
async function uploadFiles(client, owner, repo, release_id, all_files) {
const attachments = await client.repository.repoListReleaseAttachments({
owner: owner,
repo: repo,
id: release_id,
})
for (const filepath in all_files) {
for (const attachment in attachments) {
if (attachment.name === path.basename(filepath)) {
await client.repository.repoDeleteReleaseAttachment({
owner: owner,
repo: repo,
id: id,
attachmentId: attachment.id,
})
console.log(`Successfully deleted old release attachment ${attachment.name}`)
}
const content = fs.readFileSync(filepath);
const blob = new Blob([content]);
await client.repository.repoCreateReleaseAttachment({
owner: owner,
repo: repo,
id: release_id,
attachment: blob,
name: path.basename(filepath),
})
console.log(`Successfully uploaded release attachment ${filepath}`)
}
}
}
run();