Skip to content

Instantly share code, notes, and snippets.

@SakuraKoi
Forked from douglascayers/github-export-labels.js
Last active January 3, 2021 14:10
Show Gist options
  • Save SakuraKoi/68af75f83893d42454680d381a68fd9a to your computer and use it in GitHub Desktop.
Save SakuraKoi/68af75f83893d42454680d381a68fd9a to your computer and use it in GitHub Desktop.
Export and import GitHub labels between projects by running JavaScript in the browser console to automate clicks.
/**
* Inspired by @MoOx original script: https://gist.github.com/MoOx/93c2853fee760f42d97f
* Adds file download per @micalevisk https://gist.github.com/MoOx/93c2853fee760f42d97f#gistcomment-2660220
* Fixed color parsing @SakuraKooi
*
* Changes include:
* - Get the description from the `title` attribute instead of `aria-label` (doesn't exist anymore)
* - Use style.backgroundColor and parse the rgb(...) to hex (rather than regex parsing of 'style' string)
* - Downloads labels to a JSON file named after the webpage to know which GitHub repo they came from.
*
* Last tested 2021-1-3:
* - Chrome 87.0.4280.88
*/
function exportGitHubLabels() {
let labels = [];
[].slice.call( document.querySelectorAll( '.js-label-link' ) )
.forEach( element => {
labels.push({
name: element.textContent.trim(),
description: element.getAttribute( 'title' ),
color: (
// --label-r:255; --label-g:34; --label-b:34; --label-h:0; --label-s:100; --label-l:56;
element.style.cssText
// --label-r:255; --label-g:34; --label-b:34
.substr(0, element.style.cssText.indexOf("; --label-h"))
// 255; 34; 34
.replaceAll(/--label-.:/g, "")
.split( '; ' )
// reduce array of three numbers into single hex color
.reduce( ( hexValue, rgbValue ) => {
return (
// append next two-digit hex value
hexValue +
// convert decimal to hex
Number( rgbValue ).toString( 16 )
// each number in a hex color is two characters
.padStart( 2, '0' )
);
}, '' )
)
});
});
return labels;
}
function saveDataAsJSON( data, filename ) {
const blob = new Blob( [ JSON.stringify( data, null, 4 ) ], { type: 'text/json' } );
const a = document.createElement( 'a' );
a.download = filename;
a.href = window.URL.createObjectURL( blob );
a.dataset.downloadurl = [ 'text/json', a.download, a.href ].join( ':' );
a.click();
}
saveDataAsJSON( exportGitHubLabels(), document.title + '.json' );
/**
* Inspired by @Isaddo original script: https://gist.github.com/Isaddo/7efebcb673a0957b9c6f07cd14826ea4
* Adds descriptions per @NillerMedDild https://gist.github.com/Isaddo/7efebcb673a0957b9c6f07cd14826ea4#gistcomment-2715349
*
* Changes include:
* - CSS selectors use `js` prefix
*
* Last tested 2019-July-27:
* - Chrome 75.0.3770.142
* - Safari 12.1.2
* - macOS 10.14.6
*/
function createLabel( 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 updateLabel( label ) {
let updatedLabel = false;
[].slice.call( document.querySelectorAll( '.js-labels-list-item' ) ).forEach( element => {
if ( element.querySelector( '.js-label-link' ).textContent.trim() === label.name ) {
updatedLabel = 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 updatedLabel;
}
function createOrUpdate( label ) {
if ( !updateLabel( label ) ) {
createLabel( label );
}
}
[
// YOUR LABELS JSON HERE
].forEach( label => createOrUpdate( label ) );
[
{
"name": "a11y",
"description": "This needs improved accessibility. https://a11yproject.com/",
"color": "20e5d8"
},
{
"name": "bug: crash 💥",
"description": "App crashes and is unusable in a significant way.",
"color": "fbca04"
},
{
"name": "bug: regression ↩️",
"description": "A new version of the app broke something.",
"color": "fbca04"
},
{
"name": "bug 🐞",
"description": "App is not working correctly.",
"color": "fbca04"
},
{
"name": "discussion 💬",
"description": "Discussing usage, best practices, questions, etc.",
"color": "e99695"
},
{
"name": "documentation 📓",
"description": "Related to improving documentation and the wiki.",
"color": "6addf7"
},
{
"name": "enhancement ✨",
"description": "A new feature suggestion or improvement upon an existing feature.",
"color": "84b6eb"
},
{
"name": "salesforce known issue ⚠️",
"description": "A known issue with the Salesforce platform and likely not something the app can address.",
"color": "fcec85"
},
{
"name": "security 🔒",
"description": "Questions, concerns, or suggestions for improving the security of the app.",
"color": "1d76db"
},
{
"name": "status: in progress ❇️",
"description": "Currently being developed for a future release.",
"color": "c2e0c6"
},
{
"name": "status: on hold 💤",
"description": "Work has stopped. There may be one or more blockers or needs more information.",
"color": "c2e0c6"
},
{
"name": "status: resolved ✅",
"description": "This has been addressed in a branch and will be scheduled for release in the assigned milestone.",
"color": "c2e0c6"
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment