{"id":16732365,"url":"https://github.com/expelledboy/smash","last_synced_at":"2025-03-15T19:24:59.439Z","repository":{"id":68292984,"uuid":"309981707","full_name":"expelledboy/smash","owner":"expelledboy","description":"Change the state of the universe, from \u003c200 lines of bash!","archived":false,"fork":false,"pushed_at":"2020-11-11T05:20:41.000Z","size":1989,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-22T08:38:39.944Z","etag":null,"topics":["hacktoberfest","infrastructure-as-code","provisioning"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/expelledboy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2020-11-04T11:24:42.000Z","updated_at":"2023-04-20T22:52:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"036668ef-751f-4d96-913c-0dcbe749c7ad","html_url":"https://github.com/expelledboy/smash","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expelledboy%2Fsmash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expelledboy%2Fsmash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expelledboy%2Fsmash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expelledboy%2Fsmash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/expelledboy","download_url":"https://codeload.github.com/expelledboy/smash/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243779218,"owners_count":20346678,"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":["hacktoberfest","infrastructure-as-code","provisioning"],"created_at":"2024-10-12T23:44:05.711Z","updated_at":"2025-03-15T19:24:59.431Z","avatar_url":"https://github.com/expelledboy.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Smash\n\n\u003e  Change the state of the universe, from \u0026lt;200 lines of bash!\n\n\u003cimg title=\"\" src=\"docs/lemme-smash.gif\" alt=\"lemme-smash\" data-align=\"left\"\u003e\n\n## Introduction\n\nI liked `terraform`, but I wanted to be evil and use the full power of bash. 👺\n\nUsing simple scripts, determine system state and create plans to change it.\n\n```\nusage: smash [-anpst] [-o action,..]\n  -o Only run comma seperated list of actions.\n  -p Plan only; generate an execution plan. Can be approved in PR.\n  -a Apply only; ensure state has not changed, and execute plan.\n  -n Dry run; print the commands that would be executed, but do not execute them.\n  -s Silent operation; do not print to stdout as they are executed.\n  -t Output planned tests in tap format.\n```\n\nLets create a simple smash action to install your dotfiles!\n\n```sh\n# Create an action directory\nmkdir -p smash/install_mac\n\necho '\n#!/bin/bash\n\n# We are going to need a script to install your dotfiles\ngit clone https://github.com/username/dotfiles.git ~/.dotfiles\n' \u003e install.sh\n\necho '\n#!/bin/bash\n\n# Another to determine if dotfiles are installed\necho \"DOTFILES_INSTALLED=$(test -d ~/.dotfiles \u0026\u0026 echo true)\"\n' \u003e smash/install_mac/state\n\necho '\n#!/bin/bash\n\n# Use that context to plan what must be done to install your dotfiles\nif [[ \"$DOTFILES_INSTALLED\" != \"true\" ]]; then\n  echo \"run bash ./install.sh\"\nfi\n\n# You could optionally add unit tests\necho \"test [[ -d ~/.dotfiles ]] || exit 1\"\n' \u003e smash/install_mac/state\n\n# Make them all executablable\nchmod +x ./smash/install_mac/* ./install.sh\n\n# Test your action with a dry run first.\nsmash -n\n# Create a plan\nsmash -p\n# Review plan\ncat ./smash/engine/plan\n# Apply plan\nsmash -a\n\n# Or dont be a Becky...\nsmash\n```\n\n```\n$ smash\n==\u003e init\n$ smash/install_mac/state\nDOTFILES_INSTALLED=\n==\u003e plan\n$ smash/install_mac/plan\nrun bash ./install.sh\ntest [[ -d /Users/anthony/.dotfiles ]]\n==\u003e run\n$ bash ./install.sh\ngit clone https://github.com/username/dotfiles.git /Users/anthony/.dotfiles\n==\u003e test\n$ [[ -d /Users/anthony/.dotfiles ]]\n==\u003e done\n\n$ echo $? # winning\n0\n```\n\nAnd you can write these scripts in any language your heart desired!\n\n## Installation methods\n\n**source**\n\n```\nsudo curl -L --fail \\\n  https://raw.githubusercontent.com/expelledboy/smash/master/smash.sh \\\n  -o /usr/local/bin/smash\nsudo chmod +x /usr/local/bin/smash\n```\n\n**docker**\n\n```\ndocker run --rm -it -v \"${PWD}:/code\" expelledboy/smash:latest -o make_target\n```\n\n## Guide\n\n- Your actions must be directories installed in `./smash/\u003caction\u003e`\n  - A smash action needs only one file `./smash/\u003caction\u003e/plan`\n  - Actions can contribute to state in `./smash/\u003caction\u003e/state`\n  - By default all actions in `./smash/*` are run unless you use the `-o` option\n    - Actions prefixed with `undo_` are always ignored and must use `-o`\n- State is ENV vars printed to stdout by the state script in `.env` format\n  - eg. `MY_VAR=useful_info`\n- These environment variables will be available in all phases of smash\n- There are quite afew phases of smash;\n  - state\n  - plan\n  - setup\n  - run\n  - test\n- You can hook into `setup`, `run` and `test`\n  - There are also pre and post hooks eg. `pre-plan` `plan` `post-plan`\n  - Create a hook by printing to stdout in the plan script `\u003chook\u003e cmd args`\n- You can create global util scripts in `./smash/scripts/*`\n  - These will be available in all phases\n- You can commit `./smash/engine/*` files as part of CI/CD review process\n\n### Rollbacks\n\nIts important understand that actions push your system towards a desired state.\nRather than supporting `undo` functionality in smash actions my feeling is it\nwould be preferred to create actions that achieve the opposite desired state.\nYou can read previous system states in the `./smash/engine/state.*` files during\nplanning which provides maximum flexibility.\n\nInteresting side effects which fell out of the design was toggling.\n\n```\n$ smash.sh -s -o make_target,undo_make_target \u0026\u0026 ls ./target\n==\u003e done\nversion\n\n$ smash.sh -s -o make_target,undo_make_target \u0026\u0026 ls ./target\n==\u003e done\nls: ./target: No such file or directory\n\n$ smash.sh -s -o make_target,undo_make_target \u0026\u0026 ls ./target\n==\u003e done\nversion\n```\n\n# Contributions\n\nIf you want to change behavior please create a unit test in `./test.sh`.\n\nOtherwise I welcome changes early in the development of this project!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpelledboy%2Fsmash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexpelledboy%2Fsmash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpelledboy%2Fsmash/lists"}