{"id":26379923,"url":"https://github.com/lifailon/usup","last_synced_at":"2026-03-15T18:14:53.587Z","repository":{"id":280710094,"uuid":"942909604","full_name":"Lifailon/usup","owner":"Lifailon","description":"A very simple deployment tool, like Ansible, but for running bash commands.","archived":false,"fork":false,"pushed_at":"2025-03-13T10:43:49.000Z","size":1856,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-16T01:11:28.398Z","etag":null,"topics":["ansible-like","automation","devops","devops-tools","go","golang","jenkins-pipeline","jenkinsfile","ssh","stack","stackup","sup"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lifailon.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":"2025-03-04T21:48:53.000Z","updated_at":"2025-03-13T10:53:12.000Z","dependencies_parsed_at":"2025-03-07T02:38:57.255Z","dependency_job_id":null,"html_url":"https://github.com/Lifailon/usup","commit_stats":null,"previous_names":["lifailon/lazysup","lifailon/usup"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lifailon%2Fusup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lifailon%2Fusup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lifailon%2Fusup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lifailon%2Fusup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lifailon","download_url":"https://codeload.github.com/Lifailon/usup/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243976472,"owners_count":20377691,"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":["ansible-like","automation","devops","devops-tools","go","golang","jenkins-pipeline","jenkinsfile","ssh","stack","stackup","sup"],"created_at":"2025-03-17T05:17:33.669Z","updated_at":"2026-03-15T18:14:53.581Z","avatar_url":"https://github.com/Lifailon.png","language":"Go","readme":"# Update Stack Up\n\nA very simple deployment tool that runs a given set of `bash` commands on multiple hosts in parallel. It reads `yaml` configuration, which defines networks (groups of hosts), global variables (which can be changed via arguments), command(s) and targets (groups of commands).\n\n\u003e [!NOTE]\n\u003e The goal is to revive the [sup](https://github.com/pressly/sup) project, which has not been supported since 2018. First of all, to solve common problems (for example, an error when connecting via `ssh`), expand the functionality (for example, add reading the configuration from the `url`), add support for the Windows system and implement a simple user interface (example for [Jenkins](#jenkins)).\n\n## Install\n\nRun the command in the console to quickly install or update the stable version for Linux or macOS system:\n\n```shell\ncurl -sS https://raw.githubusercontent.com/Lifailon/usup/main/install.sh | bash\n```\n\nTo install on Windows, download the binary file from the [releases](https://github.com/Lifailon/usup/releases) page.\n\n## Usage\n\n```bash\nusup [options] network \u003ccommand(s)/target\u003e\n\nusup dev date\nusup -u https://raw.githubusercontent.com/Lifailon/usup/refs/heads/main/usupfile.yml dev date\n```\n\nThis is a simple example that clones a repository and runs tests on two specified machines, which I use to test the [lazyjournal](https://github.com/Lifailon/lazyjournal) project on BSD-based systems:\n\n![go-test](/img/go-test.jpg)\n\n## Templates \u0026 Contributing\n\nThis repository also plans to contain a set of [templates](/templates/) for [installing packages](/templates/packages.yml), [getting information](/templates/fetch.yml) and configuring the system.\n\nYou can contribute and add your template to this repository via a [Pull Request](https://github.com/Lifailon/usup/pulls).\n\n## Supported file names\n\nBy default, the following configuration file names will be searched for on startup, in order of priority.\n\n```\nusupfile.yml\nusupfile.yaml\nUsupfile.yml\nUsupfile.yaml\nsupfile.yml\nsupfile.yaml\nSupfile.yml\nSupfile.yaml\n```\n\n## Options\n\nList of available flags.\n\n| Option                                  | Description                         |\n| -                                       | -                                   |\n| `-f usupfile.yml`                       | Custom path to file configuration   |\n| `-u https://example.com/usupfile.yml`   | Url path to file configuration      |\n| `-e`, `--env=[]`                        | Set environment variables           |\n| `--only REGEXP`                         | Filter hosts matching regexp        |\n| `--except REGEXP`                       | Filter out hosts matching regexp    |\n| `-D`, `--debug`                         | Enable debug/verbose mode           |\n| `--disable-prefix`                      | Disable hostname prefix             |\n| `-h`, `--help`                          | Show help/usage                     |\n| `-v`, `--version`                       | Print version                       |\n\n## Network\n\nNetwork is a group of hosts that can be static or dynamic from URL or a local file.\n\n```yaml\nnetworks:\n  local:\n    hosts:\n      - localhost\n  dev:\n    hosts:\n      - lifailon@192.168.3.101:2121\n      - lifailon@192.168.3.104:2121\n  remote-host-list:\n    # Read host list from URL in Linux\n    inventory: printf '%s\\n' $(curl -s https://raw.githubusercontent.com/Lifailon/usup/refs/heads/main/hostlist)\n    # Windows PowerShell or PowerShell Core\n    # inventory: Invoke-RestMethod https://raw.githubusercontent.com/Lifailon/usup/refs/heads/main/hostlist\n  local-host-list:\n    # Linux\n    inventory: printf '%s\\n' $(cat ./hostlist)\n    # Windows\n    # inventory: Get-Content ./hostlist\n```\n\n## Variables and Command\n\n```yaml\nenv:\n  FILE_NAME: test\n  FILE_FORMAT: txt\n\nnetworks:\n  dev:\n    hosts:\n      - lifailon@192.168.3.101:2121\n      - lifailon@192.168.3.104:2121\n\ncommands:\n  echo:\n    desc: Print filename from env vars\n    run: echo $FILE_NAME.$FILE_FORMAT\n```\n\nOutput the contents of variables:\n\n```bash\nusup dev echo\nlifailon@192.168.3.101:2121 | test.txt\nlifailon@192.168.3.104:2121 | test.txt\n```\n\nChange the contents of variables:\n\n```bash\nusup -e \"FILE_NAME=new_test\" -e \"FILE_FORMAT=temp\" dev echo\nlifailon@192.168.3.104:2121 | new_test.temp\nlifailon@192.168.3.101:2121 | new_test.temp\n```\n\nDefault environment variables available:\n\n| Variable Name     | Description                                           |\n| -                 | -                                                     |\n| `$SUP_HOST`       | Current host                                          |\n| `$SUP_NETWORK`    | Current network                                       |\n| `$SUP_USER`       | User who invoked command                              |\n| `$SUP_TIME`       | Date/time of command invocation                       |\n| `$SUP_ENV`        | Environment variables provided on command invocation  |\n\n## Serial and once command\n\n`serial: N` constraints a command to be run on `N` hosts at a time at maximum.\n\n```yaml\ncommands:\n  echo:\n    desc: Print filename from env vars\n    run: echo $FILE_NAME.$FILE_FORMAT\n    serial: 2\n```\n\n`once: true` constraints a command to be run only on one host.\n\n```yaml\ncommands:\n  file:\n    desc: Creat new test file\n    run: echo \"This is test\" \u003e ./$FILE_NAME.$FILE_FORMAT\n    once: true\n```\n\n`usup dev echo file`\n\n## Upload files\n\nUploads files/directories to all remote hosts (uses `tar` under the hood).\n\n```yaml\ncommands:\n  upload:\n    desc: Upload dist files to all hosts\n    upload:\n      - src: ./$FILE_NAME.$FILE_FORMAT\n        dst: /tmp/\n```\n\n## Local command\n\nRuns command always on localhost.\n\n```yaml\ncommands:\n    build:\n        desc: Build in Windows\n        local: go build -o ./bin/sup.exe ./cmd/sup\n```\n\n## Interactive Bash\n\nYou can pass any `bash` commands from `stdin` to execute them on all hosts:\n\n```yaml\ncommands:\n  bash:\n    desc: Interactive Bash on all hosts\n    stdin: true\n    run: bash\n```\n\nSend commands to all hosts simultaneously for execution.\n\n```bash\necho 'sudo apt-get update -y \u0026\u0026 sudo apt-get upgrade -y' | usup production bash\n# or\nusup dev bash\nls\nexit\n```\n\n## Target\n\nTarget is an alias for a set of commands. Each command will be run on all hosts in parallel, will check the return status from all hosts and continue running subsequent commands only if successful (any error on any host will abort the process).\n\n```yaml\ntargets:\n  get:\n    - uptime\n    - date\n  up:\n    - upload\n    - cat\n```\n\n`usup dev get` get uptime and current time in the system from all hosts simultaneously (run `uptime` and `date` commands).\n\n`usup dev up` download and read the file.\n\n## Jenkins\n\nYou can use the Jenkins generic pipeline, which uploads a list of all available configuration files (in `yaml/yml` format) to a specified GitHub repository, to select the file you want and define all the parameters available in it to run. A list of networks, commands and targets to choose from is available, as well as a list of available variables and their values, which can be overridden.\n\n### Plugins used (dependencies)\n\n- [Active Choices](https://plugins.jenkins.io/uno-choice) for use dynamic parameters.\n- [SSH Pipeline Steps](https://plugins.jenkins.io/ssh-steps) for import ssh key from credentials on the agent.\n- [AnsiColor](https://plugins.jenkins.io/ansicolor) (optional) for support output coloring.\n\n### Import\n\nYou can import the [config](/jenkins/config.xml) file in the `jenkins_home/jobs/\u003cNew_Job_Name\u003e` directory and reload the configuration from disk in the interface or connect using SCM from GitHub.\n\n![jenkins-import](/img/jenkins-import.jpg)\n\n### Parameters\n\n![jenkins-params](/img/jenkins-params.jpg)\n\nExample of execution results:\n\n![jenkins-build](/img/jenkins-build.jpg)\n\n## License\n\nLicensed under the [MIT License](./LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flifailon%2Fusup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flifailon%2Fusup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flifailon%2Fusup/lists"}