使用命令提交PR进行自动化部署

79 阅读1分钟

Github 鉴权

  • 访问 GitHub 网站并登录你的账户。
  • 前往 Personal Access Tokens 页面
  • 点击 "Generate new token" 按钮。
  • 选择适当的权限(例如 repo 权限)。
  • 生成并复制令牌。

打开命令行窗口输入:gh auth login,选择Github.com -> HTTPS -> Y -> Paste an authentication token,黏贴上面的生成的令牌

编写执行的脚本create-pr.js

const { execSync } = require('child_process');
const readline = require('readline');
const axios = require('axios');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// 使用 Promise 包装 readline.question 以实现异步等待
const question = (query) =>
  // eslint-disable-next-line no-promise-executor-return
  new Promise((resolve) => rl.question(query, resolve));

(async () => {
  try {
    // 获取目标分支
    const targetBranch = process.argv[2] || 'develop';
    if (!targetBranch) {
      throw new Error(
        'Target branch is required. Usage: npm run create-pr <target-branch>',
      );
    }

    // 获取当前分支名称
    const currentBranch = execSync('git symbolic-ref --short HEAD')
      .toString()
      .trim();
    // 获取最后一次提交的消息
    const lastCommitMessage = execSync('git log -1 --pretty=%B')
      .toString()
      .trim();
    // 获取 GitHub 操作人名称
    const githubUserName = execSync('git config user.name').toString().trim();

    // 询问 PR 标题和描述
    const title = await question(
      `Enter PR title (leave empty to use the last commit message: "${lastCommitMessage}"): `,
    );
    const body = await question('Enter PR description: ');
    rl.close();

    // 如果标题为空,则使用最后一次提交的消息作为标题
    const prTitle = title || lastCommitMessage;

    // 推送当前分支到远程仓库
    execSync(`git push origin ${currentBranch}`, { stdio: 'inherit' });
    console.log('Pushed current branch to remote repository.');

    // 构建并执行 gh pr create 命令
    const createCommand = `gh pr create --base ${targetBranch} --head ${currentBranch} --title "${prTitle}" --body "${body}"`;
    console.log(`Running command: ${createCommand}`);
    let createOutput;
    try {
      createOutput = execSync(createCommand, { stdio: 'pipe' })
        .toString()
        .trim();
      console.log(createOutput);
    } catch (error) {
      const errorMessage = error.message;
      if (
        errorMessage.includes('a pull request for branch') &&
        errorMessage.includes('already exists')
      ) {
        console.log('A pull request already exists.');
        createOutput = errorMessage;
      } else {
        throw error;
      }
    }

    // 提取 PR URL 以获取 PR 编号
    const prUrlMatch = createOutput.match(
      /https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/(\d+)/,
    );
    if (!prUrlMatch) {
      throw new Error('Failed to parse PR URL.');
    }
    const prNumber = prUrlMatch[1];

    // 仅当目标分支不是 master 时合并 PR
    if (targetBranch !== 'master') {
      // 构建并执行 gh pr merge 命令
      const mergeCommand = `gh pr merge ${prNumber} --merge`;
      console.log(`Running command: ${mergeCommand}`);
      execSync(mergeCommand, { stdio: 'inherit' });
    } else {
      console.log(`PR created but not merged because target branch is master.`);
      // 如果获取到分支名称,提取分支代码
      let branchCode = '无';
      if (currentBranch) {
        const regex = /^b(\d{4})-/;
        const match = currentBranch.match(regex);
        if (match) {
          branchCode = 'b' + match[1];
        }
      }

      // 发送飞书消息
      const webhookUrl = '替换成你飞书推入的url地址';
      const message = {
        title: prTitle,
        url: prUrlMatch[0],
        operator: githubUserName, // 添加操作人名称到消息中
        branchCode, //飞书任务分支代码
      };

      console.log('====================================');
      console.log('Sending notification to Feishu:', message);
      console.log('====================================');

      try {
        const response = await axios.post(webhookUrl, message, {
          headers: { 'Content-Type': 'application/json' },
        });
        console.log('Notification sent:', response.data);
      } catch (error) {
        console.error('Failed to send notification:', error.message);
      }
    }
  } catch (error) {
    console.error('Error creating and merging PR:', error.message);
  }
})();