不想看前面这么多废话的可以直接跳到具体实现
Github Actions 是什么?
说到 Github Actions 不得不提一下。
- )
开始动手了
目录结构
shh-deploy
|—— dist(编译后的目录可用直接运行)
| |—— index.js
|—— lib(TS输出文件)
|—— src(源码文件)
| |—— main.ts
| |—— sftp.ts
| |—— ssh-deploy.ts
| action.yml(Github Actions的配置文件)
| tsconfig.json(TS配置文件)
思考?
我们既然要实现自动部署。
- 需要连接到服务器
ip
、port
、username
、password
- 需要哪些文件(
source
) - 部署到服务器哪个目录下(
target
) - 文件复制完后需要执行安装依赖重启服务等等之内的工作(
after command
)
知道我们需要什么后,接下来就来看具体实现。
Github Actions 具体实现
# action.yml 配置文件
name: 'SSH Auto Deploy' # 名称
description: 'ssh auto deploy' # 描述
author: 'hengkx' # 作者
branding:
icon: 'crosshair' # 使用的是Feather的图标
color: 'gray-dark' # 图标颜色
inputs: # 输入参数
HOST: # 服务器地址
description: 'remote host' # 参数描述
required: true # 是否必填
USERNAME: # 用户名
description: 'username'
required: true
PASSWORD: # 密码
description: 'password'
required: true
PORT: # 端口
description: 'port'
default: 22 # 默认值
SOURCE: # 源目录
description: 'local path'
required: true
TARGET: # 目标目录
description: 'remote target'
required: true
AFTER_COMMAND: # 文件上传文成后执行
description: 'upload success execute command'
runs: # 运行环境
using: 'node12'
main: 'dist/index.js' # 所执行的文件
有一点需要注意我们所提交的代码包含node_modules
或者使用@zeit/ncc
直接打包成可执行文件
// main.ts
import * as core from '@actions/core';
import { Client } from 'ssh2';
import Sftp from './sftp';
function exec(conn: Client, command: string) {
return new Promise((resolve, reject) => {
conn.exec(command, (err, stream) => {
if (err) return reject(err);
stream
.on('close', function (code) {
resolve(code);
})
.on('data', function (data) {
core.info(data.toString());
})
.stderr.on('data', function (data) {
core.error(data.toString());
});
});
});
}
export async function run() {
try {
const host = core.getInput('HOST'); // 使用这个方法来获取我们在action.yml配置文件中设置的输入参数
const port = parseInt(core.getInput('PORT'));
const username = core.getInput('USERNAME');
const password = core.getInput('PASSWORD');
const src = core.getInput('SOURCE');
const dst = core.getInput('TARGET');
const afterCommand = core.getInput('AFTER_COMMAND');
// 下面为ssh链接服务器上传文件并执行命令
const conn = new Client();
conn.on('ready', async () => {
const sftp = new Sftp(conn);
core.info('begin upload');
await sftp.uploadDir(src, dst);
core.info('end upload');
let code: any = 0;
if (afterCommand) {
core.info('begin execute command'); // 输出一条日志
code = await exec(conn, `cd ${dst} && ${afterCommand}`);
core.info('end execute command');
}
conn.end();
if (code === 1) {
core.setFailed(`command execute failed`); // 告诉Github Actions执行失败了
}
});
conn.connect({ host, port, username, password });
} catch (error) {
core.setFailed(error.message);
}
}
我的项目配置文件
name: Deploy
on: # 在master分支上提交代码执行
push:
branches: [master]
jobs: # 作业
build-and-deploy: # 作业名称
runs-on: ubuntu-latest # 运行的环境
steps: #步骤
- name: Checkout # 步骤名
uses: actions/checkout@master # 所使用的action
- name: Setup Node.js environment
uses: actions/[email protected]
with:
node-version: '12.x'
- name: Build Project
run: yarn && yarn run ci
- name: Deploy to Server
uses: hengkx/[email protected]
with: # 以下为参数
USERNAME: ${{ secrets.DEPLOY_USER }} # 为了用户信息安全对敏感数据可以在secrets中配置请看下图
PASSWORD: ${{ secrets.DEPLOY_PASSWORD }}
HOST: ${{ secrets.DEPLOY_HOST }}
SOURCE: 'dist'
TARGET: '/root/task-market/api'
AFTER_COMMAND: 'npm run stop && npm install --production && npm run start'