Система управления проектами от 0 до 1 узла: создание базовой платформы (ниже)

Node.js

предисловие

Базовая конструкция платформы, часть 1Представьте дизайн процесса проекта, создание базы данных, вход в систему jwt и другие модули.

Базовая конструкция платформы, часть IIВнедните дизайн управления филиалом, Websocket Basic Module

В этой статье будут представлены основные модули, связанные с управлением процессами и тестированием.

внутренний модуль

  1. DevOps — использование Gitlab Api (завершено, нажмите, чтобы перейти)
  2. DevOps — создание базовой платформы DevOps (выполнено на 70 %).
  3. DevOps — сборка конвейера Gitlab CI
  4. DevOps — Jenkins Pipeline Builds
  5. DevOps — использование Docker
  6. DevOps — проектирование задач по выпуску
  7. DevOps — проверка кода застряла
  8. DevOps — мониторинг качества обслуживания узлов

Интерфейсный модуль

  1. DevOps — основные шаблоны H5
  2. DevOps — разработка React-проектов

Вышеуказанная серия может быть скорректирована позже в соответствии с фактическим ходом разработки проекта DevOps.

Управление процессами и тестами

Управление процессом

существуетБазовая конструкция платформы, часть 1Представлен дизайн процесса, вот краткое пояснение

  1. Студенты-разработчики создают соответствующие проекты и ветки для функционального развития
  2. Когда руководитель проекта создает процесс, он связывает несколько веток разработки и добавляет дополнительные требования (модуль требований упрощается до описания поля описания, которое не извлекается отдельно)
  3. Состояние процесса объединяется соответствующим состоянием ветки.Когда все связанные состояния ветки разработки будут изменены на завершенные, будет введено следующее состояние.

Все управление проектом должно быть разобрано на проекты->требования->проекты, зарезервированные поля, напрямую объединять требования и процессы, выполнять сначала основные функции, а потом еще расширяться

Управление тестированием

  1. После того, как разработчик закончит разработку соответствующей функции, проект будет протестирован
  2. Ветки несвязанных процессов не могут быть извлечены
  3. После теста студенты-испытатели вмешиваются в тест и проводят тест в соответствии с описанием (требованием).
  4. После повторного тестирования разрабатываемого контента он может быть выпущен для предварительного или производственного выпуска, в противном случае он может быть выпущен только в тестовой среде (запретить непроверенные требования напрямую выходить в онлайн)

Не будьте слишком хлопотными.На самом деле, продукты могут быть запущены, как только вы их попросите.Есть ли еще случаи, когда возникают проблемы? Строгие контрольные точки также помогают снизить нагрузку.

DevOps-разработка, часть 2

Создайте модуль процесса

import { Post, Prefix, Get } from "egg-shell-decorators";
import BaseController from "./base";

@Prefix("process")
export default class ProcessController extends BaseController {
  /**
   * @author: Cookie
   * @description: 创建 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),
    });
    // 联表查询分支信息
    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: 创建提测记录
   */
  @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: "存在未关联流程的分支",
      });

    const status = await ctx.service.testRecord.createTestRecord({
      desc,
      name,
      branchIds,
      submitUserId,
      testUserId,
      testStatus: 0,
    });
    this.success(status);
  }
}

Прогнозирование принятия push-уведомленийПочта (официальная) против ботов (мгновенная), содержание теста, время, качество и т. д. записываются в базу данных, а сама система также может отслеживаться в качестве вспомогательного средства для последующей оценки производительности.

Электронная почта

Конкретный код реализации тестового модуля разделен на 3 блока.

  1. отправить почту с помощьюnodemailer
  2. Использование шаблона электронной почтыnunjucksМеханизм шаблонов, настройка шаблонов электронной почты
  3. Использование пользовательского контента электронной почты во внешнем интерфейсеmarkedСинтаксис парсинга уценки плагина
import { MAIL_CONFIG } from "../../config/default.config";

const marked = require("marked"); // marked 转换
const nodemailer = require("nodemailer"); // 发送邮件
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 接收者,可以同时发送多个,以逗号隔开
 * 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, // 发送者,与上面的 user 一致
    to: toEmail,
    subject,
    cc,
    text,
    html,
    attachments,
  };
  try {
    transporter.sendMail(mailOpts);
    return true;
  } catch (err) {
    console.log(err);
    return false;
  }
};

export default { sendMail };

Групповой робот Dingding

конкретная ссылкаДокументация робота DingTalkКонкретный код реализации прилагается ниже (для безопасности и простоты используйтедобавить подписьпроверка безопасности)

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({});
  }
}

Вышеприведенное относится только к текстовым сообщениям, уценке, ссылке, FeedCard и другим типам сообщений, просто следуйте примеру и измените его напрямую.

предложение

В настоящее время студенты с первого, чтобы увидеть этот блог, в том случае, если команда не хватает правильного узла управления проектами или желать практиковать, вы можете попытаться начать работу, общий ключ, который я напрямую прикреплен к блогу (большинство из Копировать на банку ах).

Следующее содержание представляет собой прямой сырный код, который подходит для бизнеса, и на этом основы заканчиваются.

В следующей статье будет строительная статья.Команда может увеличивать или уменьшать функции в зависимости от фактической ситуации в своих собственных проектах и ​​улучшать основной процесс управления командой.

Оставьте сообщение, если вы не понимаете

конец

Этот проект разработан с нуля, и последующая серия блогов будет запущена в соответствии с фактическим ходом разработки (Действительно TMD устал), после завершения проекта часть исходного кода будет открыта для вашего ознакомления.

Почему часть исходного кода открыта, потому что некоторые бизнесы нужно разрабатывать в соответствии с реальным проектом, а открытые публичные модули написаны аккуратно.

Для того, чтобы написать серию блогов, получается написать целую систему (не обычный уставший(Нравится, подписывайтесь, делайте репост).

Если у вас есть какие-либо вопросы или идеи по содержанию статьи, вы можете добавить WeChat Cookieboty для общения.

Также обратите внимание на официальный аккаунт Cookieboty1024, добро пожаловать в лагерь роста фронтовика