Skip to content

Latest commit

 

History

372 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

x-cmd/action

GitHub composite Action that bootstraps a CI runner with x-cmd, git, docker and SSH — so your workflow only contains the build step.

License: Apache-2.0 中文文档


Overview

x-cmd/action is a composite GitHub Action from x-cmd/action. It collapses the repetitive "spin up a runner" steps — installing x-cmd, configuring git/docker/SSH, optionally cloning a workspace repo, and uploading artifacts — into a single reusable step.

┌──────────────┐    ┌──────────────┐    ┌────────────────────┐
│   init step  │ →  │   run step   │ →  │  upload-artifact   │
│ ssh / x-cmd  │    │ prehook →    │    │  (always last)     │
│ docker / git │    │ script →     │    │  ~/ws/.artifact    │
│              │    │ code →       │    │                    │
│              │    │ posthook     │    │                    │
└──────────────┘    └──────────────┘    └────────────────────┘

You just write a step. You don't worry about how x-cmd gets onto the runner.


Design Philosophy — a portable Action

Most GitHub Actions are tightly coupled to GitHub's runtime. actions/checkout checks out a repo in a GitHub-specific way. actions/setup-node downloads Node in a GitHub-specific way. The moment you stitch your CI together out of these, your script only runs on GitHub — and often only on GitHub's hosted runners.

x-cmd/action takes the opposite approach: write your script in plain POSIX shell, run it anywhere.

The action does exactly three things:

  1. Install x-cmd — a POSIX-compatible shell library (works in dash, ash, bash, zsh) into ~/.x-cmd.root/. Once installed, x cowsay, x ws build, x eget, etc. are just shell commands on PATH.
  2. Run your scriptsource it (or eval the inline code:), with x-cmd already loaded. This is the same file you'd run locally with ./scripts/ci.sh. No ${{ github.* }} interpolation, no actions/checkout shim, no YAML quoting gymnastics.
  3. Upload the artifact — the only step that's truly GitHub-specific, because artifact storage is GitHub's service. Anything you write to ~/ws/.artifact gets uploaded.

That's the whole design. git is just git, docker is just docker, ssh is just ssh. The action installs the shell library you already know how to use.

Why this matters:

  • Your CI script is your dev script. Same file, same syntax, same commands. Debug locally with ./scripts/ci.sh — no act, no Docker, no PR-then-watch-logs loop.
  • CI-provider-agnostic. Switching from GitHub Actions to another provider means changing one line (- uses: x-cmd/action@main → the new provider's equivalent). The script body is untouched.
  • The artifact is the bridge between local and CI. Locally you keep state on disk; in CI the runner is ephemeral, so the action uploads ~/ws/.artifact automatically — you get back the same files you would have had if you'd run the script yourself.

In other words: CI = install x-cmd + run my script + upload artifact. That's it.


Part A — Using x-cmd Without This Action

Skip everything below if you came here just to plug x-cmd/action into a workflow. This part is for users who don't need GitHub Actions, or want to understand what the action is doing under the hood.

A.1 Load x-cmd into a shell

The same one-liner works in both a script body and a shell init file:

if [ -f "$HOME/.x-cmd.root/X" ]; then
    . "$HOME/.x-cmd.root/X"
else
    eval "$(curl -s https://get.x-cmd.com)"
fi
  • In a script — paste at the top. Idempotent: re-runs fine because X itself guards against double-loading.
  • Globally (per user) — paste into ~/.bashrc / ~/.zshrc. After login, x <module> works in every interactive shell.

A.2 Calling x-cmd — two distinct modes

The two invocations styles look interchangeable but are not equivalent. Pick deliberately based on whether you need shell state to survive across calls.

# Mode 1: as an external command — fresh subshell each call
x-cmd cowsay "hello"

# Mode 2: load x-cmd into the current shell, then call x as a function
. "$HOME/.x-cmd.root/X"
x cowsay "hello"
x ws build
x sysinfo
Mode 1: x-cmd <module> Mode 2: . X then x <module>
What x is an external program on PATH a shell function defined by sourcing X
Setup needed none must . X first
Per-call cost fork + exec direct function call
Sees shell-local vars / functions / aliases no (fresh shell each call) yes
Can mutate the calling shell (set vars, define aliases, modify PATH) no yes
Available in shells that haven't sourced X yes, if x-cmd is on PATH no
Typical use cron jobs, sh -c "...", before login scripts, one-off CLI interactive shell, scripts that call x many times

The non-equivalence in one sentence: Mode 2 lets x participate in your shell's state; Mode 1 cannot. If your script needs x to see (or change) variables defined outside the call, you need Mode 2.

Note also that the two are not always both available — Mode 1 requires x-cmd to have been installed as an external command on PATH; Mode 2 only needs the X source file to exist. The if [ -f "$HOME/.x-cmd.root/X" ] pattern in §A.1 covers Mode 2's bootstrap regardless of whether Mode 1 is wired up.

A.3 What x-cmd/action does, in those terms

x-cmd/action's init step is just A.1 in disguise: it ensures ~/.x-cmd.root/X exists (by eval-installing via x-cmd/get), then the run step . ${___X_CMD_ROOT}/X switches you into Mode 2. The artifact upload at the end is the only piece that's GitHub-specific. Everything else is plain x-cmd.


Part B — Using x-cmd Inside GitHub Actions

The rest of this README documents x-cmd/action itself.

1. Basic Usage

1.1 Hello world — one inline command

# .github/workflows/hello.yml
name: Hello
on: [push]
jobs:
  hello:
    runs-on: ubuntu-latest
    steps:
      - uses: x-cmd/action@main
        with:
          code: x cowsay "hello from x-cmd"

That's the whole thing. The action installs x-cmd, then evals whatever you put in code.

1.2 A few one-liners to feel it out

# inspect the runner
code: x sysinfo

# grab a binary via x eget
code: x eget use jq && jq --version

# fetch weather
code: x wttr 'Beijing'

# disk usage
code: x df

1.3 Convention script — drop a file, no script: needed

When script: is omitted, the action defaults to .x-cmd/<github.job> and sources it with bash. So a job named build automatically picks up .x-cmd/build:

# .github/workflows/build.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: x-cmd/action@main
# .x-cmd/build
type x
x ws build

Override the path explicitly:

- uses: x-cmd/action@main
  with:
    script: scripts/ci.sh

1.4 Running multiple commands — three patterns

Pick one based on how serious the script is.

Pattern A — multi-line code: (throwaway)

Quickest. Use when the commands are short and tied to the workflow file.

- uses: x-cmd/action@main
  with:
    code: |
      x cowsay "step 1"
      x sysinfo | head
      x ws build

Pattern B — repeat the action (cleanest separation)

Each invocation is independent. Good when steps are conceptually unrelated.

steps:
  - uses: x-cmd/action@main
    with:
      code: x ws build

  - uses: x-cmd/action@main
    with:
      code: x ws test

  - uses: x-cmd/action@main
    with:
      code: x ws publish

Pattern C — portable script (recommended)

Write the script once, run it locally, in CI, anywhere. One line at the top loads x-cmd into the current shell.

# scripts/ci.sh — portable: works in any shell on any machine

. "$HOME/.x-cmd.root/X"

x cowsay "step 1"
x sysinfo | head
x ws build
# .github/workflows/build.yml
- uses: x-cmd/action@main
  with:
    script: scripts/ci.sh

Why this is the recommended pattern:

  • Same file runs ./scripts/ci.sh on your laptop and inside GitHub Actions.
  • The script is the single source of truth — no copy-paste between local dev and CI.
  • When x-cmd is missing, the script fails loudly with a clear error — which is what you want.
  • When the script grows, refactor freely without touching action.yml.

2. Advanced Usage

2.1 Pre/post hooks

Run shell code before and after the main script:

- uses: x-cmd/action@main
  with:
    prehook: |
      x log :setup "preparing"
      mkdir -p build
    script: .x-cmd/build
    posthook: |
      x log :teardown "cleaning up"
      rm -rf build

Execution order: prehookscriptcodeposthook.

2.2 Push back to GitHub over SSH

Set commit identity with git_user / git_email, and pass a private key with ssh_key. The action starts ssh-agent, writes known_hosts from x-cmd/knownhost, and ssh-adds your key — no manual plumbing.

- uses: x-cmd/action@main
  env:
    ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
  with:
    git_user: ci-bot
    git_email: ci@example.com
    code: |
      git clone git@github.com:me/notes.git
      cd notes
      echo hello >> README.md
      git commit -am "ci: update"
      git push

2.3 Clone a workspace repo first

Set ws_owner_repo + ws_repo_ref and the action clones that repo, creates a ws/ symlink, then cds into it before running your script.

- uses: x-cmd/action@main
  env:
    ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
  with:
    ws_owner_repo: x-cmd/ws
    ws_repo_ref: main
    script: .x-cmd/build

Defaults: ws_owner_repo${{ github.repository }}, ws_repo_ref${{ github.head_ref || github.ref_name }}.

Authenticated HTTPS clone when github_token is set.

2.4 Docker login + buildx

- uses: x-cmd/action@main
  with:
    docker_username: ${{ secrets.DOCKERHUB_USERNAME }}
    docker_password: ${{ secrets.DOCKERHUB_TOKEN }}
    docker_buildx_init: 'true'
    code: docker buildx build --platform linux/amd64,linux/arm64 -t me/app .

2.5 Upload an artifact

The final step is always actions/upload-artifact@v4. Anything under ~/ws/.artifact is uploaded.

- uses: x-cmd/action@main
  with:
    code: x ws art                     # populates ~/ws/.artifact
    artifact_name: release
    artifact_path: ~/ws/.artifact
    artifact_retention_days: 30
Knob Default Notes
artifact_name artifact
artifact_path ~/ws/.artifact
artifact_not_found ignore warn / error / ignore
artifact_retention_days 10 1–90

2.6 Matrix build across containers or OS

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        image: [xcmd/ubuntu-dev, xcmd/centos-dev]
    container:
      image: ${{ matrix.image }}
    steps:
      - uses: x-cmd/action@main
        with:
          code: x ws build ${{ matrix.image }}

2.7 Switch x-cmd release stream

By default the action pulls the stable installer (index.html). To test a non-release stream, set ___X_CMD_GHACTION_X:

- uses: x-cmd/action@main
  env:
    ___X_CMD_GHACTION_X: x7    # x0 (community-dev) / x1-x6 (experimental) / x7 (alpha)
  with:
    code: x --version

2.8 Fall back to env vars

Any input falls back to a matching environment variable if it isn't set explicitly. Useful for matrix jobs that share most knobs:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
      git_user: ci-bot
      git_email: ci@example.com
    strategy:
      matrix: { os: [ubuntu-latest, macos-latest] }
    steps:
      - uses: x-cmd/action@main        # no `with:` needed; uses job-level env
        with:
          code: x ws build ${{ matrix.os }}

3. All Parameters

Input Default Description
prehook Shell code evaluated before the main script.
script .x-cmd/<github.job> Script file (source-d with bash).
code Inline shell code evaluated after the script.
posthook Shell code evaluated after the main script.
ws_owner_repo ${{ github.repository }} <owner>/<repo> cloned into ws/.
ws_repo_ref ${{ github.head_ref || github.ref_name }} Branch / tag / SHA.
github_token secrets.GITHUB_TOKEN Used for authenticated HTTPS clone.
ssh_key Private SSH key (PEM) loaded into ssh-agent.
git_user head-commit author git config user.name.
git_email head-commit author email git config user.email.
docker_username docker login username.
docker_password docker login password.
docker_buildx_init false If truthy, runs docker buildx create --use.
artifact_name artifact Name passed to upload-artifact.
artifact_path ~/ws/.artifact Path passed to upload-artifact.
artifact_not_found ignore warn / error / ignore.
artifact_retention_days 10 1–90.

artifact_* knobs are forwarded to the always-last actions/upload-artifact@v4 step — the action always runs it.


4. How it Works

At the user level, the action is just three steps: install x-cmd → run your script → upload artifact. The rest of this section is the mechanical view of how those three steps are wired up.

4.1 Layout

action.yml          composite-action metadata & steps
lib/index.sh        core init / run dispatcher (pulled via curl)
.github/workflows/  example workflows (art, build-docker, build-node, build-os, cowsay)
.x-cmd/             convention: scripts named after the job, e.g. .x-cmd/build
LICENSE             Apache 2.0

4.2 Why two shell: bash steps

The three user-facing steps map onto three composite steps: init runs the install, run executes the script, and the artifact upload is a third. Composite-action steps are independent shell processes — variables and functions don't carry over — so the dispatcher script is downloaded to ~/xghaction once, then re-sourced in each step so its functions come back.

4.3 Step 1 — init

- run: |
    curl -s https://raw.githubusercontent.com/x-cmd/action/main/lib/index.sh > ~/xghaction
    . ~/xghaction init

___x_cmd_ghaction_init runs four sub-steps:

  1. SSH — start ssh-agent, write ~/.ssh/known_hosts from x-cmd/knownhost, ssh-add the key.
  2. x-cmdeval "$(curl ... x-cmd/get/main/<stream>)" installs to ~/.x-cmd.root/.
  3. Docker — optional docker login and docker buildx create --use.
  4. Git — set user.name / user.email, optionally clone ws_owner_repows/.

All wrapped in set +o errexit and || true, so a sub-step failure doesn't kill the job.

Conditional execution. Every sub-step is gated by its inputs — without the matching input (or env var), the sub-step is skipped entirely. So a minimal workflow using only code: only pays for the x-cmd install:

Sub-step Runs when
x-cmd install always
SSH (known_hosts, ssh-agent, ssh-add) ssh_key is set
Docker login docker_username and docker_password are both set
Docker buildx init docker_buildx_init is truthy
Git user.name / user.email git_user or git_email is set
Clone workspace repo ws_owner_repo and ws_repo_ref are both set

4.4 Step 2 — run

- run: . ~/xghaction run

___x_cmd_ghaction_run:

. "${___X_CMD_ROOT:-~/.x-cmd.root}/X"   # actually load x-cmd into PATH
cd ws
eval "$prehook"
source "$script"
eval "$code"
eval "$posthook"

Note that init is for setup; x-cmd is only loaded into the shell here, after step 1 has finished installing.

4.5 Step 3 — actions/upload-artifact@v4

Always runs. Forwards artifact_* inputs verbatim.

4.6 Scope — what's first-class, what's delegated

x-cmd/action only handles a small set of "first-class" infrastructure: SSH, Docker, AI credentials, and the auto-available GITHUB_TOKEN. Everything else — language toolchains, package managers, linters, anything you'd apt install or brew install — is deliberately not the action's job.

Why this split:

  • SSH, Docker, AI, and gh-token are both essential and security-sensitive. They each get a dedicated input so secrets don't have to be pasted into a code: string, and so the action can wire them into the system correctly (loading ssh-agent, writing ~/.docker/config.json, etc.) rather than leaving the script to do it ad-hoc.
  • Other tools can be installed on-demand from inside the script. x-cmd itself ships modules for most ecosystems; if the action tried to provide all of them, every invocation would re-download dozens of toolchains. Better to let the script pull what it needs, when it needs it.
  • Goal: parity with local dev, with minimum config. When you sit down at your laptop you already have git, ssh, docker, plus whatever languages you happen to use (node, python, etc.). x-cmd/action replicates the first half out of the box; the second half is one line in the script — x env use node, x env use python, etc.
  • Future direction. x-cmd's hub will surface npm, crates.io, pip, jsr as first-class x-cmd modules. Once that lands, no action input is needed for them — x npm, x cargo, etc. will work the same way inside the action as they do locally.

In short: the action's job is to remove infrastructure friction. Toolchain friction is x-cmd's job.


5. FAQ

Do I need to set git_user / git_email on every step?

No — set them once per job and they persist. The action runs git config --global user.name/email, which writes to ~/.gitconfig. The runner filesystem is shared across all steps in a single job, so any subsequent git commit in the same job uses the identity already on disk:

steps:
  - uses: x-cmd/action@main
    with:
      git_user: ci-bot
      git_email: ci@example.com
      code: |
        echo a >> README.md
        git add . && git commit -m "a"

  - uses: x-cmd/action@main
    # no git_user/git_email here — still commits as ci-bot
    with:
      code: |
        echo b >> README.md
        git add . && git commit -m "b"

Across jobs in the same workflow, runners are usually fresh VMs and ~/.gitconfig doesn't carry. Set git_user / git_email per job (or hoist them to job-level env: — the action falls back to env vars). On self-hosted persistent runners the file does carry over, which can be surprising — set explicitly when in doubt.

Do I need actions/checkout first?

No. The action pulls its own dispatcher via curl and clones the workspace repo via git clone only if you set ws_owner_repo. If you need the current repo checked out for your own scripts, add actions/checkout@v4 separately.

Will x-cmd installation fail break my job?

No. The init step runs with errexit disabled and the eval has || true. Failures show up in logs but the workflow continues. To debug, look for -------------------------------HOME[...] and the curl output.

Where is x-cmd installed?

~/.x-cmd.root/. It's per-runner, per-job — gone the moment the job ends.

Can I pin a specific x-cmd version?

Indirectly — by pinning this action (x-cmd/action@v1.2.3) and switching ___X_CMD_GHACTION_X to a known stream. There's no per-commit hash pinning for the x-cmd installer itself.

Does it work on macOS / Windows runners?

bash + curl + git + ssh-agent + docker must be present. GitHub-hosted ubuntu-latest and macos-latest are tested. windows-latest may work but is not a primary target — wrap with shell: bash and verify.

Can I run the action multiple times in one job?

Yes. Each invocation is independent — a fresh init then a fresh run. The first one pays the install cost; subsequent ones reuse the same ~/.x-cmd.root/ (it's idempotent).

Why two separate bash steps instead of one big script?

Composite-action steps don't share shell state, and init (slow, installs x-cmd) and run (fast, executes user code) belong to different stages. Splitting them makes the action composable — you can uses: x-cmd/action for the run only, after doing your own setup.

How is ws/ created?

When ws_owner_repo and ws_repo_ref are both set, the action does git clone --branch <ref> <url> and then ln -s $(pwd)/<repo> $(pwd)/ws. The symlink is what your script: path resolves against after cd ws.

How does x-cmd/action's install differ from eval "$(curl -s https://get.x-cmd.com)"?

Functionally identical — both end up with the same x-cmd installed under ~/.x-cmd.root/. The action just knows it's inside GitHub Actions, so it pins the install to a specific URL.

From lib/index.sh, the action does:

eval "$(curl "https://raw.githubusercontent.com/x-cmd/get/main/$___X_CMD_GHACTION_X")" || true

…where ___X_CMD_GHACTION_X defaults to index.html (stable), with x0 (community-dev) / x1-x6 (experimental) / x7 (alpha) available for non-release builds.

The generic eval "$(curl -s https://get.x-cmd.com)" is the same content served via a different endpoint — a CDN-fronted domain that ultimately serves x-cmd/get's index.html. In the action's git history you can see the older versions of this line used x-bash/get and get.x-cmd.com before settling on the direct raw URL.

Why the action uses a direct GitHub URL:

For GitHub-hosted runners (the default — ubuntu-latest, macos-latest, etc.), the runner runs inside GitHub's own data centers. raw.githubusercontent.com is also GitHub's infrastructure, so the curl is effectively an internal fetch — same network, no external hop, no cross-ISP routing, no third-party DNS. By contrast, get.x-cmd.com is an external CDN: the request leaves GitHub's network, hits the public DNS, traverses the public internet, and lands at a third-party edge. Same content either way; on hosted runners the internal path is shorter and more controlled.

For self-hosted runners, this assumption doesn't hold — your runner is wherever you put it. Connectivity to raw.githubusercontent.com and to get.x-cmd.com will depend on your own network. In that case the CDN URL may actually be faster, but you can still use the action and let it pick the raw URL; just don't assume the topology benefit applies.

One important counterpoint. get.x-cmd.com carries a regional routing layer that raw.githubusercontent.com does not — explicit support for connectivity from China is part of why the CDN exists. So:

  • For hosted runners (mostly in US/EU data centers), raw.githubusercontent.com wins on the internal-fetch argument.
  • For self-hosted runners in China, or for users in China installing x-cmd locally, get.x-cmd.com is often the more reliable choice — its routing is tuned for that network.

The action's hard-coded raw URL is the right default for the common case (hosted runners worldwide), but it's worth knowing the trade-off if you're running x-cmd from inside China.

The two real differences in summary:

x-cmd/action eval "$(curl ... get.x-cmd.com)"
Install URL direct raw: raw.githubusercontent.com/x-cmd/get/main/<stream> CDN: get.x-cmd.com
Network path (on GitHub-hosted runners) internal to GitHub's data center leaves GitHub's network → public internet → CDN edge
Network path (on self-hosted runners) depends on your network depends on your network
Stream selection explicit via ___X_CMD_GHACTION_X env var (index.html / x0 / x1-x6 / x7) whatever the CDN serves at request time
Failure handling || true + init context has errexit off — install failure doesn't kill the job up to the caller

Use x-cmd/action inside GitHub Actions; use the generic install (§A.1 pattern) everywhere else.

Why can't my shell find binaries installed by x eget use or x env use?

x eget use drops the binary into $HOME/.local/bin/. x env use (and other x-cmd package installs) drop into a per-package path under ~/.x-cmd.root/local/data/pkg/sphere/.../bin/. Neither directory is on PATH by default in a fresh shell — installing a tool is not the same as putting it on PATH.

Fix: either configure PATH explicitly, or load x-cmd into the current shell — . "$HOME/.x-cmd.root/X" does the PATH setup for you.

# Option 1: source x-cmd first — PATH is wired up
. "$HOME/.x-cmd.root/X"
x eget use jq
jq --version                # works

# Option 2: prepend the install paths yourself
export PATH="$HOME/.local/bin:$PATH"

Inside x-cmd/action: the run step already does . $___X_CMD_ROOT/X, so binaries installed by x eget use / x env use inside code: are callable from the same code: block (and from the same step's subsequent invocations):

- uses: x-cmd/action@main
  with:
    code: |
      x eget use jq
      jq --version            # works — PATH was set up by the action's . X

Across separate action steps: each step is an independent bash process, so PATH does not carry over. If step A does x eget use jq and step B wants to call jq, step B must load x-cmd again (which the action does automatically) — and since the install in $HOME/.local/bin survives between steps, jq will be found as long as x-cmd is loaded in step B.

What's ~/xghaction?

A transient dispatcher file downloaded by the first step and re-sourced by the second. Safe to ignore; don't put your own file at that path.

How do I run multiple x-cmd commands?

Three options, see §1.4:

  • Multi-line code: for throwaway inline sequences.

  • Repeat the action for cleanly separated, unrelated steps.

  • Portable script (recommended) — one file, runs locally and in CI. Add this line at the top:

    . "$HOME/.x-cmd.root/X"

    In CI via x-cmd/action, x-cmd is installed by the init step before the script runs, so this source succeeds. Locally, run eval "$(curl -s https://get.x-cmd.com)" once to install, then the same line works thereafter.

    X is idempotent — sourcing it again on a shell where x-cmd is already loaded is a no-op, so it's safe to leave the line at the top of every script (and safe to source the script itself multiple times).

Why is my artifact not appearing?

Most common causes:

  • artifact_path is wrong (default is ~/ws/.artifact, not ./artifact).
  • code: ran but didn't write anything to the path.
  • artifact_not_found is set to error, hiding the actual issue. Try warn.

Related Links

Example Workflows

The .github/workflows/ directory is a demonstration gallery, not production CI for this repo (the action itself is just action.yml + lib/index.sh). Each workflow is workflow_dispatch-only — never auto-runs on push — and you can trigger it by hand from the Actions tab to see the pattern working end-to-end.

See .github/workflows/README.md for the full list. Highlights:

  • test-git-push.yml — push a commit back using ssh_key + git_user + git_email.
  • test-workspace-repo.yml — clone a separate repo into ws/ via ws_owner_repo.
  • test-docker-buildx.yml — Docker login + buildx init + multi-arch build.
  • test-hooks.yml — trace prehookscriptcodeposthook order.
  • test-pipeline.yml — multi-job build → test → publish with artifact handoff.
  • test-toolchain.ymlx env use node / python instead of actions/setup-*.
  • test-portable-script.ymlscript: input sourcing .x-cmd/<job-name> (Pattern C).
  • test-channels.yml — matrix across ___X_CMD_GHACTION_X streams (index.html / x0 / x1-x6 / x7).

License

Apache License 2.0 — see LICENSE.

About

GitHub composite Action that bootstraps a CI runner with x-cmd, git, docker and SSH

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages