ProTip: How To Split Large Branches Into Small Pull Requests
ref: https://medium.com/@groksrc/protip-how-to-split-large-branches-into-small-pull-requests-81d607660c05
# Step 1: Create a patch against your base branch
$git diff develop feature/player-management > ../my_pr_patch
# Step 2: Checkout a new branch
$ git checkout develop
$ git checkout -b xxxxxxxxxxxxx
# Step 3: Apply Changes Selectively
$git apply — ignore-space-change — ignore-whitespace ../my_pr_patch
# Step 4: Stash the Remaining Changes
Doc — private npm: how to document for each version
How to build a release note
*Azure Pipelines
- Extensions (Release Notes & WIKI)
- https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes
- https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-WIKIUpdater-Tasks (need to updated by project folders
- GitHub: https://github.com/rfennell/AzurePipelines/tree/main/Extensions/GenerateReleaseNotes — Connect to preview
- Use Azure Pipelines
- Create automatic release notes on AzureDevOps
- Handlebars templates show as below Link
Write code on Azure DevOps with Azure Functions
Other references
Github automated
Use custom tools (gren & vuepress)
Q: How to align those versions?
- NX multiple library & ProGet package versions & Azure DevOps release tag version
- Git release & Publish to ProGet auto or manually?
- Options:
1.Like angular update all lib to the same version?
- https://github.com/angular/angular-cli/releases
- library versions = package versions = release tag version
2.Mention lib name & version in git commit messages and version it one by one?
- What’s the format? (eg. xxxxlib-0.1.1 message……… )
Handlebars templates:
workItems, relatedWorkItems: (Azure Boards)
Using work items to track user stories, & more — Azure Boards
- build-handlebars-template.md - a very simple template for build
- release-handlebars-template.md - a very simple template for a classic Release
- release-handlebars-dump-template.md - a template to use with Classic Releases to dump the contents of each available object
Ngx-translate relative
Ngx-translate plugins
- ngx-translate-zombies
- by @seveves: A vscode extension that finds unused translation keys and shows them in a diff view (so called zombies).
- ngx-translate-lint
- by @svoboda-rabstvo: Simple CLI tools for check ngx-translate keys in whole app
Tool for vs code
- Lingua
- by @chr33z: A visual studio code extension to help managing translations for ngx-translate — featuring inline translation lookup and in-place translation creation and editing.
Program to find and replace text:
Javascript,Nodejs: search for a specific word string in files
get translate rule from Lingua
const regEx = /['|"|`]([a-zA-Z0-9\.\_\-]+)['|"|`]/gm;
const text = editor.document.getText();
const translationDecorations: DecorationOptions[] = [];
const identifierDecorations: DecorationOptions[] = [];const maxTranslationLength = Configuration.maxTranslationLength();
const showInLineTranslation = Configuration.showInlineTranslation();let match;
while ((match = regEx.exec(text))) {
let path = match[0].replace(/['|"|`]/g, '').trim();
path = path
.split('.')
.filter((seg) => seg.length > 0)
.join('.');const translation = translationSet.getTranslation(path);
const isPartialTranslation = translationSet.isPartialMatch(path);
const startPos = editor.document.positionAt(match.index + 1);
const endPos = editor.document.positionAt(match.index + match[0].length);
const n = maxTranslationLength;if (translation) {
// Translation availble
const shortTranslation = translation.length > n ? translation.substr(0, n - 1) + '...' : translation;
const decoration = getDecoration(showInLineTranslation, startPos, endPos, shortTranslation);
translationDecorations.push(decoration);
} else if (isPartialTranslation) {
// Partial translation
const shortPath = path.length > n ? path.substr(0, n - 1) + '...' : path;
const decoration = getDecoration(false, startPos, endPos, 'Translations available: ' + shortPath + ' ...');
translationDecorations.push(decoration);
}
}
I18n.js replace JSON key format
Working on branch/i18n-json
Config setting
const appPath = "src/app";
const fileExtensions = [".ts", ".html"];
const regEx = /['|"|`]([a-zA-Z0-9\.\_\-]+)['|"|`]/gm;const translationKey = {
all: new Set(),
full: new Set(),
partial: new Set(),
zombie: new Set(),
};
First start with replaceAppI18n, we use en as our translation key provider and use findJsonKeys to get all and partial keys.
function replaceAppI18n() {
// read json file and key
const jsonPath = "src/assets/i18n/en-US.json";
let rawData = fs.readFileSync(jsonPath);
let enJson = JSON.parse(rawData);
findJsonKeys("", enJson);
// console.log(translationKeySet);
// search
searchFilesInDirectory();console.log("check zombie", translationKey.zombie);
}function findJsonKeys(path, json) {
if (!!path) {
translationKey.all.add(path);
if (typeof json === "string") {
translationKey.full.add(path);
translationKey.zombie.add(path);
} else {
translationKey.partial.add(path);
}path += ".";
}if (typeof json !== "object") {
return;
}
Object.keys(json).forEach((x) => {
findJsonKeys(`${path}${x}`, json[x]);
});
}
Then we call searchFilesInDirectory and use getFilesInDirectory to list all file paths within the folder.
function searchFilesInDirectory() {
if (!fs.existsSync(appPath)) {
console.log(`Specified directory: ${dir} does not exist`);
return;
}
const files = getFilesInDirectory(appPath);files.forEach((file) => {
let fileContent = fs.readFileSync(file).toString("utf8");// We want full words, so we use full word boundary in regex.
let match;
while ((match = regEx.exec(fileContent))) {
let path = match[0].replace(/['|"|`]/g, "").trim();
path = path
.split(".")
.filter((seg) => seg.length > 0)
.join(".");
if (translationKey.all.has(path)) {
const newPath = capitalizeFirstLetter(path);
const re = new RegExp(path, "g");
fileContent = fileContent.replace(re, newPath);
console.log("From:", path);
console.log("To: ", newPath);
// check zombie
translationKey.zombie.delete(path);
}
}
// write file back
fs.writeFile(file, fileContent, "utf8", function (err) {
if (err) return console.log(err);
});
});
}// Using recursion, we find every file with the desired extention, even if its deeply nested in subfolders.
function getFilesInDirectory(dir) {
if (!fs.existsSync(dir)) {
console.log(`Specified directory: ${dir} does not exist`);
return;
}let files = [];
fs.readdirSync(dir).forEach((file) => {
const filePath = path.join(dir, file);
const stat = fs.lstatSync(filePath);// If we hit a directory, apply our function to that dir. If we hit a file, add it to the array of files.
if (stat.isDirectory()) {
const nestedFiles = getFilesInDirectory(filePath);
files = files.concat(nestedFiles);
} else {
if (fileExtensions.includes(path.extname(file))) {
files.push(filePath);
}
}
});return files;
}function findJsonKeys(path, json) {
if (!!path) {
translationKey.all.add(path);
if (typeof json === "string") {
translationKey.full.add(path);
translationKey.zombie.add(path);
} else {
translationKey.partial.add(path);
}path += ".";
}if (typeof json !== "object") {
return;
}
Object.keys(json).forEach((x) => {
findJsonKeys(`${path}${x}`, json[x]);
});
}
We scant all file that contains the string eg: “string“, ‘string’, `string`, and find is it match to translationKey.
If so we start to replace text with capitalizeFirstLetter Rule.
function capitalizeFirstLetter(path) {
// Only transfer all upper case
if (path !== path.toUpperCase()) {
return path;
}
const capital = (string) =>
string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
let keyList = path.split(".").filter((x) => x.length > 0);
keyList = keyList.map((key) => {
key = key.split("_").filter((x) => x.length > 0);
key = key.map((x) => capital(x));
return key.join("");
});
return keyList.join(".");
}
Finally, we call replaceJsonKey , to format others JSON file’s keys
function replaceJsonKey() {
// read json file and key
const jsonPathList = [
"src/assets/i18n/en-US.json",
"src/assets/i18n/ja-JP.json",
"src/assets/i18n/zh-CN.json",
];
const regExJsonKey = /"([^"]+?)"\s*:/gm;jsonPathList.forEach((file) => {
let fileContent = fs.readFileSync(file).toString("utf8");
let match;
while ((match = regExJsonKey.exec(fileContent))) {
let key = match[0].replace(/['|"|`|:]/g, "").trim();;
const newKey = capitalizeFirstLetter(key);
fileContent = fileContent.replace(key, newKey);
console.log("From:", key);
console.log("To: ", newKey);
}
// write file back
fs.writeFile(file, fileContent, "utf8", function (err) {
if (err) return console.log(err);
});
});
}