前端構建 DevOps :搭建 DevOps 基礎平臺(下)

前言

基礎平臺搭建上篇 介紹項目流程設計市怎、數據庫搭建、jwt 登錄等模塊

基礎平臺搭建中篇 介紹分支管理設計辛慰、webSocket 基礎模塊

本篇下將介紹流程管理與提測相關基礎模塊

后端模塊

  1. DevOps - Gitlab Api使用(已完成区匠,點擊跳轉)
  2. DevOps - 搭建 DevOps 基礎平臺(已完成 70%)
  3. DevOps - Gitlab CI 流水線構建
  4. DevOps - Jenkins 流水線構建
  5. DevOps - Docker 使用
  6. DevOps - 發(fā)布任務流程設計
  7. DevOps - 代碼審查卡點
  8. DevOps - Node 服務質量監(jiān)控

前端模塊

  1. DevOps - H5 基礎腳手架
  2. DevOps - React 項目開發(fā)

后期可能會根據 DevOps 項目的實際開發(fā)進度對上述系列進行調整

流程與提測管理

流程管理

基礎平臺搭建上篇已經介紹過流程的設計,這里再簡單解釋下

  1. 開發(fā)同學創(chuàng)建對應的工程以及分支帅腌,進行功能開發(fā)
  2. 項目負責人創(chuàng)建流程時驰弄,關聯(lián)多個開發(fā)分支,附加需求(需求模塊簡化成 desc 字段描述速客,沒有單獨抽出去)
  3. 流程的狀態(tài)由關聯(lián)的分支狀態(tài)組合戚篙,當所關聯(lián)所有的開發(fā)分支狀態(tài)全部轉變?yōu)橐淹瓿傻臅r候,才會進入下一個狀態(tài)

整個項目管理溺职,應該拆解成項目->需求->工程岔擂,預留字段位喂,將需求跟流程直接合并在一起,先完成主要功能乱灵,后期再進一步的拓展

提測管理

  1. 開發(fā)人員在開發(fā)完對應功能進行項目提測
  2. 未關聯(lián)流程的分支不能進行提測
  3. 提測之后塑崖,測試同學介入測試,根據 desc (需求)進行測試
  4. 開發(fā)內容再提測之后痛倚,才能發(fā)布到預發(fā)或生產规婆,否則只能在測試環(huán)境發(fā)布(禁止未測試的需求直接上線)

不要嫌麻煩,現實中状原,產品隨便提個需求就上聋呢,出現問題到處甩鍋的情況還少嗎?嚴格卡關也是減輕工作量的一個小助力

DevOps 開發(fā)下篇

創(chuàng)建流程模塊

image
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);
  }
}

提測模塊

image
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 塊

  1. 發(fā)送郵件使用 nodemailer
  2. 郵件模板使用 nunjucks 模板引擎朋截,配置郵件模板
  3. 郵件前端自定義內容使用 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}&timestamp=${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({});
  }
}
image

上述只附帶了 text 文本消息推送部服,markdown唆姐、link、FeedCard 等其他消息類型廓八,照著例子直接上手改就行了

建議

從第一篇看到目前這篇博客的同學奉芦,如果團隊缺少合適的項目管理或者想練習 node 的情況下,可以上手試試看剧蹂,一般關鍵的代碼声功,我有直接貼在博客上(大部分復制就能用啊)宠叼。

后面的內容就是貼合業(yè)務直接 curd 代碼先巴,基礎篇到此結束。

下一篇就會出構建篇冒冬,團隊可以結合自己項目實際情況增減功能伸蚯,完善團隊基礎管理流程。

不明白的地方可以留言

尾聲

此項目是從零開發(fā)简烤,后續(xù)此系列博客會根據實際開發(fā)進度推出(真 TMD 累)剂邮,項目完成之后,會開放部分源碼供各位同學參考乐埠。

為什么是開放部分源碼抗斤,因為有些業(yè)務是需要貼合實際項目針對性開發(fā)的,開放出去的公共模塊我寫的認真點

為了寫個系列博客丈咐,結果要寫完一整個系統(tǒng)(不是一般的累)瑞眼,覺得不錯的同學麻煩順手三連(點贊笼平,關注意敛,轉發(fā))耕驰。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末胞得,一起剝皮案震驚了整個濱河市毙籽,隨后出現的幾起案子奋渔,更是在濱河造成了極大的恐慌张足,老刑警劉巖笨枯,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛙讥,死亡現場離奇詭異锯蛀,居然都是意外死亡,警方通過查閱死者的電腦和手機次慢,發(fā)現死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門旁涤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迫像,你說我怎么就攤上這事劈愚。” “怎么了闻妓?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵菌羽,是天一觀的道長。 經常有香客問我由缆,道長注祖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任犁功,我火速辦了婚禮氓轰,結果婚禮上,老公的妹妹穿的比我還像新娘浸卦。我一直安慰自己署鸡,他們只是感情好,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布限嫌。 她就那樣靜靜地躺著靴庆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怒医。 梳的紋絲不亂的頭發(fā)上炉抒,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音稚叹,去河邊找鬼焰薄。 笑死拿诸,一個胖子當著我的面吹牛,可吹牛的內容都是我干的塞茅。 我是一名探鬼主播亩码,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼野瘦!你這毒婦竟也來了描沟?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鞭光,失蹤者是張志新(化名)和其女友劉穎吏廉,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體惰许,經...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡席覆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了啡省。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娜睛。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖卦睹,靈堂內的尸體忽然破棺而出畦戒,到底是詐尸還是另有隱情,我是刑警寧澤结序,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布障斋,位于F島的核電站,受9級特大地震影響徐鹤,放射性物質發(fā)生泄漏垃环。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一返敬、第九天 我趴在偏房一處隱蔽的房頂上張望遂庄。 院中可真熱鬧,春花似錦劲赠、人聲如沸涛目。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霹肝。三九已至,卻和暖如春塑煎,著一層夾襖步出監(jiān)牢的瞬間沫换,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工最铁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讯赏,地道東北人垮兑。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像漱挎,于是被迫代替她去往敵國和親甥角。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內容