Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
![Release](https://github.com/brsyuksel/shellican/actions/workflows/release.yml/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/brsyuksel/shellican)](https://goreportcard.com/report/github.com/brsyuksel/shellican)

<div align="center">
<img src="assets/shellican.gif" alt="shellican demo" width="800" />
</div>

## Why shellican?

**shellican** bridges the gap between simple shell aliases and complex Makefile setups.
Expand Down Expand Up @@ -61,13 +57,17 @@ Default storage location: `~/.shellican` (or `$SHELLICAN_HOME/.shellican`).

### Commands

- **New Collection**: `shellican new collection <name>`
- **New Runnable**: `shellican new runnable <collection> <name>`
- **New Collection**: `shellican new <collection>`
- **New Runnable**: `shellican new <collection> <runnable>`
- **Run**: `shellican run <collection> <runnable> [args...]`
- **List**: `shellican list collections` or `shellican list runnables <collection>`
- **Show**: `shellican show collection <name>` or `shellican show runnable <collection> <name>`
- **Create Shell Shortcut**: `shellican create-shell <collection>` (creates `~/.local/bin/<collection>-shell`)
- **Import/Export**: `shellican import <source>` / `shellican export <collection>`
- **List Collections**: `shellican list`
- **List Runnables**: `shellican list <collection>`
- **Show Collection**: `shellican show <collection> [--readme]`
- **Show Runnable**: `shellican show <collection> <runnable> [--readme]`
- **Create Shell Helper**: `shellican create-shell <collection> [name]` (creates `~/.local/bin/<collection>-shell`)
- **Import Collection**: `shellican import <source> [name]`
- **Export Collection**: `shellican export <collection> [output]`
- **Version**: `shellican version`

## Configuration

Expand Down
Binary file removed assets/shellican.gif
Binary file not shown.
12 changes: 12 additions & 0 deletions pkg/config/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,15 @@ func LoadRunnableConfig(path string) (*RunnableConfig, error) {
}
return &cfg, nil
}

// SaveCollectionConfig saves the collection configuration to the given path.
func SaveCollectionConfig(path string, cfg *CollectionConfig) error {
data, err := yaml.Marshal(cfg)
if err != nil {
return fmt.Errorf("failed to marshal collection config: %w", err)
}
if err := os.WriteFile(filepath.Join(path, "collection.yml"), data, 0644); err != nil {
return fmt.Errorf("failed to write collection.yml: %w", err)
}
return nil
}
32 changes: 29 additions & 3 deletions pkg/core/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"
"path/filepath"

"github.com/brsyuksel/shellican/pkg/config"
)

// CreateCollection creates a new collection.
Expand All @@ -26,7 +28,6 @@ func CreateCollection(name string) error {
help: "Usage for %s"
readme: "README.md"
runnables: []
# - example_runnable
environments:
COLLECTION_ENV: "value"
`, name, name)
Expand Down Expand Up @@ -88,7 +89,32 @@ environments:
fmt.Printf("Warning: failed to create README.md: %v\n", err)
}

fmt.Printf("Runnable '%s' created at %s\n", runnableName, runnablePath)
fmt.Println("Hint: Don't forget to add it to 'runnables' in collection.yml!")
// Load collection config and add the runnable
collectionCfg, err := config.LoadCollectionConfig(collectionPath)
if err != nil {
return fmt.Errorf("failed to load collection config: %w", err)
}
if collectionCfg == nil {
return fmt.Errorf("collection config not found")
}

// Add runnable to the list if not already present
found := false
for _, r := range collectionCfg.Runnables {
if r == runnableName {
found = true
break
}
}
if !found {
collectionCfg.Runnables = append(collectionCfg.Runnables, runnableName)
}

// Save updated collection config
if err := config.SaveCollectionConfig(collectionPath, collectionCfg); err != nil {
return fmt.Errorf("failed to save collection config: %w", err)
}

fmt.Printf("Runnable '%s' created and added to collection at %s\n", runnableName, runnablePath)
return nil
}
23 changes: 23 additions & 0 deletions pkg/core/scaffold_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"os"
"path/filepath"
"testing"

"github.com/brsyuksel/shellican/pkg/config"
)

func TestCreateCollection(t *testing.T) {
Expand Down Expand Up @@ -56,6 +58,27 @@ func TestCreateRunnable(t *testing.T) {
t.Errorf("runnable.yml not created")
}

// Verify runnable was added to collection.yml
colPath := filepath.Join(tempDir, ".shellican", colName)
cfg, err := config.LoadCollectionConfig(colPath)
if err != nil {
t.Fatalf("Failed to load collection config: %v", err)
}
if cfg == nil {
t.Fatal("Collection config is nil")
}

found := false
for _, r := range cfg.Runnables {
if r == runName {
found = true
break
}
}
if !found {
t.Errorf("Runnable '%s' not found in collection.yml runnables list", runName)
}

// Missing collection test
err = CreateRunnable("missing", "run")
if err == nil {
Expand Down