mirror of
https://github.com/chenasraf/tx.git
synced 2026-05-18 01:29:08 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45bd05c07d | ||
| b3d357b386 | |||
| ae6de6bf57 |
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 }()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"},
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user