Shared CI action for "putting" plugins or themes to various "press" sites (classicpress/wordpress)
  • Shell 94.4%
  • Dockerfile 5.6%
Find a file
2026-06-02 00:48:17 +00:00
action.yml Add distignore logic for build pipelines 2026-06-01 18:46:46 -06:00
AGENTS.md Initial commit 2026-05-21 11:13:38 -06:00
Dockerfile Add cleaner remote activation 2026-05-21 15:33:48 -06:00
entrypoint.sh Add distignore logic for build pipelines 2026-06-01 18:46:46 -06:00
README.md Simplify wp_root and dest_path logic 2026-05-21 15:00:54 -06:00
remote-activate.sh Again but this time with feeling 2026-05-21 15:42:45 -06:00

Pressput

A shared CI action that deploys plugins or themes to ClassicPress and WordPress sites running in Docker on our internal servers.

What it does

  1. Rsyncs your build output to the target theme/plugin directory on the server
  2. Activates the theme/plugin via wp-cli (run as a sidecar container on the appropriate Docker network)

Setup

Forgejo

Set these as repository or organization secrets/variables:

  • SERVER_IP (variable) — server IP/hostname
  • CI_USER_SSH_KEY (secret) — SSH private key for ci-deploy-user

Docker host

The target server must have:

  • A ci-deploy-user account with the matching public key in ~/.ssh/authorized_keys
  • ci-deploy-user in the docker group (to run docker commands without sudo)
  • Write access for ci-deploy-user to the target wp-content/themes/ and wp-content/plugins/ directories (group www-data with setgid bit is the typical setup)
  • Sites organized as /opt/sites/<stack>/<site_name>/site_data/ with WP/CP installed, and a Docker network named db-<site_name> connecting the site container to its database

Usage

# .forgejo/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: debian-13
    steps:
      - uses: actions/checkout@v4

      # build steps here — npm install, npm run build, composer install, etc.

      - uses: https://git.ouzelsoftware.com/sitetender/pressput@v1.0.0
        with:
          host: ${{ vars.SERVER_IP }}
          ssh_key: ${{ secrets.CI_USER_SSH_KEY }}
          src: ./dist
          destinations: |
            /opt/sites/classicpress/sitetender/site_data:theme:sitetender-theme

Inputs

Input Required Description
host yes Server IP or hostname
ssh_key yes SSH private key for ci-deploy-user
src no Path to source directory in the repo to rsync. Default: .
destinations yes Newline-separated list of deploy targets in the format wp_root:type:slug (see below)

destinations format

Each line is wp_root:type:slug:

  • wp_root — absolute path to the WP/CP root on the server (e.g., /opt/sites/classicpress/sitetender/site_data). The Docker network is derived from this path: it must be db-<parent-dir-name>. For /opt/sites/classicpress/sitetender/site_data, the network is db-sitetender.
  • typetheme or plugin
  • slug — directory name under wp-content/themes/ or wp-content/plugins/

The action computes the rsync target as <wp_root>/wp-content/<type>s/<slug> and runs wp <type> activate <slug> after copying.

Examples

Deploy a theme to one site:

destinations: |
  /opt/sites/classicpress/sitetender/site_data:theme:sitetender-theme

Roll out the same plugin to multiple sites:

destinations: |
  /opt/sites/classicpress/site1/site_data:plugin:ouzel-analytics
  /opt/sites/classicpress/site2/site_data:plugin:ouzel-analytics
  /opt/sites/classicpress/site3/site_data:plugin:ouzel-analytics

Versioning

Tag releases as vMAJOR.MINOR.PATCH. Pin to a specific tag in your workflows:

- uses: https://git.ouzelsoftware.com/sitetender/pressput@v1.0.0

Avoid @main — the Forgejo Actions runner caches action checkouts by ref, and floating refs can serve stale code.