├── .github └── workflows │ └── main.yml ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── entrypoint.sh ├── resources └── logo.png ├── with_key.sh └── with_pass.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | 12 | services: 13 | ssh_server: 14 | image: rastasheep/ubuntu-sshd:latest 15 | ports: 16 | - 22/tcp 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Generate SSH Key Pair 22 | id: generate_key 23 | run: | 24 | echo "Generating a new SSH key pair..." 25 | mkdir -p ${{ github.workspace }}/.ssh_temp 26 | ssh-keygen -t rsa -C "github-action@$(date +%s)" -f ${{ github.workspace }}/.ssh_temp/id_rsa_action -N "" 27 | echo "Key generation complete. Keys are in ${{ github.workspace }}/.ssh_temp" 28 | echo "private_key_path=${{ github.workspace }}/.ssh_temp/id_rsa_action" >> $GITHUB_OUTPUT 29 | 30 | - name: Read Private Key File 31 | id: read_key 32 | run: | 33 | echo "Reading private key content..." 34 | # Use multi-line output method for the key content 35 | echo "private_key_content<> $GITHUB_OUTPUT 36 | cat "${{steps.generate_key.outputs.private_key_path}}" >> $GITHUB_OUTPUT 37 | echo "EOF" >> $GITHUB_OUTPUT 38 | echo "Private key content loaded into output." 39 | 40 | - name: Test ssh-scp deploy with password 41 | uses: marcodallasanta/ssh-scp-deploy@main 42 | with: 43 | local: "${{ github.workspace }}/.ssh_temp/id_rsa_action.pub" 44 | remote: "/root/.ssh/authorized_keys" 45 | host: ssh_server 46 | user: root 47 | password: root 48 | pre_upload: echo "pass pre_upload 👈" 49 | post_upload: echo "pass post_upload 👉" && chown root:root /root/.ssh/authorized_keys && passwd -d root 50 | ssh_options: -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 51 | 52 | - name: Test ssh-scp deploy with ssh key 53 | uses: marcodallasanta/ssh-scp-deploy@main 54 | with: 55 | local: "LICENSE" 56 | remote: "~/" 57 | host: ssh_server 58 | user: root 59 | key: ${{steps.read_key.outputs.private_key_content}} 60 | pre_upload: echo "key pre_upload 👈" 61 | post_upload: echo "key post_upload 👉" 62 | ssh_options: -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 63 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [Unreleased] 2 | 3 | ## [v1.2.0] - 2021-03-22 4 | 5 | ### Added 6 | - [Issue #17](https://github.com/marcodallasanta/ssh-scp-deploy/issues/15) - Using /bin/sh instead of /bin/bash. 7 | 8 | ## [v1.1.0] - 2021-10-02 9 | 10 | ### Added 11 | - [Issue #15](https://github.com/marcodallasanta/ssh-scp-deploy/issues/15) - Added -p {INPUT_PORT} option. 12 | 13 | ## [v1.0.5] - 2021-09-08 14 | 15 | ### Fixed 16 | - [Issue #12](https://github.com/marcodallasanta/ssh-scp-deploy/issues/12) - Action never failed also when file/dir was not uploaded. 17 | 18 | ## [v1.0.4] - 2021-02-10 19 | 20 | ### Fixed 21 | - [Issue #9](https://github.com/marcodallasanta/ssh-scp-deploy/issues/9) - Wrong if on password. 22 | 23 | ## [v1.0.3] - 2021-02-08 24 | 25 | ### Fixed 26 | - Hardcoded user "ubuntu" in scp. 27 | 28 | ## [v1.0.2] - 2020-12-21 29 | 30 | ### Fixed 31 | - Dockerfile used to copy just entrypoint.sh. 32 | 33 | ## [v1.0.1] - 2020-12-21 34 | 35 | ### Fixed 36 | - Dockerfile used to copy just entrypoint.sh. 37 | 38 | ## [v1.0.0] - 2020-12-18 39 | 40 | ### Added 41 | - First definition of the action. 42 | 43 | 44 | [unreleased]: https://github.com/marcodallasanta/ssh-scp-deploy/compare/main...development 45 | [v1.1.0]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.1.0 46 | [v1.0.5]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.0.5 47 | [v1.0.4]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.0.4 48 | [v1.0.3]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.0.3 49 | [v1.0.2]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.0.2 50 | [v1.0.1]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.0.1 51 | [v1.0.0]: https://github.com/marcodallasanta/ssh-scp-deploy/tree/v1.0.0 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk update && \ 4 | apk add --no-cache ca-certificates \ 5 | openssh-client \ 6 | sshpass 7 | 8 | COPY LICENSE README.md / 9 | COPY entrypoint.sh with_key.sh with_pass.sh / 10 | 11 | ENTRYPOINT ["/entrypoint.sh"] 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2020 Marco Dalla Santa 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | Action type 7 | License 8 | Pipeline status 9 |

10 | 11 | # ssh-scp-deploy 12 | 13 | ## ❔ Why should I use this action? 14 | 15 | Because this action provide an easy and highly customizable way to upload files via scp and execute a set of command via ssh before or/and after. 16 | I use this action to deploy my personal projects to remote server, restarting the needed services or to do a simple upload via scp. 17 | 18 | ## 🏃 Supported runners 19 | [![Supported runner](https://img.shields.io/badge/Linux-262b31?style=for-the-badge&logo=linux&logoColor=fcc624)](https://docs.github.com/en/actions/creating-actions/about-actions#docker-container-actions) 20 | 21 | 22 | ## 👤 Author 23 | 24 | **Marco Dalla Santa** 25 | 26 | * Github: [@marcodallasanta](https://github.com/marcodallasanta) 27 | * LinkedIn: [@marcodallasanta](https://linkedin.com/in/marcodallasanta) 28 | 29 | 30 | ## ⚙️ Usage 31 | ```yaml 32 | - uses: mdallasanta/ssh-scp-deploy@{version} 33 | with: 34 | local: './' # Local file path - REQUIRED false - DEFAULT ./ 35 | remote: '~/' # Remote file path - REQUIRED false - DEFAULT ~/ 36 | host: ${{secrets.HOST}} # Remote server address - REQUIRED true 37 | port: ${{secrets.PORT}} # Remote server port - REQUIRED false - DEFAULT 22 38 | user: ${{secrets.USER}} # Remote server user - REQUIRED true 39 | password: ${{secrets.PASSWORD}} # User password - REQUIRED at least one of "password" or "key" 40 | key: ${{secrets.KEY}} # Remote server private key - REQUIRED at least one of "password" or "key" 41 | pre_upload: echo "This will be executed before the upload!" # Command to run via ssh before scp upload - REQUIRED false 42 | post_upload: echo "This will be executed after the upload!" # Command to run via ssh after scp upload - REQUIRED false 43 | ssh_options: -o StrictHostKeyChecking=no # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 44 | scp_options: -v # Flags to use during scp - REQUIRED false - DEFAULT '' 45 | ``` 46 | 47 | ## 🤝 Contributing 48 | 49 | Contributions, issues and feature requests are welcome! 50 | 51 | Feel free to check [issues page](https://github.com/mdallasanta/ssh-scp-deploy/issues). 52 | 53 | ## 🙏 Thanks 54 | 55 | Thanks to: 56 | 57 | - [Raphaël Bussa](https://github.com/raphaelbussa) for help in testing. 58 | - [jamesremuscat](https://github.com/jamesremuscat) for resolving [issue#15](https://github.com/marcodallasanta/ssh-scp-deploy/issues/15) 59 | - [Blake Drumm](https://github.com/x-limitless-x) for resolving [issue#19](https://github.com/marcodallasanta/ssh-scp-deploy/issues/19) 60 | 61 | 62 | ## 📝 License 63 | 64 | Copyright © 2020-2022 [Marco Dalla Santa](https://github.com/marcodallasanta) 65 | 66 | The source code, scripts and documentation in this project are released under the [MIT License](LICENSE) 67 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'ssh-scp-deploy' 2 | description: 'A GitHub Action that upload the artifact via scp and runs commands before or/and after.' 3 | author: 'Marco Dalla Santa' 4 | 5 | inputs: 6 | local: 7 | description: 'Local file path' 8 | required: false 9 | default: './' 10 | 11 | remote: 12 | description: 'Remote file path' 13 | required: false 14 | default: '~/' 15 | 16 | host: 17 | description: 'Remote server address' 18 | required: true 19 | 20 | port: 21 | description: 'Remote server port (default 22)' 22 | required: false 23 | default: 22 24 | 25 | user: 26 | description: 'Remote server user' 27 | required: true 28 | 29 | password: 30 | description: 'User password' 31 | required: false 32 | 33 | key: 34 | description: 'Remote server private key' 35 | required: false 36 | 37 | pre_upload: 38 | description: 'Command to run via ssh before scp upload' 39 | required: false 40 | 41 | post_upload: 42 | description: 'Command to run via ssh after scp upload' 43 | required: false 44 | 45 | ssh_options: 46 | description: 'A set of ssh_option separated by -o' 47 | required: false 48 | default: -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 49 | 50 | scp_options: 51 | description: 'Flags to use during scp' 52 | required: false 53 | default: 54 | 55 | runs: 56 | using: 'docker' 57 | image: 'Dockerfile' 58 | 59 | branding: 60 | icon: 'upload-cloud' 61 | color: 'green' -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PASSWORD=${INPUT_PASSWORD}; 4 | KEY=${INPUT_KEY}; 5 | 6 | if [ -z "$KEY" ] && [ -z "$PASSWORD" ]; then 7 | echo "🔑 Please provide at least a key or a password..."; 8 | exit 0; 9 | fi 10 | 11 | if [[ -n "$KEY" ]]; then 12 | echo "🔑 Using key file..."; 13 | source /with_key.sh; 14 | else 15 | echo "🔑 Using password..."; 16 | source /with_pass.sh; 17 | fi -------------------------------------------------------------------------------- /resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcodallasanta/ssh-scp-deploy/9abd91cde1181aefa2995a9ee4eccd104d29b76e/resources/logo.png -------------------------------------------------------------------------------- /with_key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "🔑 Adding ssh key..." && 4 | eval $(ssh-agent -s) && 5 | ssh-add <(echo "${INPUT_KEY}") && 6 | echo "🔐 Added ssh key"; 7 | 8 | PRE_UPLOAD=${INPUT_PRE_UPLOAD} 9 | if [ ! -z "$PRE_UPLOAD" ]; then 10 | { 11 | echo "👌 Executing pre-upload script..." && 12 | ssh ${INPUT_SSH_OPTIONS} -p "${INPUT_PORT}" ${INPUT_USER}@${INPUT_HOST} "$INPUT_PRE_UPLOAD && exit" && 13 | echo "✅ Executed pre-upload script" 14 | } || { 15 | echo "😢 Something went wrong during pre-upload script" && exit 1 16 | } 17 | fi 18 | 19 | { 20 | echo "🚚 Uploading via scp..." && 21 | scp ${INPUT_SSH_OPTIONS} ${INPUT_SCP_OPTIONS} -P "${INPUT_PORT}" -r ${INPUT_LOCAL} ${INPUT_USER}@${INPUT_HOST}:"${INPUT_REMOTE}" && 22 | echo "🙌 Uploaded via scp" 23 | } || { 24 | echo "😢 Something went wrong during upload" && exit 1  25 | } 26 | 27 | POST_UPLOAD=${INPUT_POST_UPLOAD} 28 | if [ ! -z "$POST_UPLOAD" ]; then 29 | { 30 | echo "👌 Executing post-upload script..." && 31 | ssh ${INPUT_SSH_OPTIONS} -p "${INPUT_PORT}" ${INPUT_USER}@${INPUT_HOST} "$POST_UPLOAD && exit" && 32 | echo "✅ Executed post-upload script" 33 | } || { 34 | echo "😢 Something went wrong during post-upload script" && exit 1 35 | } 36 | fi 37 | 38 | echo "🎉 Done"; -------------------------------------------------------------------------------- /with_pass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PRE_UPLOAD=${INPUT_PRE_UPLOAD} 4 | if [ ! -z "$PRE_UPLOAD" ]; then 5 | { 6 | echo "👌 Executing pre-upload script..." && 7 | sshpass -p ${PASSWORD} ssh ${INPUT_SSH_OPTIONS} -p "${INPUT_PORT}" ${INPUT_USER}@${INPUT_HOST} "$INPUT_PRE_UPLOAD && exit" && 8 | echo "✅ Executed pre-upload script" 9 | } || { 10 | echo "😢 Something went wrong during pre-upload script" && exit 1 11 | } 12 | fi 13 | 14 | { 15 | echo "🚚 Uploading via scp..." && 16 | sshpass -p ${PASSWORD} scp ${INPUT_SSH_OPTIONS} ${INPUT_SCP_OPTIONS} -P "${INPUT_PORT}" -r ${INPUT_LOCAL} ${INPUT_USER}@${INPUT_HOST}:"${INPUT_REMOTE}" && 17 | echo "🙌 Uploaded via scp" 18 | } || { 19 | echo "😢 Something went wrong during upload" && exit 1 20 | } 21 | 22 | POST_UPLOAD=${INPUT_POST_UPLOAD} 23 | if [ ! -z "$POST_UPLOAD" ]; then 24 | { 25 | echo "👌 Executing post-upload script..." && 26 | sshpass -p ${PASSWORD} ssh ${INPUT_SSH_OPTIONS} -p "${INPUT_PORT}" ${INPUT_USER}@${INPUT_HOST} "$POST_UPLOAD && exit" && 27 | echo "✅ Executed post-upload script" 28 | } || { 29 | echo "😢 Something went wrong during post-upload script" && exit 1 30 | } 31 | fi 32 | 33 | echo "🎉 Done"; --------------------------------------------------------------------------------