diff --git a/.github/changelog-configuration.json b/.github/changelog-configuration.json
new file mode 100644
index 0000000..1308884
--- /dev/null
+++ b/.github/changelog-configuration.json
@@ -0,0 +1,95 @@
+{
+ "categories": [
+ {
+ "title": "\n\n
\n\n#### 🪛 Continuous integration",
+ "labels": [ "kind/ci", "ci" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🚀 Features",
+ "labels": [ "kind/feature", "feature", "feat" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🐛 Bugfixes",
+ "labels": [ "kind/bug", "fix", "bug" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🔧 Changes",
+ "labels": [ "kind/chore", "change", "chore" ]
+ },
+ {
+ "title": "\n\n
\n\nn#### ✨ Optimizations",
+ "labels": [ "kind/perf", "optimization", "perf", "optimize" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🚨 Security ",
+ "labels": [ "kind/security", "security" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🧹 Housekeeping",
+ "labels": [ "kind/refactor", "refactor", "style" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🐒 Miscellaneous",
+ "labels": [ "kind/misc", "misc" ]
+ },
+ {
+ "title": "\n\n
\n\n#### ⛔ Deprecated",
+ "labels": [ "kind/deprecate", "deprecate" ]
+ },
+ {
+ "title": "\n\n
\n\n#### ⛔ Removed",
+ "labels": [ "kind/remove", "remove" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 📦 Build & Dependencies",
+ "labels": [ "kind/build", "build", "dependency", "dep", "package" ]
+ },
+ {
+ "title": "\n\n
\n\n#### ✏️ Docs",
+ "labels": [ "kind/docs", "doc", "docs", "wiki" ]
+ },
+ {
+ "title": "\n\n
\n\n#### 🧪 Tests & Demo Vault",
+ "labels": [ "kind/test", "test", "tests", "vault" ]
+ }
+ ],
+ "sort": "ASC",
+ "pr_template": "- ${{TITLE_ONLY}} : #{{MERGE_SHA}} @#{{AUTHOR}}",
+ "empty_template": "- No major changes to address in this release",
+ "custom_placeholders": [
+ {
+ "name": "TITLE_ONLY",
+ "source": "TITLE",
+ "transformer": {
+ "method": "regexr",
+ "pattern": "(\\w+(\\(.+\\))?: ?)?(.+)",
+ "target": "$2 $3"
+ }
+ }
+ ],
+ "label_extractor": [
+ {
+ "pattern": "^(build|ci|change|chore|doc|docs|wiki|remove|deprecate|security|dependency|dep|package|feat|feature|fix|bug|perf|optimize|optimization|refactor|style|test|tests|vault):(.*)",
+ "target": "$1",
+ "on_property": "title"
+ },
+ {
+ "pattern": "^(build|ci|change|chore|doc|docs|wiki|remove|deprecate|security|dependency|dep|package|feat|feature|fix|bug|perf|optimize|optimization|refactor|style|test|tests|vault){1}(\\([\\w\\-\\.]+\\))?(!)?:(.*)",
+ "target": "$1",
+ "on_property": "title"
+ }
+ ],
+ "duplicate_filter": {
+ "pattern": "github.*",
+ "on_property": "author",
+ "method": "match"
+ },
+ "max_tags_to_fetch": 200,
+ "max_pull_requests": 200,
+ "max_back_track_time_days": 365,
+ "exclude_merge_branches": [],
+ "tag_resolver": {
+ "method": "semver"
+ },
+ "base_branches": []
+}
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..6f733de
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,37 @@
+# MIT License
+#
+# Copyright (c) 2024 Aetherinox
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+version: 2
+updates:
+- package-ecosystem: npm
+ directory: "/"
+ schedule:
+ interval: daily
+ labels:
+ - "Type ◦ Dependency"
+
+- package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ labels:
+ - "Type ◦ Git Action"
\ No newline at end of file
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 0000000..4085b2c
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,45 @@
+# Number of labels to fetch (optional). Defaults to 100
+numLabels: 40
+# These labels will not be used even if the issue contains them (optional).
+# Pass a blank array if no labels are to be excluded.
+# excludeLabels: []
+excludeLabels:
+ - pinned
+# custom configuration to override default behaviour
+# control explicitly what gets added and when
+custom:
+ - location: title
+ keywords:
+ - '[roadmap]'
+ labels:
+ - Type ◦ Roadmap
+ - location: title
+ keywords:
+ - '[road-map]'
+ labels:
+ - Type ◦ Roadmap
+ - location: title
+ keywords:
+ - '[bug]'
+ labels:
+ - Type ◦ Bug
+ - location: title
+ keywords:
+ - '[issue]'
+ labels:
+ - Type ◦ Bug
+ - location: title
+ keywords:
+ - '[feature]'
+ labels:
+ - Type ◦ Feature
+ - location: body
+ keywords:
+ - 'request feature'
+ labels:
+ - Type ◦ Feature
+ - location: title
+ keywords:
+ - '[request]'
+ labels:
+ - Type ◦ Feature
\ No newline at end of file
diff --git a/.github/workflows/issues-new-assign.yml b/.github/workflows/issues-new-assign.yml
new file mode 100644
index 0000000..68ec968
--- /dev/null
+++ b/.github/workflows/issues-new-assign.yml
@@ -0,0 +1,838 @@
+# ---------------------------------------------------------------------------------------
+# @parent : github workflow
+# @desc : allows you to auto assign labels to new issues and pull requests
+# @author : Aetherinox
+# @url : https://github.com/Aetherinox
+#
+# requires the following labels to be created in your repo:
+# - bug
+# - feature
+# - urgent
+# - roadmap
+# ---------------------------------------------------------------------------------------
+
+name: "🎫 Issue › New › Assignment"
+run-name: "🎫 Issue › New › Assignment - ${{ github.event.issue.number }}: ${{ github.event.issue.title }}"
+
+# ---------------------------------------------------------------------------------------
+# triggers
+# ---------------------------------------------------------------------------------------
+
+on:
+ issues:
+ types:
+ - reopened
+ - opened
+
+# ---------------------------------------------------------------------------------------
+# environment variables
+# ---------------------------------------------------------------------------------------
+
+env:
+ PREFIX_BUG: "Bug"
+ PREFIX_FEATURE: "Feature"
+ PREFIX_ROADMAP: "Roadmap"
+ PREFIX_DEPENDENCY: "Dependency"
+ PREFIX_PR: "PR"
+ PREFIX_DOCS: "Docs"
+ PREFIX_GIT: "Git Action"
+ PREFIX_URGENT: "Urgent"
+
+ LABEL_BUG: "Type ◦ Bug"
+ LABEL_FEATURE: "Type ◦ Feature"
+ LABEL_ROADMAP: "Type ◦ Roadmap"
+ LABEL_DEPENDENCY: "Type ◦ Dependency"
+ LABEL_PR: "Type ◦ Pull Request"
+ LABEL_DOCS: "Type ◦ Docs"
+ LABEL_GIT: "Type ◦ Git Action"
+ LABEL_URGENT: "⚠ Urgent"
+
+ ASSIGN_USER: Aetherinox
+ BOT_NAME_1: AdminServ
+ BOT_NAME_2: AdminServX
+ BOT_NAME_3: EuropaServ
+ BOT_NAME_DEPENDABOT: dependabot[bot]
+
+ LABELS_JSON: |
+ [
+ { "name": "Type ◦ Bug", "color": "9a2c2c", "description": "Something isn't working" },
+ { "name": "Type ◦ Dependency", "color": "243759", "description": "Item is associated to dependency" },
+ { "name": "Type ◦ Docs", "color": "0e588d", "description": "Improvements or modifications to docs" },
+ { "name": "Type ◦ Feature", "color": "3c4e93", "description": "Feature request" },
+ { "name": "Type ◦ Git Action", "color": "030406", "description": "GitHub Action / workflow" },
+ { "name": "Type ◦ Pull Request", "color": "8F1784", "description": "Normal pull request" },
+ { "name": "Type ◦ Roadmap", "color": "8F1784", "description": "Feature or bug currently planned for implementation" }
+ ]
+
+jobs:
+
+ # ---------------------------------------------------------------------------------------
+ # Verify Existing Labels
+ # This job will ensure you have labels already created in your repo.
+ #
+ # All labels come from the JSON table LABELS_JSON.
+ # ---------------------------------------------------------------------------------------
+
+ issues-preconfig-labels:
+ name: ⚙️ Preconfigure
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: "✅ Start"
+ run: |
+ echo "Assigning labels and assignees"
+
+ - name: "☑️ Checkout"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ # ---------------------------------------------------------------------------------------
+ # Check if repo has labels currently added to issues
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ Verify Existing Labels
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const labels = JSON.parse( process.env.LABELS_JSON );
+ for ( const label of labels )
+ {
+ try
+ {
+ await github.rest.issues.createLabel(
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ name: label.name,
+ description: label.description || '',
+ color: label.color
+ });
+ }
+ catch ( err )
+ {
+ if ( err.status === 422 )
+ {
+ console.log( `Label '${label.name}' already exists. Skipping.` );
+ }
+ else
+ {
+ console.error( `Error creating label '${label.name}': ${err}` );
+ }
+ }
+ }
+
+ # ---------------------------------------------------------------------------------------
+ # Issues > Assign Labels
+ # ---------------------------------------------------------------------------------------
+
+ issues-assign-labels:
+ name: >-
+ 🏷️ Labels › Assign
+ needs:
+ - issues-preconfig-labels
+ runs-on: ubuntu-latest
+ permissions:
+ contents: 'read'
+ id-token: 'write'
+ issues: 'write'
+ environment:
+ name: Orion
+ steps:
+
+
+ # ---------------------------------------------------------------------------------------
+ # Get Issue Title
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ Get Issue Title
+ uses: actions/github-script@v7
+ id: label_issues_initialize
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+
+ let iss_title = `${ context.payload.issue.title }`;
+
+ core.setOutput( 'issue_title', iss_title )
+ core.info( `Setting env issue title: ${ iss_title }` )
+
+ console.log( "\n\n" )
+
+
+ # ---------------------------------------------------------------------------------------
+ # Label > Bug
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ ${{ env.PREFIX_BUG }} › Assignment
+ uses: actions/github-script@v7
+ id: label_issues_bug
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+
+ const issueLabels = await github.rest.issues.listLabelsOnIssue(
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number
+ });
+
+ let add_labels = issueLabels.data.map( label => label.name );
+
+ let iss_title = `${{ steps.label_issues_initialize.outputs.issue_title }}` || `${ context.payload.issue.title }`;
+ let iss_body = `${ context.payload.issue.body }`;
+ let iss_author = `${ context.payload.issue.user.login }`;
+
+ const iss_title_lc = iss_title.toLowerCase( );
+
+ console.log( "Feat Title .................... " + iss_title )
+ console.log( "Feat Output ................... " + `${{ steps.label_issues_initialize.outputs.issue_title }}` )
+ console.log( "Feat Payload .................. " + `${ context.payload.issue.title }` )
+
+ /*
+ Tags
+ */
+
+ const bug_tag = `${{ env.PREFIX_BUG }}:`;
+ const bug_lbl = `${{ env.LABEL_BUG }}`;
+ const feat_tag = `${{ env.PREFIX_FEATURE }}:`;
+ const feat_lbl = `${{ env.LABEL_FEATURE }}`;
+ const urgn_tag = `${{ env.PREFIX_URGENT }}:`;
+ const urgn_lbl = `${{ env.LABEL_URGENT }}`;
+ const road_tag = `${{ env.PREFIX_ROADMAP }}:`;
+ const road_lbl = `${{ env.LABEL_ROADMAP }}`;
+
+ /*
+ Bugs
+ */
+
+ const words = [ "bug", "broke", "issue", "fail" ];
+ const bIncWordT = words.some( s => s.includes( iss_title_lc ) || iss_title_lc.includes( s ) );
+
+ /*
+ Find regex based phrases
+
+ Regex:
+ https://regex101.com/r/Z99Gnq/2
+ */
+
+ const findWordList = /^\b(?:I?\s*have\s*(?:a|an)\s*(?:issue|problem|bug))|(?:will\s*not\s*work)|(?:it\s*is\s*(?:broken|broke|stuck))|(?:found\s*(?:an?|the)\s*(?:bug|issue))|(?:can\s*I\s*fix\s*the\s*(?:bug|issue))|(?:(?:does not|doesn'?t|don'?t|won'?t|can'?t|can\s?not|will\s*not)\s*(?:work|load|function))|(?:it\s*(?:will\s?not|won'?t|can\s?not|can'?t))\s*(?:get|find)\s*the\s*(?:website|site|webpage|page)|(?:the\s*(?:window|frame)\s*is\s*(?:blank|white|empty|missing))\b$/igm;
+ const bFoundMatchTitle = Boolean( findWordList.test( iss_title ) );
+ const bFoundMatchBody = Boolean( findWordList.test( iss_body ) );
+
+ /*
+ Do not change a title if the item starts with a PR: #
+
+ Regex:
+ https://regex101.com/r/JOrqbN/1
+ */
+
+ const bug_findPRTitle = /^PR\s?#?(?:[0-9]*:)/igm;
+ const bug_bFoundPRTitle = Boolean( bug_findPRTitle.test( iss_title ) );
+
+ console.log( "Title Lowercase ............... " + iss_title_lc )
+ console.log( "Startswith " + bug_tag.toLowerCase( ) + "................ " + iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) )
+ console.log( "Title Includes Keyword ........ " + bIncWordT )
+ console.log( "Title Includes Regex .......... " + bFoundMatchTitle )
+ console.log( "Body Includes Regex ........... " + bFoundMatchBody )
+ console.log( "\n" )
+
+ /*
+ - Check if issue title matches the issue label "Bug:"
+ - Check if title contains word in words
+ */
+
+ if ( iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) || bIncWordT || bFoundMatchTitle || bFoundMatchBody )
+ {
+
+ console.log( "⚠️ " + bug_tag + " ---------------------------------------" )
+ console.log( "Already starts with " + bug_tag + " ......... " + iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + feat_tag + " ..... " + iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + urgn_tag + " ...... " + iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + road_tag + " ..... " + iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+
+ add_labels.push( `${ bug_lbl }` );
+
+ console.log( `Adding Tag ....................... ${ bug_lbl }` )
+ console.log( "\n" )
+
+ if ( iss_author === `${{ env.BOT_NAME_DEPENDABOT }}` )
+ core.info( `Skipping: Detected ${ iss_author }` )
+
+ // Rename title to contain Bug:
+ // Make sure issue / pr title doesnt already contain a beginning title tag
+
+ if ( iss_author !== `${{ env.BOT_NAME_DEPENDABOT }}` && !bug_bFoundPRTitle && !iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+ {
+ console.log( "Renaming Title" )
+ console.log( `Old Title: .................. ${ iss_title }` )
+
+ const title = context.payload.issue.title
+ let title_new = title.replace( /^\s?bug\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?fail\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?issue\s*(.*?)\b/gi, '' );
+ iss_title = `${ bug_tag } ${ title_new }`;
+ }
+
+ console.log( `New Title: ...................... ${ iss_title }` )
+
+ await github.rest.issues.update(
+ {
+ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
+ title: `${ iss_title }`, labels: add_labels
+ } );
+ }
+
+ core.setOutput( 'issue_title', iss_title )
+ console.log( "\n\n" )
+
+ # ---------------------------------------------------------------------------------------
+ # Label > FEATURE
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ ${{ env.PREFIX_FEATURE }} › Assignment
+ uses: actions/github-script@v7
+ id: label_issues_feature
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+
+ const issueLabels = await github.rest.issues.listLabelsOnIssue(
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number
+ });
+
+ let add_labels = issueLabels.data.map( label => label.name );
+
+ let iss_title = `${{ steps.label_issues_bug.outputs.issue_title }}` || `${ context.payload.issue.title }`;
+ let iss_body = `${ context.payload.issue.body }`;
+
+ const iss_title_lc = iss_title.toLowerCase( );
+
+ console.log( "Feat Title .................... " + iss_title )
+ console.log( "Feat Output ................... " + `${{ steps.label_issues_bug.outputs.issue_title }}` )
+ console.log( "Feat Payload .................. " + `${ context.payload.issue.title }` )
+
+ /*
+ Tags
+ */
+
+ const bug_tag = `${{ env.PREFIX_BUG }}:`;
+ const bug_lbl = `${{ env.LABEL_BUG }}`;
+ const feat_tag = `${{ env.PREFIX_FEATURE }}:`;
+ const feat_lbl = `${{ env.LABEL_FEATURE }}`;
+ const urgn_tag = `${{ env.PREFIX_URGENT }}:`;
+ const urgn_lbl = `${{ env.LABEL_URGENT }}`;
+ const road_tag = `${{ env.PREFIX_ROADMAP }}:`;
+ const road_lbl = `${{ env.LABEL_ROADMAP }}`;
+
+ /*
+ Features
+ */
+
+ const words = [ "feature", "request", "add support" ];
+ const bIncWordT = words.some( s => s.includes( iss_title_lc ) || iss_title_lc.includes( s ) );
+
+ /*
+ Find regex based phrases
+
+ Regex:
+ https://regex101.com/r/fR1Hm6/1
+ */
+
+ const findWordList = /^(?:(?:request|include|see)\s*(?:an?|the?)\s*(?:feature|addon|addition|plugin))|(?:(?:add|see|get)\s*support\s*(?:for|with|of))|(?:can\s*we\s*get\s*(?:the|a)\s*(?:ability|feature))|(?:💡 Feature:)$/igm;
+ const bFoundMatchTitle = Boolean( findWordList.test( iss_title ) );
+ const bFoundMatchBody = Boolean( findWordList.test( iss_body ) );
+
+ /*
+ Do not change a title if the item starts with a PR: #
+
+ Regex:
+ https://regex101.com/r/JOrqbN/1
+ */
+
+ const feat_findPRTitle = /^PR\s?#?(?:[0-9]*:)/igm;
+ const feat_bFoundPRTitle = Boolean( feat_findPRTitle.test( iss_title ) );
+
+ console.log( "Title Lowercase ............... " + iss_title_lc )
+ console.log( "Startswith " + feat_tag.toLowerCase( ) + "............ " + iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) )
+ console.log( "Title Includes Keyword ........ " + bIncWordT )
+ console.log( "Title Includes Regex .......... " + bFoundMatchTitle )
+ console.log( "Body Includes Regex ........... " + bFoundMatchBody )
+ console.log( "\n" )
+
+ /*
+ - Check if issue title matches the issue label "Feature:"
+ - Check if title contains word in words
+ */
+
+ // change TAG per category
+ if ( iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) || bIncWordT || bFoundMatchTitle || bFoundMatchBody )
+ {
+
+ console.log( "⚠️ " + feat_tag + " ---------------------------------------" )
+ console.log( "Already starts with " + bug_tag + " ......... " + iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + feat_tag + " ..... " + iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + urgn_tag + " ...... " + iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + road_tag + " ..... " + iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+
+ // change LBL per category
+ add_labels.push( `${ feat_lbl }` );
+
+ console.log( `Adding Tag ....................... ${ feat_lbl }` )
+ console.log( "\n" )
+
+ if ( iss_author === `${{ env.BOT_NAME_DEPENDABOT }}` )
+ core.info( `Skipping: Detected ${ iss_author }` )
+
+ // Rename title to contain Feature:
+ // Make sure issue / pr title doesnt already contain a beginning title tag
+
+ if ( iss_author !== `${{ env.BOT_NAME_DEPENDABOT }}` && !feat_bFoundPRTitle && !iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+ {
+ console.log( "Renaming Title" )
+ console.log( `Old Title: .................. ${ iss_title }` )
+
+ const title = context.payload.issue.title
+ let title_new = title.replace( /^\s?feature\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?request\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?add(.*?)\s?feature\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?add(.*?)\s?support\s*(.*?)\b/gi, '' );
+ iss_title = `${ feat_tag } ${ title_new }`; // change TAG per category
+ }
+
+ console.log( `New Title: ...................... ${ iss_title }` )
+
+ await github.rest.issues.update(
+ {
+ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
+ title: `${ iss_title }`, labels: add_labels
+ } );
+ }
+
+ core.setOutput( 'issue_title', iss_title )
+ console.log( "\n\n" )
+
+ # ---------------------------------------------------------------------------------------
+ # Label > URGENT
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ ${{ env.PREFIX_URGENT }} › Assignment
+ uses: actions/github-script@v7
+ id: label_issues_urgent
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+
+ const issueLabels = await github.rest.issues.listLabelsOnIssue(
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number
+ });
+
+ let add_labels = issueLabels.data.map( label => label.name );
+
+ let iss_title = `${{ steps.label_issues_feature.outputs.issue_title }}` || `${ context.payload.issue.title }`;
+ let iss_body = `${ context.payload.issue.body }`;
+
+ const iss_title_lc = iss_title.toLowerCase( );
+
+ console.log( "Urgn Title .................... " + iss_title )
+ console.log( "Urgn Output ................... " + `${{ steps.label_issues_feature.outputs.issue_title }}` )
+ console.log( "Urgn Payload .................. " + `${ context.payload.issue.title }` )
+
+ /*
+ Tags
+ */
+
+ const bug_tag = `${{ env.PREFIX_BUG }}:`;
+ const bug_lbl = `${{ env.LABEL_BUG }}`;
+ const feat_tag = `${{ env.PREFIX_FEATURE }}:`;
+ const feat_lbl = `${{ env.LABEL_FEATURE }}`;
+ const urgn_tag = `${{ env.PREFIX_URGENT }}:`;
+ const urgn_lbl = `${{ env.LABEL_URGENT }}`;
+ const road_tag = `${{ env.PREFIX_ROADMAP }}:`;
+ const road_lbl = `${{ env.LABEL_ROADMAP }}`;
+
+ /*
+ Urgent
+ */
+
+ const words = [ "urgent", "urgency", "emergency", "important", "critical" ];
+ const bIncWordT = words.some( s => s.includes( iss_title_lc ) || iss_title_lc.includes( s ) );
+
+ /*
+ Find regex based phrases
+
+ Regex:
+ https://regex101.com/r/eE9tJX/2
+ */
+
+ const findWordList = /(?:(?:this)?is\s*a?n?\s*?(?:emergency|urgent|important|vital|acute|crucial|grave|pressing|serious|top.?priority|high.?priority))|(?:reply|respond|answer|write|address)\s*(?:immediate|quick|asap|urgent|now|fast|(?:as)?\s*(?:soon|quick|immediate|fast))(?:ly)?|(?:need\s*(?:help|support|fixed|answer|reply|response)!)|(?:emergency|critical|urgen(?:t|cy)|high.?priority)/igm;
+ const bFoundMatchTitle = Boolean( findWordList.test( iss_title ) );
+ const bFoundMatchBody = Boolean( findWordList.test( iss_body ) );
+
+ /*
+ Do not change a title if the item starts with a PR: #
+
+ Regex:
+ https://regex101.com/r/JOrqbN/1
+ */
+
+ const urgn_findPRTitle = /^PR\s?#?(?:[0-9]*:)/igm;
+ const urgn_bFoundPRTitle = Boolean( urgn_findPRTitle.test( iss_title ) );
+
+ console.log( "Title Lowercase ............... " + iss_title_lc )
+ console.log( "Startswith " + urgn_tag.toLowerCase( ) + "............. " + iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) )
+ console.log( "Title Includes Keyword ........ " + bIncWordT )
+ console.log( "Title Includes Regex .......... " + bFoundMatchTitle )
+ console.log( "Body Includes Regex ........... " + bFoundMatchBody )
+ console.log( "\n" )
+
+ /*
+ - Check if issue title matches the issue label "Urgent:"
+ - Check if title contains word in words
+ */
+
+ // change TAG per category
+ if ( iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) || bIncWordT || bFoundMatchTitle || bFoundMatchBody )
+ {
+
+ console.log( "⚠️ " + urgn_tag + " ---------------------------------------" )
+ console.log( "Already starts with " + bug_tag + " ......... " + iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + feat_tag + " ..... " + iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + urgn_tag + " ...... " + iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + road_tag + " ..... " + iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+
+ // change LBL per category
+ add_labels.push( `${ urgn_lbl }` );
+
+ console.log( `Adding Tag ....................... ${ urgn_lbl }` )
+ console.log( "\n" )
+
+ if ( iss_author === `${{ env.BOT_NAME_DEPENDABOT }}` )
+ core.info( `Skipping: Detected ${ iss_author }` )
+
+ // Rename title to contain Urgent:
+ // Make sure issue / pr title doesnt already contain a beginning title tag
+
+ if ( iss_author !== `${{ env.BOT_NAME_DEPENDABOT }}` && !urgn_bFoundPRTitle && !iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+ {
+ console.log( "Renaming Title" )
+ console.log( `Old Title: .................. ${ iss_title }` )
+
+ const title = context.payload.issue.title
+ let title_new = title.replace( /^\s?emergency\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?urgent\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?urgency\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?important\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?critical\s*(.*?)\b/gi, '' );
+ iss_title = `${ urgn_tag } ${ title_new }`; // change TAG per category
+ }
+
+ console.log( `New Title: ...................... ${ iss_title }` )
+
+ await github.rest.issues.update(
+ {
+ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
+ title: `${ iss_title }`, labels: add_labels
+ } );
+ }
+
+ core.setOutput( 'issue_title', iss_title )
+ console.log( "\n\n" )
+
+ # ---------------------------------------------------------------------------------------
+ # Label > ROADMAP
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ ${{ env.PREFIX_ROADMAP }} › Assignment
+ uses: actions/github-script@v7
+ id: label_issues_roadmap
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+
+ const issueLabels = await github.rest.issues.listLabelsOnIssue(
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number
+ });
+
+ let add_labels = issueLabels.data.map( label => label.name );
+
+ let iss_title = `${{ steps.label_issues_urgent.outputs.issue_title }}` || `${ context.payload.issue.title }`;
+ let iss_body = `${ context.payload.issue.body }`;
+
+ const iss_title_lc = iss_title.toLowerCase( );
+
+ console.log( "Road Title .................... " + iss_title )
+ console.log( "Road Output ................... " + `${{ steps.label_issues_urgent.outputs.issue_title }}` )
+ console.log( "Road Payload .................. " + `${ context.payload.issue.title }` )
+
+ /*
+ Tags
+ */
+
+ const bug_tag = `${{ env.PREFIX_BUG }}:`;
+ const bug_lbl = `${{ env.LABEL_BUG }}`;
+ const feat_tag = `${{ env.PREFIX_FEATURE }}:`;
+ const feat_lbl = `${{ env.LABEL_FEATURE }}`;
+ const urgn_tag = `${{ env.PREFIX_URGENT }}:`;
+ const urgn_lbl = `${{ env.LABEL_URGENT }}`;
+ const road_tag = `${{ env.PREFIX_ROADMAP }}:`;
+ const road_lbl = `${{ env.LABEL_ROADMAP }}`;
+
+ /*
+ Roadmap
+ */
+
+ const words = [ "roadmap", "road map", "planned" ];
+ const bIncWordT = words.some( s => s.includes( iss_title_lc ) || iss_title_lc.includes( s ) );
+
+ /*
+ Find regex based phrases
+ Roadmap requires headers #Summary and #Proposal | #Objective
+
+ Regex:
+ https://regex101.com/r/ucajBZ/1
+ */
+
+ const findWordList = /#\s*Summary[\S\s]+#\s*(?:Proposal|Objective)[^\]]+/igm;
+ const bFoundMatchTitle = Boolean( findWordList.test( iss_title ) );
+ const bFoundMatchBody = Boolean( findWordList.test( iss_body ) );
+
+ /*
+ Do not change a title if the item starts with a PR: #
+
+ Regex:
+ https://regex101.com/r/JOrqbN/1
+ */
+
+ const road_findPRTitle = /^PR\s?#?(?:[0-9]*:)/igm;
+ const road_bFoundPRTitle = Boolean( road_findPRTitle.test( iss_title ) );
+
+ console.log( "Title Lowercase ............... " + iss_title_lc )
+ console.log( "Startswith " + road_tag.toLowerCase( ) + "............ " + iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+ console.log( "Title Includes Keyword ........ " + bIncWordT )
+ console.log( "Title Includes Regex .......... " + bFoundMatchTitle )
+ console.log( "Body Includes Regex ........... " + bFoundMatchBody )
+ console.log( "\n" )
+
+ /*
+ - Check if issue title matches the issue label "Roadmap:"
+ - Check if title contains word in words
+ */
+
+ // change TAG per category
+ if ( iss_title_lc.startsWith( road_tag.toLowerCase( ) ) || bIncWordT || bFoundMatchTitle || bFoundMatchBody )
+ {
+
+ console.log( "⚠️ " + road_tag + " ---------------------------------------" )
+ console.log( "Already starts with " + bug_tag + " ...... " + iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + feat_tag + " .. " + iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + urgn_tag + " ... " + iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) )
+ console.log( "Already starts with " + road_tag + " .. " + iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+
+ // change LBL per category
+ add_labels.push( `${ road_lbl }` );
+
+ console.log( `Adding Tag .................... ${ road_lbl }` )
+ console.log( "\n" )
+
+ if ( iss_author === `${{ env.BOT_NAME_DEPENDABOT }}` )
+ core.info( `Skipping: Detected ${ iss_author }` )
+
+ // Rename title to contain Roadmap:
+ // Make sure issue / pr title doesnt already contain a beginning title tag
+
+ if ( iss_author !== `${{ env.BOT_NAME_DEPENDABOT }}` && !road_bFoundPRTitle && !iss_title_lc.startsWith( bug_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( feat_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( urgn_tag.toLowerCase( ) ) && !iss_title_lc.startsWith( road_tag.toLowerCase( ) ) )
+ {
+ console.log( "Renaming Title" )
+ console.log( `Old Title: .................. ${ iss_title }` )
+
+ const title = context.payload.issue.title
+ let title_new = title.replace( /^\s?broad(.*?)\s?map\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?planned\s*(.*?)\b/gi, '' );
+ title_new = title.replace( /^\s?broadmap\s*(.*?)\b/gi, '' );
+ iss_title = `${ road_tag } ${ title_new }`; // change TAG per category
+ }
+
+ console.log( `New Title: .................... ${ iss_title }` )
+
+ await github.rest.issues.update(
+ {
+ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number,
+ title: `${ iss_title }`, labels: add_labels
+ } );
+ }
+
+ core.setOutput( 'issue_title', iss_title )
+ console.log( "\n\n" )
+
+ # ---------------------------------------------------------------------------------------
+ # Phrases - Search
+ # ---------------------------------------------------------------------------------------
+
+ issues-phrase-search:
+ name: >-
+ 🏷️ Labels › Phrase Search
+ needs:
+ - issues-preconfig-labels
+ runs-on: ubuntu-latest
+ permissions:
+ contents: 'read'
+ id-token: 'write'
+ issues: 'write'
+ environment:
+ name: Orion
+ steps:
+
+ # ---------------------------------------------------------------------------------------
+ # checkout
+ # ---------------------------------------------------------------------------------------
+
+ - name: "☑️ Prepare"
+ id: issues-labels-check-checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: 👄 Search Phrases
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+ const fs = require( 'fs' );
+ const iss_title = `${ context.payload.issue.title }`;
+ const iss_body = `${ context.payload.issue.body }`;
+ let message = [ "\n
\n" ]
+ let bHasMessage = false
+
+ /*********************************************
+ Keyword > OpenGist
+ **********************************************/
+
+ let OG_message =
+ `
+ ⚠️ It appears you may be looking for OpenGist help.
+ - [Opengist Repo](https://github.com/thomiceli/opengist)
+ - [Opengist Docs](https://github.com/thomiceli/opengist/blob/master/docs/index.md)
+ - [Opengist Demo](https://opengist.thomice.li/all)
+
+ If you are looking for OpenGist support, it will be very minimal. Please utilize the links above.
+
+ ---
+
+ I am a bot reaching out to you with an automated response. If the above info doesn't apply to you, please ignore it.
+ `;
+
+ /*
+ Check for keyword in message title and body
+ */
+
+ const OGfindWordList = /(\s*open\s*-?gist\s*)/ig;
+ const OGbFoundMatchTitle = Boolean( OGfindWordList.test( iss_title ) );
+ const OGbFoundMatchBody = Boolean( OGfindWordList.test( iss_body ) );
+
+ /*
+ found searched word "Opengist"
+ append / prepare message for bot to send
+ */
+
+ if ( OGbFoundMatchTitle || OGbFoundMatchBody )
+ {
+ message.push ( OG_message );
+ bHasMessage = true;
+ }
+
+ /*********************************************
+ Keyword > Help
+ **********************************************/
+
+ let HE_message =
+ `
+ 💡 It appears you might need help, please check the resources below for documentation that might assist with your issue:
+ - [Noxenv Documentation](https://aetherinox.github.io/noxenv)
+
+ ---
+
+ I am a bot reaching out to you with an automated response. If the above info doesn't apply to you, please ignore it.
+ `;
+
+ /*
+ found searched word "for help"
+ append / prepare message for bot to send
+ */
+
+ const HEfindWordList = /^\b(?:have\s*(?:a|some)?\s*question*s?)|(?:can\s*you\s*(?:tell|help)\s*me)|(?:need\s*(?:some)?\s*(?:help|assistance|guidance))|(?:how\s*can\s*I\s*find)|(?:point\s*me\s*in\s*the\s*direction)|(?:where\s*can\s*I\s*find)|(?:where\s*(?:\N*)\s*(?:\N*)\s*find)|(?:please\s*help)|(?:where\s*\N*\s*(?:located|at))|(?:documentation)\b$/igm;
+ const HEbFoundMatchTitle = Boolean( HEfindWordList.test( iss_title ) );
+ const HEbFoundMatchBody = Boolean( HEfindWordList.test( iss_body ) );
+
+ if ( HEbFoundMatchTitle || HEbFoundMatchBody )
+ {
+ message.push ( HE_message );
+ bHasMessage = true;
+ }
+
+ /*
+ Bot has message to send
+ */
+
+ if ( bHasMessage == true )
+ {
+ await github.rest.issues.createComment(
+ {
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: message.join('\n'),
+ } );
+ }
+
+ # ---------------------------------------------------------------------------------------
+ # Issues > Add Assignees
+ # ---------------------------------------------------------------------------------------
+
+ issues-assign-assignees:
+ name: >-
+ ✍️ Issue › Assignees
+ runs-on: ubuntu-latest
+ needs: [ issues-assign-labels ]
+ if: |
+ always()
+ && contains( needs.*.result, 'success' )
+ && !contains( needs.*.result, 'failure' )
+ permissions:
+ contents: write
+ steps:
+
+ - name: ✍️ Set Assignees
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+ const assignees = [ 'Aetherinox' ];
+
+ if ( assignees.length > 0 )
+ {
+ try
+ {
+ await github.rest.issues.addAssignees(
+ {
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ assignees
+ });
+ }
+ catch ( error )
+ {
+ core.setFailed( error.message );
+ }
+ }
diff --git a/.github/workflows/labels-create.yml b/.github/workflows/labels-create.yml
new file mode 100644
index 0000000..90f34c2
--- /dev/null
+++ b/.github/workflows/labels-create.yml
@@ -0,0 +1,151 @@
+# ---------------------------------------------------------------------------------------
+# @parent : github workflow
+# @desc : manually activated workflow to create issue labels
+# @author : Aetherinox
+# @url : https://github.com/Aetherinox
+# ---------------------------------------------------------------------------------------
+
+name: "🎫 Labels › Create"
+run-name: "🎫 Labels › Create"
+
+# ---------------------------------------------------------------------------------------
+# triggers
+# ---------------------------------------------------------------------------------------
+
+on:
+ workflow_dispatch:
+
+# ---------------------------------------------------------------------------------------
+# environment variables
+# ---------------------------------------------------------------------------------------
+
+env:
+ ASSIGN_USER: Aetherinox
+ BOT_NAME_1: AdminServ
+ BOT_NAME_2: AdminServX
+ BOT_NAME_3: EuropaServ
+ BOT_NAME_DEPENDABOT: dependabot[bot]
+ LABELS_JSON: |
+ [
+ { "name": "AC › Changes Made", "color": "8F1784", "description": "Requested changes have been made and are pending a re-scan" },
+ { "name": "AC › Changes Required", "color": "8F1784", "description": "Requires changes to be made to the package before being accepted" },
+ { "name": "AC › Failed", "color": "a61f2d", "description": "Autocheck failed to run through a complete cycle, requires investigation" },
+ { "name": "AC › Needs Rebase", "color": "8F1784", "description": "Due to the permissions on the requesting repo, this pull request must be rebased by the author" },
+ { "name": "AC › Passed", "color": "146b4a", "description": "Ready to be reviewed" },
+ { "name": "AC › Review Required", "color": "8F1784", "description": "PR needs to be reviewed by another person, after the requested changes have been made" },
+ { "name": "AC › Security Warning", "color": "761620", "description": "Does not conform to developer policies, or includes potentially dangerous code" },
+ { "name": "AC › Skipped Scan", "color": "8F1784", "description": "Author has skipped code scan" },
+ { "name": "Status 𐄂 Duplicate", "color": "75536b", "description": "Issue or pull request already exists" },
+ { "name": "Status 𐄂 Accepted", "color": "2e7539", "description": "This pull request has been accepted" },
+ { "name": "Status 𐄂 Autoclosed", "color": "3E0915", "description": "Originally stale and was autoclosed for no activity" },
+ { "name": "Status 𐄂 Denied", "color": "ba4058", "description": "Pull request has been denied" },
+ { "name": "Status 𐄂 Locked", "color": "550F45", "description": "Automatically locked by AdminServ for a prolonged period of inactivity" },
+ { "name": "Status 𐄂 Need Info", "color": "2E3C4C", "description": "Not enough information to resolve" },
+ { "name": "Status 𐄂 No Action", "color": "030406", "description": "Closed without any action being taken" },
+ { "name": "Status 𐄂 Pending", "color": "984b12", "description": "Pending pull request" },
+ { "name": "Status 𐄂 Released", "color": "1b6626", "description": "Issues or PR has been implemented and is now live" },
+ { "name": "Status 𐄂 Reopened", "color": "8a6f14", "description": "A previously closed PR which has been re-opened" },
+ { "name": "Status 𐄂 Review", "color": "9e1451", "description": "Currently pending review" },
+ { "name": "Status 𐄂 Stale", "color": "928282", "description": "Has not had any activity in over 30 days" },
+ { "name": "Type ◦ Bug", "color": "9a2c2c", "description": "Something isn't working" },
+ { "name": "Type ◦ Dependency", "color": "243759", "description": "Item is associated to dependency" },
+ { "name": "Type ◦ Docs", "color": "0e588d", "description": "Improvements or modifications to docs" },
+ { "name": "Type ◦ Feature", "color": "3c4e93", "description": "Feature request" },
+ { "name": "Type ◦ Git Action", "color": "030406", "description": "GitHub Action / workflow" },
+ { "name": "Type ◦ Pull Request", "color": "8F1784", "description": "Normal pull request" },
+ { "name": "Type ◦ Roadmap", "color": "8F1784", "description": "Feature or bug currently planned for implementation" },
+ { "name": "Type ◦ Internal", "color": "A51994", "description": "Assigned items are for internal developer use." },
+ { "name": "Build ◦ Desktop", "color": "c7ca4a", "description": "Specific to desktop" },
+ { "name": "Build ◦ Linux", "color": "c7ca4a", "description": "Specific to Linux" },
+ { "name": "Build ◦ MacOS", "color": "c7ca4a", "description": "Specific to MacOS" },
+ { "name": "Build ◦ Mobile", "color": "c7ca4a", "description": "Specific to mobile" },
+ { "name": "Build ◦ Web", "color": "c7ca4a", "description": "Specific to web" },
+ { "name": "Build ◦ Windows", "color": "c7ca4a", "description": "Specific to Windows" },
+ { "name": "› API", "color": "F99B50", "description": "Plugin API, CLI, browser JS API" },
+ { "name": "› Auto-type", "color": "9141E0", "description": "Auto-type functionality in desktop apps" },
+ { "name": "› Browser", "color": "9141E0", "description": "Browser plugins and passing data to <=> from KeeWeb" },
+ { "name": "› Customization", "color": "E3F0FC", "description": "Customizing KeeWeb: plugins, themes, configs" },
+ { "name": "› Design", "color": "FA70DE", "description": "Design related queries" },
+ { "name": "› Dist", "color": "FA70DE", "description": "Installers and other forms of software distribution" },
+ { "name": "› Enterprise", "color": "11447a", "description": "Issues about collaboration, administration, and so on" },
+ { "name": "› Hardware", "color": "5a7503", "description": "YubiKey, other tokens, biometrics" },
+ { "name": "› Import/Export", "color": "F5FFCC", "description": "Import from and export to different file formats" },
+ { "name": "› kdbxweb", "color": "eb6420", "description": "Core library: https://github.com/keeweb/kdbxweb" },
+ { "name": "› Performance", "color": "006b75", "description": "Web and desktop performance issues" },
+ { "name": "› Plugin Request", "color": "FCE9CA", "description": "Requested changes should be implemented as a plugin" },
+ { "name": "› Security", "color": "F75D39", "description": "Security issues" },
+ { "name": "› Self-Hosting", "color": "fad8c7", "description": "Self-hosting installations and configs" },
+ { "name": "› Storage", "color": "5319e7", "description": "Storage providers: Dropbox, Google, WebDAV, etc." },
+ { "name": "› Updater", "color": "1BADDE", "description": "Auto-updater issues" },
+ { "name": "› UX", "color": "1BADDE", "description": "UX and usability" },
+ { "name": "› Website", "color": "fef2c0", "description": "Website https://keeweb.info" },
+ { "name": "⚠ Urgent", "color": "a8740e", "description": "Requires urgent attention" },
+ { "name": "⚠ Announcement", "color": "DB4712", "description": "KeeWeb announcements" },
+ { "name": "📰 Progress Report", "color": "392297", "description": "Updates on the development of KeeWeb" },
+ { "name": "📦 Release", "color": "277542", "description": "Release announcements" },
+ { "name": "✔️ Poll", "color": "972255", "description": "Community polls" },
+ { "name": "❔ Question", "color": "FFFFFF", "description": "All questions" }
+ ]
+
+jobs:
+
+ # ---------------------------------------------------------------------------------------
+ # Verify Existing Labels
+ # This job will ensure you have labels already created in your repo.
+ #
+ # All labels come from the JSON table LABELS_JSON.
+ # ---------------------------------------------------------------------------------------
+
+ issues-labels-create:
+ name: 🎫 Labels › Create
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: "✅ Start"
+ run: |
+ echo "Assigning labels and assignees"
+
+ # ---------------------------------------------------------------------------------------
+ # checkout
+ # ---------------------------------------------------------------------------------------
+
+ - name: "☑️ Checkout"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ # ---------------------------------------------------------------------------------------
+ # Check if repo has labels currently added to issues
+ # ---------------------------------------------------------------------------------------
+
+ - name: 🏷️ Verify Existing Labels
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.ADMINSERV_TOKEN_CL }}
+ script: |
+ const labels = JSON.parse( process.env.LABELS_JSON );
+ for ( const label of labels )
+ {
+ try
+ {
+ await github.rest.issues.createLabel(
+ {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ name: label.name,
+ description: label.description || '',
+ color: label.color
+ });
+ }
+ catch ( err )
+ {
+ if ( err.status === 422 )
+ {
+ console.log( `Label '${label.name}' already exists. Skipping.` );
+ }
+ else
+ {
+ console.error( `Error creating label '${label.name}': ${err}` );
+ }
+ }
+ }