3 Commits

Author SHA1 Message Date
github-actions[bot]
45bd05c07d chore(master): release 1.0.1 2026-01-29 14:08:42 +02:00
b3d357b386 docs: update README.md 2026-01-29 14:08:21 +02:00
ae6de6bf57 fix: error & cancel outputs 2026-01-29 14:06:51 +02:00
17 changed files with 59 additions and 52 deletions

View File

@@ -1,5 +1,12 @@
# Changelog
## [1.0.1](https://github.com/chenasraf/tx/compare/v1.0.0...v1.0.1) (2026-01-29)
### Bug Fixes
* error & cancel outputs ([ae6de6b](https://github.com/chenasraf/tx/commit/ae6de6bf578bd059e88633d87cd45c09bbd27fdd))
## 1.0.0 (2026-01-29)

View File

@@ -23,7 +23,7 @@ A tmux session manager that creates sessions from YAML configuration files.
### Download Precompiled Binaries
Precompiled binaries for `tx` are available for **Linux** and **macOS**:
Precompiled binaries for `tx` are available for **Linux**, **macOS** and **Windows**:
- Visit the [Releases Page](https://github.com/chenasraf/tx/releases/latest) to download the latest
version for your platform.

View File

@@ -30,7 +30,7 @@ func TestCreateCmd_Aliases(t *testing.T) {
func TestCreateCmd_Flags(t *testing.T) {
rootDirFlag := createCmd.Flags().Lookup("root-dir")
if rootDirFlag == nil {
t.Error("expected --root-dir flag")
t.Fatal("expected --root-dir flag")
}
if rootDirFlag.Shorthand != "r" {
t.Errorf("expected -r shorthand, got %q", rootDirFlag.Shorthand)
@@ -38,7 +38,7 @@ func TestCreateCmd_Flags(t *testing.T) {
windowFlag := createCmd.Flags().Lookup("window")
if windowFlag == nil {
t.Error("expected --window flag")
t.Fatal("expected --window flag")
}
if windowFlag.Shorthand != "w" {
t.Errorf("expected -w shorthand, got %q", windowFlag.Shorthand)
@@ -46,7 +46,7 @@ func TestCreateCmd_Flags(t *testing.T) {
saveFlag := createCmd.Flags().Lookup("save")
if saveFlag == nil {
t.Error("expected --save flag")
t.Fatal("expected --save flag")
}
if saveFlag.Shorthand != "s" {
t.Errorf("expected -s shorthand, got %q", saveFlag.Shorthand)
@@ -54,7 +54,7 @@ func TestCreateCmd_Flags(t *testing.T) {
saveOnlyFlag := createCmd.Flags().Lookup("save-only")
if saveOnlyFlag == nil {
t.Error("expected --save-only flag")
t.Fatal("expected --save-only flag")
}
if saveOnlyFlag.Shorthand != "S" {
t.Errorf("expected -S shorthand, got %q", saveOnlyFlag.Shorthand)
@@ -62,7 +62,7 @@ func TestCreateCmd_Flags(t *testing.T) {
localFlag := createCmd.Flags().Lookup("local")
if localFlag == nil {
t.Error("expected --local flag")
t.Fatal("expected --local flag")
}
if localFlag.Shorthand != "l" {
t.Errorf("expected -l shorthand, got %q", localFlag.Shorthand)

View File

@@ -30,7 +30,7 @@ func TestEditCmd_Aliases(t *testing.T) {
func TestEditCmd_Flags(t *testing.T) {
localFlag := editCmd.Flags().Lookup("local")
if localFlag == nil {
t.Error("expected --local flag")
t.Fatal("expected --local flag")
}
if localFlag.Shorthand != "l" {
t.Errorf("expected -l shorthand, got %q", localFlag.Shorthand)

View File

@@ -34,7 +34,7 @@ func TestListCmd_Aliases(t *testing.T) {
func TestListCmd_Flags(t *testing.T) {
bareFlag := listCmd.Flags().Lookup("bare")
if bareFlag == nil {
t.Error("expected --bare flag")
t.Fatal("expected --bare flag")
}
if bareFlag.Shorthand != "b" {
t.Errorf("expected -b shorthand, got %q", bareFlag.Shorthand)
@@ -42,7 +42,7 @@ func TestListCmd_Flags(t *testing.T) {
sessionsFlag := listCmd.Flags().Lookup("sessions")
if sessionsFlag == nil {
t.Error("expected --sessions flag")
t.Fatal("expected --sessions flag")
}
if sessionsFlag.Shorthand != "s" {
t.Errorf("expected -s shorthand, got %q", sessionsFlag.Shorthand)

View File

@@ -10,8 +10,8 @@ func TestRunMain_NoConfig(t *testing.T) {
// Create a temp directory with no config
tmpDir := t.TempDir()
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
// Set dry mode to prevent actual tmux operations
dry = true
@@ -41,8 +41,8 @@ testproject:
}
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
// Set dry mode
dry = true
@@ -70,8 +70,8 @@ existingproject:
}
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
dry = true
defer func() { dry = false }()

View File

@@ -33,7 +33,7 @@ func TestPrjCmd_Aliases(t *testing.T) {
func TestPrjCmd_Flags(t *testing.T) {
saveFlag := prjCmd.Flags().Lookup("save")
if saveFlag == nil {
t.Error("expected --save flag")
t.Fatal("expected --save flag")
}
if saveFlag.Shorthand != "s" {
t.Errorf("expected -s shorthand, got %q", saveFlag.Shorthand)
@@ -41,7 +41,7 @@ func TestPrjCmd_Flags(t *testing.T) {
localFlag := prjCmd.Flags().Lookup("local")
if localFlag == nil {
t.Error("expected --local flag")
t.Fatal("expected --local flag")
}
if localFlag.Shorthand != "l" {
t.Errorf("expected -l shorthand, got %q", localFlag.Shorthand)

View File

@@ -30,7 +30,7 @@ func TestRemoveCmd_Aliases(t *testing.T) {
func TestRemoveCmd_Flags(t *testing.T) {
localFlag := removeCmd.Flags().Lookup("local")
if localFlag == nil {
t.Error("expected --local flag")
t.Fatal("expected --local flag")
}
if localFlag.Shorthand != "l" {
t.Errorf("expected -l shorthand, got %q", localFlag.Shorthand)

View File

@@ -47,6 +47,8 @@ It supports complex pane layouts, fzf selection, and config merging.`,
Args: cobra.MaximumNArgs(1),
PersistentPreRunE: initConfig,
RunE: runMain,
SilenceErrors: true, // We handle error printing in Execute()
SilenceUsage: true, // Don't print usage on runtime errors
}
// initConfig loads global configuration and applies settings
@@ -65,11 +67,7 @@ func initConfig(cmd *cobra.Command, args []string) error {
// Execute adds all child commands to the root command and sets flags appropriately
func Execute() {
if err := rootCmd.Execute(); err != nil {
if _, ok := err.(*UserError); ok {
fmt.Fprintln(os.Stderr, "Error:", err.Error())
} else {
fmt.Fprintln(os.Stderr, err)
}
fmt.Fprintln(os.Stderr, "Error:", err.Error())
os.Exit(1)
}
}

View File

@@ -33,7 +33,7 @@ func TestShowCmd_Aliases(t *testing.T) {
func TestShowCmd_Flags(t *testing.T) {
jsonFlag := showCmd.Flags().Lookup("json")
if jsonFlag == nil {
t.Error("expected --json flag")
t.Fatal("expected --json flag")
}
if jsonFlag.Shorthand != "j" {
t.Errorf("expected -j shorthand, got %q", jsonFlag.Shorthand)

View File

@@ -297,8 +297,8 @@ testproject:
// Change to temp directory
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
result, err := findConfigFile("tmux")
if err != nil {

View File

@@ -112,8 +112,8 @@ func parseWindow(w TmuxWindowInput, root string) ParsedTmuxWindow {
func parseLayout(layoutInput *TmuxLayoutInput, root string) TmuxPaneLayout {
if layoutInput == nil {
return TmuxPaneLayout{
Cwd: resolvePath(root, "."),
Zoom: DefaultEmptyLayout.Zoom,
Cwd: resolvePath(root, "."),
Zoom: DefaultEmptyLayout.Zoom,
Split: copyTmuxSplitLayout(DefaultEmptyLayout.Split, root),
}
}

View File

@@ -15,7 +15,7 @@ func TestNameFix(t *testing.T) {
{"foo", "foo"},
{"foo.bar", "foo"},
{"foo.bar.baz", "foo"},
{".hidden", "hidden"}, // .hidden splits to ["", "hidden"], first non-empty is "hidden"
{".hidden", "hidden"}, // .hidden splits to ["", "hidden"], first non-empty is "hidden"
{"", ""},
{"noextension", "noextension"},
}

View File

@@ -67,9 +67,11 @@ func AddSimpleConfigToFile(config ParsedTmuxConfigItem, local bool, dryRun bool)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(sb.String())
if closeErr := f.Close(); err == nil {
err = closeErr
}
return err
}

View File

@@ -67,8 +67,8 @@ existing:
// Change to temp directory so config is found
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
config := ParsedTmuxConfigItem{
Name: "newproject",
@@ -106,8 +106,8 @@ func TestAddSimpleConfigToFile(t *testing.T) {
// Change to temp directory so config is found
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
config := ParsedTmuxConfigItem{
Name: "newproject",
@@ -161,8 +161,8 @@ third:
// Change to temp directory so config is found
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
err = RemoveConfigFromFile("second", false, false)
if err != nil {
@@ -199,8 +199,8 @@ func TestRemoveConfigFromFile_NotFound(t *testing.T) {
// Change to temp directory so config is found
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
err = RemoveConfigFromFile("nonexistent", false, false)
if err == nil {
@@ -223,8 +223,8 @@ func TestRemoveConfigFromFile_DryRun(t *testing.T) {
// Change to temp directory so config is found
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
err = RemoveConfigFromFile("toremove", false, true)
if err != nil {
@@ -259,8 +259,8 @@ last:
// Change to temp directory so config is found
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
defer func() { _ = os.Chdir(oldWd) }()
_ = os.Chdir(tmpDir)
err = RemoveConfigFromFile("last", false, false)
if err != nil {

View File

@@ -159,8 +159,8 @@ func TestGetShell_Default(t *testing.T) {
// Unset env var
oldEnv := os.Getenv("SHELL")
os.Unsetenv("SHELL")
defer os.Setenv("SHELL", oldEnv)
_ = os.Unsetenv("SHELL")
defer func() { _ = os.Setenv("SHELL", oldEnv) }()
shell := getShell()
// Should return one of the default shells or "sh"
@@ -177,8 +177,8 @@ func TestGetShell_EnvVar(t *testing.T) {
// Set env var
oldEnv := os.Getenv("SHELL")
os.Setenv("SHELL", "/custom/shell")
defer os.Setenv("SHELL", oldEnv)
_ = os.Setenv("SHELL", "/custom/shell")
defer func() { _ = os.Setenv("SHELL", oldEnv) }()
shell := getShell()
if shell != "/custom/shell" {
@@ -194,8 +194,8 @@ func TestGetShell_ConfigOverridesEnv(t *testing.T) {
// Set env var too
oldEnv := os.Getenv("SHELL")
os.Setenv("SHELL", "/env/shell")
defer os.Setenv("SHELL", oldEnv)
_ = os.Setenv("SHELL", "/env/shell")
defer func() { _ = os.Setenv("SHELL", oldEnv) }()
shell := getShell()
// Config should take priority over env

View File

@@ -19,10 +19,10 @@ func TestSessionExists_DryMode(t *testing.T) {
func TestAttachToSession_InsideTmux(t *testing.T) {
// Save original TMUX env
origTmux := os.Getenv("TMUX")
defer os.Setenv("TMUX", origTmux)
defer func() { _ = os.Setenv("TMUX", origTmux) }()
// Set TMUX to simulate being inside tmux
os.Setenv("TMUX", "/tmp/tmux-1000/default,12345,0")
_ = os.Setenv("TMUX", "/tmp/tmux-1000/default,12345,0")
opts := exec.Opts{Verbose: false, Dry: true}
err := AttachToSession(opts, "testsession")
@@ -36,10 +36,10 @@ func TestAttachToSession_InsideTmux(t *testing.T) {
func TestAttachToSession_OutsideTmux(t *testing.T) {
// Save original TMUX env
origTmux := os.Getenv("TMUX")
defer os.Setenv("TMUX", origTmux)
defer func() { _ = os.Setenv("TMUX", origTmux) }()
// Unset TMUX to simulate being outside tmux
os.Unsetenv("TMUX")
_ = os.Unsetenv("TMUX")
opts := exec.Opts{Verbose: false, Dry: true}
err := AttachToSession(opts, "testsession")