{"id":17383115,"url":"https://github.com/shopwarelabs/psh","last_synced_at":"2025-04-09T10:07:12.971Z","repository":{"id":10689895,"uuid":"66642034","full_name":"shopwareLabs/psh","owner":"shopwareLabs","description":"PSH - PHP shell helper","archived":false,"fork":false,"pushed_at":"2024-03-04T21:03:52.000Z","size":8867,"stargazers_count":62,"open_issues_count":8,"forks_count":19,"subscribers_count":19,"default_branch":"master","last_synced_at":"2024-04-24T18:26:13.484Z","etag":null,"topics":["build-automation","build-tool","cli-app","composer-package","phar","shell-scripts","templating"],"latest_commit_sha":null,"homepage":null,"language":"PHP","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/shopwareLabs.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":"2016-08-26T11:20:02.000Z","updated_at":"2024-08-04T09:09:04.769Z","dependencies_parsed_at":"2024-08-04T09:08:58.094Z","dependency_job_id":"a291a9db-62e5-434c-a58f-5a7300e49548","html_url":"https://github.com/shopwareLabs/psh","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shopwareLabs%2Fpsh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shopwareLabs%2Fpsh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shopwareLabs%2Fpsh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shopwareLabs%2Fpsh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shopwareLabs","download_url":"https://codeload.github.com/shopwareLabs/psh/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248018060,"owners_count":21034048,"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":["build-automation","build-tool","cli-app","composer-package","phar","shell-scripts","templating"],"created_at":"2024-10-16T07:40:38.920Z","updated_at":"2025-04-09T10:07:12.953Z","avatar_url":"https://github.com/shopwareLabs.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/shopwareLabs/psh/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/shopwareLabs/psh/?branch=master)[![Build Status](https://scrutinizer-ci.com/g/shopwareLabs/psh/badges/build.png?b=master)](https://scrutinizer-ci.com/g/shopwareLabs/psh/build-status/master)[![codecov](https://codecov.io/gh/shopwareLabs/psh/branch/master/graph/badge.svg)](https://codecov.io/gh/shopwareLabs/psh)\n\n[![Latest Stable Version](https://poser.pugx.org/shopware/psh/v/stable)](https://packagist.org/packages/shopware/psh)\n[![Total Downloads](https://poser.pugx.org/shopware/psh/downloads)](https://packagist.org/packages/shopware/psh)\n[![Latest Unstable Version](https://poser.pugx.org/shopware/psh/v/unstable)](https://packagist.org/packages/shopware/psh)\n[![License](https://poser.pugx.org/shopware/psh/license)](https://packagist.org/packages/shopware/psh)\n\nPSH - PHP shell helper\n====================\n\n**Keep using your standard shell scripts**\n\nPSH is intended to be a **simple** and **easy** alternative to other build script solutions.\n\n\nTable of contents\n------------\n\n* [Introduction](#introduction)\n* [Installation](#installation)\n * [Through composer](#through-composer)\n * [As a PHAR archive (preferred)](#as-a-phar-archive-preferred)\n * [Build it yourself](#build-it-yourself)\n* [Usage](#usage)\n* [Configuration](#configuration)\n    * [Paths](#paths)\n    * [Placeholders](#placeholders)\n    * [Constants](#constants)\n    * [Variables](#variables)\n    * [Dotenv](#dotenv)\n    * [Require](#require)\n    * [Templates](#templates)\n    * [Environments](#environments)\n    * [Headers](#headers)\n    * [Overriding configuration file](#overriding-configuration-file)\n    * [Importing configuration files](#importing-configuration-files)\n* [PSH-Scripts](#sh-scripts)\n    * [Defining placeholders](#defining-placeholders)\n    * [Including other actions](#including-other-actions)\n    * [Including other scripts](#including-other-scripts)\n    * [On demand templates](#on-demand-templates)\n    * [Open a ssh connection to another machine](#open-a-ssh-connection-to-another-machine)\n    * [Ignoring if a statement errored](#ignoring-if-a-statement-errored)\n    * [Breaking statements into multiple lines](#breaking-statements-into-multiple-lines)\n    * [Description](#description)\n    * [Downsides](#downsides)\n* [BASH-Scripts](#bash-scripts)\n* [Executing it](#executing-it)\n* [Bash Autocompletion](#bash-autocompletion)\n\nIntroduction\n------------\n\nYou do not have to learn a new - and in most cases much more verbose - language, but can scale your existing skills \non the command line.\n\nKey benefits are:\n\n* Share your existing shell scripts with your team members\n* Add error handling if single statement in the *sh* scripts fails\n* Replace placeholders in *sh* scripts with variables\n* Overload variables and scripts in an environment configuration\n \nInstallation\n------------\n\nAlthough you can use PSH as a composer dependency, we recommend to use the **PHAR archive** instead. PSH only communicates through\nthe shell with your application and therefore does not need any influence on your other project dependencies.\n\n### Through composer\n\nLocally:\n\n```sh\ncomposer require shopware/psh --dev\n```\n\nGlobally:\n\n```sh\ncomposer global require shopware/psh\n```\n\n### As a PHAR archive\n\nDownload `psh.phar` to your local environment. \n\n```sh\nwget https://shopwarelabs.github.io/psh/psh.phar # PHP7 Version\nchmod +x psh.phar\n```\n\n### As a PHAR archive via phive (preferred)\n\n```sh\nphive install psh\n```\n\nIf you want to know how to install phive please click [here](https://phar.io/#Install). \n\n### Build it yourself\n\nPSH is used to build itself. You need to clone the repository and install the composer dependencies by yourself first.\n\n```sh\ngit clone https://github.com/shopwareLabs/psh.git\ncd psh\ncomposer install # assuming you have composer installed globally\ncomposer bin box install # box is needed to build phar file\n\n./psh unit # verify your installation by executing the test suite.\n./psh build \n```\n\nThis will create a release phar in the `build/psh.phar` directory. The project itself requires PHP 7.2+. \n\nUsage\n------------\n\n\u003e Notice: The YAML configuration format is deprecated and will be removed in version 2.0. If you need the old documentation, please refer to [older versions](https://github.com/shopwareLabs/psh/blob/v1.3.0/README.md) of this document\n\nPSH is a CLI application. Before you can use it you need to create a configuration file in your project root named `.psh.xml` or `.psh.xml.dist`.\n\n## Configuration\n\nThe minimum required file looks like this:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cpsh xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     xsi:noNamespaceSchemaLocation=\"https://raw.githubusercontent.com/shopwareLabs/psh/master/resource/config.xsd\"\u003e\n\n\u003c/psh\u003e\n```\nThe root element (`\u003cpsh\u003e`) can contain one many or all if the following configuration options.\n\n#### Paths\n\nIn order to use psh as a script executor, you need to define the locations in which to search.\n\n```xml\n\u003cpath\u003edeployment/scripts\u003c/path\u003e\n\u003cpath\u003etest/scripts\u003c/path\u003e\n\u003cpath\u003emore/scripts\u003c/path\u003e\n```\n\nPSH will then search in all these locations for `*.sh` files. These scripts can then be executed through PSH.\n\n\u003e Notice: If the script name starts with a dot (`.`) it will be excluded from the listing, but is callable like any other script. `\u003e psh.phar .hidden-action`\n\n#### Placeholders\n\nPlaceholders in your scripts looks like this:\n\n```sh\nln -s __PATH__\n```\n\nThe placeholder `__PATH__` now needs to be part of your configuration file as either a constant or a variable.\n\n\u003e Notice: All placeholders must be written in uppercase in scripts. Even if defined otherwise in configuration, replacement only works uppercase. With (sic!) add the end of a placeholder it will be escaped. As an example `__DIR__(sic!)`.  \n\n#### Constants\n\nConstants are the basic solution to placeholder replacements. You define placeholders in your config like this:\n\n```xml\n\u003cplaceholder\u003e\n    \u003cconst name=\"PATH\"\u003e/var/www\u003c/const\u003e\n\u003c/placeholder\u003e\n```\n\nThis will then execute \n\n```sh\nln -s /var/www\n```\n\n#### Variables\n\nWith variables you can use the output of one line shell statements in your scripts.\n  \n```xml\n\u003cplaceholder\u003e\n    \u003cdynamic name=\"PATH\"\u003eecho $HOME\u003c/dynamic\u003e\n\u003c/placeholder\u003e\n```\n\nThe Variables get executed before the actual statement is executed, but you can imagine the outcome to be equivalent to:\n\n```sh\nln -s `echo $HOME`\n```\n\n#### Dotenv\n\nWith dotenv you have the ability to load .env-files of your project.\n\n```xml\n\u003cplaceholder\u003e\n    \u003cdotenv\u003e.env\u003c/dotenv\u003e\n\u003c/placeholder\u003e\n```\n\nYou can also configure multiple paths to .env files.\n\n```xml\n\u003cplaceholder\u003e\n    \u003cdotenv\u003e.env\u003c/dotenv\u003e\n    \u003cdotenv\u003e.env2\u003c/dotenv\u003e\n\u003c/placeholder\u003e\n```\n\n`.env2` overrides `.env` in this example.\n\nExample:\n\n.psh.xml\n```xml\n\u003cpath\u003edev-ops/common/actions\"\u003c/path\u003e\n\u003cplaceholder\u003e\n    \u003cdotenv\u003e.env\u003c/dotenv\u003e\n\u003c/placeholder\u003e\n```\n\n.env\n```dotenv\nTEST=mytest\n```\n\ndev-ops/common/actions/test.sh\n```bash\n#!/usr/bin/env bash\n\necho __TEST__\n```\n\n#### Require\n\nIt may be necessary to require a placeholder to be set, but can't set right away. One such example might be a system dependent path. PSH allows you to communicate this to the user by adding this:\n\n```xml\n\u003cplaceholder\u003e\n    \u003crequire name=\"FOO\" description=\"Foo needs to be a reference to bar\"/\u003e\n\u003c/placeholder\u003e\n```\n\nNow unless foo is set, it is not possible to execute any psh script. The description is optional and can be omitted.\n\n#### Templates\n\nIf your application depends on files that are not part of your repository because they differ for different systems (Typically `*.dist` files), \nyou can use templates to achieve automatic deployment of these files.\n\n```xml\n\u003ctemplate \n    source=\"templates/consts.tpl\" \n    destination=\"app/consts.php\"\n/\u003e\n```\n\nThis reads the contents of `templates/consts.tpl`, replaces placeholders with constants or variables from your configuration and writes the result to `app/consts.php`.\n\nIt is even possible to use placeholders in template destinations:\n\n```xml\n\u003ctemplate\n    source=\"templates/consts.tpl\"\n    destination=\"app/consts-__ENVIRONMENT__.php\"\n/\u003e\n```\n\n#### Environments\n\nEnvironments are used to extend or overwrite your base configuration. You can add more scripts, redefine or add constants or variables. \nA environment called `foo` may look like this:\n\n```xml\n\u003cenvironment name=\"foo\"\u003e\n\n    \u003cpath\u003efoo/sh/scripts\u003c/path\u003e\n    \u003cpath\u003ebar/sh/scripts\u003c/path\u003e\n    \n    \u003cplaceholder\u003e\n        \u003cconst name=\"TEST\"\u003e1\u003c/const\u003e\n        \u003cdynamic name=\"ID\"\u003eid\u003c/dynamic\u003e   \n    \u003c/placeholder\u003e\n\n\u003c/environment\u003e\n```\n\nThis environment loads all scripts from `foo/sh/scripts` and `bar/sh/scripts`, adds a constant `TEST` and a variable `ID`. \nIf you want to call a script in this environment you have to prefix your call with `foo:`.\n\nIn order to exclude a whole environment from the listing add the `hidden` attribute to the environment tag and set it to `true`, like this: \n\n```xml\n\u003cenvironment name=\"internal\" hidden=\"true\"\u003e\n    \u003cpath\u003einternal/only/scripts\u003c/path\u003e\n\u003c/environment\u003e\n```\n\nThese scripts can be executed like any regular script, they will just not be shown in the listing.\n\n#### Headers\n\nOptionally - and just for fun - you can output a ASCII header in front of every PSH execution.\n\n```xml\n    \u003cheader\u003e\u003c![CDATA[\n         _\n     ___| |__   ___  _ ____      ____ _ _ __ ___\n    / __| '_ \\ / _ \\| '_ \\ \\ /\\ / / _` | '__/ _ \\\n    \\__ \\ | | | (_) | |_) \\ V  V / (_| | | |  __/\n    |___/_| |_|\\___/| .__/ \\_/\\_/ \\__,_|_|  \\___|\n                    |_|\n    ]]\u003e\u003c/header\u003e\n\n```\n\n#### Overriding configuration file\n\nYou can place a `.psh.xml.override` inside your directory where the `.psh.xml` is located to override the specific configurations.\n\n\u003e Notice: You can overwrite a XML config file with a YAML file to ease the migration from one format to the other.\n\n#### Importing configuration files\n\nYou can import environments, actions and placeholders by using the import statement and telling psh to look in another place.\n\n```xml\n\u003cimport path=\"another/config/file/location\" /\u003e\n```\n\nThese directories should contain a `psh.xml` or `psh.xml.dist`. If no file is found a warning is issued but no braking error, since it may very well be that psh is currently installing or downloading the files. You can also use a glob pattern like \"tools/**/config\"\n\n\u003e Notice: This happens through merging the different configurations into one. Be aware that you might overwrite base configuration. \n\n## PSH-Scripts\n\nAlthough most of your existing sh scripts should work just fine, you may find some of the following additions useful or necessary.\n\nKeep in mind: **Commands will be validated for successful execution -\u003e All failures will fail the script!**\n\n#### Defining placeholders\n\nIn order to ensure that your scripts are reusable you can add placeholders that PSH will replace with configured values. All placeholders\nstart and end with `__`, and contain only upper case letters, numbers, and single `_` characters.\n\n```sh\n__TEST_IT__\n```\n\n#### Including other actions\n\nIt is possible to include other scripts by it's name.\n\n```sh\nACTION: build # default environment or\nACTION: pipelines:build # if it's in an environment\n```\n\nThe benefit of this instead of `Including other scripts` is that you don't have to deal with absolute or relative paths in general.\n\n#### Including other scripts\n\nPrefixing a line with `INCLUDE: ` will treat the remaining part of the line as the path to another script to be included and executed here.\n\n```sh\nINCLUDE: my/sub/script.sh\n```\n\nIf the path is relative, PSH will attempt to load the script relative to the location of the current script or relative to the configuration file.\n\n#### On demand templates\n\nPrefixing a line with `TEMPLATE: ` will trigger an on demand template creation. The remaining part of the line then must look like this: `SOURCE_PATH:DESTINATION_PATH`\n\n```sh\nTEMPLATE: ../templates/template.ini.tpl:../destination/template.ini\n```\n\nNotice that all paths here must be **relative** to the script location.\n\n#### Defer execution to the background\n\nExecute the script in the background, so the following command gets executed right away\n\n```sh\nD: php generate_some_things.php\n```\n\n#### Wait for all deferred commands to execute\n\nIf you then want to wait for all results, just add a `WAIT` in there.\n\n```sh\nWAIT:\n```\n\n\n#### Open a ssh connection to another machine\n\nMany dev-ops script open a SSH channel to a locally running virtual machine / container or a remote staging / test system. If you do this \nthrough PSH you have to prefix the line with `TTY:` \n\n```sh\nTTY: vagrant ssh\n```\n\n#### Ignoring if a statement errored\n\nContrary to your usual shell scripts, to PSH it matters if a sh statement fails or not. If you need it to ignore errors, you have to prefix the line with `I:`\n\n```sh\nI: rm -R sometimes/there\n```\n#### Breaking statements into multiple lines\n\nIf a single shell statement is to long for a single line, you can break it in PSH and intend it with three spaces in the next line. \nPSH will then concatenate it prior to execution and execute it all in one.\n\n```sh\nbin/phpunit\n    --debug\n    --verbose\n```\n\n#### Description\n\nYou can add a description to a script which will be printed when the command list will be displayed.\n\n```sh\n#!/usr/bin/env bash\n#DESCRIPTION: My useful comment.\n```\n\n#### Downsides\n\n* `export` statements and internal variables do not work, since the statements do **no longer share a single environment**.\n* Statements that change the flow of a script do not work out of the box.\n\n## BASH-Scripts\n\nPSH allows you to execute bash scripts directly. Most features from the above described PSH-Scripts do not work in this part of the runtime, but placeholder usage is still possible an encouraged.\n\nSo if you have Bash scripts that you want PSH to execute directly just add a second line after the shebang:\n\n```bash\n#!/usr/bin/env bash\n# \u003cPSH_EXECUTE_THROUGH_CMD\u003e\n\nFOO=\"BAR\"\n\necho $PWD\necho $FOO\necho __PLACEHOLDER__\n\n```\n\n`# \u003cPSH_EXECUTE_THROUGH_CMD\u003e` will advice PSH to execute the script through your current OS.\n\n\u003e Notice: PSH is written for security and predictability first, so it will warn you if you forget to add `set -euo pipefail` to the beginning of your script.  \n\n#### Internals\n\n* If and only if a placeholder is present PSH will internally create a hidden file in the same directory and mark it executable, please make shure that your environment allows that.\n* Future versions of PSH will change this to requiring a special shebang line for PSH-Scripts, please be aware of that (Something like `#!/usr/bin/env psh`).  \n\n## Executing it\n\nThe general format is `./psh.phar \u003capplication-options\u003e \u003cscript-names\u003e \u003cscript-options\u003e`. The only currently supported application option is `--no-header`, script names are a comma separated list of actions (or one) and script options are key value pairs to overwrite placeholders. Let's look at some examples:\n\n\nExecuting the phar will print a listing overview of all available commands\n\n```sh\n\u003e ./psh.phar\n\n###################\nAvailable commands:\n\n\t- build\n\t- unit\n\n2 script(s) available\n```\n\nThe first argument is always the script name. This for example will execute the unit script:\n\n```sh\n\u003e ./psh.phar unit\n\n###################\nStarting Execution of 'unit' ('actions/unit.sh')\n\n\n(1/3) Starting\n\u003e bin/php-cs-fixer fix\n\tYou are running php-cs-fixer with xdebug enabled. This has a major impact on runtime performance.\n\t\n\tLoaded config from \"/var/www/swag/psh/.php_cs\".\n\t\n\t[....]\n```\n\nYou can add more commands to be executed in a chain, by comma separating the script names:\n\n```sh\n\u003e ./psh.phar unit,build #executes both scripts in order\n```\n\nYou can add parameter for replace placeholder in your .sh files like the following examples:\n\n```sh \n    ./psh.phar unit --param someValue  #or\n    ./psh.phar unit --param=someValue --otherParam value --onMoreParam=value ...\n    ./psh.phar list --add -l\n```\n\nin your .sh files write.\n```sh \n    ls __ADD__\n```\n\nexecutes:\n```sh\n    ls -l\n```\n\n### Bash Autocompletion\n\nBash autocompletion is only provided by [PSH-Global](https://github.com/shopwareLabs/psh-global). This will install a global script that fetches \nthe psh.phar file in your project and that will install the autocompletion for you. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshopwarelabs%2Fpsh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshopwarelabs%2Fpsh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshopwarelabs%2Fpsh/lists"}