OpsNexus

Plugins

Use reusable plugin steps in pipelines, how their inputs are checked, how to write your own, and a reference for all 22 official plugins.

On this page

A plugin is a reusable pipeline step, like a Jenkins plugin. It has typed inputs and a script, and it runs on your build agents, never on the OpsNexus server. OpsNexus ships 22 official plugins (Slack, Docker, Helm, Terraform, Trivy and more), and you can write your own in YAML.

Plugins are managed under Build & deploy → Plugins.

Install a plugin

A plugin must be installed before a pipeline can use it.

  1. Open Plugins and select the Available tab.
  2. Under Install into, choose This project or Shared with all projects.
  3. Select Install on the plugin.
  • A plugin installed in a project is used only by that project's pipelines. A shared plugin is used by every project. If a project has its own plugin with the same name as a shared one, the project's plugin wins.
  • Installing or sharing needs modify access to CI/CD pipelines. Shared plugins need that access in your organization role, and an organization admin can turn sharing off.
  • When a newer official version is available, the Installed tab shows an update count, and the plugin's page has an Update to button with the new version number. Older versions stay installed, so pipelines pinned to them keep working.

The Installed tab lists each plugin with its category, version, where it is installed, and where it is used (jobs and builds in the last 30 days). Report plugins is a separate tab for PDF reports made by the OpsNexus server; those are not pipeline steps.

Use a plugin in a pipeline file

Write a step with uses: and put the inputs under with::

yaml
stages:
  - name: Image
    steps:
      - uses: docker-build-push@1
        with:
          image: registry.example.com/team/api
          tags: "${{ run.number }}, latest"
          registry: registry.example.com
          login: registry-login            # name of a credential
post:
  failure:
    - uses: slack-notify@1
      with:
        webhook: slack-webhook
        status: failure
        message: "Build #${{ run.number }} of ${{ job.name }} failed"
uses: Picks
name@1 The newest installed 1.x version
name@1.2 The newest installed 1.2.x version
name@1.2.3 Exactly that version
name@latest or name The newest installed version

A plugin step also accepts name, env, continue_on_error, timeout_minutes and working_directory. It does not take run or shell. See Pipeline syntax.

The version is resolved when the build starts. The build page shows the exact plugin version each step used.

Each plugin's page has Use it in a pipeline file with a ready-to-paste step: required inputs filled in, optional inputs as commented-out lines with their defaults. CI/CD → Pipeline syntax lists every installed plugin with its required inputs.

In a Freestyle project

On a Freestyle project's Build steps or Post-build tab, select Add plugin step, choose the plugin and fill in its form. The form is generated from the plugin's inputs.

How inputs are checked

OpsNexus checks plugin inputs when it validates the pipeline and again when a build starts. Problems are reported with their place, for example stages[1].steps[0].with.region: required.

Rule Detail
Unknown inputs An input the plugin does not have is an error. The message lists the plugin's inputs.
Required inputs An input marked required, with no default, must have a value.
Defaults An empty or missing input uses its default.
One value An input takes one value, not a mapping or list (except multichoice).
boolean true or false.
number A number, for example 22 or 0.5.
choice One of the listed options.
multichoice One or more options, as a comma-separated text (CRITICAL,HIGH) or a YAML list.
credential The name of a credential from Secrets & variables, not the secret itself.
Expressions A value containing ${{ ... }} is not checked. It is filled in at build time.

How inputs reach the plugin's script:

  • Each input becomes an environment variable INPUT_<NAME>, for example INPUT_REGION. Values are never pasted into the script text.
  • A credential input becomes ${{ secrets.<name> }}. It is masked in the log like any secret.
  • A credential input with fields also sets one variable per field, for example INPUT_AWS_ACCESS_KEY_ID and INPUT_AWS_SECRET_ACCESS_KEY for an input called aws.
  • For a Secret file credential (such as a kubeconfig), the input holds the path of a file the agent writes for the build.
  • Defaults can contain expressions. For example, the default tag of docker-build-push is ${{ run.number }}.

Where plugins run

  • Plugins with an image run their script in that pinned container image. The agent needs Docker. The workspace is mounted at the same path. Only the plugin's INPUT_* variables and CI, BUILD_NUMBER, JOB_NAME, BUILD_URL, GIT_COMMIT, GIT_BRANCH are passed into the container.
  • Plugins without an image run on the agent with their shell. Plugins that list required tools check them first and fail with Plugin <name> needs '<tool>' on this agent if one is missing.
  • A step fails when the plugin's script exits with a non-zero code.

Manage plugins

On a plugin's page:

Action What it does
Enable / disable toggle A disabled plugin cannot be used. Builds that use it fail until it is enabled again.
Export Downloads the latest version as a YAML file.
New version Custom plugins only: publish the next version.
Remove Removes the plugin. If jobs still use it, OpsNexus lists them and asks you to confirm by typing the name. Needs full access.

The page also shows About (how it runs and what it needs on the agent), Inputs, Script, Used by and Versions.

Write your own plugin

To create a plugin:

  1. Open Plugins and select Create plugin.
  2. Choose Where to create it: this project or all projects.
  3. Write the manifest. The page validates it as you type and previews the step form and the pipeline snippet.
  4. Select Create plugin.

A manifest:

yaml
name: notify-webhook              # 3-40 lowercase letters, digits and '-', starting with a letter
version: 1.0.0                    # MAJOR.MINOR.PATCH
title: Notify a webhook
description: Post a JSON message to a webhook URL.
category: notifications
inputs:
  url:     { type: credential, kinds: [secret_text], required: true, description: Webhook URL }
  message: { type: text, default: "Build ${{ run.number }} of ${{ job.name }} finished" }
  level:   { type: choice, options: [info, warning, error], default: info }
artifacts:                        # optional: files the step writes, archived with the build
  - reports/notify.json
runs:
  shell: python                   # bash | sh | python | pwsh | powershell | cmd
  script: |
    import json, os, urllib.request
    body = json.dumps({"text": os.environ["INPUT_MESSAGE"], "level": os.environ["INPUT_LEVEL"]}).encode()
    req = urllib.request.Request(os.environ["INPUT_URL"], data=body, headers={"Content-Type": "application/json"})
    urllib.request.urlopen(req, timeout=30)

Manifest keys:

Key Required Description
name Yes What uses: refers to. Cannot be the name of an official plugin.
version Yes MAJOR.MINOR.PATCH. Published versions never change; each new version must be higher.
title Yes 2 to 120 characters.
description No Shown on the Plugins page.
category No notifications, build, test, security, deploy, cloud, cost, infra, report or utility (default).
icon No A built-in icon name, or a small data:image/...;base64, image (under 48 KB).
author, license, changelog No Shown on the plugin page.
homepage No An https:// URL.
inputs No Up to 40 inputs. See below.
artifacts No Up to 20 workspace paths or globs. ${{ inputs.<name> }} inserts an input's value.
runs.shell No Default bash.
runs.script Yes Up to 64 KB. It must not contain ${{ }}; read INPUT_<NAME> variables instead.
runs.image No Run in this container image. Pin a version tag or digest; latest is refused. Only bash, sh and python work with an image.
runs.requires No Commands checked before a bash or sh script starts, for example [curl, jq].

Input keys: type (string default, text, number, boolean, choice, multichoice, credential), required, default, description, options (for choice types), kinds (allowed credential types), fields (credential fields to expose), secret and placeholder. Input names use lowercase letters, digits and _. Credential inputs cannot have a default.

The plugin file can be at most 200 KB.

Official plugin catalog

All official plugins have version 1.0.0, except trivy-scan (1.1.1). Credential types are the names shown on Secrets & variables.

Plugin Category Runs with
aws-cli Cloud Image amazon/aws-cli:2.22.0
aws-cost-guard Cost Image amazon/aws-cli:2.22.0
docker-build-push Build & containers bash on the agent, needs docker
email-notify Notifications python on the agent
helm-deploy Deploy Image alpine/k8s:1.31.2
http-request Utilities python on the agent
iac-security-scan Security & quality Image python:3.12-slim
infracost-estimate Cost Image infracost/infracost:ci-0.10
jira-comment Notifications python on the agent
junit-report Testing & reports python on the agent
kubectl-apply Deploy Image alpine/k8s:1.31.2
opsnexus-infra-deploy Infrastructure Image python:3.12-alpine
pdf-report Reports & charts Image python:3.12-slim
s3-upload Cloud Image amazon/aws-cli:2.22.0
slack-notify Notifications python on the agent
sonarqube-scan Security & quality Image sonarsource/sonar-scanner-cli:11.1
ssh-deploy Deploy bash on the agent, needs ssh and scp
teams-notify Notifications python on the agent
terraform Cloud Image hashicorp/terraform:1.9.8
terraform-plan-report Infrastructure Image hashicorp/terraform:1.9.8
trivy-scan Security & quality Image aquasec/trivy:0.57.1
workspace-cleanup Utilities python on the agent

aws-cli

Runs AWS CLI commands with an AWS credential and region, for example ECS deploys, CloudFront invalidations or Lambda updates. It can assume an IAM role first and prints the identity it uses.

Input Required Default Description
aws Yes AWS access key credential.
region Yes AWS region, for example ap-south-1.
role_arn No Assume this IAM role first (cross-account deploys).
commands Yes Commands to run, one or more lines.
yaml
- uses: aws-cli@1
  with:
    aws: aws-deployer
    region: ap-south-1
    commands: aws ecs update-service --cluster prod --service web --force-new-deployment

aws-cost-guard

Checks this month's AWS spend (Cost Explorer) and AWS's forecast for the month against a budget, lists the top services, and fails or warns before you deploy more. The credential needs ce:GetCostAndUsage and ce:GetCostForecast.

Input Required Default Description
aws Yes AWS access key credential (payer or member account).
budget Yes Monthly budget in USD.
check No forecast forecast or month-to-date: what to compare with the budget.
on_exceed No fail fail or warn.
top No 8 How many services to list.
yaml
- uses: aws-cost-guard@1
  with:
    aws: aws-billing
    budget: 2500
    check: forecast
    on_exceed: fail

docker-build-push

Builds a Docker image from the workspace and pushes it to any registry (Docker Hub, ECR, ACR, GHCR, Harbor, Nexus). Adds the commit and build URL as image labels.

Input Required Default Description
image Yes Image name without the tag, for example registry.example.com/team/app.
tags No ${{ run.number }} Tags separated by commas, for example 1.4.2, latest.
context No . Build context folder.
dockerfile No Dockerfile Dockerfile, relative to context.
build_args No One KEY=value per line.
target No Multi-stage target to build.
platform No For example linux/amd64.
registry No Registry to log in to (empty = Docker Hub), for example ghcr.io.
login No Username with password or Git access token credential. Leave empty if the agent is already logged in.
push No true Push the tags after building.
yaml
- uses: docker-build-push@1
  with:
    image: ghcr.io/acme/api
    tags: "${{ run.number }}, latest"
    registry: ghcr.io
    login: ghcr-login

email-notify

Sends an email through your SMTP server, optionally with workspace files attached. The build link is added to the body.

Input Required Default Description
smtp_host Yes For example smtp.office365.com.
smtp_port No 587 SMTP port.
security No starttls starttls, ssl or none.
login No Username with password credential. Leave empty for an open relay.
sender Yes From address.
to Yes Recipients, separated by commas.
subject No ${{ job.name }} #${{ run.number }} Subject.
body No Build ${{ run.number }} of ${{ job.name }} finished. Message text.
attachments No Workspace files to attach, one glob per line, for example reports/*.html.
yaml
- uses: email-notify@1
  with:
    smtp_host: smtp.example.com
    login: smtp-login
    sender: ci@example.com
    to: team@example.com
    attachments: reports/*.html

helm-deploy

Installs or upgrades a Helm chart (helm upgrade --install) and waits until it is ready. Creates the namespace if needed.

Input Required Default Description
kubeconfig Yes Secret file credential holding the kubeconfig.
release Yes Release name, for example web.
chart Yes Chart folder in the workspace (./chart), repo/name, or oci://....
namespace No default Namespace.
version No Chart version (repository or OCI charts).
values_files No Values files in the workspace, one per line.
set No One key=value per line, for example image.tag=1.4.2.
repo_url No Add this chart repository first, then use repo/name as chart.
wait_timeout No 5m0s How long Helm waits.
atomic No true Roll back automatically if the upgrade fails.
yaml
- uses: helm-deploy@1
  with:
    kubeconfig: prod-kubeconfig
    release: web
    chart: ./chart
    namespace: web
    values_files: chart/values-prod.yaml
    set: image.tag=${{ run.number }}

http-request

Calls any HTTP API, or waits for a URL to become healthy, with retries, an expected status and an optional bearer token.

Input Required Default Description
url Yes For example https://api.example.com/health.
method No GET GET, POST, PUT, PATCH, DELETE or HEAD.
headers No One header per line, for example Content-Type: application/json.
body No Request body.
token No Secret text, Git access token or Password credential, sent as Authorization: Bearer <token>.
expected_status No 200-299 A status, a range (200-299) or a list (200,201,204).
retries No 0 Extra attempts when the status does not match.
retry_delay_seconds No 10 Wait between attempts.
timeout_seconds No 30 Timeout per request.
save_to No Save the response body to this workspace file.
yaml
- uses: http-request@1
  with:
    url: https://staging.example.com/health
    retries: 12
    retry_delay_seconds: 10

iac-security-scan

Scans Terraform, CloudFormation, Kubernetes, Helm, Dockerfiles and GitHub Actions workflows for misconfigurations with Checkov, writes a JUnit report and fails on findings. The report is archived with the build as a test report, with passed and failed counts.

Input Required Default Description
directory No . Folder to scan.
frameworks No terraform,kubernetes,dockerfile One or more of terraform, cloudformation, kubernetes, helm, dockerfile, github_actions.
skip_checks No Check IDs to skip, comma-separated, for example CKV_AWS_20,CKV_AWS_18.
soft_fail No false Report findings without failing the step.
report_file No checkov-junit.xml JUnit XML report, archived with the build.
yaml
- uses: iac-security-scan@1
  with:
    directory: infra
    frameworks: [terraform, dockerfile]

infracost-estimate

Estimates the monthly cost of Terraform code with Infracost, prints a breakdown per resource, and fails when it is above your budget. Needs an Infracost API key.

Input Required Default Description
directory No . Folder with the .tf files.
api_key Yes Secret text credential with the Infracost API key.
currency No USD Currency.
budget No Fail when the estimated monthly cost is above this. Empty = never fail.
usage_file No infracost-usage.yml with expected usage.
report_file No infracost.json JSON breakdown, archived with the build.
yaml
- uses: infracost-estimate@1
  with:
    directory: infra/environments/prod
    api_key: infracost-key
    budget: 1200

jira-comment

Adds a comment with a link to the build to one or more Jira issues. Fails if any issue could not be commented on.

Input Required Default Description
site Yes For example https://yourcompany.atlassian.net.
login Yes Username with password credential: Jira email and API token.
issues Yes Issue keys separated by commas, for example OPS-12, OPS-15.
comment No Build #${{ run.number }} of ${{ job.name }} finished. Comment text.
yaml
- uses: jira-comment@1
  with:
    site: https://acme.atlassian.net
    login: jira-bot
    issues: OPS-12

junit-report

Reads JUnit or xUnit XML results (pytest, Jest, Maven Surefire, Go, .NET), prints a summary with every failure, and fails or warns on failed tests.

Input Required Default Description
results No **/TEST-*.xml and **/junit*.xml Result files, one glob per line.
fail_on_failure No true Fail the step when a test failed.
allow_empty No false Do not fail when no result files are found.
yaml
- uses: junit-report@1
  with:
    results: |
      reports/junit/*.xml
    fail_on_failure: true

To keep the XML files with the build, add them to artifacts: in the pipeline file.

kubectl-apply

Applies manifests (or kustomizations) to a Kubernetes cluster and waits for rollouts.

Input Required Default Description
kubeconfig Yes Secret file credential holding the kubeconfig.
manifests No k8s/ Files or folders in the workspace, one per line.
kustomize No false Treat each path as a kustomization folder (-k).
namespace No Namespace for objects that do not set one.
wait_for No Rollouts to wait for, one per line, for example deployment/web.
timeout No 300s Rollout wait timeout.
dry_run No false Validate on the server without changing anything.
yaml
- uses: kubectl-apply@1
  with:
    kubeconfig: staging-kubeconfig
    manifests: k8s/overlays/staging
    kustomize: true
    wait_for: deployment/web

opsnexus-infra-deploy

Plans, applies or destroys an Infra Designer stack from a pipeline, waits for it and prints the plan and outputs. It calls the OpsNexus API with an API key. The deployment itself also runs on a build agent, so keep a second executor free.

Input Required Default Description
server_url Yes OpsNexus address the agent can reach.
api_key Yes Secret text credential with an OpsNexus API key (access.secret) of a user with Cloud: modify (Cloud: full to approve from the pipeline).
project_id No Project of the stack. Empty = the key's default project.
stack_id Yes Stack ID, from the stack page URL.
action No plan plan, apply or destroy.
approve No false For apply: approve the plan from the pipeline. Otherwise someone approves it in OpsNexus.
confirm No For destroy: the stack name, as OpsNexus asks for it.
timeout_minutes No 60 How long to wait.
yaml
- uses: opsnexus-infra-deploy@1
  with:
    server_url: https://opsnexus.example.com
    api_key: opsnexus-deployer
    stack_id: 0b6f7c1e-0000-0000-0000-000000000000
    action: apply

pdf-report

Turns your pipeline's own results (a JSON or CSV file with test counts, timings, coverage, costs and so on) into a PDF with charts and tables. The PDF is archived with the build.

Input Required Default Description
data_file Yes CSV (first column = labels, other columns = series) or JSON.
title No Build report Report title.
chart No bar Chart for CSV data: bar, hbar, pie, donut or line. JSON charts name their own type.
style No classic classic, modern, minimal or dark.
palette No default default, ocean, sunset, forest, vivid or mono.
include_table No true Also print the data as a table.
output No report.pdf PDF file, archived with the build.

The JSON format:

json
{
  "title": "Nightly tests",
  "summary": {"Tests": 120, "Failed": 2},
  "charts": [{"title": "Duration", "type": "bar", "labels": ["api", "web"],
              "series": [{"name": "seconds", "values": [41, 63]}], "unit": "s"}],
  "tables": [{"title": "Slowest", "columns": ["Test", "s"], "rows": [["checkout", 12.4]]}]
}
yaml
- uses: pdf-report@1
  with:
    data_file: reports/summary.json
    style: modern
    output: reports/summary.pdf

s3-upload

Uploads files or folders from the workspace to an S3 bucket. A folder is synced; a file is copied. It can also invalidate a CloudFront distribution for static sites.

Input Required Default Description
aws Yes AWS access key credential.
region Yes AWS region.
source Yes File or folder in the workspace, for example dist/.
bucket Yes Bucket name.
prefix No ${{ job.name }}/${{ run.number }} Folder (key prefix) in the bucket.
sync_delete No false Delete objects under the prefix that are no longer in the source.
cache_control No For example public, max-age=300.
cloudfront_distribution No Invalidate this distribution afterwards.
yaml
- uses: s3-upload@1
  with:
    aws: aws-deployer
    region: ap-south-1
    source: dist/
    bucket: www-example-com
    prefix: /
    sync_delete: true
    cloudfront_distribution: E1ABCDEF234567

slack-notify

Posts a build message to a Slack channel through an incoming webhook.

Input Required Default Description
webhook Yes Secret text credential with the Slack incoming webhook URL.
message No Build #${{ run.number }} of ${{ job.name }} finished Message text (Slack mrkdwn).
status No success Colour of the message bar: success, warning, failure or info.
channel No Override the webhook's default channel, for example #deploys.
include_link No true Add a link to the build.
yaml
- uses: slack-notify@1
  with:
    webhook: slack-webhook
    status: success
    message: "Deployed ${{ job.name }} #${{ run.number }} to production"

sonarqube-scan

Runs SonarScanner on the workspace and sends the analysis to SonarQube or SonarCloud, optionally waiting for the quality gate.

Input Required Default Description
host_url Yes For example https://sonarqube.example.com.
token Yes Secret text credential with a SonarQube user or project analysis token.
project_key Yes Project key.
sources No . Source folder.
organization No SonarCloud organization key.
extra_properties No More analysis properties, one key=value per line.
wait_for_quality_gate No true Fail the step when the quality gate fails.
yaml
- uses: sonarqube-scan@1
  with:
    host_url: https://sonarqube.example.com
    token: sonar-token
    project_key: web-app
    extra_properties: sonar.exclusions=**/test/**

ssh-deploy

Copies files to a server over SSH and runs commands there.

Input Required Default Description
host Yes For example app-01.example.com.
port No 22 SSH port.
user Yes Login user, for example deploy.
key Yes SSH username with private key credential.
known_hosts No Host key lines from ssh-keyscan. Empty = accept the host key on first connect (less safe).
files No Workspace files or folders to copy, one per line.
remote_dir No /tmp/deploy Where the files go on the server.
command No Commands to run on the server after copying.
yaml
- uses: ssh-deploy@1
  with:
    host: app-01.example.com
    user: deploy
    key: deploy-ssh
    files: dist.tgz
    remote_dir: /opt/app/releases
    command: |
      cd /opt/app/releases && tar xzf dist.tgz && sudo systemctl restart app
Warning

Set known_hosts for production servers. Without it, the plugin accepts whatever host key the server presents on first connect.

teams-notify

Posts a build card to a Microsoft Teams channel through a Workflows webhook ("Post to a channel when a webhook request is received").

Input Required Default Description
webhook Yes Secret text credential with the Teams Workflows webhook URL.
title No ${{ job.name }} #${{ run.number }} Card title.
message No Build finished Card text.
status No success success, warning, failure or info.
yaml
- uses: teams-notify@1
  with:
    webhook: teams-webhook
    status: failure
    message: Build failed on ${{ git.branch }}

terraform

Runs terraform init and then plan, apply, destroy or validate in a workspace folder. apply and destroy run with -auto-approve; put an approval stage before them.

Input Required Default Description
command No plan plan, apply, destroy or validate.
directory No . Folder with the .tf files.
workspace No Terraform workspace to select (created if missing).
vars No One name=value per line, passed as -var.
var_files No .tfvars files, one per line.
backend_config No One key=value per line for terraform init -backend-config.
aws No AWS access key credential for the AWS provider or S3 backend.
azure No Azure service principal credential.
azure_subscription_id No Azure subscription ID.
region No AWS_REGION for the AWS provider.
yaml
stages:
  - name: Plan
    steps:
      - uses: terraform@1
        with: { command: plan, directory: infra, aws: aws-deployer, region: ap-south-1 }
  - name: Apply
    approval: { message: Apply the Terraform plan? }
    steps:
      - uses: terraform@1
        with: { command: apply, directory: infra, aws: aws-deployer, region: ap-south-1 }

terraform-plan-report

Runs terraform plan and writes a readable Markdown summary (resources to add, change, replace and destroy) that is archived with the build. It can block destroys or any change.

Input Required Default Description
directory No . Folder with the .tf files.
var_files No .tfvars files, one per line.
backend_config No One key=value per line for terraform init -backend-config.
aws No AWS access key credential for the AWS provider or S3 backend.
region No AWS_REGION for the AWS provider.
fail_on No destroy nothing, destroy (fails when the plan destroys or replaces resources) or any-change.
report_file No terraform-plan-report.md Report file, archived with the build.
yaml
- uses: terraform-plan-report@1
  with:
    directory: infra/environments/prod
    aws: aws-deployer
    region: ap-south-1
    fail_on: destroy

trivy-scan

Scans the workspace (dependencies, IaC misconfigurations, leaked secrets, licenses) or a registry image for vulnerabilities and fails on the severities you choose. The full JSON report is archived with the build and its findings appear under Security.

Input Required Default Description
target No workspace workspace (the checked-out code) or image.
path No . Folder to scan (workspace target).
image No Image to scan (image target), for example ghcr.io/org/app:1.4.2.
registry_login No Username with password or Git access token credential for a private registry.
scanners No vuln,misconfig,secret One or more of vuln, misconfig, secret, license (workspace target).
severity No CRITICAL,HIGH One or more of CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN: shown in the table and used to fail.
fail_on_findings No true Fail the step when something at these severities is found.
ignore_unfixed No false Hide vulnerabilities that have no fix yet.
report_file No reports/trivy-report.json JSON report, archived with the build. Empty = no report.
yaml
- uses: trivy-scan@1
  with:
    target: image
    image: ghcr.io/acme/api:${{ run.number }}
    registry_login: ghcr-login
    severity: [CRITICAL, HIGH]

workspace-cleanup

Deletes files from the build workspace (everything, or only matching patterns) to save disk on the agent. It never deletes outside the workspace.

Input Required Default Description
patterns No Globs to delete, one per line, for example node_modules or **/*.log. Empty = the whole workspace.
keep No .git Top-level names to keep when cleaning everything, one per line.
dry_run No false Only list what would be deleted.
yaml
post:
  always:
    - uses: workspace-cleanup@1
      with:
        patterns: |
          node_modules
          **/*.log