Skip to content

Instantly share code, notes, and snippets.

@phpwalter
Last active February 4, 2026 21:28
Show Gist options
  • Select an option

  • Save phpwalter/2ce7e735a879a0c843d676ef65a72725 to your computer and use it in GitHub Desktop.

Select an option

Save phpwalter/2ce7e735a879a0c843d676ef65a72725 to your computer and use it in GitHub Desktop.
Import Github Labels
/*
Before running:
1. Go to your GitHub Settings > Developer Settings > Personal Access Tokens (classic).
[https://github.com/settings/tokens]
2. GENERATE NEW TOKEN -> GENERATE NEW TOKEN [not classic!]
3. name it "labels"
4. Experation: tommorow
5. Select ONLY SELECT REPOSITORIES: your target repository
6. + ADD PERMISSIONS
7. Select ISSUES
NOTE:
For a token to be granted "Read and write" access to Issues
8. ACCESS: Read and Write
9. GENERATE TOKEN
10. Review your settings -> GENERATE TOKENS
11. Copy token
12. Paste that token into the YOUR_TOKEN_HERE.
13. go to your ISSUES page
[yourname/your_project/issues/]
14. Open the browser CONSOLE
15. paste the modified script
16. run script and select JSON file
17. verify it placed issues as expected
Use the sample JSON file to see how this works, than modify the JSON
to add your own issues, desc, etc.
NOTE:
- All fields are required
- DESC must be less than 100 characters
*/
// 1. CONFIGURATION
const CONFIG = {
token: "YOUR_ACCESS_TOKEN_HERE",
owner: "USERNAME_OR_ORG",
repo: "REPOSITORY_NAME"
};
// 2. MAIN LOGIC
async function startImport() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = async (event) => {
try {
const json = JSON.parse(event.target.result);
console.log(`πŸ“‚ Loaded ${json.length} labels. Starting strict import...`);
await importToGitHub(json);
} catch (err) {
console.error("❌ Invalid JSON:", err.message);
}
};
reader.readAsText(file);
};
input.click();
}
async function importToGitHub(labels) {
const headers = {
"Authorization": `token ${CONFIG.token}`,
"Accept": "application/vnd.github.v3+json",
"Content-Type": "application/json"
};
let created = 0, skipped = 0, errors = 0;
for (const [i, item] of labels.entries()) {
// --- STRICT LENGTH CHECK ---
const desc = item.description || "";
if (desc.length > 99) {
console.error(`❌ SKIPPED [${i+1}] "${item.label}": Description too long (${desc.length} chars > 99)`);
errors++;
continue; // Skip to next iteration immediately
}
// Prepare Payload
const payload = {
name: item.label,
description: desc,
color: item.color.replace("#", "")
};
try {
const res = await fetch(`https://api.github.com/repos/${CONFIG.owner}/${CONFIG.repo}/labels`, {
method: "POST",
headers,
body: JSON.stringify(payload)
});
if (res.status === 201) {
console.log(`βœ… [${i+1}] Created: "${payload.name}"`);
created++;
}
else if (res.status === 422) {
// We still check for duplicates here just in case
const data = await res.json().catch(() => ({}));
if (data.errors?.[0]?.code === 'already_exists') {
console.warn(`⚠️ [${i+1}] Skipped (Exists): "${payload.name}"`);
skipped++;
} else {
console.error(`❌ [${i+1}] API Error: "${payload.name}"`, data);
errors++;
}
}
else {
console.error(`❌ [${i+1}] Failed: "${payload.name}" (${res.status})`);
errors++;
}
} catch (err) {
console.error(`❌ Network Error on "${payload.name}"`, err);
errors++;
}
// Safety Delay (500ms)
await new Promise(r => setTimeout(r, 500));
}
console.log(`\n🏁 IMPORT COMPLETE\nβœ… Created: ${created}\n⚠️ Skipped (Exists): ${skipped}\n❌ Skipped (Errors/Long): ${errors}`);
}
// 3. RUN
startImport();
[
{
"label": "prio:high",
"description": "Critical path item; must be completed for milestone sign-off.",
"color": "#B60205"
},
{
"label": "prio:low",
"description": "Nice to have, but not a BLOCKER",
"color": "#1DC036"
},
{
"label": "prio:medium",
"description": "",
"color": "#F0A795"
}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment