preface
Jenkins for internal continuous integration, Spike for office communications, And GitLab for code maintenance.
Build details of continuous integration need to be checked frequently during daily development, whether errors are reported during the process, and submitted profiles.
But the old version of the process, only recorded when the main stem, output a check in check out text,
Therefore, sometimes we need to use the help of operation and maintenance bosses to find out why failure is a waste of everyone’s time, and the cost is too high.
So I was thinking about how to simplify the process and make it more efficient.
I knew the game was on when I saw that Dingpin supported card and Markdown push messages.
rendering
Implementation process
Old lookup location
Before this thing comes out, there are several steps you have to take to build information.
Current process
You don’t have to pay attention to others or take up other people’s time to help you locate basic information.
Implemented functions
- Provide jump to corresponding GitLab warehouse (including issues and so on)
- Check whether the root directory has Changelog. If yes, the changelog file corresponding to gitlab is provided
- Who pushed? The act of pushing
- Quickly jump to the corresponding Jenkins-job to see the build process
- Output the warehouse profile
- The name of the output repository
- Get the last five commit profiles, ignoring merge Request
- Shows the build commit and supports jumping to GitLab to see the change record for that commit
- Shows built branches and supports jumping to gitLab branches
- Support document link incoming
- Support to push information to multiple groups simultaneously
No third party libraries are used, and Node’s built-in apis are used for file reading and HTTP requests.
Implementation process
Configuration is read
How do I read the configuration file that executes the root directory? Process. CWD is mainly used to query the execution path to read package.json and parameters of independent configuration files
const fs = require("fs");
const path = require("path");
const process = require("process");
const jk2dtFile = path.resolve(process.cwd(), "./jk2dtrc.js");
const pkgFile = require(path.resolve(process.cwd(), "./package.json"));
let importConfig = {};
if (fs.existsSync(jk2dtFile)) {
process.stdout.write("Jk2dt profile exists \n");
const config = require(jk2dtFile);
importConfig = config;
} else {
if (fs.existsSync(pkgFile)) {
process.stdout.write("Jk2dt config file does not exist, try reading \n from package.json");
if (pkgFile.jk2dt && typeof pkgFile.jk2dt === "object") {
importConfig = pkgFile.jk2dt;
} else {
process.stdout.write("Package. json also has no corresponding configuration item, default configuration \n is used"); }}}module.exports = importConfig;
Copy the code
Markdown custom template conversion
Provide placeholders in Markdown for customization, the simplest and most crude form of template substitution
- us-msg.md
{{TIPS_BANNER}}
{{GitRepoDesc}}
### --- {{GitRepoName}} ---
** Build branch :** {{GitRepoBranchUrl}}
{{PkgVersion}}
{{GitBuildCommitLink}}
{{GitRepoChangeLog}}
{{RepoRecentTitle}}
{{RepoRecentCommitMsg}}
{{GitRepoActionType}}
### --- Jenkins ---
Executive :** {{PushBy}}
** Build task :** {{JK_JOBS_NAME}}
** Build log :** {{JK_JOBS_CONSOLE}}
** Build state :** {{JK_JOBS_STATUS}}
** Build time :** {{JK_JOBS_TIME}}
Copy the code
- covert-md-2-str
const fs = require("fs");
const path = require("path");
function mdTemplateStr({ TipsBanner, TemplateName, PkgVersion, JobInfo: { JOB_NAME, JOB_BUILD_DISPLAY_NAME, JOB_BUILD_URL, JOB_STATUS, JOB_END_TIME }, GitInfo: { RepoUrl, RepoBranch, RepoName, RepoDesc, RepoBranchUrl, RepoChangeLog, RepoPushMan, RepoActionType, RepoRecentCommitMsg, BuildCommitMDLink } }) {
const PlacehoderVar = {
"{{TIPS_BANNER}}": TipsBanner,
"{{JK_JOBS_NAME}}": JOB_NAME,
"{{JK_JOBS_TIME}}": JOB_END_TIME,
"{{JK_JOBS_CONSOLE}}": ` [${JOB_BUILD_DISPLAY_NAME}] (${JOB_BUILD_URL}) `."{{JK_JOBS_STATUS}}": JOB_STATUS,
"{{GitRepoName}}": RepoName,
"{{GitRepoDesc}}": RepoDesc,
"{{GitRepoBranch}}": RepoBranch,
"{{GitRepoBranchUrl}}": RepoBranchUrl,
"{{PkgVersion}}": PkgVersion ? ** Packaged version :**${PkgVersion}` : ""."{{RepoRecentTitle}}": RepoRecentCommitMsg ? "** Submission summary :**" : ""."{{RepoRecentCommitMsg}}": RepoRecentCommitMsg,
"{{GitRepoChangeLog}}":
RepoBranch === "master"
? '** CHANGELOG :** [CHANGELOG](${RepoChangeLog}) `
: ""."{{GitBuildCommitLink}}": BuildCommitMDLink
? '** Build commit :**${BuildCommitMDLink}`
: ""."{{GitRepoActionType}}": RepoActionType
? ** Push behavior :**${RepoActionType}`
: ""."{{PushBy}}": RepoPushMan
};
let mdStr = fs.readFileSync(
path.join(__dirname, `.. /template/${TemplateName}.md`)); mdStr = mdStr.toString();for (const [k, v] of Object.entries(PlacehoderVar)) {
const re = new RegExp(k, "g");
mdStr = mdStr.replace(re, v);
}
return mdStr;
}
module.exports = mdTemplateStr;
Copy the code
Example Check whether the Changelog file exists
- Check whether the root directory of the project has the corresponding Changelog. md
- No one uses Linux anymore
grep
The querychanglog.md(ignore case), useexecSync
Synchronous execution shell
const path = require("path");
const pkgFile = require(path.resolve(process.cwd(), "./package.json"));
const projectExecShellPath = process.cwd();
const fs = require("fs");
const { execSync } = require("child_process");
function rootExistChangelogFile() {
const CHANGELOG = path.resolve(process.cwd(), "./CHANGELOG.md");
try {
if (fs.existsSync(CHANGELOG)) {
return true;
} else {
return!!!!! execSync(`ls -l ${projectExecShellPath} | grep -i "changelog.md"`
).toString();
}
return false;
} catch (error) {
return false; }}Copy the code
Example Query the NPM package version
- Check whether package.name or main exists, which are necessary elements of the package
- And then determine if we’re looking at the branch range
- Finally, the shell queries
/** * get the package dist-tags */
function getPackageDistTag(branch) {
if(! pkgFile || ! pkgFile.name || ! pkgFile.main || ["master"."dev"."develop"."next"].indexOf(branch) === - 1
) {
return "";
}
let distTag;
switch (branch) {
case "master":
distTag = "latest";
break;
case "dev":
distTag = "dev";
break;
case "develop":
distTag = "dev";
break;
case "next":
distTag = "next";
break;
default:
distTag = "dev";
break;
}
const execShell = `npm show ${pkgFile.name} dist-tags.${distTag} 2>/dev/null`;
try {
return execSync(execShell).toString();
} catch (error) {
return ""; }}Copy the code
Gets the last five commit profiles
- Default and branches less than or equal to 0 do not exist as do not query
- with
grep
Ignore contains “lerna | into | merge” submit summary of vocabulary - Sed transforms the string to print a markdown formatted string with a newline
function getLastNCommit(n = 5, branch) {
if (n <= 0| |! branch) {return "";
}
const readLineFilterResult =
branch === "master"
? 'grep -E -i -v "lerna"'
: 'grep -E -i -v "lerna|into|merge"';
const lineModify = "sed 's/^/> /g' |sed 's/$/\\\n/g' ";
const execShell = `git log --oneline -${n} ${branch}| ${readLineFilterResult} | ${lineModify} `;
try {
return execSync(execShell).toString();
} catch (error) {
return ""; }}Copy the code
Determine whether accessToken is valid
Support string and array, strong check
function findValidAK(dict) {
let tempObj = {};
for (let [k, v] of Object.entries(dict)) {
if (isType.isString(v) && v) {
tempObj[k] = v;
}
if (
isType.isObj(v) &&
Array.isArray(v.success) &&
Array.isArray(v.error) &&
v.success.length > 0 &&
v.error.length > 0) { tempObj[k] = v; }}return tempObj;
}
Copy the code
Pure type judgment
/** ** @param {*} obj - Object * @return {Boolean} - Boolean * @description - Check whether this is a Promise */
function isThenable(obj) {
return(!!!!! obj && (typeof obj === "object" || typeof obj === "function") &&
typeof obj.then === "function"
);
}
function isString(o) {
// Whether it is a string
return Object.prototype.toString.call(o).slice(8.- 1) = = ="String";
}
function isNumber(o) {
// Whether it is a number
return Object.prototype.toString.call(o).slice(8.- 1) = = ="Number";
}
function isObj(o) {
// Whether to object
return Object.prototype.toString.call(o).slice(8.- 1) = = ="Object";
}
module.exports = {
isThenable,
isString,
isObj,
isNumber
};
Copy the code
Source code and NPM package
Matters needing attention
- Support Linux/Unix/MacOS only, call some very common command lines, such as grep,ls.
- Highly coupled to Jenkins, much of the basic information is derived from Jenkins built-in temporary environment variables
- All the basic information can be overridden, default from Jenkins provided temporary environment variables to build Git repository information
repo && npm
conclusion
It has been used internally for more than a month, during which some details have been perfected.
Have better posture or find wrong place please leave a message, will be timely corrected, thank you for reading!