Skip to content

Add a "sub-Action" for the detached mode by default#218

Merged
dscho merged 4 commits intomasterfrom
detached
Apr 21, 2025
Merged

Add a "sub-Action" for the detached mode by default#218
dscho merged 4 commits intomasterfrom
detached

Conversation

@dscho
Copy link
Collaborator

@dscho dscho commented Apr 19, 2025

I find myself only using the detached mode as of the past year or so. Naturally, in hindsight I wish for that mode to be the default, for that reason. It would be far from a good idea to change the default now, after many years of users having grown accustomed to the current working of the Action.

But there's an easy way to have what I want anyway: by adding a "sub-Action", i.e. a sub-directory with an action.yml file that differs only in the default of the detached input parameter. That way, I can now use the following in my workflows and get precisely what I want:

- uses: mxschmitt/action-tmate/detached@v3

I imagine that this will be useful for other users, too, therefore I updated the README.md file accordingly.

dscho added 4 commits April 19, 2025 19:28
The `mxschmitt/action-tmate/detached` Action does exactly the same as
the `mxschmitt/action-tmate` Action, except defaulting to detached mode.

This will come in handy in the increasingly many cases I seem to
experience of late where I want to use the detached mode without the
price of adding a `with` section.

Not a big price, but it accumulates.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This "sub-"Action merely switches the default to `detached: true`. Which
is so much more convenient than having to add a `with:` section _just_
for that mode.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
We now limit access to the actor by default, iff the actor has a public
SSH key registered in their GitHub profile.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho self-assigned this Apr 19, 2025
@dscho dscho requested a review from mxschmitt as a code owner April 19, 2025 17:46
@dscho dscho merged commit c606f86 into master Apr 21, 2025
2 checks passed
@dscho dscho deleted the detached branch April 21, 2025 12:57
dscho added a commit that referenced this pull request May 1, 2025
In #218, I added a
convenient way to launch this Action in detached mode:
`mxschmitt/action-tmate/detached@v3`.

The way this is implemented is a copy/edited version of `action.yml` in
the `detached/` subdirectory.

This runs the danger of inadvertent divergences, as happened in
#221 (which I caught in
time and the contributor gracefully addressed).

Let's add automation not only to update the file easily but also to
cause a failure in the PR build with a helpful message suggesting how to
fix the problem.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit that referenced this pull request May 1, 2025
In #218, I added a
convenient way to launch this Action in detached mode:
`mxschmitt/action-tmate/detached@v3`.

The way this is implemented is a copy/edited version of `action.yml` in
the `detached/` subdirectory.

This runs the danger of inadvertent divergences, as happened in
#221 (which I caught in
time and the contributor gracefully addressed).

Let's add automation not only to update the file easily but also to
cause a failure in the PR build with a helpful message suggesting how to
fix the problem.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit that referenced this pull request May 1, 2025
In #218, I added a
convenient way to launch this Action in detached mode:
`mxschmitt/action-tmate/detached@v3`.

The way this is implemented is a copy/edited version of `action.yml` in
the `detached/` subdirectory.

This runs the danger of inadvertent divergences, as happened in
#221 (which I caught in
time and the contributor gracefully addressed).

Let's add automation not only to update the file easily but also to
cause a failure in the PR build with a helpful message suggesting how to
fix the problem.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
yanksyoon added a commit to canonical/action-tmate that referenced this pull request May 15, 2025
* Don't create /continue on macOS

* add connect-timeout variable

Signed-off-by: Dave Lee <dave@gray101.com>

* run the build

Signed-off-by: Dave Lee <dave@gray101.com>

* action.yml

Signed-off-by: Dave Lee <dave@gray101.com>

* connect-timeout-seconds is a better name

Signed-off-by: Dave Lee <dave@gray101.com>

* chore(deps): bump to use actions/checkout v4 (node20 runtime) (mxschmitt#197)

* chore(deps-dev): bump braces from 3.0.2 to 3.0.3 (mxschmitt#196)

* chore(deps-dev): bump micromatch from 4.0.5 to 4.0.8 (mxschmitt#201)

* Adding support for RHEL-based distributions

Signed-off-by: Loic Pottier <pottier1@llnl.gov>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* chore(deps-dev): bump cross-spawn from 7.0.3 to 7.0.5 (mxschmitt#207)

* add new input msys2-location

add new msys2-location input and use instead of hardcoding c:\msys64

* Update README.md with new input

* Update index.js

* use msys2-location input in didTmateQuit and continueFileExists

* Offer `mxschmitt/action-tmate/detached` for convenience

The `mxschmitt/action-tmate/detached` Action does exactly the same as
the `mxschmitt/action-tmate` Action, except defaulting to detached mode.

This will come in handy in the increasingly many cases I seem to
experience of late where I want to use the detached mode without the
price of adding a `with` section.

Not a big price, but it accumulates.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* README: document the `mxschmitt/action-tmate/detached` Action

This "sub-"Action merely switches the default to `detached: true`. Which
is so much more convenient than having to add a `with:` section _just_
for that mode.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* ci(manual-detached-test): use the `./detached` "sub-Action"

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* ci(manual-detached-test): drop no-longer-needed setting

We now limit access to the actor by default, iff the actor has a public
SSH key registered in their GitHub profile.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* ci(manual-test): stop mentioning the obsolete ubuntu-20.04 pool

It has gone to the ~Google~GitHub Graveyard.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Add support for output

* Add ssh to output

* (feature) Add outputs to detached action as well

* ci: verify that the `action.yml` files are in sync

In mxschmitt#218, I added a
convenient way to launch this Action in detached mode:
`mxschmitt/action-tmate/detached@v3`.

The way this is implemented is a copy/edited version of `action.yml` in
the `detached/` subdirectory.

This runs the danger of inadvertent divergences, as happened in
mxschmitt#221 (which I caught in
time and the contributor gracefully addressed).

Let's add automation not only to update the file easily but also to
cause a failure in the PR build with a helpful message suggesting how to
fix the problem.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* detached/action.yml: synchronize with `action.yml`

There was a difference in whitespace, caught by the new step in
`checkin.yml`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* ci: fix 'Verify that the project is built'

The output of that step, if something goes wrong, claims that `dist/` is
not up to date, but the build product is in `lib/`.

Also, `git status -s` shows not only differences in the tracked files,
but also untracked files (which should not exist at that stage). Let's
avoid puzzling contributors when there are untracked files by logging
the output of `git status -s`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* ci(manual-test): update list of runner images

See https://github.com/actions/runner-images/blob/310e8e963731084df01bcbdbd5044a5ca7fc0c88/README.md#available-images.

* ci(manual-test): convert from a matrix job to a single job

With this change, the `manual-test` workflow accepts user input as to
what runner OS or Docker image to run on.

It is more useful this way, too, as I never encountered a situation
where I would want to run this Action on multiple runners, having to log
in concurrently into multiple tmate sessions, and I doubt that anyone
else has encountered that situation, either.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Add a node.js script to update manual-test's `runs-on` options

As I had suggested in
mxschmitt#224 (comment),
it would be good to have some sort of automation to update the
ever-changing list of runner pools that are supported by GitHub.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* ci(manual-test): update `runs-on` options

Brought to you by the new `update-manual-test.js` script.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* update-manual-test: special-case Windows/ARM64 runners

For a little more than two weeks, as of time of writing, there are
GitHub-hosted Windows/ARM64 runners (at long last!), announced here:
https://github.blog/changelog/2025-04-14-windows-arm64-hosted-runners-now-available-in-public-preview/

These are not yet listed in the `runner-images` README, therefore we
want to add them manually.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* manual-test: install MSYS2 on Windows/ARM64

The Windows/ARM64 runners that are currently in public preview do not
have MSYS2 installed by default, so let's do that.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

---------

Signed-off-by: Dave Lee <dave@gray101.com>
Signed-off-by: Loic Pottier <pottier1@llnl.gov>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
Co-authored-by: Dave Lee <dave@gray101.com>
Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Co-authored-by: Rui Chen <rui@chenrui.dev>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Loic Pottier <pottier1@llnl.gov>
Co-authored-by: jeremyd2019 <github@jdrake.com>
Co-authored-by: Max schwenk <maschwenk@gmail.com>
Co-authored-by: Yukai Chou <muzimuzhi@gmail.com>
dscho added a commit to dscho/action-upterm that referenced this pull request Mar 4, 2026
Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/action-upterm that referenced this pull request Mar 6, 2026
Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/action-upterm that referenced this pull request Mar 6, 2026
Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/action-upterm that referenced this pull request Mar 6, 2026
Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/action-upterm that referenced this pull request Mar 6, 2026
Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
dscho added a commit to dscho/action-upterm that referenced this pull request Mar 8, 2026
Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
owenthereal pushed a commit to owenthereal/action-upterm that referenced this pull request Mar 8, 2026
* Replace pgrep with tmux's own client tracking

The `setupSessionTimeout()` function used `pgrep -f '^tmux attach '` to
detect whether any user had connected to the upterm session. This is
fragile because `pgrep -f` matches against the full command line of
every process on the system, so any unrelated process whose command line
happens to start with `tmux attach ` would be a false positive.

tmux itself can report its clients via `list-clients -t upterm`. The
complication is that the upterm host process holds one tmux client
connection of its own: the inner `tmux new -s upterm` (without `-d`)
both creates the session and attaches a client from the
`upterm-wrapper` pane. That host-side client would make `list-clients`
always return non-empty output, defeating a simple emptiness check.

To distinguish user SSH connections from the host's own client, the
inner `tmux new -s upterm` now gets `-f read-only`. The host client
never needs to send keystrokes (it just provides the session), so
read-only is appropriate. The timeout check then uses
`list-clients -f '#{?client_readonly,,1}'` which is a tmux format
filter that excludes read-only clients, returning only writable ones,
i.e. those arriving via the `--force-command 'tmux attach -t upterm'`
SSH entry point. Non-empty output from that filtered query means a
real user has connected.

The prior art in `action-tmate` uses `tmate display -p
'#{tmate_num_clients}'` for the same purpose, but tmux has no
equivalent built-in variable, so the `list-clients` approach with a
read-only flag is the next best thing.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Rebuild with `yarn build`

* Implement a "detached" mode

In "detached" mode, the `upterm` session will be created, the Action will
then print the information how to connect, and then exit with success.

The workflow job's steps will run concurrently with the `upterm` session,
allowing the user to monitor the steps as they are progressing.

At the end of the job, the Action's newly-introduced post-job Action
will wait until the session is ended, or up to 10 minutes for any client
to connect at all.

Changes:
- Add post-job action support via `post` and `post-if` in action.yml
- Implement runDetachedMode() and runPost() functions
- Add tests for detached mode and POST action handling
- Document detached mode in README.md

This detached mode is inspired by `action-tmate`'s detached mode, which
I modeled after CircleCI/CirrusCI's debugging support that _only_ allows a
concurrent shell terminal to be opened.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Rebuild with `yarn build`

The Typescript code cannot actually be used directly in GitHub Actions,
therefore we must follow the the practice that should otherwise be
avoided at all cost to commit generated code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Offer the detached mode in a more convenient way

Just like I did with `action-tmate` in
mxschmitt/action-tmate#218, this adds a
convenient shortcut:

	- uses: owenthereal/action-upterm/detached@v1

does the exact same thing as:

	- uses: owenthereal/action-upterm@v1
	  with:
	    detached: true

just with fewer keystrokes ;-)

This trick was performed via:

	mkdir -p detached
	sed -e 's/lib\//..\/&/g' \
	  -e '/detached:/{:1;n;s/\(default: \).*/\1"true"/;t;b1}' \
	  <action.yml >detached/action.yml

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* e2e: add test for detached mode

The detached mode lets the workflow continue while the upterm session
stays active in the background. To verify this works end-to-end, this
adds a fixture workflow that uses `./detached` and has a subsequent
step printing a marker string, plus a test that confirms three things:
the SSH command appears in the output, the marker step actually runs
(proving act proceeded past the upterm step), and SSH connectivity to
the session works.

The `runActWorkflow` helper is parameterized to accept a workflow file
and job name (defaulting to the existing fixture), and gains a
`waitForOutput` method that attaches an additional stdout listener to
watch for arbitrary patterns.

The fixture intentionally omits `wait-timeout-minutes` because the
background subshell spawned by the timeout script holds Node's event
loop alive, preventing the process from exiting after
`runDetachedMode()` returns. This is a pre-existing limitation of how
`execShellCommand` spawns child processes; the timeout feature is
exercised separately by the normal (blocking) e2e test.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* e2e: verify that the post action gives the user a chance to connect

One of the most crucial aspects of the detached mode is the post-action
behavior: after the main workflow steps complete, the post action
ensures the user had a chance to connect. If no one has connected yet,
it waits (with a configurable countdown) so the user can still start an
SSH session and investigate. Without this, the workflow run would exit
before the user had a chance to start debugging, defeating the entire
purpose of the detached mode.

This extends the detached mode e2e test to verify that lifecycle. After
confirming the workflow continues past the upterm step, we wait for the
post action to enter its monitoring loop ("Waiting for client to
connect"), then gracefully end the session by sending Ctrl+D to the
upterm tmux session inside the act container via `docker exec`, and
verify that the post action detects the session exit.

We do not specifically test the "user is connected" path (where the
post action switches from a countdown to indefinite waiting) because
that would require a fully-blown interactive SSH session with a TTY,
which would drastically complicate the test code.

Two small helpers are added to e2e/utils.ts: `findContainer` discovers
the act container by name substring via `docker ps`, and
`dockerExecTmuxSendKeys` sends tmux keys into a container. The output
watchers are registered early (before awaiting any of them) to avoid
race conditions where the post action message might appear before the
listener is set up.

Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

---------

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants