{"id":23682876,"url":"https://github.com/yindia/iapetus","last_synced_at":"2026-01-04T06:30:13.949Z","repository":{"id":270105043,"uuid":"909348777","full_name":"yindia/iapetus","owner":"yindia","description":"A Go package for executing and validating command-line workflows with built-in assertions and error handling.","archived":false,"fork":false,"pushed_at":"2025-02-12T17:27:34.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-12T18:35:02.337Z","etag":null,"topics":["cli","golang","integration-testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yindia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-28T12:41:29.000Z","updated_at":"2025-02-12T17:27:37.000Z","dependencies_parsed_at":"2025-02-12T18:37:04.721Z","dependency_job_id":null,"html_url":"https://github.com/yindia/iapetus","commit_stats":null,"previous_names":["yindia/iapetus"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yindia%2Fiapetus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yindia%2Fiapetus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yindia%2Fiapetus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yindia%2Fiapetus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yindia","download_url":"https://codeload.github.com/yindia/iapetus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239734527,"owners_count":19688256,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","golang","integration-testing"],"created_at":"2024-12-29T19:55:35.792Z","updated_at":"2026-01-04T06:30:11.903Z","avatar_url":"https://github.com/yindia.png","language":"Go","readme":"# iapetus 🚀\n\nA Go package for executing and validating command-line workflows with built-in assertions and error handling.\n\n## Overview 📋\n\nThe `iapetus` package provides:\n- 📦 Structured workflow execution with sequential steps\n- ✅ Built-in and custom assertions for validating outputs\n- 🔄 Retry mechanisms for flaky operations\n- 🏗️ Fluent builder pattern for readable workflow construction\n\n## Installation 💻\n\n```go\ngo get github.com/yindia/iapetus\n```\n\n## Usage 🛠️\n\n### Quick Start\n\n```go\n// Create a simple task\ntask := iapetus.NewTask(\"verify-service\", 5*time.Second, 0).\n    AddCommand(\"curl\").\n    AddArgs(\"-f\", \"http://localhost:8080\").\n    AddExpected(iapetus.Output{ExitCode: 0}).\n    AddAssertion(iapetus.AssertByExitCode)\n\n// Run the task\nif err := task.Run(); err != nil {\n    log.Fatalf(\"Task failed: %v\", err)\n}\n```\n\n### Defining a Step\n\nA `Step` is defined with the command to run, its arguments, environment variables, and expected output. You can also add custom assertions to a step.\n\n```go\nstep := iapetus.Step{\n    Command: \"kubectl\",\n    Args:    []string{\"get\", \"pods\", \"-n\", \"default\"},\n    Env:     []string{},\n    Expected: iapetus.Output{\n        ExitCode: 1,\n    },\n    LogLevel: 0,\n    Asserts: []func(*iapetus.Step) error{\n        iapetus.AssertByExitCode,\n        func(i *iapetus.Step) error {\n            // TODO: Add custom assertion\n            return nil\n        },\n    },\n}\n\nerr := step.Run()\nif err != nil {\n    log.Fatalf(\"Failed to run step: %v\", err)\n}\n```\n\n\n### Define a Workflow\n\nA `Workflow` consists of multiple steps that are executed in sequence. If any step fails its assertions, the workflow stops.\n\n```go\n\tworkflow := iapetus.Workflow{\n\t\tName: \"Entire flow\",\n\t\tPreRun: func(w *iapetus.Workflow) error {\n\t\t\t//# Do sonething like setup kind cluster\n\t\t\treturn nil\n\t\t},\n\t\tLogLevel: 1,\n\t\tSteps: []iapetus.Task{\n\t\t\t{\n\t\t\t\tName:    \"kubectl-create-ns\",\n\t\t\t\tCommand: \"kubectl\",\n\t\t\t\tArgs:    []string{\"create\", \"ns\", ns},\n\t\t\t\tEnv:     []string{},\n\t\t\t\tExpected: iapetus.Output{\n\t\t\t\t\tExitCode: 0,\n\t\t\t\t},\n\t\t\t\tAsserts: []func(*iapetus.Task) error{\n\t\t\t\t\tiapetus.AssertByExitCode,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"kubectl-create-deployment\",\n\t\t\t\tCommand: \"kubectl\",\n\t\t\t\tArgs:    []string{\"create\", \"deployment\", \"test\", \"--image\", \"nginx\", \"--replicas\", \"30\", \"-n\", ns},\n\t\t\t\tEnv:     []string{},\n\t\t\t\tExpected: iapetus.Output{\n\t\t\t\t\tExitCode: 0,\n\t\t\t\t},\n\t\t\t\tAsserts: []func(*iapetus.Task) error{\n\t\t\t\t\tiapetus.AssertByExitCode,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"kubectl-get-pods-with-deployment\",\n\t\t\t\tCommand: \"kubectl\",\n\t\t\t\tArgs:    []string{\"get\", \"pods\", \"-n\", ns, \"-o\", \"json\"},\n\t\t\t\tEnv:     []string{},\n\t\t\t\tRetries: 1,\n\t\t\t\tExpected: iapetus.Output{\n\t\t\t\t\tExitCode: 0,\n\t\t\t\t},\n\t\t\t\tAsserts: []func(*iapetus.Task) error{\n\t\t\t\t\tiapetus.AssertByExitCode,\n\t\t\t\t\tfunc(s *iapetus.Task) error {\n\t\t\t\t\t\tdeployment := \u0026appsv1.DeploymentList{}\n\t\t\t\t\t\terr := json.Unmarshal([]byte(s.Actual.Output), \u0026deployment)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to unmarshal deployment specs: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif len(deployment.Items) == 1 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"deployment length should be 1\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, item := range deployment.Items {\n\t\t\t\t\t\t\tif item.Name == \"test\" {\n\t\t\t\t\t\t\t\tfor _, container := range item.Spec.Template.Spec.Containers {\n\t\t\t\t\t\t\t\t\tif container.Image != \"nginx\" {\n\t\t\t\t\t\t\t\t\t\treturn fmt.Errorf(\"container image should be nginx\")\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif item.Status.Replicas != *item.Spec.Replicas {\n\t\t\t\t\t\t\t\t\treturn fmt.Errorf(\"deployment replicas do not match desired state\")\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\t\n\tif err := workflow.Run(); err != nil {\n\t\tlog.Fatalf(\"Failed to run workflow: %v\", err)\n\t}\n```\n\n### Builder Pattern\n\nThe package provides a fluent builder pattern for creating tasks and workflows, making it easier to construct complex workflows with a more readable syntax:\n\n```go\n// Create a task with timeout and log level\nstep1 := iapetus.NewTask(\"create cluster\", 10*time.Second, 0).\n    AddCommand(\"kind\").\n    AddArgs(\"create\", \"cluster\").\n    AddExpected(iapetus.Output{\n        ExitCode: 0,\n    }).\n    AddAssertion(iapetus.AssertByExitCode)\n\n// Create another task\nstep2 := iapetus.NewTask(\"verify pods\", 10*time.Second, 0).\n    AddCommand(\"kubectl\").\n    AddArgs(\"get\", \"pods\").\n    AddExpected(iapetus.Output{\n        ExitCode: 0,\n    }).\n    AddAssertion(iapetus.AssertByExitCode)\n\n// Combine tasks into a workflow\nworkflow := iapetus.NewWorkflow(\"cluster-setup\", 0).\n    AddTask(step2).\n    AddPreRun(func(w *Workflow) error {\n        if err := step1.Run(); err != nil {\n            return err\n        }\n    })\n\n// Run the workflow\nif err := workflow.Run(); err != nil {\n    log.Fatalf(\"Workflow failed: %v\", err)\n}\n```\n\n### Assertions\n\nThe package provides several built-in assertion functions:\n\n- `AssertByExitCode`: Validates the exit code of a step.\n- `AssertByOutputString`: Compares the actual output string with the expected output.\n- `AssertByOutputJson`: Compares JSON outputs, allowing for specific node skipping.\n- `AssertByContains`: Checks if the actual output contains specific strings.\n- `AssertByError`: Validates the error message.\n- `AssertByRegexp`: Validates the output with regx\n\n\n### Custom Assertions\n\nYou can add custom assertions to a step using the `AddAssertion` method. A custom assertion is a function that takes a `*Step` as an argument and returns an error if the assertion fails.\n\n```go\nstep.AddAssertion(func(i *iapetus.Step) error {\n    if i.Actual.ExitCode != 0 {\n        return fmt.Errorf(\"expected exit code 0, but got %d\", i.Actual.ExitCode)\n    }\n    return nil\n})\n```\n\n### Key Features ⭐\n\n#### Retries 🔄\nTasks can be configured with retries for handling transient failures:\n\n```go\ntask := iapetus.NewTask(\"flaky-operation\", timeout, 0).\n    AddCommand(\"some-command\").\n    SetRetries(3)  // Will retry up to 3 times\n```\n\n#### Built-in Assertions ✅\n```go\ntask.AddAssertion(iapetus.AssertByExitCode).        // Check exit code\n    AddAssertion(iapetus.AssertByContains(\"Ready\")) // Check output contains\n```\n\nAvailable assertions:\n- `AssertByExitCode`: Validates command exit code\n- `AssertByOutputString`: Exact string matching\n- `AssertByOutputJson`: JSON comparison with node skipping\n- `AssertByContains`: Substring presence check\n- `AssertByError`: Error message validation\n- `AssertByRegexp`: Regular expression matching\n\n#### Custom Assertions 🎯\n```go\ntask.AddAssertion(func(t *iapetus.Task) error {\n    if !strings.Contains(t.Actual.Output, \"success\") {\n        return fmt.Errorf(\"expected 'success' in output\")\n    }\n    return nil\n})\n```\n\n## Contributing 👥\n\nContributions to the `iapetus` package are welcome. Please submit issues or pull requests via the project's repository.\n\n## License 📄\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyindia%2Fiapetus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyindia%2Fiapetus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyindia%2Fiapetus/lists"}