From 53c32297d2720c8d1a9ccf6ebaf24e3616ba5fb9 Mon Sep 17 00:00:00 2001 From: Elara Liu <40444637+ZL-Asica@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:46:41 -0600 Subject: [PATCH] feat: add global error handling. (#13) * ci: update PR labelers. * feat: add global error handling. --- .github/workflows/code-lint-format.yml | 4 + .github/workflows/label-pr-based-on-paths.yml | 91 ++++++++++++++++++ .github/workflows/label-pr-size.yml.yml | 93 +++++++++++++++++++ app.vue | 20 +--- components/layout/SiteHeader.vue | 7 +- components/pages/EventList.vue | 4 +- components/pages/SocialLinks.vue | 4 +- error.vue | 43 +++++++++ i18n/locales/en.json | 15 +++ i18n/locales/zh.json | 15 +++ layouts/default.vue | 14 +++ 11 files changed, 287 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/label-pr-based-on-paths.yml create mode 100644 .github/workflows/label-pr-size.yml.yml create mode 100644 error.vue create mode 100644 layouts/default.vue diff --git a/.github/workflows/code-lint-format.yml b/.github/workflows/code-lint-format.yml index b7a4bba..d257c64 100644 --- a/.github/workflows/code-lint-format.yml +++ b/.github/workflows/code-lint-format.yml @@ -16,6 +16,10 @@ jobs: build-and-deploy: name: 🛠️ Code linter and formatter runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: write steps: - name: 📥 Checkout Code diff --git a/.github/workflows/label-pr-based-on-paths.yml b/.github/workflows/label-pr-based-on-paths.yml new file mode 100644 index 0000000..b8ee98c --- /dev/null +++ b/.github/workflows/label-pr-based-on-paths.yml @@ -0,0 +1,91 @@ +name: Auto-label PR based on file paths + +on: + pull_request: + types: [opened, synchronize] + +jobs: + label: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Label PR based on changes with colors + uses: actions/github-script@v7 + with: + script: | + const prFiles = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + + // Define the labels and their colors + const labelsToColor = { + components: '1f77b4', // Blue - Components Related + pages: 'ff7f0e', // Orange - Pages Related + stores: '2ca02c', // Green - Stores Related (for Vuex or Pinia) + server: '9467bd', // Purple - Server Related + layouts: 'ffdd57', // Yellow - Layouts Related + assets: 'd62728', // Red - Assets Related + i18n: '8c564b', // Brown - i18n Related + types: 'e377c2', // Pink - Types Related + dependencies: 'e377c2', // Pink - Dependencies Related + }; + + const labels = new Set(); + + const labelPaths = { + components: 'components', + pages: ['pages', 'app.vue'], + stores: ['store', 'stores'], + server: 'server', + layouts: 'layouts', + assets: ['public', 'assets'], + i18n: 'i18n', + types: 'types', + dependencies: ['package.json', 'pnpm-lock.yaml'] + }; + + prFiles.data.forEach(file => { + Object.keys(labelPaths).forEach(label => { + const paths = Array.isArray(labelPaths[label]) ? labelPaths[label] : [labelPaths[label]]; + if (paths.some(path => file.filename.startsWith(path))) { + labels.add(label); + } + }); + }); + + if (labels.size > 0) { + for (const label of labels) { + try { + // Check if the label exists + await github.rest.issues.getLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: label + }); + } catch (error) { + // If label doesn't exist, create it with the specified color + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: label, + color: labelsToColor[label] || 'b0b0b0', // Use default gray if no color specified + }); + } + } + + // Add labels to the PR + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: Array.from(labels) + }); + } diff --git a/.github/workflows/label-pr-size.yml.yml b/.github/workflows/label-pr-size.yml.yml new file mode 100644 index 0000000..521c51f --- /dev/null +++ b/.github/workflows/label-pr-size.yml.yml @@ -0,0 +1,93 @@ +name: size-label + +on: + pull_request: + types: [opened, synchronize] + +jobs: + size-label: + permissions: + contents: read + pull-requests: write + issues: write + runs-on: ubuntu-latest + + steps: + - name: 🛎️ Checkout repository + uses: actions/checkout@v4 + + - name: Determine PR size and add label + id: size-label + uses: pascalgn/size-label-action@v0.5.5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + IGNORED: | + yarn.lock + package-lock.json + pnpm-lock.yaml + package.json + .pnp.* + dist/ + build/ + .cache/ + LICENSE + + with: + sizes: > + { + "0": "XS", + "50": "S", + "150": "M", + "500": "L", + "1000": "XL", + "3000": "XXL" + } + + - name: Set label colors + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labelsToColor = { + 'XS': 'd4c5f9', // Light purple + 'S': 'c2e0c6', // Light green + 'M': 'f9d0c4', // Light red + 'L': 'f7c6c7', // Light pink + 'XL': 'fef2c0', // Light yellow + 'XXL': 'e99695', // Light coral + }; + + const sizeLabel = ${{ steps.size-label.outputs.sizeLabel }}; + const color = labelsToColor[sizeLabel] || 'b0b0b0'; + + if (sizeLabel) { + try { + await github.rest.issues.updateLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: sizeLabel, + color: color, + }); + } catch (error) { + // Label doesn't exist, create it + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: sizeLabel, + color: color, + }); + } + } + + - name: Comment on large PRs + if: ${{ contains('XL XXL', steps.size-label.outputs.sizeLabel) }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: "This PR is too large and may need to be broken into smaller pieces." + }); diff --git a/app.vue b/app.vue index 890b965..c298060 100644 --- a/app.vue +++ b/app.vue @@ -1,24 +1,12 @@ diff --git a/i18n/locales/en.json b/i18n/locales/en.json index 8436ad6..69767b1 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -20,5 +20,20 @@ "language": "Switch language", "link": "Click to visit %{link}", "external": "Open in a new tab" + }, + "error": { + "backToHome": "Back to home", + "unauthorized": { + "title": "(¬_¬) Unauthorized", + "description": "Sorry, you need to log in or authorize to access this page 🔑" + }, + "notFound": { + "title": "(;′⌒`) Page not found", + "description": "Sorry, the page you are looking for is missing or never existed 🔍" + }, + "default": { + "title": "(╥﹏╥) Server error", + "description": "Sorry, something went wrong on our end, we are working on it 🛠️" + } } } diff --git a/i18n/locales/zh.json b/i18n/locales/zh.json index 746bb57..e3afbc1 100644 --- a/i18n/locales/zh.json +++ b/i18n/locales/zh.json @@ -20,5 +20,20 @@ "language": "切换语言", "link": "点击跳转至 %{title}", "external": "此链接将在新标签页中打开" + }, + "error": { + "backToHome": "返回首页", + "unauthorized": { + "title": "(¬_¬) 未授权", + "description": "抱歉,您需要登录或授权才能访问这个页面 🔑" + }, + "notFound": { + "title": "(;′⌒`) 页面迷路啦~", + "description": "抱歉,您要找的页面已经不见了,或者它从未存在过 🔍" + }, + "default": { + "title": "(╥﹏╥) 服务器出错啦~", + "description": "抱歉,内部出现了一点问题,我们正在抢修 🛠️" + } } } diff --git a/layouts/default.vue b/layouts/default.vue new file mode 100644 index 0000000..994e03b --- /dev/null +++ b/layouts/default.vue @@ -0,0 +1,14 @@ +