前言
基礎平臺搭建上篇 介紹項目流程設計市怎、數據庫搭建、jwt 登錄等模塊
基礎平臺搭建中篇 介紹分支管理設計辛慰、webSocket 基礎模塊
本篇下將介紹流程管理與提測相關基礎模塊
后端模塊
- DevOps - Gitlab Api使用(已完成区匠,點擊跳轉)
- DevOps - 搭建 DevOps 基礎平臺(已完成 70%)
- DevOps - Gitlab CI 流水線構建
- DevOps - Jenkins 流水線構建
- DevOps - Docker 使用
- DevOps - 發(fā)布任務流程設計
- DevOps - 代碼審查卡點
- DevOps - Node 服務質量監(jiān)控
前端模塊
- DevOps - H5 基礎腳手架
- DevOps - React 項目開發(fā)
后期可能會根據 DevOps 項目的實際開發(fā)進度對上述系列進行調整
流程與提測管理
流程管理
在基礎平臺搭建上篇已經介紹過流程的設計,這里再簡單解釋下
- 開發(fā)同學創(chuàng)建對應的工程以及分支帅腌,進行功能開發(fā)
- 項目負責人創(chuàng)建流程時驰弄,關聯(lián)多個開發(fā)分支,附加需求(需求模塊簡化成 desc 字段描述速客,沒有單獨抽出去)
- 流程的狀態(tài)由關聯(lián)的分支狀態(tài)組合戚篙,當所關聯(lián)所有的開發(fā)分支狀態(tài)全部轉變?yōu)橐淹瓿傻臅r候,才會進入下一個狀態(tài)
整個項目管理溺职,應該拆解成項目->需求->工程岔擂,預留字段位喂,將需求跟流程直接合并在一起,先完成主要功能乱灵,后期再進一步的拓展
提測管理
- 開發(fā)人員在開發(fā)完對應功能進行項目提測
- 未關聯(lián)流程的分支不能進行提測
- 提測之后塑崖,測試同學介入測試,根據 desc (需求)進行測試
- 開發(fā)內容再提測之后痛倚,才能發(fā)布到預發(fā)或生產规婆,否則只能在測試環(huán)境發(fā)布(禁止未測試的需求直接上線)
不要嫌麻煩,現實中状原,產品隨便提個需求就上聋呢,出現問題到處甩鍋的情況還少嗎?嚴格卡關也是減輕工作量的一個小助力
DevOps 開發(fā)下篇
創(chuàng)建流程模塊
import { Post, Prefix, Get } from "egg-shell-decorators";
import BaseController from "./base";
@Prefix("process")
export default class ProcessController extends BaseController {
/**
* @author: Cookie
* @description: 創(chuàng)建 devOps 任務流
*/
@Post("/create")
public async createProcess({
request: {
body: { params },
},
}) {
const { ctx } = this;
const { username } = this.userInfo;
const { name, branchIds, workflowTplId, desc } = params;
const branchStatus = await ctx.service.branch.checkProcess({ branchIds });
if (!branchStatus)
this.error({
msg: "已有分支在流程中",
});
const status = await ctx.service.process.createProcess({
desc,
name,
branchIds,
workflowTplId,
createdUser: username,
updateUser: username,
});
await ctx.service.branch.updateBranch({
branchIds,
opt: {
processId: status.id,
},
});
this.success(status);
}
/**
* @author: Cookie
* @description: 查詢 devOps 任務流
*/
@Get("/getList")
public async getProcessList({ request: { query } }) {
const { ctx } = this;
const { pageSize = 10, pageNum = 1 } = query;
const processList = await ctx.service.process.getProcessList({
pageNum: parseInt(pageNum),
pageSize: parseInt(pageSize),
});
// 聯(lián)表查詢分支信息
for (let process of processList.rows) {
const { branchIds } = process;
process.branches = await ctx.service.branch.getSelfBranchList({
branchIds,
});
}
this.success(processList);
}
}
提測模塊
import { Post, Prefix, Get } from "egg-shell-decorators";
import BaseController from "./base";
@Prefix("testRecord")
export default class TestRecord extends BaseController {
/**
* @author: Cookie
* @description: 創(chuàng)建提測記錄
*/
@Post("/create")
public async createTestRecord({
request: {
body: { params },
},
}) {
const { ctx } = this;
const { id: submitUserId } = this.userInfo;
const { desc, name, branchIds, testUserId } = params;
const branchStatus = await ctx.service.branch.checkProcess({
branchIds,
status: "every",
});
if (branchStatus)
this.error({
msg: "存在未關聯(lián)流程的分支",
});
const status = await ctx.service.testRecord.createTestRecord({
desc,
name,
branchIds,
submitUserId,
testUserId,
testStatus: 0,
});
this.success(status);
}
}
提測消息推送采用郵件(正式)與機器人(即時)颠区,提測內容削锰、次數、質量等寫入數據庫毕莱,系統(tǒng)本身也能追蹤器贩,作為后期效能評估的輔助
郵件推送
提測模塊的具體實現代碼,我們分為 3 塊
- 發(fā)送郵件使用 nodemailer
- 郵件模板使用 nunjucks 模板引擎朋截,配置郵件模板
- 郵件前端自定義內容使用 marked 插件解析 markdown 語法
import { MAIL_CONFIG } from "../../config/default.config";
const marked = require("marked"); // marked 轉換
const nodemailer = require("nodemailer"); // 發(fā)送郵件
const nunjucks = require("nunjucks"); // 模板引擎
const path = require("path");
// 郵箱配置初始化
const transporter = nodemailer.createTransport({
host: MAIL_CONFIG.service,
secureConnection: true, // 使用 SSL 方式(安全方式蛹稍,防止被竊取信息)
port: MAIL_CONFIG.port,
auth: {
user: MAIL_CONFIG.user_email, // 賬號
pass: MAIL_CONFIG.auth_code, // 授權碼
},
});
const htmlModel = ({ storyMail, exitInfo, summitUser, iterationMail }) => {
const html = nunjucks.render(path.join(__dirname, "./emailTpl/email.njk"), {
storyMail,
exitInfo,
summitUser,
iterationMail,
});
return html;
};
/*
* toEmail: String 接收者,可以同時發(fā)送多個,以逗號隔開
* subject: String 標題
* cc: String 抄送
* text: String 文本
* html: Object titleList表頭 conterFontList內容
* attachments: any 附件
* [
* {
filename: 'img1.png', // 改成你的附件名
path: 'public/images/img1.png', // 改成你的附件路徑
cid : '00000001' // cid可被郵件使用
}
* ]
*/
interface mailInterface {
toEmail: string;
subject: string;
cc?: string;
text?: string;
html?: any;
attachments?: any;
storyMail?: any;
exitInfo?: any;
summitUser?: String;
iterationMail?: any;
}
const sendMail = async (mailOptions: mailInterface) => {
const {
toEmail,
subject,
cc,
text,
attachments,
storyMail,
exitInfo,
summitUser,
iterationMail,
} = mailOptions;
Object.keys(exitInfo).forEach((key) => {
exitInfo[key] = marked(exitInfo[key]);
});
const html = htmlModel({ storyMail, exitInfo, summitUser, iterationMail });
const mailOpts = {
from: MAIL_CONFIG.user_email, // 發(fā)送者,與上面的 user 一致
to: toEmail,
subject,
cc,
text,
html,
attachments,
};
try {
transporter.sendMail(mailOpts);
return true;
} catch (err) {
console.log(err);
return false;
}
};
export default { sendMail };
釘釘群機器人
具體參考釘釘機器人文檔下面附帶具體的實現代碼(為了安全且簡單,采用加簽的安全驗證)
const crypto = require("crypto");
const secret ="";
const sendUrl =""; // 替換成自己的
export default (app) => {
return {
async send(content) {
const timestamp = Date.now();
const str = crypto
.createHmac("sha256", secret)
.update(timestamp + "\n" + secret)
.digest()
.toString("base64", "UTF-8");
try {
const { res, data } = await app.curl(
`${sendUrl}×tamp=${timestamp}&sign=${encodeURIComponent(str)}`,
{
headers: {
"Content-Type": "application/json; charset=utf-8",
},
method: "POST",
data: JSON.stringify(content),
}
);
return res;
} catch (error) {
return error;
}
},
text({ content = {}, at }) {
console.log("content===>", content);
at = at || {};
this.send({
msgtype: "text",
text: {
content,
},
at,
});
},
};
};
// 測試機器人 Controller
import { Post, Prefix, Get } from "egg-shell-decorators";
import BaseController from "./base";
@Prefix("robot")
export default class ProjectController extends BaseController {
@Post("/ding")
public async getProjectList({
request: {
body: { params },
},
}) {
const { ctx } = this;
const { content } = params;
await ctx.helper.robot.ding.text({ content });
this.success({});
}
}
上述只附帶了 text 文本消息推送部服,markdown唆姐、link、FeedCard 等其他消息類型廓八,照著例子直接上手改就行了
建議
從第一篇看到目前這篇博客的同學奉芦,如果團隊缺少合適的項目管理或者想練習 node 的情況下,可以上手試試看剧蹂,一般關鍵的代碼声功,我有直接貼在博客上(大部分復制就能用啊)宠叼。
后面的內容就是貼合業(yè)務直接 curd 代碼先巴,基礎篇到此結束。
下一篇就會出構建篇冒冬,團隊可以結合自己項目實際情況增減功能伸蚯,完善團隊基礎管理流程。
不明白的地方可以留言
尾聲
此項目是從零開發(fā)简烤,后續(xù)此系列博客會根據實際開發(fā)進度推出(真 TMD 累)剂邮,項目完成之后,會開放部分源碼供各位同學參考乐埠。
為什么是開放部分源碼抗斤,因為有些業(yè)務是需要貼合實際項目針對性開發(fā)的,開放出去的公共模塊我寫的認真點
為了寫個系列博客丈咐,結果要寫完一整個系統(tǒng)(不是一般的累)瑞眼,覺得不錯的同學麻煩順手三連(點贊笼平,關注意敛,轉發(fā))耕驰。