-
Star
(155)
You must be signed in to star a gist -
Fork
(34)
You must be signed in to fork a gist
-
-
Save MoOx/93c2853fee760f42d97f to your computer and use it in GitHub Desktop.
// go on you labels pages | |
// eg https://github.com/cssnext/cssnext/labels | |
// paste this script in your console | |
// copy the output and now you can import it using https://github.com/popomore/github-labels ! | |
var labels = []; | |
[].slice.call(document.querySelectorAll(".label-link")) | |
.forEach(function(element) { | |
labels.push({ | |
name: element.textContent.trim(), | |
// using style.backgroundColor might returns "rgb(...)" | |
color: element.getAttribute("style") | |
.replace("background-color:", "") | |
.replace(/color:.*/,"") | |
.trim() | |
// github wants hex code only without # or ; | |
.replace(/^#/, "") | |
.replace(/;$/, "") | |
.trim(), | |
}) | |
}) | |
console.log(JSON.stringify(labels, null, 2)) |
Thanks for this! Very helpful
Adding support for description
(aria-label
does not work for me):
description: element.parentElement.nextElementSibling.textContent.trim()
Support for settings.yml
:
function saveYML(text, filename) {
const blob = new Blob([text], { type: 'text/plain' });
const e = document.createEvent('MouseEvents');
const a = document.createElement('a');
a.download = filename;
a.href = window.URL.createObjectURL(blob);
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':');
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(e);
}
let out = "labels:\n";
for (const l of labels){
out += ` - name: ${l.name}\n color: ${l.color}\n description: ${l.description || '""'}\n`;
}
console.log(out) // or saveYML(out, "labels.yml")
The HTML of the /labels
site changed and the querySelector in the code of the gist doesn't find any elements.
To fix it, edit the script and replace:
[].slice.call(document.querySelectorAll(".label-link"))
with:
[].slice.call(document.querySelectorAll(".js-label-link"))
(e.g.: .js- label-link)
Here my code example that includes changes to CSS classname and captures the label's description.
var labels = [];
[].slice.call(document.querySelectorAll(".js-label-link"))
.forEach(function(element) {
labels.push({
name: element.textContent.trim(),
description: element.getAttribute("title"),
// using style.backgroundColor might returns "rgb(...)"
color: element.getAttribute("style")
.replace("background-color:", "")
.replace(/color:.*/,"")
.trim()
// github wants hex code only without # or ;
.replace(/^#/, "")
.replace(/;$/, "")
.trim(),
})
})
console.log(JSON.stringify(labels, null, 2))
Thanks for the original script and thanks @jamesperrin for the update!!
Thanks, very helpful!
Unfortunately seems that GitHub (recently?) changed the color output in style:
<a href="bug" title="Something isn't working" data-name="bug" style="--label-r:215;--label-g:58;--label-b:74;--label-h:353;--label-s:66;--label-l:53;" class="IssueLabel hx_IssueLabel IssueLabel--big lh-condensed js-label-link d-inline-block v-align-top">
<span>bug</span>
</a>
so in JSON you get:
{
"name": "bug",
"description": "Something isn't working",
"color": "--label-r:215;--label-g:58;--label-b:74;--label-h:353;--label-s:66;--label-l:53"
}
and import fails throwing:
An invalid form control with name='label[color]' is not focusable.
with an error on color input required format.
Hi all,
I updated the code, to solve the color output problem (RGBA to Hex). (@dademaru)
I also changed the attribute from which the description will be pulled.
var labels = [];
function hex(x) {
return ("0" + parseInt(x).toString(16)).slice(-2);
}
function rgba2hex(rgba) {
rgba = rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(,\s*\d+\.*\d+)?\)$/);
return hex(rgba[1]) + hex(rgba[2]) + hex(rgba[3]);
}
[].slice.call(document.querySelectorAll(".js-label-link"))
.forEach(function (element) {
labels.push({
name: element.textContent.trim(),
description: element.getAttribute("title"),
color: rgba2hex(window.getComputedStyle(element).getPropertyValue("background-color")),
})
})
console.log(JSON.stringify(labels, null, 2))
One can also use: gh api /repos/elastic/$repo/labels
to list a repo's label data, e.g.:
% gh api /repos/elastic/apm-agent-nodejs/labels
[
{
"id": 2510059555,
"node_id": "MDU6TGFiZWwyNTEwMDU5NTU1",
"url": "https://api.github.com/repos/elastic/apm-agent-nodejs/labels/agent-nodejs",
"name": "agent-nodejs",
"color": "2c4bba",
"default": false,
"description": "Make available for APM Agents project planning."
},
{
"id": 2411255376,
"node_id": "MDU6TGFiZWwyNDExMjU1Mzc2",
"url": "https://api.github.com/repos/elastic/apm-agent-nodejs/labels/agent-spec",
"name": "agent-spec",
"color": "d8136f",
"default": false,
"description": "Related to a cross agent functionality spec."
},
{
"id": 1151180629,
"node_id": "MDU6TGFiZWwxMTUxMTgwNjI5",
"url": "https://api.github.com/repos/elastic/apm-agent-nodejs/labels/automation",
"name": "automation",
"color": "81a2ef",
"default": false,
"description": null
},
{
"id": 1322034517,
"node_id": "MDU6TGFiZWwxMzIyMDM0NTE3",
"url": "https://api.github.com/repos/elastic/apm-agent-nodejs/labels/awaiting%20reply",
"name": "awaiting reply",
"color": "f3a0f7",
"default": false,
"description": ""
},
...
Useful, thanks @NibrasAbuAyyash
Supe @NibrasAbuAyyash & @trentm 🚀
I make my 2 penny's contrib 🤗
https://gist.github.com/davorpa/8201479803ff2a9bcc93a76a8fe71e43
All in one: gen + file export, wrapped in an IIFE, to merely save it as browser bookmark
the class has changed to js-label-link
and the description attribute to title
. The colour is now saved in variables and I haven't found a way to grab the computed colour that is anyhow in rgb
not hex
var labels = [];
[].slice.call(document.querySelectorAll(".js-label-link"))
.forEach(function(element) {
labels.push({
name: element.textContent.trim(),
description: element.getAttribute("title"),
// using style.backgroundColor might returns "rgb(...)"
color: element.getAttribute("style")
.replace("background-color:", "")
.replace(/color:.*/,"")
.trim()
// github wants hex code only without # or ;
.replace(/^#/, "")
.replace(/;$/, "")
.trim(),
})
})
console.log(JSON.stringify(labels, null, 2))
@giuliogallerini, I can't see something new.
var labels = []; [].slice.call(document.querySelectorAll(".js-label-link")) .forEach(function(element) { labels.push({ name: element.textContent.trim(), description: element.getAttribute("title"), // using style.backgroundColor might returns "rgb(...)" color: element.getAttribute("style") .replace("background-color:", "") .replace(/color:.*/,"") .trim() // github wants hex code only without # or ; .replace(/^#/, "") .replace(/;$/, "") .trim(), }) }) console.log(JSON.stringify(labels, null, 2))
is duplicated of https://gist.github.com/MoOx/93c2853fee760f42d97f#gistcomment-3069259
the class has changed to
js-label-link
and the description attribute totitle
. The colour is now saved in variables and I haven't found a way to grab the computed colour that is anyhow inrgb
nothex
Using computed style window.getComputedStyle(element).getPropertyValue("background-color")
, as suggested by @NibrasAbuAyyash, avoids headaches of this kind of frontend changes
Per @NibrasAbuAyyash and @davorpa using the background-color property, I got this to work in Chrome
function rgbaToHex(rgba) {
const match = rgba.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
const r = Number(match[1]);
const g = Number(match[2]);
const b = Number(match[3]);
return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
var labels = [];
[].slice.call(document.querySelectorAll(".js-label-link"))
.forEach(function(element) {
labels.push({
name: element.textContent.trim(),
description: element.getAttribute("title"),
color: rgbaToHex(window.getComputedStyle(element).backgroundColor),
})
})
console.log(JSON.stringify(labels, null, 2))
@BraidenCutforth is just like I post here
https://gist.github.com/MoOx/93c2853fee760f42d97f#gistcomment-3870544
Also allows safe file to disk
The other way is use GitHub api: https://docs.github.com/en/rest/reference/issues#list-labels-for-a-repository
E.g.: https://api.github.com/repos/octocat/hello-world/labels
Also to easily import and export things.
Use @davorpa code mentioned here. (direct link)
And for importing just install "Settings" app (link) by probot and make this file :
.github/settings.yml
# Labels: define labels for Issues and Pull Requests
labels:
- name: api
description: This issue or pull request is related to API
color: b60205
- name: not related
description: not related to us or our plugins/addons
color: d93f0b
- name: awaiting response
description: Waiting for response
Happy importing. And thanks to @davorpa for both json and yml / yaml file saver.
Here are my updates for exporting and importing issues labels.
It should be cross browser compatible except for IE which is pretty much dead.
github-labels-export.js
https://gist.github.com/jamesperrin/c2bf6d32fbb8142682f6107e561b664d
/*
Purpose: Export the configuration settings for GitHub Labels.
(c) James Perrin, MIT License, https://www.countrydawgg.com, | @jamesperrin
Exporting Instructions:
1. Open a web browser.
2. Navigate to the desired GitHub repository.
3. Navigate to Issues tab.
4. Navigate to Labels link.
5. Open the web browser's Developer Tools
6. Navigate to the Console
7. Copy and Paste below code into the Console.
8. Save github-labels.json to a desired computer folder location.
Please visit the below link to download the import JavaScript script.
github-labels-import.js - https://gist.github.com/jamesperrin/d811fadea2bd199ecf98195d96513afd
*/
/**
* @description Exports GitHub repository Issues labels to a JSON file
*
*/
(function () {
function hex(x) {
return ('0' + parseInt(x).toString(16)).slice(-2);
}
function rgba2hex(rgba) {
rgba = rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(,\s*\d+\.*\d+)?\)$/);
return hex(rgba[1]) + hex(rgba[2]) + hex(rgba[3]);
}
// Process to export labels into a JSON object
function getLabels() {
const jsLabels = document.querySelectorAll('.js-label-link');
if (!jsLabels || jsLabels.length < 1) {
console.error('Unable to find GitHub labels');
return;
}
const labels = [];
[].slice.call(jsLabels).forEach((jsLabel) => {
const name = `${jsLabel.dataset.name.trim()}`;
const description = jsLabel.parentElement.nextElementSibling.firstElementChild;
const color = rgba2hex(window.getComputedStyle(jsLabel).getPropertyValue('background-color'));
labels.push({
name: name ? name : '',
description: description ? description.innerText.trim() : '',
color: color ? color : '',
});
});
// Outputs labels to the Console
console.log(JSON.stringify(labels, null, 2));
return labels;
}
// Function save JSON object to a file
function saveJSON(data, filename) {
if (!data || data.length < 1) {
console.error('No data');
return;
}
const blob = new Blob([JSON.stringify(data, undefined, 4)], { type: 'text/json' });
const anchorElement = document.createElement('a');
const mouseEventOptions = {
bubbles: true,
cancelable: false,
screenX: 0,
screenY: 0,
clientX: 0,
clientY: 0,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
button: 0,
buttons: 0,
relatedTarget: null,
region: null,
};
const mouseEvent = new MouseEvent('click', mouseEventOptions);
anchorElement.download = filename;
anchorElement.href = window.URL.createObjectURL(blob);
anchorElement.dataset.downloadurl = ['text/json', anchorElement.download, anchorElement.href].join(':');
anchorElement.dispatchEvent(mouseEvent);
}
// Saves labels to JSON file.
saveJSON(getLabels(), 'github-labels.json');
})();
github-labels-import.js
https://gist.github.com/jamesperrin/d811fadea2bd199ecf98195d96513afd
/*
Purpose: Import settings for GitHub Labels.
(c) James Perrin, MIT License, https://www.countrydawgg.com, | @jamesperrin
Importing Instructions:
1. Update the labels JSON object.
2. Open a web browser.
3. Navigate to the desired GitHub repository.
4. Navigate to Issues tab.
5. Navigate to Labels link.
6. Open the web browswer's Developer Tools
7. Navigate to the Console window.
8. Copy and Paste the below code snippets into the Console window.
Please visit the below link to download the export JavaScript script.
github-labels-export.js - https://gist.github.com/jamesperrin/c2bf6d32fbb8142682f6107e561b664d
*/
const labels = [
{
name: 'bug',
description: "Something isn't working",
color: 'ee0701',
},
{
name: 'duplicate',
description: 'This issue or pull request already exists',
color: 'cccccc',
},
{
name: 'enhancement',
description: 'New feature or request',
color: '84b6eb',
},
{
name: 'good first issue',
description: 'Good for newcomers',
color: '7057ff',
},
{
name: 'help wanted',
description: 'Extra attention is needed',
color: '33aa3f',
},
{
name: 'invalid :notebook:',
description: "This doesn't seem right",
color: 'e6e6e6',
},
{
name: 'question',
description: 'Further information is requested',
color: 'cc317c',
},
{
name: 'wontfix',
description: 'This will not be worked on',
color: 'ffffff',
},
];
// Function to update an existing label
function updateLabel(label) {
let flag = false;
[].slice.call(document.querySelectorAll('.labels-list-item')).forEach((element) => {
if (element.querySelector('.label-link').textContent.trim() === label.name) {
flag = true;
element.querySelector('.js-edit-label').click();
element.querySelector('.js-new-label-name-input').value = label.name;
element.querySelector('.js-new-label-description-input').value = label.description;
element.querySelector('.js-new-label-color-input').value = `#${label.color}`;
element.querySelector('.js-edit-label-cancel ~ .btn-primary').click();
}
});
return flag;
}
// Function to add a new label
function addNewLabel(label) {
document.querySelector('.js-new-label-name-input').value = label.name;
document.querySelector('.js-new-label-description-input').value = label.description;
document.querySelector('.js-new-label-color-input').value = `#${label.color}`;
document.querySelector('.js-details-target ~ .btn-primary').disabled = false;
document.querySelector('.js-details-target ~ .btn-primary').click();
}
// Function to update or add a new label
function addLabel(label) {
if (!updateLabel(label)) {
addNewLabel(label);
}
}
labels.map((label) => {
addLabel(label);
});
Update June 2022: As far as I can see the description no longer exists as title
on the label element itself.
Though it might be brittle to rely on the DOM structure of the labels page, this is my fix getting the description from the column after the label itself:
...
description: jsLabel.parentElement.nextElementSibling.firstElementChild.innerText.trim(),
...
@jakobe I updated my code based on your comments. At the moment, looks like a good option.
@jakobe I updated my code based on your comments. At the moment, looks like a good option.
Awesome 👍
The official GitHub CLI now includes functionality that allows you to clone labels easily from one repo to another.
Example syntax:
gh label clone org-name/repo-to-clone-from --repo org-name/repo-to-clone-to
See the documentation for more information.
gh label clone org-name/repo-to-clone-from --repo org-name/repo-to-clone-to
bet
The GitHub CLI docs also illustrate listing the labels using custom JSON output templates: https://cli.github.com/manual/gh_label_list
The official GitHub CLI now includes functionality that allows you to clone labels easily from one repo to another. Example syntax:
gh label clone org-name/repo-to-clone-from --repo org-name/repo-to-clone-to
See the documentation for more information.
Thanks works well!🎉
@jamesperrin I get the following error when i try to paste the export code in the console browser
3188:30 Uncaught TypeError: Cannot read properties of null (reading 'innerText')
at <anonymous>:30:77
at Array.map (<anonymous>)
at getLabels (<anonymous>:27:27)
at <anonymous>:79:11
at <anonymous>:80:3
(anonymous) @ VM3188:30
getLabels @ VM3188:27
(anonymous) @ VM3188:79
(anonymous) @ VM3188:80
Do you have a fix for this?
@jamesperrin I get the following error when i try to paste the export code in the console browser
3188:30 Uncaught TypeError: Cannot read properties of null (reading 'innerText') at <anonymous>:30:77 at Array.map (<anonymous>) at getLabels (<anonymous>:27:27) at <anonymous>:79:11 at <anonymous>:80:3 (anonymous) @ VM3188:30 getLabels @ VM3188:27 (anonymous) @ VM3188:79 (anonymous) @ VM3188:80Do you have a fix for this?
@deffcolony I need a little more information. What is the URL for GitHub repository you tried to run the script against?
@jamesperrin I get the following error when i try to paste the export code in the console browser
3188:30 Uncaught TypeError: Cannot read properties of null (reading 'innerText') at <anonymous>:30:77 at Array.map (<anonymous>) at getLabels (<anonymous>:27:27) at <anonymous>:79:11 at <anonymous>:80:3 (anonymous) @ VM3188:30 getLabels @ VM3188:27 (anonymous) @ VM3188:79 (anonymous) @ VM3188:80Do you have a fix for this?
@deffcolony I need a little more information. What is the URL for GitHub repository you tried to run the script against?
@jamesperrin The URL is https://github.com/deffcolony/HP-Witchcraft-and-Wizardry/labels
@jamesperrin I get the following error when i try to paste the export code in the console browser
3188:30 Uncaught TypeError: Cannot read properties of null (reading 'innerText') at <anonymous>:30:77 at Array.map (<anonymous>) at getLabels (<anonymous>:27:27) at <anonymous>:79:11 at <anonymous>:80:3 (anonymous) @ VM3188:30 getLabels @ VM3188:27 (anonymous) @ VM3188:79 (anonymous) @ VM3188:80Do you have a fix for this?
@deffcolony I need a little more information. What is the URL for GitHub repository you tried to run the script against?
@jamesperrin The URL is https://github.com/deffcolony/HP-Witchcraft-and-Wizardry/labels
@deffcolony I added validations checks for all the label properties. The issue was some label may not have a description which caused the error. You should be able to run the script without issue.
tl;dr gh label clone src-org/src_repo --repo dest-org/dest_org
If you're coming by this thread in 2024 or later, I highly recommend seeing the official GitHub CLI [1].
and this function to download
labels
as file directlyexample