Skip to content

Commit 9399392

Browse files
committed
0.0.6
* PipeLine支持`Task`和`TaskRaw` * 新增范例`example/airport-raw.ts` * 优化日志函数与日志输出格式 * 新增测试模式: `PipeLine.test()`
1 parent 96fc27d commit 9399392

File tree

10 files changed

+292
-65
lines changed

10 files changed

+292
-65
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# CHANGELOG
22

33

4+
## [0.0.6] - 2025-07-03
5+
6+
* PipeLine支持`Task``TaskRaw`
7+
* 新增范例`example/airport-raw.ts`
8+
* 优化日志函数与日志输出格式
9+
* 新增测试模式: `PipeLine.test()`
10+
11+
412
## [0.0.5] - 2025-07-01
513

614
* 日志模块更新,增加特殊日志

example/airport-raw.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { join } from 'path'
2+
import { name, version } from '../package.json'
3+
import { PipeLine, remote, logError } from '../src/airport'
4+
5+
const file = [name, version].join('-') + '.tgz'
6+
7+
// 创建部署任务
8+
const deployTask = {
9+
name: '部署应用',
10+
steps: [
11+
{
12+
name: '构建项目',
13+
run: [
14+
'mkdir -p .cache',
15+
'mv `npm pack` .cache/',
16+
],
17+
},
18+
{
19+
name: '发布到远程服务器',
20+
async run() {
21+
const ssh = remote('gavin@192.168.5.121')
22+
const dir = (path?: string) => join('/home/gavin/test', path ?? '')
23+
try {
24+
await ssh.run('rm -f', dir('latest'))
25+
await ssh.run('mkdir -p', dir(version))
26+
await ssh.scp(`.cache/${file}`, dir())
27+
await ssh.run('tar -zxvf', dir(file), '-C', dir(version))
28+
await ssh.run('ln -s', dir(version), dir('latest'))
29+
}
30+
catch (e) {
31+
logError(e)
32+
}
33+
},
34+
},
35+
],
36+
}
37+
38+
// 执行流水线
39+
PipeLine.run([deployTask])

example/airport-test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { join } from 'path'
2+
import { name, version } from '../package.json'
3+
import { PipeLine, Task, remote, logError } from '../src/airport'
4+
5+
const file = [name, version].join('-') + '.tgz'
6+
7+
// 创建部署任务
8+
const deployTask = new Task({
9+
name: '部署应用',
10+
steps: [
11+
{
12+
name: '构建项目',
13+
run: [
14+
'mkdir -p .cache',
15+
'mv `npm pack` .cache/',
16+
],
17+
},
18+
{
19+
name: '发布到远程服务器',
20+
async run() {
21+
const ssh = remote('gavin@192.168.5.121')
22+
const dir = (path?: string) => join('/home/gavin/test', path ?? '')
23+
try {
24+
await ssh.run('rm -f', dir('latest'))
25+
await ssh.run('mkdir -p', dir(version))
26+
await ssh.scp(`.cache/${file}`, dir())
27+
await ssh.run('tar -zxvf', dir(file), '-C', dir(version))
28+
await ssh.run('ln -s', dir(version), dir('latest'))
29+
}
30+
catch (e) {
31+
logError(e)
32+
}
33+
},
34+
},
35+
],
36+
})
37+
38+
// 执行流水线
39+
PipeLine.test([deployTask])

example/airport.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const deployTask = new Task({
2626
await ssh.scp(`.cache/${file}`, dir())
2727
await ssh.run('tar -zxvf', dir(file), '-C', dir(version))
2828
await ssh.run('ln -s', dir(version), dir('latest'))
29+
await ssh.run('rm -f', dir(file))
2930
}
3031
catch (e) {
3132
logError(e)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "airport2",
3-
"version": "0.0.5",
3+
"version": "0.0.6",
44
"main": "src/index.ts",
55
"type": "module",
66
"files": [

src/airport/air/pipeline.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,58 @@
11
import { Task } from './task'
2-
import { log, purple } from '../lib'
3-
import {
4-
START,
5-
END,
6-
PIPE_TOP_LEFT,
7-
PIPE_TOP_RIGHT,
8-
PIPE_BOTTOM_LEFT,
9-
PIPE_BOTTOM_RIGHT,
10-
} from '../conf'
2+
import { logPipeStart, logPipeEnd } from '../lib'
3+
import type { TaskRaw } from '../types'
114

125
export class PipeLine {
136
public name?: string
7+
// public log: boolean = true // 决定是否打印日志
148
private tasks: Task[]
159

16-
static run(tasks: Task[]) {
10+
static run(tasks: Task[] | TaskRaw[]) {
1711
return new PipeLine(tasks).run()
1812
}
1913

20-
constructor(tasks: Task[]) {
21-
this.tasks = tasks
14+
static test(tasks: Task[] | TaskRaw[]) {
15+
return new PipeLine(tasks).test()
16+
}
17+
18+
constructor(tasks: Task[] | TaskRaw[]) {
19+
if (tasks.length > 0 && tasks[0] instanceof Task) {
20+
this.tasks = tasks as Task[]
21+
} else {
22+
this.tasks = (tasks as TaskRaw[]).map((task) => new Task(task))
23+
}
2224
}
2325

2426
/**
2527
* 执行任务中的所有步骤
2628
*/
2729
async run() {
28-
log(PIPE_TOP_LEFT, purple('Airport PipeLine'), START, PIPE_TOP_RIGHT)
30+
this.beforeRun()
31+
for (const [index, task] of this.tasks.entries()) {
32+
if (!task.skip) {
33+
task.index = index + 1
34+
await task._runPipeLine()
35+
}
36+
}
37+
this.afterRun()
38+
}
2939

30-
for (const task of this.tasks) {
31-
await task.run()
40+
test() {
41+
this.beforeRun()
42+
for (const [index, task] of this.tasks.entries()) {
43+
if (!task.skip) {
44+
task.index = index + 1
45+
task.test()
46+
}
3247
}
48+
this.afterRun()
49+
}
50+
51+
private beforeRun() {
52+
logPipeStart()
53+
}
3354

34-
log(PIPE_BOTTOM_LEFT, purple('Airport PipeLine'), END, PIPE_BOTTOM_RIGHT)
55+
private afterRun() {
56+
logPipeEnd()
3557
}
3658
}

src/airport/air/step.ts

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,48 @@
1-
import { log, run } from '../lib'
21
import type { StepRaw } from '../types'
2+
import { log, run, logStepStart, logStepEnd, logTesting } from '../lib'
33

44
export class Step {
55
public name: string
66
public skip: boolean = false
7+
public index: number = 1 // 当前索引
78
private step: StepRaw
8-
private test: boolean
9+
private testing: boolean = false
910

10-
constructor(step: StepRaw, test: boolean = false) {
11-
this.test = test
11+
constructor(step: StepRaw) {
1212
this.step = step
1313
this.name = step.name
1414
this.skip = step.skip ?? false
1515
}
1616

17+
async run() {
18+
this.beforeRun()
19+
await this.exec()
20+
this.afterRun()
21+
}
22+
23+
async test() {
24+
this.testing = true
25+
this.beforeRun()
26+
if (typeof this.step.run === 'string') {
27+
this.runStringTesting()
28+
} else if (Array.isArray(this.step.run)) {
29+
this.runArrayTesting()
30+
} else {
31+
logTesting('[async function run]')
32+
}
33+
this.afterRun()
34+
}
35+
1736
/**
1837
* 执行步骤
1938
*/
20-
async run(): Promise<any> {
39+
private async exec(): Promise<any> {
2140
if (typeof this.step.run === 'string') {
2241
return this.runString()
2342
} else if (Array.isArray(this.step.run)) {
2443
return this.runArray()
2544
} else {
26-
// 函数类型的步骤
27-
if (this.test) {
28-
log(`[TEST MODE] Would execute function: ${this.step.run.name}`)
29-
} else {
30-
// 实际执行函数
31-
return await this.step.run()
32-
}
45+
return await this.step.run()
3346
}
3447
}
3548

@@ -38,25 +51,36 @@ export class Step {
3851
*/
3952
private async runString() {
4053
const runString = this.step.run as string
41-
if (this.test) {
42-
log(`[TEST MODE] Would execute: ${runString}`)
43-
} else {
44-
return await run(runString)
45-
}
54+
return await run(runString)
4655
}
4756

4857
/**
4958
* 处理字符串数组类型的命令执行
5059
*/
5160
private async runArray() {
5261
const runArray = this.step.run as string[]
53-
if (this.test) {
54-
log(`[TEST MODE] Would execute array: ${runArray}`)
55-
} else {
56-
for (const cmd of runArray) {
57-
await run(cmd)
58-
}
62+
for (const cmd of runArray) {
63+
await run(cmd)
5964
}
6065
}
61-
}
6266

67+
private runStringTesting() {
68+
const runString = this.step.run as string
69+
logTesting(runString)
70+
}
71+
72+
private runArrayTesting() {
73+
const runArray = this.step.run as string[]
74+
for (const cmd of runArray) {
75+
logTesting(cmd)
76+
}
77+
}
78+
79+
private beforeRun() {
80+
logStepStart(this)
81+
}
82+
83+
private afterRun() {
84+
logStepEnd(this)
85+
}
86+
}

src/airport/air/task.ts

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,74 @@
11
import { Step } from './step'
2-
import { logStart, purple, blue } from '../lib'
3-
import { START, END } from '../conf'
4-
import type { TaskOptions, StepRaw } from '../types'
2+
import { logTaskStart, logTaskEnd } from '../lib'
3+
import type { TaskRaw, StepRaw } from '../types'
54

65
export class Task {
6+
// 任务名称
77
public name: string
8-
public opt: TaskOptions
8+
9+
/** Task元数据 */
10+
public opt: TaskRaw
11+
12+
/** 在流水线中的任务索引 */
13+
public index: number = 1 // 当前索引
14+
15+
/** 流水线中是否跳过当前任务 */
16+
public skip: boolean = false
17+
18+
// 是否无头模式,是否自调用
19+
// true: PipeLine模式,Task由PipeLine.run调用
20+
// false: 自调用,独立任务模式,外部直接调用Task.run
21+
public inPipeLine: boolean = false
22+
23+
// 任务步骤
924
private steps: StepRaw[]
1025

11-
constructor(opt: TaskOptions) {
26+
constructor(opt: TaskRaw) {
1227
this.opt = opt
1328
this.name = opt.name
1429
this.steps = opt.steps
30+
this.skip = opt.skip ?? false
1531
}
1632

1733
/**
1834
* 执行任务中的所有步骤
1935
*/
20-
async run(test: boolean = false) {
21-
const steps = this.steps.map((step) => new Step(step, test))
22-
23-
logStart(purple('T'), START, blue(this.name))
36+
async run() {
37+
this.beforeRun()
38+
const steps = this.steps.map((step) => new Step(step))
2439

25-
for (const step of steps) {
40+
for (const [index, step] of steps.entries()) {
2641
if (!step.skip) {
27-
logStart(purple('S'), START, blue(step.name))
42+
step.index = index + 1
2843
step.skip || (await step.run())
29-
logStart(purple('S'), END, blue(step.name))
3044
}
3145
}
46+
this.afterRun()
47+
}
48+
49+
test() {
50+
this.inPipeLine = true
51+
this.beforeRun()
52+
const steps = this.steps.map((step) => new Step(step))
53+
for (const [index, step] of steps.entries()) {
54+
if (!step.skip) {
55+
step.index = index + 1
56+
step.skip || (step.test())
57+
}
58+
}
59+
this.afterRun()
60+
}
61+
62+
async _runPipeLine() {
63+
this.inPipeLine = true
64+
await this.run()
65+
}
66+
67+
private beforeRun() {
68+
logTaskStart(this)
69+
}
3270

33-
logStart(purple('T'), END, blue(this.name))
71+
private afterRun() {
72+
logTaskEnd(this)
3473
}
3574
}

0 commit comments

Comments
 (0)