Skip to content

Commit db64429

Browse files
committed
Initial commit
0 parents  commit db64429

File tree

491 files changed

+64039
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

491 files changed

+64039
-0
lines changed

.github/dependabot.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: 'npm'
4+
directory: '/'
5+
schedule:
6+
interval: 'daily'

README.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# SSH & SCP Deploy
2+
This GitHub Action lets you deploy your project to a remote server using SSH and SCP. Even though there are many other actions like this, i wanted to create a more customizable one.
3+
4+
## Input Variables
5+
- `host` - [**REQUIRED**] Remote host
6+
- `port` - Remote port. Default: 22
7+
- `username` - [**REQUIRED**] SSH remote user
8+
- `password` - SSH remote password
9+
- `key` - SSH private key, can be either a path to a file or the key itself
10+
- `passphrase` - SSH key passphrase
11+
- `files` - [**REQUIRED**] Files and folders to upload. You can use glob patterns.
12+
- `remote-path` - Remote destination path
13+
- `clean` - Whether to clean the remote path before uploading. Default: false
14+
- `before-upload` - Commands to execute before the SCP file transfer, on the host machine
15+
- `after-upload` - Commands to execute after the SCP file transfer, on the host machine
16+
17+
## Example Usage
18+
**NOTE**: For security reasons, it is recommended to store things like passwrds, ssh keys, passphrases etc. in the `Secrets` section of your GitHub repository.
19+
### Using User & Password
20+
```yaml
21+
uses: ilCollez/ssh-scp-deploy@main
22+
with:
23+
host: ${{ secrets.SSH_HOST }} # "example.com"
24+
port: ${{ secrets.SSH_PORT }} # 22
25+
username: ${{ secrets.SSH_USER }} # "user"
26+
password: ${{ secrets.SSH_PASSWORD }} # "password"
27+
files: |
28+
*.json
29+
public
30+
dist
31+
lib/**/*.js
32+
remote-path: "/var/www/html"
33+
clean: true
34+
```
35+
36+
### Using Private Key
37+
```yaml
38+
uses: ilCollez/ssh-scp-deploy@main
39+
with:
40+
host: ${{ secrets.SSH_HOST }} # "example.com"
41+
port: ${{ secrets.SSH_PORT }} # 22
42+
username: ${{ secrets.SSH_USER }} # "user"
43+
key: ${{ secrets.SSH_KEY }} # "~/.ssh/id_rsa", can also be the key itself
44+
passphrase: ${{ secrets.SSH_PASSPHRASE }} # "passphrase"
45+
files: |
46+
*.json
47+
public
48+
dist
49+
lib/**/*.js
50+
remote-path: "/var/www/html"
51+
```
52+
53+
### Using pre-upload and post-upload commands
54+
```yaml
55+
uses: ilCollez/ssh-scp-deploy@main
56+
with:
57+
host: ${{ secrets.SSH_HOST }} # "example.com"
58+
port: ${{ secrets.SSH_PORT }} # 22
59+
username: ${{ secrets.SSH_USER }} # "user"
60+
key: ${{ secrets.SSH_KEY }} # "~/.ssh/id_rsa", can also be the key itself
61+
passphrase: ${{ secrets.SSH_PASSPHRASE }} # "passphrase"
62+
files: |
63+
*.json
64+
public
65+
dist
66+
lib/**/*.js
67+
remote-path: "/var/www/html"
68+
clean: true
69+
before-upload: |
70+
echo "Executed before upload"
71+
72+
pm2 stop service
73+
after-upload: |
74+
echo "Executed after upload"
75+
76+
npm ci --production
77+
npm run build
78+
npm test
79+
80+
pm2 start service
81+
```
82+
83+
## To Do
84+
- [ ] Add support for SSH proxy
85+
- [ ] Add Tests
86+
87+
## License
88+
This GitHub Action is licensed under the MIT License.

action.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: 'SSH-SCP Server Deploy'
2+
author: 'Collez'
3+
description: 'Deploys files and executes commands to a remote host'
4+
5+
inputs:
6+
host:
7+
description: 'Remote host'
8+
required: true
9+
port:
10+
description: 'Remote port'
11+
default: 22
12+
username:
13+
description: 'SSH remote user'
14+
required: true
15+
password:
16+
description: 'SSH remote password'
17+
key:
18+
description: 'SSH private key, can be either a path to a file or the key itself'
19+
passphrase:
20+
description: 'SSH key passphrase'
21+
files:
22+
description: 'Files and folders to upload. You can use glob patterns'
23+
required: true
24+
remote-path:
25+
description: 'Remote destination path'
26+
clean:
27+
description: 'Whether to clean the remote path before uploading'
28+
default: false
29+
before-upload:
30+
description: 'Commands to execute before the SCP file transfer, on the host machine'
31+
after-upload:
32+
description: 'Commands to execute after the SCP file transfer, on the host machine'
33+
34+
branding:
35+
icon: 'server'
36+
color: 'blue'
37+
38+
runs:
39+
using: 'node12'
40+
main: 'index.js'

index.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const {
2+
getInput,
3+
getMultilineInput,
4+
setFailed,
5+
setSecret,
6+
getBooleanInput,
7+
} = require('@actions/core');
8+
9+
const Deployer = require('./lib/Deployer.js');
10+
11+
const deployer = new Deployer();
12+
13+
const fail = (message) => {
14+
setFailed(message);
15+
deployer.disconnect();
16+
process.exit(1);
17+
};
18+
19+
const password = getInput('password');
20+
const privateKey = getInput('key');
21+
const passphrase = getInput('passphrase');
22+
23+
setSecret(password);
24+
setSecret(privateKey);
25+
setSecret(passphrase);
26+
27+
if (!password && !privateKey)
28+
fail('You must provide either a password or a private key');
29+
30+
(async () => {
31+
console.log('🚀 Connecting...');
32+
33+
await deployer
34+
.connect({
35+
host: getInput('host', { required: true }),
36+
port: parseInt(getInput('port')),
37+
username: getInput('username', { required: true }),
38+
password,
39+
privateKey,
40+
passphrase,
41+
})
42+
.catch(fail);
43+
44+
console.log('✅ Successfully connected');
45+
46+
deployer.cwd = getInput('remote-path');
47+
48+
const beforeUpload = getMultilineInput('before-upload');
49+
if (beforeUpload) {
50+
console.log('📄 Executing before-upload script...');
51+
await deployer.run(beforeUpload).catch(fail);
52+
console.log('✅ Successfully executed before-upload');
53+
}
54+
55+
if (getBooleanInput('clean')) {
56+
console.log('🗑 Cleaning remote directory...');
57+
await deployer.run('rm -rf *').catch(fail);
58+
console.log('✅ Successfully cleaned remote path');
59+
}
60+
61+
const files = getMultilineInput('files', { required: true });
62+
console.log('📂 Uploading files...');
63+
await deployer.upload(files, '.').catch(fail);
64+
console.log('✅ Files uploaded successfully');
65+
66+
const afterUpload = getMultilineInput('after-upload');
67+
if (afterUpload) {
68+
console.log('📄 Executing after-upload script...');
69+
await deployer.run(afterUpload);
70+
console.log('✅ Successfully executed after-upload');
71+
}
72+
73+
console.log('🚀 All done! disconnecting...');
74+
75+
deployer.disconnect();
76+
})();

lib/Deployer.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const { NodeSSH } = require('node-ssh');
2+
const fg = require('fast-glob');
3+
const { join } = require('path');
4+
5+
module.exports = class Deployer {
6+
_sshClient = new NodeSSH();
7+
cwd = undefined;
8+
9+
async connect(options) {
10+
await this._sshClient.connect(options);
11+
}
12+
13+
async run(command, options) {
14+
if (Array.isArray(command)) {
15+
command = command.join('&&');
16+
}
17+
18+
await this._sshClient.execCommand(command, {
19+
cwd: this.cwd,
20+
...options
21+
});
22+
}
23+
24+
async upload(file, remotePath) {
25+
const glob = await fg(file, {
26+
onlyFiles: false,
27+
markDirectories: true
28+
});
29+
30+
for (const file of glob) {
31+
console.log(`📦 Uploading ${file}...`);
32+
33+
const localPath = join(process.cwd(), file);
34+
const remoteFilePath = join(this.cwd || '', remotePath, file);
35+
36+
if (file.endsWith('/')) {
37+
await this._sshClient.putDirectory(localPath, remoteFilePath);
38+
} else {
39+
await this._sshClient.putFile(localPath, remoteFilePath);
40+
}
41+
}
42+
}
43+
44+
disconnect() {
45+
this._sshClient.dispose();
46+
}
47+
}

node_modules/.bin/semver

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/semver.cmd

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node_modules/.bin/semver.ps1

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)