Use Drone plugins in Gitea Actions

Running existing Drone plugin images as Gitea Actions steps

Drone.IO runs each pipeline step in a Docker container. Drone plugins are containers with a predefined task and settings supplied by the pipeline. Because they are published as Docker images, the same plugins can also run in Gitea Actions.

One plugin I used was drone-scp, which copies files from the build pipeline to a remote server. My Drone step looked like this:

- name: scp files
  image: appleboy/drone-scp
  settings:
    host: example1.com
    username: ubuntu
    password:
      from_secret: ssh_password
    target: /home/deploy/web
    source:
      - release/*.tar.gz

The step calls the predefined binary in the drone-scp image, which copies files from the release directory to the target directory on the remote server. The full script does not need to live in the pipeline.

Because drone-scp is published as a Docker image, Gitea Actions can run it too. The quick approach works for most plugins. The more involved approach wraps the plugin as a full Gitea Action.

The simple approach: use the Docker image directly

The easiest way to use a Drone plugin in Gitea Actions is to reference the Docker image directly with uses: docker:// and pass the plugin's expected PLUGIN_ environment variables via the step's env: block:

name: copy files
on: [push]
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: docker://appleboy/drone-scp
      env:
        PLUGIN_HOST: ${{ secrets.HOST }}
        PLUGIN_USERNAME: ubuntu
        PLUGIN_PASSWORD: ${{ secrets.SSH_PASSWORD }}
        PLUGIN_TARGET: /home/deploy/web
        PLUGIN_SOURCE: release/*.tar.gz

This works because Drone plugins read their configuration from PLUGIN_-prefixed environment variables (derived from the settings: block in Drone), and step-level env: variables in Gitea Actions are passed directly into Docker containers. No repackaging is needed.

The full approach: wrap the plugin as a Gitea Action

If you want to publish a reusable Action with defined inputs (so consumers use with: instead of env:), you can wrap the Drone plugin in a Dockerfile, entrypoint script, and action.yml. The Dockerfile should look something like this:

FROM appleboy/drone-scp

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

The entrypoint passes the action's input arguments to the drone-scp binary:

#!/bin/sh

set -eu

sh -c "/bin/drone-scp $*"

Note: When using the with: block in Gitea Actions (like GitHub Actions), inputs are passed to Docker containers as environment variables prefixed with INPUT_ (e.g. INPUT_HOST). Drone plugins natively expect the PLUGIN_ prefix (e.g. PLUGIN_HOST). Many popular Drone plugin authors (including Appleboy) have updated their binaries to accept both prefixes. If a plugin does not recognise INPUT_ variables, you may need to translate them in the entrypoint script by mapping each INPUT_* variable to its corresponding PLUGIN_* variable.

The action.yml file tells Gitea Actions which inputs to use.

name: 'drone-scp Gitea Action'
# This tells the Gitea Action runner what type of Action this is
# in this case, it's "docker", and the image to use is the Dockerfile
runs:
  using: 'docker'
  image: 'Dockerfile'
inputs:
  host:
    description: 'scp remote host'
# ... define all the remaining inputs that exist for the Drone Plugin

You can then reference this action in a Gitea Actions workflow the same way you used the Drone.IO plugin.

For example:

name: copy files
on: [push]
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: https://gitea.com/techknowlogick/scp-gitea-action@main
      with:
        host: ${{ secrets.HOST }}
...

Appleboy, the author of the SCP Drone plugin, has already done this. The resulting scp-action can be used directly.

Plugins that accept INPUT_ variables can use this wrapper directly. Plugins that only accept PLUGIN_ variables need the mapping described above, but the plugin itself does not need to be rewritten. This keeps the existing implementation, including plugins written in languages the runner does not support natively.