diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index e78071a1..85617d07 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -1,7 +1,7 @@ name: 🐛 Bug Report description: Report a reproducible bug or regression. type: bug -labels: ['status: unconfirmed', bug] +labels: [triage] title: 'Bug: ' body: - type: markdown @@ -33,9 +33,11 @@ body: - HTML (@videojs/html) - React (@videojs/react) - Utils (@videojs/utils) + - HTML Example + - React Example + - Next.js Example - Website - - Example / Demo Apps (html-demo, react-demo, next-demo) - - Other/unknown (please mention in description) + - Other (please mention in description) - type: textarea id: environment validations: diff --git a/.github/ISSUE_TEMPLATE/2.feature_request.yml b/.github/ISSUE_TEMPLATE/2.feature_request.yml index 4349ee13..49b479e5 100644 --- a/.github/ISSUE_TEMPLATE/2.feature_request.yml +++ b/.github/ISSUE_TEMPLATE/2.feature_request.yml @@ -1,7 +1,7 @@ name: 💎 Feature Request description: Request a new feature or enhancement type: enhancement -labels: [] +labels: [triage] title: 'Feature Request: ' body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/3.docs_feedback.yml b/.github/ISSUE_TEMPLATE/3.docs_feedback.yml index 48eafe4b..2af04a2b 100644 --- a/.github/ISSUE_TEMPLATE/3.docs_feedback.yml +++ b/.github/ISSUE_TEMPLATE/3.docs_feedback.yml @@ -1,6 +1,6 @@ name: 📄 Docs Feedback description: Report a discrepancy in or an improvement to the docs. -labels: [documentation] +labels: [triage, docs] title: 'Docs: ' body: - type: markdown diff --git a/.github/scripts/label-issue.js b/.github/scripts/label-issue.js new file mode 100644 index 00000000..a5d95b74 --- /dev/null +++ b/.github/scripts/label-issue.js @@ -0,0 +1,114 @@ +import core from '@actions/core'; +import github from '@actions/github'; + +// eslint-disable-next-line node/prefer-global/process +const GH_TOKEN = process.env.GITHUB_TOKEN; + +const pkgLabel = { + 'Core (@videojs/core)': 'pkg:core', + 'Icons (@videojs/icons)': 'pkg:icons', + 'HTML (@videojs/html)': 'pkg:html', + 'React (@videojs/react)': 'pkg:react', + 'Utils (@videojs/utils)': 'pkg:utils', + 'HTML Example': 'example:html', + 'React Example': 'example:react', + 'Next.js Example': 'example:next.js', + Website: 'site', +}; + +const envLabel = { + // Browsers + chrome: 'browser:chrome', + chromium: 'browser:chrome', + firefox: 'browser:firefox', + safari: 'browser:safari', + edge: 'browser:edge', + msedge: 'browser:edge', + // OS + macos: 'os:mac', + 'mac os': 'os:mac', + darwin: 'os:mac', + windows: 'os:windows', + win32: 'os:windows', + win10: 'os:windows', + linux: 'os:linux', + ubuntu: 'os:linux', + debian: 'os:linux', + android: 'os:android', + ios: 'os:ios', + iphone: 'os:ios', + ipad: 'os:ios', +}; + +async function run() { + try { + const { issue } = github.context.payload; + + if (!issue || !issue.body) { + console.log('No issue body found, skipping.'); + return; + } + + const labels = new Set(); + + const pkg = extractSection(issue, '### Which package(s) or projects are affected?'); + if (pkg) { + for (const [option, label] of Object.entries(pkgLabel)) { + if (pkg.includes(option)) { + labels.add(label); + } + } + } + + const env = extractSection(issue, '### Browser/OS/Node environment'); + if (env) { + const envText = env.toLowerCase(); + for (const [keyword, label] of Object.entries(envLabel)) { + if (envText.includes(keyword)) { + labels.add(label); + } + } + } + + if (labels.size === 0) { + console.log('No matching labels found.'); + return; + } + + console.log(`Matched labels: ${Array.from(labels).join(', ')}`); + + // eslint-disable-next-line node/prefer-global/process + if (process.env.DRY_RUN === 'true') { + console.log('⚠️ DRY RUN: Skipping API call.'); + return; + } + + if (!GH_TOKEN) { + throw new Error('GITHUB_TOKEN is not set'); + } + + const octokit = github.getOctokit(GH_TOKEN); + + await octokit.rest.issues.addLabels({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + issue_number: issue.number, + labels: Array.from(labels), + }); + } catch (error) { + core.setFailed(`Action failed with error: ${error}`); + } +} + +/** + * @param {*} issue + * @param {string} header + */ +function extractSection(issue, header) { + const escapedHeader = header.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regex = new RegExp(`${escapedHeader}\\r?\\n([\\s\\S]*?)(?=\\r?\\n###|$)`, 'i'); + const match = issue.body.match(regex); + return match ? match[1].trim() : null; +}; + +run(); diff --git a/.github/workflows/label-issue.yml b/.github/workflows/label-issue.yml new file mode 100644 index 00000000..a019e23a --- /dev/null +++ b/.github/workflows/label-issue.yml @@ -0,0 +1,32 @@ +name: Label Issue +on: + issues: + types: [opened, edited] + +permissions: + issues: write + contents: read + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 22 + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Run + run: node .github/scripts/label-issue.js + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/commitlint.config.js b/commitlint.config.js index c67ed3d6..be55bfcc 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -16,6 +16,7 @@ export default { 'docs', 'example/html', 'example/react', + 'example/next', 'html', 'icons', 'packages', diff --git a/package.json b/package.json index e609c66d..12010722 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "typecheck": "pnpm run generate:icons && tsc --build --noEmit" }, "devDependencies": { + "@actions/core": "^1.11.1", + "@actions/github": "^6.0.1", "@antfu/eslint-config": "^5.4.1", "@commitlint/cli": "^20.1.0", "@commitlint/config-conventional": "^20.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddf761ad..e7fbbe09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,12 @@ importers: .: devDependencies: + '@actions/core': + specifier: ^1.11.1 + version: 1.11.1 + '@actions/github': + specifier: ^6.0.1 + version: 6.0.1 '@antfu/eslint-config': specifier: ^5.4.1 version: 5.4.1(@eslint-react/eslint-plugin@1.53.1(eslint@9.37.0(jiti@2.6.1))(ts-api-utils@2.1.0(typescript@5.9.2))(typescript@5.9.2))(@prettier/plugin-xml@3.4.2(prettier@3.6.2))(@vue/compiler-sfc@3.5.21)(astro-eslint-parser@1.2.2)(eslint-plugin-astro@1.3.1(eslint@9.37.0(jiti@2.6.1)))(eslint-plugin-format@1.0.2(eslint@9.37.0(jiti@2.6.1)))(eslint-plugin-jsx-a11y@6.10.2(eslint@9.37.0(jiti@2.6.1)))(eslint-plugin-react-hooks@6.1.1(eslint@9.37.0(jiti@2.6.1)))(eslint-plugin-react-refresh@0.4.23(eslint@9.37.0(jiti@2.6.1)))(eslint@9.37.0(jiti@2.6.1))(prettier-plugin-astro@0.14.1)(typescript@5.9.2)(vitest@3.2.4) @@ -417,6 +423,21 @@ importers: packages: + '@actions/core@1.11.1': + resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} + + '@actions/exec@1.1.1': + resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==} + + '@actions/github@6.0.1': + resolution: {integrity: sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==} + + '@actions/http-client@2.2.3': + resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} + + '@actions/io@1.1.3': + resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} + '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} @@ -1044,6 +1065,10 @@ packages: resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -1365,6 +1390,54 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@octokit/auth-token@4.0.0': + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + + '@octokit/core@5.2.2': + resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} + engines: {node: '>= 18'} + + '@octokit/endpoint@9.0.6': + resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} + engines: {node: '>= 18'} + + '@octokit/graphql@7.1.1': + resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} + engines: {node: '>= 18'} + + '@octokit/openapi-types@20.0.0': + resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==} + + '@octokit/openapi-types@24.2.0': + resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} + + '@octokit/plugin-paginate-rest@9.2.2': + resolution: {integrity: sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-rest-endpoint-methods@10.4.1': + resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/request-error@5.1.1': + resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} + engines: {node: '>= 18'} + + '@octokit/request@8.4.1': + resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} + engines: {node: '>= 18'} + + '@octokit/types@12.6.0': + resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==} + + '@octokit/types@13.10.0': + resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} + '@open-wc/context-protocol@0.0.9': resolution: {integrity: sha512-3mMJ16BbRqFaZNR7ongBJEEvAjZFBpo5qUtc2dk/rlk3k09AVRp2Dcldu5VTB0r/tsWdfExbRLlCw/8f3cD/kQ==} @@ -2711,6 +2784,9 @@ packages: resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} hasBin: true + before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -3086,6 +3162,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -5852,6 +5931,10 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + turbo-darwin-64@2.5.8: resolution: {integrity: sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ==} cpu: [x64] @@ -5953,6 +6036,10 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@5.29.0: + resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} + engines: {node: '>=14.0'} + unicode-properties@1.4.1: resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} @@ -5999,6 +6086,9 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -6397,6 +6487,32 @@ packages: snapshots: + '@actions/core@1.11.1': + dependencies: + '@actions/exec': 1.1.1 + '@actions/http-client': 2.2.3 + + '@actions/exec@1.1.1': + dependencies: + '@actions/io': 1.1.3 + + '@actions/github@6.0.1': + dependencies: + '@actions/http-client': 2.2.3 + '@octokit/core': 5.2.2 + '@octokit/plugin-paginate-rest': 9.2.2(@octokit/core@5.2.2) + '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.2) + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + undici: 5.29.0 + + '@actions/http-client@2.2.3': + dependencies: + tunnel: 0.0.6 + undici: 5.29.0 + + '@actions/io@1.1.3': {} + '@adobe/css-tools@4.4.4': {} '@alloc/quick-lru@5.2.0': {} @@ -7186,6 +7302,8 @@ snapshots: '@eslint/core': 0.16.0 levn: 0.4.1 + '@fastify/busboy@2.1.1': {} + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -7465,6 +7583,64 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@octokit/auth-token@4.0.0': {} + + '@octokit/core@5.2.2': + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.1.1 + '@octokit/request': 8.4.1 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + + '@octokit/endpoint@9.0.6': + dependencies: + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/graphql@7.1.1': + dependencies: + '@octokit/request': 8.4.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/openapi-types@20.0.0': {} + + '@octokit/openapi-types@24.2.0': {} + + '@octokit/plugin-paginate-rest@9.2.2(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.2)': + dependencies: + '@octokit/core': 5.2.2 + '@octokit/types': 12.6.0 + + '@octokit/request-error@5.1.1': + dependencies: + '@octokit/types': 13.10.0 + deprecation: 2.3.1 + once: 1.4.0 + + '@octokit/request@8.4.1': + dependencies: + '@octokit/endpoint': 9.0.6 + '@octokit/request-error': 5.1.1 + '@octokit/types': 13.10.0 + universal-user-agent: 6.0.1 + + '@octokit/types@12.6.0': + dependencies: + '@octokit/openapi-types': 20.0.0 + + '@octokit/types@13.10.0': + dependencies: + '@octokit/openapi-types': 24.2.0 + '@open-wc/context-protocol@0.0.9': {} '@oslojs/encoding@1.1.0': {} @@ -8869,6 +9045,8 @@ snapshots: baseline-browser-mapping@2.8.6: {} + before-after-hook@2.2.3: {} + bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 @@ -9219,6 +9397,8 @@ snapshots: defu@6.1.4: {} + deprecation@2.3.1: {} + dequal@2.0.3: {} destr@2.0.5: {} @@ -12776,6 +12956,8 @@ snapshots: tslib@2.8.1: {} + tunnel@0.0.6: {} + turbo-darwin-64@2.5.8: optional: true @@ -12885,6 +13067,10 @@ snapshots: undici-types@6.21.0: {} + undici@5.29.0: + dependencies: + '@fastify/busboy': 2.1.1 + unicode-properties@1.4.1: dependencies: base64-js: 1.5.1 @@ -12959,6 +13145,8 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + universal-user-agent@6.0.1: {} + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4