12 Commits

Author SHA1 Message Date
8402f345cf fix: exit with error if missing informations 🐛 2024-10-30 10:07:42 +13:00
1f18b83405 fix: Make deletion able to use variables 🐛 2024-10-30 10:01:04 +13:00
a2d9b28aa5 fix: debug delete 2024-10-30 09:48:21 +13:00
d2dc5da7d4 fix: Default repo_name is ${GITHUB_REPOSITORY} 2024-10-30 09:47:45 +13:00
14058cc306 print env vars 2024-10-30 09:33:28 +13:00
8170a5179d fix: Image uses env vars not args, doh 🐛 2024-10-30 09:20:53 +13:00
2cb2d440c5 fix: Update base url variable 2024-10-30 07:30:21 +13:00
e80fed6fe7 fix: file not found 🐛 2024-10-29 23:29:27 +13:00
dd653b4a2f fix: Updated environment definition 🐛 2024-10-29 22:45:25 +13:00
6dbfd3e120 fix: action not running 2024-10-29 22:05:05 +13:00
d5932e3574 feat: Use Bash as runtime 2024-10-29 21:07:15 +13:00
Your Name
dbfb2c03bb 0.1.0 2024-08-23 20:07:28 +03:00
9 changed files with 203 additions and 310 deletions

View File

@@ -1,24 +0,0 @@
on:
issues:
types: [opened, edited, reopened]
issue_comment:
types: [created, edited]
jobs:
send_telegram_message:
name: send telegram message
runs-on: ubuntu-latest
steps:
- name: send telegram message
uses: appleboy/telegram-action@master
with:
to: ${{ secrets.TELEGRAM_TO }}
token: ${{ secrets.TELEGRAM_TOKEN }}
message: |
Gitea. Creating new issue
Author: ${{ gitea.actor }}
Repository: ${{ gitea.repository }}
See changes: https://gitea.com/${{ gitea.repository }}/issues/${{ gitea.event.issue.number }}

View File

@@ -1,22 +1,9 @@
FROM rosven9856/php:8.3.10-1
FROM cybercinch/base-alpine-bash:latest
RUN addgroup -g 1000 --system php
RUN adduser -G php --system -D -s /bin/sh -u 1000 php
COPY scripts/docker-entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh
RUN chown php:php /home/php
RUN chown php:php /usr/local/bin/composer
ENV upload_file="build/Package.zip"
ENV overwrite_files="false"
RUN mkdir /var/src
RUN chown -R php:php /var/src
WORKDIR /var/src
COPY ./src /var/src
RUN composer install
USER php
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/entrypoint.sh"]

View File

@@ -2,8 +2,21 @@
<img width="560" height="260" src="docs/image/github_gitea_actions.jpg" alt="github gitea actions">
</p>
# Updating a package in the Gitea system using GitHub Actions
# Add/Update a Composer package in Gitea
[![License](https://img.shields.io/github/license/rosven9856/gitea-package-action)](https://github.com/rosven9856/gitea-package-action/blob/master/LICENSE)
This action will update the package version in the Gitea system using the API and output debugging information to the log.
This action will update the package version in the Gitea system using the API and output debugging information to the log.
## Example usage
```yaml
steps:
- uses: https://hub.cybercinch.nz/gitea-composer-upload@main
with:
base_url: "https://gitea_instance_url"
access_token: "${{ secrets._G_TOKEN }}"
username: "${{ secrets._G_USERNAME }}"
owner: "owner"
package_version: "${{ env.GITHUB_REF_NAME }}"

View File

@@ -1,30 +1,39 @@
name: "Gitea updating package"
description: "Updating a package in the Gitea system using GitHub Actions"
name: "Gitea Composer upload package"
description: "Updating a composer package in the Gitea system using GitHub Actions"
inputs:
gitea_instance_base_url:
description: "gitea instance base url"
baseurl:
description: "Base URL for Gitea Instance"
required: true
gitea_access_token:
description: "gitea access token"
username:
description: "Username"
required: true
gitea_owner:
description: "gitea owner"
access_token:
description: "Access Token"
required: true
gitea_repository:
description: "gitea repository"
required: true
gitea_package_registry:
description: "gitea package registry"
owner:
description: "Package owner"
required: false
version:
description: "Version of package"
required: true
overwrite_files:
description: "Overwrite package if already exists"
required: false
default: "false"
upload_file:
description: "The file path to upload"
required: false
default: "build/Package.zip"
runs:
using: "docker"
image: "Dockerfile"
args:
- ${{ inputs.gitea_instance_base_url }}
- ${{ inputs.gitea_access_token }}
- ${{ inputs.gitea_owner }}
- ${{ inputs.gitea_repository }}
- ${{ inputs.gitea_package_registry }}
env:
baseurl: ${{ inputs.baseurl }}
username: ${{ inputs.username }}
access_token: ${{ inputs.access_token }}
version: ${{ inputs.version }}
overwrite_files: ${{ inputs.overwrite_files }}
branding:
icon: 'package'
color: 'green'

View File

@@ -1,19 +1,17 @@
services:
php-fpm:
container_name: php-fpm
composer-uploader:
container_name: compose-upload-gitea
build:
context: ./
dockerfile: Dockerfile
environment:
gitea_instance_base_url: ${GITEA_INSTANCE_BASE_URL}
gitea_access_token: ${GITEA_ACCESS_TOKEN}
gitea_owner: ${GITEA_OWNER}
gitea_repository: ${GITEA_REPOSITORY}
gitea_package_registry: ${GITEA_PACKAGE_REGISTRY}
baseurl: ${base_url}
access_token: ${access_token}
username: ${username}
owner: ${owner}
version: ${version}
repo_name: ${repo_name}
overwrite_files: true
working_dir: /
volumes:
- ./src:/var/src
networks:
- bridge
networks:
bridge:
driver: bridge
- ./build:/build

View File

@@ -1,3 +0,0 @@
#!/bin/sh
php /var/src/app.php

143
scripts/docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,143 @@
#!/bin/bash
# This is to serve as a Plugin for Drone to enable uploading of generic packages to Gitea e.g Ansible Roles
set -eo pipefail
shopt -s nullglob
# check to see if this file is being run or sourced from another script
_is_sourced() {
# https://unix.stackexchange.com/a/215279
[ "${#FUNCNAME[@]}" -ge 2 ] &&
[ "${FUNCNAME[0]}" = '_is_sourced' ] &&
[ "${FUNCNAME[1]}" = 'source' ]
}
# logging functions
action_log() {
local type="$1"
shift
# accept argument string or stdin
local text="$*"
if [ "$#" -eq 0 ]; then text="$(cat)"; fi
local dt
dt="$(date -D 'YYYY-MM-DD hh:mm[:ss]')"
printf '%s [%s] [gitea-composer-uploader]: %s\n' "$dt" "$type" "$text"
}
action_note() {
action_log INF "$@"
}
action_warn() {
action_log WRN "$@" >&2
}
action_error() {
action_log ERR "$@" >&2
}
# Verify that the minimally required password settings are set for operation.
function verify_minimum_env {
if [ -z "$username" ]; then
action_warn "username is required for action operation"
fi
if [ -z "$baseurl" ]; then
action_warn "baseurl setting is required for action operation"
fi
if [ -z "$owner" ]; then
action_warn "owner setting is required for action operation"
fi
if [ -z "$access_token" ]; then
action_warn "access_token setting is required for action operation"
fi
if [ -z "$version" ]; then
action_warn "version setting is required for action operation"
fi
if [ -z "$username" ] ||
[ -z "$baseurl" ] ||
[ -z "$version" ] ||
[ -z "$access_token" ]; then
action_error <<-'EOF'
You need to specify one/all of the following settings:
- username
- access_token
- baseurl
EOF
exit 1
fi
action_note "Sufficient configuration"
}
function delete_file {
no_prefix_version="${version##v}"
username_or_owner=${owner:-$username}
no_owner_repo_name="${GITHUB_REPOSITORY##"$username_or_owner"/}"
# shellcheck disable=SC2154
for file in ${upload_file}; do
action_note "curl -s -o /dev/null -w '%{http_code}' --user \"${username}:${access_token}\" -X DELETE ${baseurl}/api/v1/packages/${owner:-$username}/composer/${owner:-$username}%2F${no_owner_repo_name}/${no_prefix_version}"
response=$(curl -s -o /dev/null -w "%{http_code}" --user "${username}:${access_token}" -X DELETE "${baseurl}/api/v1/packages/${owner:-$username}/composer/${owner:-$username}%2F${no_owner_repo_name}/${no_prefix_version}")
if [ "${response}" == 204 ] || [ "${response}" == 200 ]; then
action_note "Deleted package version ${version} for ${owner:-$username}/${repo_name}"
elif [ "${response}" == 404 ]; then
action_error "Not Found: Odd I cannot locate your package! [bug]"
else
action_error "Response code was ${response}"
fi
done
}
function process_upload_file {
for file in ${upload_file}; do
#action_note "curl -s -o /dev/null -w '%{http_code}' --user \"${username}:${access_token}\" --upload-file ${file} \"${baseurl}/api/packages/${owner:-$username}/composer?version=${version}\""
response=$(curl -s -o /dev/null -w "%{http_code}" --user "${username}:${access_token}" --upload-file "${file}" "${baseurl}/api/packages/${owner:-$username}/composer?version=${version}")
if [ "${response}" == 409 ]; then
action_error "Conflict: File already exists"
if [ "${FILE_OVERWRITE:=$overwrite_files}" == 'true' ]; then
# Delete file as already exists
delete_file
response=$(curl -s -o /dev/null -w "%{http_code}" --user "${username}:${access_token}" --upload-file "${file}" "${baseurl}/api/packages/${owner:-$username}/composer?version=${version}")
if [ "${response}" == 409 ]; then
action_error "Conflict: File already exists"
elif [ "${response}" == 201 ]; then
action_note "File uploaded successfully"
elif [ "${response}" == 400 ]; then
action_error "Bad Request: Version likely already exists"
fi
else
action_error 'Unable to upload file. Maybe toggle overwrite_files setting to true :)'
exit 1
fi
elif [ "${response}" == 201 ]; then
action_note "File uploaded successfully"
elif [ "${response}" == 400 ]; then
action_warn "Bad Request: Version likely already exists"
if [ "${FILE_OVERWRITE:=$overwrite_files}" == 'true' ]; then
# Delete file as already exists
delete_file
response=$(curl -s -o /dev/null -w "%{http_code}" --user "${username}:${access_token}" --upload-file "${file}" "${baseurl}/api/packages/${owner:-$username}/composer?version=${version}")
if [ "${response}" == 409 ]; then
action_error "Conflict: File already exists"
elif [ "${response}" == 201 ]; then
action_note "File uploaded successfully"
elif [ "${response}" == 400 ]; then
action_error "Bad Request: Version likely already exists"
exit 1
fi
else
action_error 'Unable to upload file. Maybe toggle overwrite_files setting to true :)'
exit 1
fi
fi
done
}
_main() {
action_note "Starting"
verify_minimum_env "$@"
process_upload_file "$@"
}
# If we are sourced from elsewhere, don't perform any further actions
if ! _is_sourced; then
_main "$@"
fi

View File

@@ -1,225 +0,0 @@
<?php
\define('RED', "\033[0;31m");
\define('GREEN', "\033[1;32m");
\define('YELLOW', "\033[1;33m");
\define('LITE_CYAN', "\e[96m");
\define('NC', "\033[0m");
function sendRequest ($method = 'GET', $endpoint = '', $data = []): array {
if (!\extension_loaded('curl')) {
throw new \Exception('CURL extension is not loaded');
}
$curl = \curl_init();
if(!$curl) {
throw new \Exception('CURL extension is not loaded');
}
$payload = '';
if (isset($data['request']) && \is_array($data['request']) && \count($data['request']) > 0) {
$payload = \json_encode($data['request']);
}
$fh = null;
$fileSize = 0;
if (isset($data['file']) && !empty($data['file']) && \file_exists($data['file'])) {
$fh = \fopen($data['file'], 'r');
$fileSize = \filesize($data['file']);
}
if (isset($data['user']) && !empty($data['user'])) {
\curl_setopt($curl, CURLOPT_USERPWD, $data['user'] . ':' . \getenv('gitea_access_token'));
} else {
$endpoint .= '?access_token=' . \getenv('gitea_access_token');
}
\curl_setopt($curl, CURLOPT_URL, \getenv('gitea_instance_base_url') . $endpoint /* . '?access_token=' . \getenv('gitea_access_token')*/);
\curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
\curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
\curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($curl, CURLOPT_HEADER, true);
if ($method === 'POST' || $method === 'PUT') {
if (!empty($payload)) {
\curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
\curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
}
}
if ($method === 'PUT') {
\curl_setopt($curl, CURLOPT_PUT, true);
}
if ($fh) {
\curl_setopt($curl, CURLOPT_INFILE, $fh);
\curl_setopt($curl, CURLOPT_INFILESIZE, $fileSize);
}
\curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 20);
\curl_setopt($curl, CURLOPT_TIMEOUT, 20);
$response = \curl_exec($curl);
if(\curl_errno($curl) > 0) {
throw new \Exception('Curl error: #' . \curl_errno($curl) . ' - ' . \curl_error($curl));
}
$header = \substr($response, 0, \curl_getinfo($curl, CURLINFO_HEADER_SIZE));
$body = \substr($response, \curl_getinfo($curl, CURLINFO_HEADER_SIZE));
$httpCode = (int) \curl_getinfo($curl, CURLINFO_HTTP_CODE);
$contentType = \curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
$headers = \explode("\r\n", $header);
\curl_close($curl);
if (isset($data['file']) && !empty($data['file']) && \file_exists($data['file'])) {
\fclose($fh);
}
return [
'http_code' => $httpCode,
'content_type' => $contentType,
'headers' => $headers,
'body' => $body,
];
}
function responseEncode (array $response): mixed {
$data = [];
if ($response['content_type'] !== 'application/json;charset=utf-8') {
return $data;
}
$data = \json_decode($response['body'], true);
if (\json_last_error() !== JSON_ERROR_NONE) {
throw new \Exception('Invalid response json: ' . json_last_error_msg());
}
return $data;
}
function showTerminalMessage (string $message = '', string $color = ''): void
{
echo $color . $message . NC . "\r\n";
}
try {
if (empty(\getenv('gitea_instance_base_url'))) {
throw new \Exception('gitea_instance_base_url empty');
}
if (empty(\getenv('gitea_access_token'))) {
throw new \Exception('gitea_access_token empty');
}
if (empty(\getenv('gitea_owner'))) {
throw new \Exception('gitea_owner empty');
}
if (empty(\getenv('gitea_repository'))) {
throw new \Exception('gitea_repository empty');
}
if (empty(\getenv('gitea_package_registry'))) {
throw new \Exception('gitea_package_registry empty');
}
if (!\in_array(\getenv('gitea_package_registry'), ['composer'])) {
throw new \Exception('Package registry {' . \getenv('gitea_package_registry') . '} is not supported');
}
$response = sendRequest('GET', '/api/v1/user');
if ($response['http_code'] !== 200) {
throw new \Exception('Failed to get user information. Access denied. Response http code: ' . $response['http_code']);
}
$data = responseEncode($response);
if ($response['http_code'] !== 200) {
throw new \Exception('Failed to get user information. Response http code: ' . $response['http_code'] . ', Message: ' . $data['message']);
}
$user = $data;
$login = $user['login'];
showTerminalMessage('User data: OK', GREEN);
$response = sendRequest('GET', '/api/v1/repos/' . \getenv('gitea_owner') . '/' . \getenv('gitea_repository') . '/releases', [
'user' => $login,
]);
if ($response['http_code'] !== 200) {
throw new \Exception('Failed to get repository releases information. Access denied. Response http code: ' . $response['http_code']);
}
$data = responseEncode($response);
if ($response['http_code'] !== 200) {
throw new \Exception('Failed to get repository releases information. Response http code: ' . $response['http_code'] . ', Message: ' . $data['message']);
}
if (!isset($data[0]) || !\is_array($data[0])) {
throw new \Exception('Unexpected release data structure');
}
$lastRelease = $data[0];
$tag = $lastRelease['tag_name'];
showTerminalMessage('Last release data: OK', GREEN);
$response = sendRequest('GET', '/api/v1/repos/' . \getenv('gitea_owner') . '/' . \getenv('gitea_repository') . '/archive/' . $tag . '.zip', [
'user' => $login,
]);
$zipContent = $response['body'];
if ($response['http_code'] !== 200) {
throw new \Exception('Failed receiving zip archive. Response http code: ' . $response['http_code']);
}
if (empty($response['body'])) {
throw new \Exception('Failed receiving zip archive. Empty file');
}
\file_put_contents(__DIR__ . '/package.zip', $zipContent);
showTerminalMessage('Download zip archive: OK', GREEN);
$response = sendRequest('PUT', '/api/packages/' . \getenv('gitea_owner') . '/composer?version=' . $tag, [
'user' => $login,
'file' => __DIR__ . '/package.zip',
]);
\unlink(__DIR__ . '/package.zip');
if ($response['http_code'] !== 201) {
$data = responseEncode($response);
throw new \Exception('Failed update package. Response http code: ' . $response['http_code'] . ', Message: ' . $data['errors'][0]['message']);
}
showTerminalMessage('Update package: OK', GREEN);
} catch (\Exception $e) {
showTerminalMessage("\r\n");
showTerminalMessage( 'FAILED!', RED);
showTerminalMessage( "Error: " . $e->getMessage(), RED);
exit(1);
}
showTerminalMessage("\r\n");
showTerminalMessage('SUCCESS!', GREEN);

View File

@@ -1,5 +0,0 @@
{
"require": {
"ext-curl": "*"
}
}