├── .github ├── labeler.yml └── workflows │ ├── build.yml │ ├── node.yml │ ├── release-scheduler.yml │ ├── release.yml │ └── stale.yml ├── .gitignore ├── .npmignore ├── .prettierrc.cjs ├── CHANGELOG.md ├── LICENSE ├── README.md ├── action.yml ├── api.json ├── assets ├── book-title-in-issue.png ├── icon.svg ├── issue-bot-comment.png ├── issue-close-completed.png ├── issue-title-progress.png ├── issues.png ├── logo.svg ├── new-book-in-shelf.png ├── new-issue.png └── readme-demo.png ├── dist ├── exec-child.js ├── features │ ├── close-issue.d.ts │ ├── close-issue.js │ ├── close-issue.js.map │ ├── issue-comment.d.ts │ ├── issue-comment.js │ ├── issue-comment.js.map │ ├── new-issue.d.ts │ ├── new-issue.js │ ├── new-issue.js.map │ ├── update-summary.d.ts │ ├── update-summary.js │ └── update-summary.js.map ├── github.d.ts ├── github.js ├── github.js.map ├── goodreads.d.ts ├── goodreads.js ├── goodreads.js.map ├── google-books.d.ts ├── google-books.js ├── google-books.js.map ├── index.d.ts ├── index.js ├── index.js.map ├── index.spec.d.ts ├── index.spec.js ├── index.spec.js.map └── sourcemap-register.js ├── jest.config.js ├── package-lock.json ├── package.json ├── release.config.js ├── src ├── features │ ├── close-issue.ts │ ├── issue-comment.ts │ ├── new-issue.ts │ └── update-summary.ts ├── github.ts ├── google-books.ts ├── index.spec.ts └── index.ts └── tsconfig.json /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | config: 2 | - ./* 3 | tooling: 4 | - tooling/**/*.* 5 | assets: 6 | - static/**/*.* 7 | tests: 8 | - any: ["src/**/*.spec.js", "cypress/**/*"] 9 | package: 10 | - any: ["package.json", "package-lock.json"] 11 | source: 12 | - src/**/* 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | name: Build and publish 11 | runs-on: ubuntu-latest 12 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | with: 17 | ref: ${{ github.head_ref }} 18 | token: ${{ secrets.GH_PAT }} 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: 18 24 | cache: 'npm' 25 | 26 | - name: Install dependencies 27 | run: npm ci 28 | 29 | - name: Build TypeScript 30 | run: npm run build 31 | 32 | - name: Run tests 33 | run: npm run test 34 | 35 | - name: Build package 36 | run: npm run package 37 | 38 | - name: Publish package 39 | uses: stefanzweifel/git-auto-commit-action@v4.9.2 40 | with: 41 | commit_message: ":rocket: Deploy new version [skip ci]" 42 | commit_user_name: Finding Anand 43 | commit_user_email: bot@anandchowdhary.com 44 | commit_author: Finding Anand 45 | -------------------------------------------------------------------------------- /.github/workflows/node.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - master 7 | 8 | jobs: 9 | release: 10 | name: Build and test 11 | runs-on: ubuntu-latest 12 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Setup Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: 18 21 | cache: 'npm' 22 | 23 | - name: Install dependencies 24 | run: npm ci 25 | 26 | - name: Build TypeScript 27 | run: npm run build 28 | 29 | - name: Run tests 30 | run: npm run test 31 | -------------------------------------------------------------------------------- /.github/workflows/release-scheduler.yml: -------------------------------------------------------------------------------- 1 | name: Release Scheduler CI 2 | on: 3 | schedule: 4 | - cron: "0 0 * * 1" 5 | workflow_dispatch: 6 | jobs: 7 | releaseScheduler: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Run release-scheduler 11 | uses: koj-co/release-scheduler@master 12 | env: 13 | GH_PAT: ${{ secrets.GH_PAT }} 14 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release CI 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | name: Build, test, and release 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | with: 14 | ref: ${{ github.head_ref }} 15 | token: ${{ secrets.GH_PAT }} 16 | 17 | - name: Setup Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: 18 21 | 22 | - name: Install dependencies 23 | run: npm ci 24 | 25 | - name: Release 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GH_PAT }} 28 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 29 | run: npx semantic-release 30 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Stale Issues CI" 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" 5 | jobs: 6 | stale: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/stale@v3 10 | with: 11 | repo-token: ${{ secrets.GH_PAT }} 12 | stale-issue-message: "⚠️ This issue has not seen any activity in the past 2 months so I'm marking it as stale. I'll close it if it doesn't see any activity in the coming week." 13 | stale-pr-message: "⚠️ This PR has not seen any activity in the past 2 months so I'm marking it as stale. I'll close it if it doesn't see any activity in the coming week." 14 | days-before-stale: 60 15 | days-before-close: 7 16 | stale-issue-label: "wontfix" 17 | exempt-issue-labels: "wip" 18 | stale-pr-label: "wontfix" 19 | exempt-pr-labels: "wip" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | 84 | # Gatsby files 85 | .cache/ 86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # public 89 | 90 | # vuepress build output 91 | .vuepress/dist 92 | 93 | # Serverless directories 94 | .serverless/ 95 | 96 | # FuseBox cache 97 | .fusebox/ 98 | 99 | # DynamoDB Local files 100 | .dynamodb/ 101 | 102 | # TernJS port file 103 | .tern-port 104 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .licenses 3 | .github 4 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@koj/config").prettier; 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v1.1.0 (2023-01-14) 2 | 3 | [📝 Release notes](https://github.com/AnandChowdhary/bookshelf-action/releases/tag/v1.1.0) · [💻 Compare](https://github.com/AnandChowdhary/bookshelf-action/compare/v1.0.2...v1.1.0) · [🔖 Tag](https://github.com/AnandChowdhary/bookshelf-action/tree/v1.1.0) · 🗄️ Archive ([zip](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.1.0.zip) · [tar.gz](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.1.0.tar.gz)) 4 | 5 | ### ✨ New features 6 | 7 | - [`19a0050`](https://github.com/AnandChowdhary/bookshelf-action/commit/19a0050) Add command for only updating summary 8 | - [`ba63961`](https://github.com/AnandChowdhary/bookshelf-action/commit/ba63961) Sort books reverse-chronologically 9 | - [`5931bc1`](https://github.com/AnandChowdhary/bookshelf-action/commit/5931bc1) Add "Want to read" (#96) 10 | (Issues: [`#96`](https://github.com/AnandChowdhary/bookshelf-action/issues/96)) 11 | 12 | ### 🐛 Bug fixes 13 | 14 | - [`27edabc`](https://github.com/AnandChowdhary/bookshelf-action/commit/27edabc) Ensure comment body exists 15 | - [`4b73ff6`](https://github.com/AnandChowdhary/bookshelf-action/commit/4b73ff6) Fix fallback cover URL 16 | - [`393b5c6`](https://github.com/AnandChowdhary/bookshelf-action/commit/393b5c6) Add new line before heading, fixed #108 17 | (Issues: [`#108`](https://github.com/AnandChowdhary/bookshelf-action/issues/108)) 18 | 19 | ### ⬆️ Dependency updates 20 | 21 | - [`17d0561`](https://github.com/AnandChowdhary/bookshelf-action/commit/17d0561) Bump stefanzweifel/git-auto-commit-action 22 | - [`ed524de`](https://github.com/AnandChowdhary/bookshelf-action/commit/ed524de) Bump actions/setup-node from v2.1.4 to v2.1.5 23 | - [`3912cf2`](https://github.com/AnandChowdhary/bookshelf-action/commit/3912cf2) Bump typescript from 4.1.5 to 4.2.2 24 | - [`73858c3`](https://github.com/AnandChowdhary/bookshelf-action/commit/73858c3) Bump ts-jest from 26.5.1 to 26.5.2 25 | - [`3c755f0`](https://github.com/AnandChowdhary/bookshelf-action/commit/3c755f0) Bump stefanzweifel/git-auto-commit-action 26 | - [`ea04fb5`](https://github.com/AnandChowdhary/bookshelf-action/commit/ea04fb5) Bump semantic-release from 17.3.9 to 17.4.0 27 | - [`e636906`](https://github.com/AnandChowdhary/bookshelf-action/commit/e636906) Bump got from 11.8.1 to 11.8.2 28 | - [`2b514be`](https://github.com/AnandChowdhary/bookshelf-action/commit/2b514be) Bump semantic-release from 17.4.0 to 17.4.1 29 | - [`8318fb1`](https://github.com/AnandChowdhary/bookshelf-action/commit/8318fb1) Bump ts-jest from 26.5.2 to 26.5.3 30 | - [`73454fa`](https://github.com/AnandChowdhary/bookshelf-action/commit/73454fa) Bump stefanzweifel/git-auto-commit-action 31 | - [`7b1adb8`](https://github.com/AnandChowdhary/bookshelf-action/commit/7b1adb8) Bump typescript from 4.2.2 to 4.2.3 32 | - [`77aa071`](https://github.com/AnandChowdhary/bookshelf-action/commit/77aa071) Update all dependencies 33 | 34 | ## v1.0.2 (2021-02-20) 35 | 36 | [📝 Release notes](https://github.com/AnandChowdhary/bookshelf-action/releases/tag/v1.0.2) · [💻 Compare](https://github.com/AnandChowdhary/bookshelf-action/compare/v1.0.1...v1.0.2) · [🔖 Tag](https://github.com/AnandChowdhary/bookshelf-action/tree/v1.0.2) · 🗄️ Archive ([zip](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.0.2.zip) · [tar.gz](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.0.2.tar.gz)) 37 | 38 | ### ♻️ Updates 39 | 40 | - [`84f122b`](https://github.com/AnandChowdhary/bookshelf-action/commit/84f122b) Use resized images in README 41 | - [`7eece75`](https://github.com/AnandChowdhary/bookshelf-action/commit/7eece75) Iterate over all labels paginated 42 | 43 | ### 🐛 Bug fixes 44 | 45 | - [`654257d`](https://github.com/AnandChowdhary/bookshelf-action/commit/654257d) Support fallback images 46 | - [`ea055b5`](https://github.com/AnandChowdhary/bookshelf-action/commit/ea055b5) Ensure identifiers exist 47 | - [`5c00354`](https://github.com/AnandChowdhary/bookshelf-action/commit/5c00354) Remove " in names 48 | 49 | ### ⬆️ Dependency updates 50 | 51 | - [`09c5e6e`](https://github.com/AnandChowdhary/bookshelf-action/commit/09c5e6e) Bump pascalgn/automerge-action from v0.13.0 to v0.13.1 52 | - [`4b3b027`](https://github.com/AnandChowdhary/bookshelf-action/commit/4b3b027) Bump vsoch/pull-request-action from 1.0.13 to 1.0.14 53 | - [`9eabb3d`](https://github.com/AnandChowdhary/bookshelf-action/commit/9eabb3d) Bump semantic-release from 17.3.8 to 17.3.9 54 | - [`9f1fab8`](https://github.com/AnandChowdhary/bookshelf-action/commit/9f1fab8) Bump vsoch/pull-request-action from 1.0.14 to 1.0.15 55 | 56 | ## v1.0.1 (2021-02-14) 57 | 58 | [📝 Release notes](https://github.com/AnandChowdhary/bookshelf-action/releases/tag/v1.0.1) · [💻 Compare](https://github.com/AnandChowdhary/bookshelf-action/compare/v1.0.0...v1.0.1) · [🔖 Tag](https://github.com/AnandChowdhary/bookshelf-action/tree/v1.0.1) · 🗄️ Archive ([zip](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.0.1.zip) · [tar.gz](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.0.1.tar.gz)) 59 | 60 | ### ♻️ Updates 61 | 62 | - [`08fe191`](https://github.com/AnandChowdhary/bookshelf-action/commit/08fe191) Use simple images in README 63 | - [`201b75d`](https://github.com/AnandChowdhary/bookshelf-action/commit/201b75d) Use markdown image/links 64 | - [`3394e8b`](https://github.com/AnandChowdhary/bookshelf-action/commit/3394e8b) Use slugify for labels 65 | - [`8f27c79`](https://github.com/AnandChowdhary/bookshelf-action/commit/8f27c79) Allow supported users 66 | - [`f970fe8`](https://github.com/AnandChowdhary/bookshelf-action/commit/f970fe8) Support for date overwrites 67 | 68 | ### 🐛 Bug fixes 69 | 70 | - [`cbe00b5`](https://github.com/AnandChowdhary/bookshelf-action/commit/cbe00b5) Remove prettier because GFM doesn't like it 71 | - [`d092462`](https://github.com/AnandChowdhary/bookshelf-action/commit/d092462) Unlock issue before commenting 72 | - [`64160fe`](https://github.com/AnandChowdhary/bookshelf-action/commit/64160fe) Ensure number exists before converting 73 | - [`1018498`](https://github.com/AnandChowdhary/bookshelf-action/commit/1018498) Add newlines before heading 74 | 75 | ## v1.0.0 (2021-02-14) 76 | 77 | [📝 Release notes](https://github.com/AnandChowdhary/bookshelf-action/releases/tag/v1.0.0) · [🔖 Tag](https://github.com/AnandChowdhary/bookshelf-action/tree/v1.0.0) · 🗄️ Archive ([zip](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.0.0.zip) · [tar.gz](https://github.com/AnandChowdhary/bookshelf-action/archive/v1.0.0.tar.gz)) 78 | 79 | ### ✨ New features 80 | 81 | - [`8f51bca`](https://github.com/AnandChowdhary/bookshelf-action/commit/8f51bca) Add basic new issue creation comment 82 | - [`bcf8089`](https://github.com/AnandChowdhary/bookshelf-action/commit/bcf8089) Add progress percent from issue comments 83 | 84 | ### ♻️ Updates 85 | 86 | - [`9c3b3fb`](https://github.com/AnandChowdhary/bookshelf-action/commit/9c3b3fb) Add goodreads search 87 | - [`09202bf`](https://github.com/AnandChowdhary/bookshelf-action/commit/09202bf) Add fallback cover photos 88 | - [`89befcb`](https://github.com/AnandChowdhary/bookshelf-action/commit/89befcb) Add on close issue function 89 | - [`3925a8a`](https://github.com/AnandChowdhary/bookshelf-action/commit/3925a8a) Add summary generator 90 | - [`723c0cf`](https://github.com/AnandChowdhary/bookshelf-action/commit/723c0cf) Use promises instead of fs/promises 91 | - [`8f32862`](https://github.com/AnandChowdhary/bookshelf-action/commit/8f32862) Add README summary feature 92 | - [`0f99540`](https://github.com/AnandChowdhary/bookshelf-action/commit/0f99540) Use Google Books API to fetch 93 | - [`865ee46`](https://github.com/AnandChowdhary/bookshelf-action/commit/865ee46) Use data from Google and tags 94 | - [`8f78a60`](https://github.com/AnandChowdhary/bookshelf-action/commit/8f78a60) Use language name, not ISO code 95 | - [`bae12f9`](https://github.com/AnandChowdhary/bookshelf-action/commit/bae12f9) Update label details and colors 96 | - [`669c3bc`](https://github.com/AnandChowdhary/bookshelf-action/commit/669c3bc) Add progress % to API, README 97 | - [`97e4af2`](https://github.com/AnandChowdhary/bookshelf-action/commit/97e4af2) Lowercase label for language 98 | - [`443bf2d`](https://github.com/AnandChowdhary/bookshelf-action/commit/443bf2d) Search for kind/book labels 99 | - [`e10383e`](https://github.com/AnandChowdhary/bookshelf-action/commit/e10383e) Rename to bookshelf-action 100 | - [`74ba58c`](https://github.com/AnandChowdhary/bookshelf-action/commit/74ba58c) Format with prettier before save 101 | - [`5c0ee16`](https://github.com/AnandChowdhary/bookshelf-action/commit/5c0ee16) Change to bookshelf action 102 | - [`bc6be3a`](https://github.com/AnandChowdhary/bookshelf-action/commit/bc6be3a) Update title on completion 103 | - [`5e5877f`](https://github.com/AnandChowdhary/bookshelf-action/commit/5e5877f) Add 2 books in each row 104 | - [`1d65fb8`](https://github.com/AnandChowdhary/bookshelf-action/commit/1d65fb8) Updat README summary with links 105 | 106 | ### 🐛 Bug fixes 107 | 108 | - [`2f99d6d`](https://github.com/AnandChowdhary/bookshelf-action/commit/2f99d6d) Fix sorting with NaNs 109 | - [`0324654`](https://github.com/AnandChowdhary/bookshelf-action/commit/0324654) Fix JS sorting by rating 110 | - [`bd3644e`](https://github.com/AnandChowdhary/bookshelf-action/commit/bd3644e) List all issues, not just open ones 111 | - [`56edf51`](https://github.com/AnandChowdhary/bookshelf-action/commit/56edf51) Remove # from color 112 | - [`4589d61`](https://github.com/AnandChowdhary/bookshelf-action/commit/4589d61) Add JSON response time for got 113 | - [`3333832`](https://github.com/AnandChowdhary/bookshelf-action/commit/3333832) Use language name in tags 114 | - [`89d1ac4`](https://github.com/AnandChowdhary/bookshelf-action/commit/89d1ac4) Lowercase publisher name in tag 115 | - [`a772038`](https://github.com/AnandChowdhary/bookshelf-action/commit/a772038) Fix description for language label 116 | - [`ba2cd52`](https://github.com/AnandChowdhary/bookshelf-action/commit/ba2cd52) Skip issue comment for first comments 117 | - [`98604de`](https://github.com/AnandChowdhary/bookshelf-action/commit/98604de) Use min instead of max 118 | - [`2321b00`](https://github.com/AnandChowdhary/bookshelf-action/commit/2321b00) Multiple by 100 for percent 119 | - [`9c9e702`](https://github.com/AnandChowdhary/bookshelf-action/commit/9c9e702) Fix progress % 120 | - [`5ba4d34`](https://github.com/AnandChowdhary/bookshelf-action/commit/5ba4d34) Fix title generator 121 | - [`64bc1c8`](https://github.com/AnandChowdhary/bookshelf-action/commit/64bc1c8) Fix README summary generator 122 | - [`3ad86ff`](https://github.com/AnandChowdhary/bookshelf-action/commit/3ad86ff) Remove commas from labels 123 | - [`02ad830`](https://github.com/AnandChowdhary/bookshelf-action/commit/02ad830) Parse date for publish date 124 | - [`bdef2c1`](https://github.com/AnandChowdhary/bookshelf-action/commit/bdef2c1) Fix table summary 125 | 126 | ### ⬆️ Dependency updates 127 | 128 | - [`f92dd45`](https://github.com/AnandChowdhary/bookshelf-action/commit/f92dd45) Bump actions/cache from v2 to v2.1.4 129 | - [`f7a2786`](https://github.com/AnandChowdhary/bookshelf-action/commit/f7a2786) Bump typescript from 4.1.4 to 4.1.5 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Anand Chowdhary 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![Books Tracker](./assets/logo.svg)](https://anandchowdhary.github.io/bookshelf-action/) 2 | 3 | Track your reading using repository issues and generate a README.md and open API automagically. 4 | 5 | [![Build CI](https://github.com/AnandChowdhary/bookshelf-action/workflows/Build%20CI/badge.svg)](https://github.com/AnandChowdhary/bookshelf-action/actions?query=workflow%3A%22Build+CI%22) 6 | [![Release CI](https://github.com/AnandChowdhary/bookshelf-action/workflows/Release%20CI/badge.svg)](https://github.com/AnandChowdhary/bookshelf-action/actions?query=workflow%3A%22Release+CI%22) 7 | [![Node CI](https://github.com/AnandChowdhary/bookshelf-action/workflows/Node%20CI/badge.svg)](https://github.com/AnandChowdhary/bookshelf-action/actions?query=workflow%3A%22Node+CI%22) 8 | 9 | [**View starter repository →**](https://github.com/AnandChowdhary/books) 10 | 11 | ## ⭐ Features 12 | 13 | - End-to-end automated workflow using GitHub issues: 14 | - Create GitHub issues to add the books you're reading 15 | - Track your reading progress by adding comments to the issue 16 | - Close the issue when you've completed the book 17 | - Get a README.md summary and JSON API for your reading data 18 | - Uses Google Books API to fetch details like cover and ISBN 19 | 20 | ### Get started 21 | 22 | This repository only includes the GitHub Actions required as dependencies. To get started, [**visit AnandChowdhary/books**](https://github.com/AnandChowdhary/books) and use it as a starting point. You can use the [Use this template](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template) button to create a new repository: 23 | 24 | 1. Go to [AnandChowdhary/books](https://github.com/AnandChowdhary/books) 25 | 2. Click on the "Use this template" button or fork the repository 26 | 3. Add a book by creating a new issue with the book's name 27 | 28 |
29 | How to add a new book 30 | 31 | First, create a new issue in your repository: 32 | 33 | ![Screenshot of new issue button](./assets/new-issue.png) 34 | 35 | Then, write the name of the book and author as the issue title: 36 | 37 | ![Screenshot of issue title](./assets/book-title-in-issue.png) 38 | 39 | Lastly, press the "Submit new issue" button and you'll see a comment and labels added automatically: 40 | 41 | ![Screenshot of comment in issue](./assets/issue-bot-comment.png) 42 | 43 |
44 | 45 |
46 | How to update reading progress 47 | 48 | In your book's issue, simply enter in plain text the progress. For example, "I've reached page 100" or "I've completed 24%", or "I've reached page 42/542". The issue title will be automatically updated to include your reading progress: 49 | 50 | ![Screenshot of new issue button](./assets/issue-title-progress.png) 51 | 52 |
53 | 54 |
55 | How to complete reading a book 56 | 57 | When you've completed a book, simply close the issue. An automated comment will be added to tell you about your reading time and some new labels will be added. 58 | 59 | ![Screenshot of new issue button](./assets/issue-close-completed.png) 60 | 61 |
62 | 63 |
64 | How to add a book as "Want to read" 65 | 66 | When creating a new issue for the book, add the label "want to read". 67 | 68 |
69 | 70 | ## 📖 Example 71 | 72 | Simply create issues with names of books, and Bookshelf Action will automatically organize them with labels: 73 | 74 | ![Screenshot of issues](./assets/issues.png) 75 | 76 | Additionally, a summary of your reading progress is generated in the `README.md` file: 77 | 78 | ![Screenshot of README](./assets/readme-demo.png) 79 | 80 | ## 📄 License 81 | 82 | - Code: [MIT](./LICENSE) © [Anand Chowdhary](https://anandchowdhary.com) 83 | - Books icon by [Francielly Costantin Senra](https://thenounproject.com/franciellycs/) from [The Noun Project](https://thenounproject.com) 84 | - Merge icon by [Danil Polshin](https://thenounproject.com/everydaytemplate) from [The Noun Project](https://thenounproject.com) 85 | - "GitHub" is a trademark of GitHub, Inc. 86 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Books Tracker" 2 | 3 | description: "Track your reading using GitHub Actions" 4 | 5 | author: "Anand Chowdhary " 6 | 7 | inputs: 8 | command: 9 | required: true 10 | description: "Command to run" 11 | 12 | runs: 13 | using: "node16" 14 | main: "dist/index.js" 15 | 16 | branding: 17 | icon: "book-open" 18 | color: "purple" 19 | -------------------------------------------------------------------------------- /api.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Lean In", 4 | "authors": [ 5 | "Sheryl Sandberg" 6 | ], 7 | "publisher": "Knopf", 8 | "publishedDate": "2013-03-11", 9 | "description": "The #1 international best seller In Lean In, Sheryl Sandberg reignited the conversation around women in the workplace. Sandberg is chief operating officer of Facebook and coauthor of Option B with Adam Grant. In 2010, she gave an electrifying TED talk in which she described how women unintentionally hold themselves back in their careers. Her talk, which has been viewed more than six million times, encouraged women to “sit at the table,” seek challenges, take risks, and pursue their goals with gusto. Lean In continues that conversation, combining personal anecdotes, hard data, and compelling research to change the conversation from what women can’t do to what they can. Sandberg provides practical advice on negotiation techniques, mentorship, and building a satisfying career. She describes specific steps women can take to combine professional achievement with personal fulfillment, and demonstrates how men can benefit by supporting women both in the workplace and at home. Written with humor and wisdom, Lean In is a revelatory, inspiring call to action and a blueprint for individual growth that will empower women around the world to achieve their full potential.", 10 | "image": "http://books.google.com/books/content?id=y9_mxZLYiiMC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api", 11 | "language": "en", 12 | "averageRating": 3.5, 13 | "ratingsCount": 3751, 14 | "categories": [ 15 | "Biography & Autobiography" 16 | ], 17 | "pageCount": 240, 18 | "isbn10": "0385349955", 19 | "isbn13": "9780385349956", 20 | "googleBooks": { 21 | "id": "y9_mxZLYiiMC", 22 | "preview": "http://books.google.com/books?id=y9_mxZLYiiMC&printsec=frontcover&dq=intitle:Lean+In+by+Sheryl+Sandberg&hl=&cd=1&source=gbs_api", 23 | "info": "https://play.google.com/store/books/details?id=y9_mxZLYiiMC&source=gbs_api", 24 | "canonical": "https://play.google.com/store/books/details?id=y9_mxZLYiiMC" 25 | }, 26 | "issueNumber": 17, 27 | "progressPercent": 0, 28 | "state": "reading", 29 | "startedAt": "2021-02-14T14:36:17.000Z" 30 | }, 31 | { 32 | "title": "The Hard Thing About Hard Things", 33 | "authors": [ 34 | "Ben Horowitz" 35 | ], 36 | "publisher": "Harper Collins", 37 | "publishedDate": "2014-03-04", 38 | "description": "Ben Horowitz, cofounder of Andreessen Horowitz and one of Silicon Valley's most respected and experienced entrepreneurs, offers essential advice on building and running a startup—practical wisdom for managing the toughest problems business school doesn’t cover, based on his popular ben’s blog. While many people talk about how great it is to start a business, very few are honest about how difficult it is to run one. Ben Horowitz analyzes the problems that confront leaders every day, sharing the insights he’s gained developing, managing, selling, buying, investing in, and supervising technology companies. A lifelong rap fanatic, he amplifies business lessons with lyrics from his favorite songs, telling it straight about everything from firing friends to poaching competitors, cultivating and sustaining a CEO mentality to knowing the right time to cash in. Filled with his trademark humor and straight talk, The Hard Thing About Hard Things is invaluable for veteran entrepreneurs as well as those aspiring to their own new ventures, drawing from Horowitz's personal and often humbling experiences.", 39 | "image": "http://books.google.com/books/content?id=620pAgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api", 40 | "language": "en", 41 | "averageRating": 4, 42 | "ratingsCount": 8, 43 | "categories": [ 44 | "Business & Economics" 45 | ], 46 | "pageCount": 304, 47 | "isbn10": "0062273213", 48 | "isbn13": "9780062273215", 49 | "googleBooks": { 50 | "id": "620pAgAAQBAJ", 51 | "preview": "http://books.google.com/books?id=620pAgAAQBAJ&printsec=frontcover&dq=intitle:The+Hard+Thing+About+Hard+Things+by+Ben+Horowitz&hl=&cd=1&source=gbs_api", 52 | "info": "https://play.google.com/store/books/details?id=620pAgAAQBAJ&source=gbs_api", 53 | "canonical": "https://play.google.com/store/books/details?id=620pAgAAQBAJ" 54 | }, 55 | "issueNumber": 16, 56 | "progressPercent": 0, 57 | "state": "reading", 58 | "startedAt": "2021-02-14T14:12:40.000Z" 59 | }, 60 | { 61 | "title": "1984", 62 | "authors": [ 63 | "George Orwell" 64 | ], 65 | "publisher": "Univ. Press of Mississippi", 66 | "publishedDate": "1977", 67 | "description": "Portrays life in a future time when a totalitarian government watches over all citizens and directs all activities.", 68 | "image": "http://books.google.com/books/content?id=yxv1LK5gyV4C&printsec=frontcover&img=1&zoom=1&source=gbs_api", 69 | "language": "en", 70 | "averageRating": 4, 71 | "ratingsCount": 2320, 72 | "categories": [ 73 | "Fiction" 74 | ], 75 | "pageCount": 328, 76 | "isbn10": "0451524934", 77 | "isbn13": "9780451524935", 78 | "googleBooks": { 79 | "id": "yxv1LK5gyV4C", 80 | "preview": "http://books.google.com/books?id=yxv1LK5gyV4C&dq=intitle:1984+by+George+Orwell&hl=&cd=1&source=gbs_api", 81 | "info": "http://books.google.com/books?id=yxv1LK5gyV4C&dq=intitle:1984+by+George+Orwell&hl=&source=gbs_api", 82 | "canonical": "https://books.google.com/books/about/1984.html?hl=&id=yxv1LK5gyV4C" 83 | }, 84 | "issueNumber": 13, 85 | "progressPercent": 0, 86 | "state": "completed", 87 | "startedAt": "2021-02-14T13:01:09.000Z", 88 | "completedAt": "2021-02-14T14:17:55.000Z", 89 | "timeToComplete": 4606000, 90 | "timeToCompleteFormatted": "1 hour, 16 minutes, 46 seconds" 91 | } 92 | ] 93 | -------------------------------------------------------------------------------- /assets/book-title-in-issue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/book-title-in-issue.png -------------------------------------------------------------------------------- /assets/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/issue-bot-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/issue-bot-comment.png -------------------------------------------------------------------------------- /assets/issue-close-completed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/issue-close-completed.png -------------------------------------------------------------------------------- /assets/issue-title-progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/issue-title-progress.png -------------------------------------------------------------------------------- /assets/issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/issues.png -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/new-book-in-shelf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/new-book-in-shelf.png -------------------------------------------------------------------------------- /assets/new-issue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/new-issue.png -------------------------------------------------------------------------------- /assets/readme-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/assets/readme-demo.png -------------------------------------------------------------------------------- /dist/exec-child.js: -------------------------------------------------------------------------------- 1 | if (require.main !== module) { 2 | throw new Error('This file should not be required'); 3 | } 4 | 5 | var childProcess = require('child_process'); 6 | var fs = require('fs'); 7 | 8 | var paramFilePath = process.argv[2]; 9 | 10 | var serializedParams = fs.readFileSync(paramFilePath, 'utf8'); 11 | var params = JSON.parse(serializedParams); 12 | 13 | var cmd = params.command; 14 | var execOptions = params.execOptions; 15 | var pipe = params.pipe; 16 | var stdoutFile = params.stdoutFile; 17 | var stderrFile = params.stderrFile; 18 | 19 | var c = childProcess.exec(cmd, execOptions, function (err) { 20 | if (!err) { 21 | process.exitCode = 0; 22 | } else if (err.code === undefined) { 23 | process.exitCode = 1; 24 | } else { 25 | process.exitCode = err.code; 26 | } 27 | }); 28 | 29 | var stdoutStream = fs.createWriteStream(stdoutFile); 30 | var stderrStream = fs.createWriteStream(stderrFile); 31 | 32 | c.stdout.pipe(stdoutStream); 33 | c.stderr.pipe(stderrStream); 34 | c.stdout.pipe(process.stdout); 35 | c.stderr.pipe(process.stderr); 36 | 37 | if (pipe) { 38 | c.stdin.end(pipe); 39 | } 40 | -------------------------------------------------------------------------------- /dist/features/close-issue.d.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "@actions/github/lib/context"; 2 | import type { GitHub } from "@actions/github/lib/utils"; 3 | export declare const onCloseIssue: (owner: string, repo: string, context: Context, octokit: InstanceType) => Promise; 4 | -------------------------------------------------------------------------------- /dist/features/close-issue.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.onCloseIssue = void 0; 7 | const core_1 = require("@actions/core"); 8 | const cosmic_1 = require("@anandchowdhary/cosmic"); 9 | const slugify_1 = __importDefault(require("@sindresorhus/slugify")); 10 | const humanize_duration_1 = __importDefault(require("humanize-duration")); 11 | const update_summary_1 = require("./update-summary"); 12 | const onCloseIssue = async (owner, repo, context, octokit) => { 13 | (0, core_1.debug)("Started onCloseIssue"); 14 | try { 15 | await (0, cosmic_1.cosmic)("bookshelf"); 16 | (0, core_1.debug)("Got config object"); 17 | } 18 | catch (error) { } 19 | const issue = await octokit.rest.issues.get({ 20 | owner: context.issue.owner, 21 | repo: context.issue.repo, 22 | issue_number: context.issue.number, 23 | }); 24 | (0, core_1.debug)(`Got issue #${issue.data.number}`); 25 | if ((0, cosmic_1.config)("users") && Array.isArray((0, cosmic_1.config)("users"))) { 26 | if (!(0, cosmic_1.config)("users").find((i) => (issue.data.user || {}).login)) 27 | return (0, core_1.debug)("User not allowed, skipping"); 28 | } 29 | await octokit.rest.issues.unlock({ 30 | owner: context.issue.owner, 31 | repo: context.issue.repo, 32 | issue_number: context.issue.number, 33 | }); 34 | (0, core_1.debug)("Unlocked issue"); 35 | if (!issue.data.closed_at) 36 | throw new Error("Closed date not found"); 37 | await octokit.rest.issues.createComment({ 38 | owner: context.issue.owner, 39 | repo: context.issue.repo, 40 | issue_number: context.issue.number, 41 | body: `You completed this book in ${(0, humanize_duration_1.default)(new Date(issue.data.closed_at).getTime() - new Date(issue.data.created_at).getTime())}, great job!`, 42 | }); 43 | (0, core_1.debug)(`Created comment in issue #${issue.data.number}`); 44 | await octokit.rest.issues.lock({ 45 | owner: context.issue.owner, 46 | repo: context.issue.repo, 47 | issue_number: context.issue.number, 48 | }); 49 | (0, core_1.debug)("Locked issue"); 50 | await octokit.rest.issues.addLabels({ 51 | owner: context.issue.owner, 52 | repo: context.issue.repo, 53 | issue_number: context.issue.number, 54 | labels: [ 55 | `completed: ${(0, slugify_1.default)(new Date().toLocaleString("en", { month: "long" }))}`, 56 | `completed: ${new Date().getUTCFullYear()}`, 57 | ], 58 | }); 59 | (0, core_1.debug)(`Added "completed" labels to issue #${issue.data.number}`); 60 | const currentPercentage = issue.data.title.match(/\(\d+\%\)/g); 61 | await octokit.rest.issues.update({ 62 | owner: context.issue.owner, 63 | repo: context.issue.repo, 64 | issue_number: context.issue.number, 65 | title: currentPercentage && currentPercentage.length 66 | ? `${issue.data.title.split(currentPercentage[0])[0].trim()} (${100}%)` 67 | : `${issue.data.title.trim()} (${100}%)`, 68 | }); 69 | // Remove "want to read" label if it's there 70 | if (issue.data.labels.find((i) => typeof i === "string" ? i === "want to read" : i.name === "want to read")) { 71 | await octokit.rest.issues.removeLabel({ 72 | owner: context.issue.owner, 73 | repo: context.issue.repo, 74 | issue_number: context.issue.number, 75 | name: "want to read", 76 | }); 77 | (0, core_1.debug)("Removed 'want to read' label"); 78 | } 79 | await (0, update_summary_1.updateSummary)(owner, repo, context, octokit); 80 | }; 81 | exports.onCloseIssue = onCloseIssue; 82 | //# sourceMappingURL=close-issue.js.map -------------------------------------------------------------------------------- /dist/features/close-issue.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"close-issue.js","sourceRoot":"","sources":["../../src/features/close-issue.ts"],"names":[],"mappings":";;;;;;AAAA,wCAAsC;AAGtC,mDAAwD;AACxD,oEAA4C;AAC5C,0EAAiD;AACjD,qDAAiD;AAE1C,MAAM,YAAY,GAAG,KAAK,EAC/B,KAAa,EACb,IAAY,EACZ,OAAgB,EAChB,OAAoC,EACpC,EAAE;IACF,IAAA,YAAK,EAAC,sBAAsB,CAAC,CAAC;IAC9B,IAAI;QACF,MAAM,IAAA,eAAM,EAAC,WAAW,CAAC,CAAC;QAC1B,IAAA,YAAK,EAAC,mBAAmB,CAAC,CAAC;KAC5B;IAAC,OAAO,KAAK,EAAE,GAAE;IAClB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QAC1C,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;QAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;QACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;KACnC,CAAC,CAAC;IACH,IAAA,YAAK,EAAC,cAAc,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,IAAI,IAAA,eAAM,EAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAA,eAAM,EAAC,OAAO,CAAC,CAAC,EAAE;QACrD,IAAI,CAAE,IAAA,eAAM,EAAC,OAAO,CAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC;YAC3E,OAAO,IAAA,YAAK,EAAC,4BAA4B,CAAC,CAAC;KAC9C;IACD,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAC/B,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;QAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;QACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;KACnC,CAAC,CAAC;IACH,IAAA,YAAK,EAAC,gBAAgB,CAAC,CAAC;IACxB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACpE,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;QACtC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;QAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;QACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;QAClC,IAAI,EAAE,8BAA8B,IAAA,2BAAgB,EAClD,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CACrF,cAAc;KAChB,CAAC,CAAC;IACH,IAAA,YAAK,EAAC,6BAA6B,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACxD,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;QAC7B,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;QAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;QACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;KACnC,CAAC,CAAC;IACH,IAAA,YAAK,EAAC,cAAc,CAAC,CAAC;IACtB,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;QAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;QACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;QAClC,MAAM,EAAE;YACN,cAAc,IAAA,iBAAO,EAAC,IAAI,IAAI,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE;YAC3E,cAAc,IAAI,IAAI,EAAE,CAAC,cAAc,EAAE,EAAE;SAC5C;KACF,CAAC,CAAC;IACH,IAAA,YAAK,EAAC,sCAAsC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/D,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAC/B,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;QAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;QACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;QAClC,KAAK,EACH,iBAAiB,IAAI,iBAAiB,CAAC,MAAM;YAC3C,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI;YACvE,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI;KAC7C,CAAC,CAAC;IACH,4CAA4C;IAC5C,IACE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CACzE,EACD;QACA,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;YACpC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK;YAC1B,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;YACxB,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;YAClC,IAAI,EAAE,cAAc;SACrB,CAAC,CAAC;QACH,IAAA,YAAK,EAAC,8BAA8B,CAAC,CAAC;KACvC;IACD,MAAM,IAAA,8BAAa,EAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC,CAAC;AA9EW,QAAA,YAAY,gBA8EvB"} -------------------------------------------------------------------------------- /dist/features/issue-comment.d.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "@actions/github/lib/context"; 2 | import type { GitHub } from "@actions/github/lib/utils"; 3 | export declare const onIssueComment: (owner: string, repo: string, context: Context, octokit: InstanceType) => Promise; 4 | -------------------------------------------------------------------------------- /dist/features/issue-comment.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.onIssueComment = void 0; 4 | const core_1 = require("@actions/core"); 5 | const cosmic_1 = require("@anandchowdhary/cosmic"); 6 | const update_summary_1 = require("./update-summary"); 7 | const onIssueComment = async (owner, repo, context, octokit) => { 8 | (0, core_1.debug)("Started onIssueComment"); 9 | try { 10 | await (0, cosmic_1.cosmic)("bookshelf"); 11 | (0, core_1.debug)("Got config object"); 12 | } 13 | catch (error) { } 14 | const issue = await octokit.rest.issues.get({ 15 | owner: context.issue.owner, 16 | repo: context.issue.repo, 17 | issue_number: context.issue.number, 18 | }); 19 | (0, core_1.debug)(`Got issue #${issue.data.number}`); 20 | if ((0, cosmic_1.config)("users") && Array.isArray((0, cosmic_1.config)("users"))) { 21 | if (!(0, cosmic_1.config)("users").find((i) => (issue.data.user || {}).login)) 22 | return (0, core_1.debug)("User not allowed, skipping"); 23 | } 24 | if (!issue.data.labels.find((i) => typeof i === "string" ? i === "kind: book" : i.name === "kind: book")) 25 | return (0, core_1.debug)('Issue not of "kind: book", skipping'); 26 | if ((issue.data.body || "").includes("This comment is autogenerated")) 27 | return (0, core_1.debug)("Comment was autogenerated, skipping"); 28 | const comments = await octokit.rest.issues.listComments({ 29 | owner: context.issue.owner, 30 | repo: context.issue.repo, 31 | issue_number: context.issue.number, 32 | }); 33 | (0, core_1.debug)(`Got ${comments.data.length} comments in issue`); 34 | if (comments.data.length < 2) 35 | return (0, core_1.debug)("Less than 2 comments, skipping"); 36 | let json = undefined; 37 | try { 38 | comments.data.forEach((comment) => { 39 | if ((comment.body || "").includes("Book details (JSON)")) 40 | json = JSON.parse((comment.body || "").split("```json")[1].split("```")[0]); 41 | }); 42 | } 43 | catch (error) { 44 | console.log("JSON parsing error", error); 45 | } 46 | (0, core_1.debug)("Got JSON data for book"); 47 | if (json) 48 | (0, core_1.debug)(`Total pages in JSON are ${json.pageCount}`); 49 | const lastComment = comments.data.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0]; 50 | if (!lastComment) 51 | throw new Error("Last comment not found"); 52 | (0, core_1.debug)(`Found last comment #${lastComment.id}`); 53 | let progressPercent = 0; 54 | let totalPages = json ? json.pageCount : 1; 55 | if ((lastComment.body || "").includes("/")) { 56 | (0, core_1.debug)("Last comment includes slash so must have length"); 57 | const num = (lastComment.body || "").split("/")[1].match(/\d+/g); 58 | if (num && num.length) { 59 | (0, core_1.debug)(`Got ${num.length} numerical matches`); 60 | const potentialPages = parseInt(num[0]); 61 | if (!isNaN(potentialPages)) { 62 | if (potentialPages) 63 | totalPages = potentialPages; 64 | (0, core_1.debug)(`Total pages from comment are ${totalPages}`); 65 | } 66 | } 67 | } 68 | else 69 | (0, core_1.debug)("Last comment doesn't have slash"); 70 | (0, core_1.debug)(`Total pages in book are ${totalPages}`); 71 | const valuesInComment = (lastComment.body || "").match(/\d+\%?/g); 72 | if (valuesInComment && valuesInComment.length) { 73 | (0, core_1.debug)(`Got ${valuesInComment.length} numerical matches`); 74 | const values = valuesInComment.map((val) => parseInt(val)).filter((val) => !isNaN(val)); 75 | const firstVal = valuesInComment[0]; 76 | (0, core_1.debug)(`Potential value is ${firstVal}`); 77 | if (values.length) 78 | if (firstVal.includes("%") && !isNaN(parseInt(firstVal))) { 79 | progressPercent = parseInt(firstVal); 80 | (0, core_1.debug)(`Potential value has % sign: ${progressPercent}`); 81 | } 82 | else { 83 | progressPercent = Math.min(Math.round((100 * values[0]) / totalPages), 100); 84 | (0, core_1.debug)(`Potential value is in pages: ${values[0]}`); 85 | (0, core_1.debug)(`Potential percent count rounded: ${Math.round((100 * values[0]) / totalPages)}`); 86 | } 87 | } 88 | (0, core_1.debug)(`Progress is ${progressPercent}%`); 89 | if (progressPercent !== 0) { 90 | try { 91 | await octokit.rest.reactions.createForIssueComment({ 92 | owner: context.issue.owner, 93 | repo: context.issue.repo, 94 | issue_number: context.issue.number, 95 | comment_id: lastComment.id, 96 | content: "+1", 97 | }); 98 | (0, core_1.debug)("Added reaction to comment"); 99 | } 100 | catch (error) { 101 | (0, core_1.debug)("Unable to add reaction to comment"); 102 | } 103 | const currentPercentage = issue.data.title.match(/\(\d+\%\)/g); 104 | await octokit.rest.issues.update({ 105 | owner: context.issue.owner, 106 | repo: context.issue.repo, 107 | issue_number: context.issue.number, 108 | title: currentPercentage && currentPercentage.length 109 | ? `${issue.data.title.split(currentPercentage[0])[0].trim()} (${progressPercent}%)` 110 | : `${issue.data.title.trim()} (${progressPercent}%)`, 111 | }); 112 | (0, core_1.debug)("Updated issue title with progress"); 113 | // Remove "want to read" label if it's there 114 | if (issue.data.labels.find((i) => typeof i === "string" ? i === "want to read" : i.name === "want to read")) { 115 | await octokit.rest.issues.removeLabel({ 116 | owner: context.issue.owner, 117 | repo: context.issue.repo, 118 | issue_number: context.issue.number, 119 | name: "want to read", 120 | }); 121 | (0, core_1.debug)("Removed 'want to read' label"); 122 | } 123 | } 124 | await (0, update_summary_1.updateSummary)(owner, repo, context, octokit); 125 | }; 126 | exports.onIssueComment = onIssueComment; 127 | //# sourceMappingURL=issue-comment.js.map -------------------------------------------------------------------------------- /dist/features/issue-comment.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"issue-comment.js","sourceRoot":"","sources":["../../src/features/issue-comment.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/features/new-issue.d.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "@actions/github/lib/context"; 2 | import type { GitHub } from "@actions/github/lib/utils"; 3 | export declare const onNewIssue: (owner: string, repo: string, context: Context, octokit: InstanceType) => Promise; 4 | -------------------------------------------------------------------------------- /dist/features/new-issue.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.onNewIssue = void 0; 7 | const core_1 = require("@actions/core"); 8 | const cosmic_1 = require("@anandchowdhary/cosmic"); 9 | const slugify_1 = __importDefault(require("@sindresorhus/slugify")); 10 | const locale_codes_1 = require("locale-codes"); 11 | const google_books_1 = require("../google-books"); 12 | const update_summary_1 = require("./update-summary"); 13 | const clean = (str) => (0, slugify_1.default)(str, { lowercase: true, separator: " " }); 14 | const onNewIssue = async (owner, repo, context, octokit) => { 15 | (0, core_1.debug)("Started onNewIssue"); 16 | try { 17 | await (0, cosmic_1.cosmic)("bookshelf"); 18 | (0, core_1.debug)("Got config object"); 19 | } 20 | catch (error) { } 21 | const issue = await octokit.rest.issues.get({ 22 | owner: context.issue.owner, 23 | repo: context.issue.repo, 24 | issue_number: context.issue.number, 25 | }); 26 | (0, core_1.debug)(`Got issue #${issue.data.number}`); 27 | if ((0, cosmic_1.config)("users") && Array.isArray((0, cosmic_1.config)("users"))) { 28 | if (!(0, cosmic_1.config)("users").find((i) => i === (issue.data.user || {}).login)) 29 | return (0, core_1.debug)("User not allowed, skipping"); 30 | } 31 | let body = "\n\n"; 32 | const labels = [ 33 | "kind: book", 34 | `started: ${clean(new Date().toLocaleString("en", { month: "long" }))}`, 35 | `started: ${new Date().getUTCFullYear()}`, 36 | ]; 37 | try { 38 | (0, core_1.debug)(`Searching for "${issue.data.title}"`); 39 | const details = await (0, google_books_1.search)(issue.data.title); 40 | body += `Congrats on adding **${details.title}** by ${details.authors.join(", ")} to your bookshelf, I hope you enjoy it! It has an average of ${details.averageRating || "unknown"}/5 stars and ${(details.ratingsCount || 0).toLocaleString()} ratings on [Google Books](${details.googleBooks.info}).\n\n
41 | Book details (JSON) 42 | 43 | \`\`\`json 44 | ${JSON.stringify(details, null, 2)} 45 | \`\`\` 46 | 47 |
`; 48 | details.authors.forEach((i) => labels.push(`author: ${clean(i)}`)); 49 | details.categories.forEach((i) => labels.push(`category: ${clean(i)}`)); 50 | if (details.publishedDate) { 51 | const publishDate = new Date(details.publishedDate); 52 | labels.push(`year: ${publishDate.getUTCFullYear()}`); 53 | labels.push(`decade: ${Math.floor(publishDate.getUTCFullYear() / 10) * 10}s`); 54 | } 55 | if (details.language) 56 | labels.push(`language: ${clean((0, locale_codes_1.getByTag)(details.language).name || details.language)}`); 57 | if (details.publisher) 58 | labels.push(`publisher: ${clean(details.publisher)}`); 59 | (0, core_1.debug)("Added labels from search results"); 60 | } 61 | catch (error) { 62 | console.log(error); 63 | (0, core_1.debug)(`Got an error in search results: ${String(error)}`); 64 | body += 65 | "I couldn't find details about this book using the Google Books API. Don't worry, you can still track it.\n\n"; 66 | } 67 | body += `When you're finished with reading this book, just close this issue and I'll mark it as completed. Best of luck! 👍`; 68 | await octokit.rest.issues.createComment({ 69 | owner: context.issue.owner, 70 | repo: context.issue.repo, 71 | issue_number: context.issue.number, 72 | body, 73 | }); 74 | (0, core_1.debug)("Added comment to issue"); 75 | await octokit.rest.issues.addLabels({ 76 | owner: context.issue.owner, 77 | repo: context.issue.repo, 78 | issue_number: context.issue.number, 79 | labels: labels.map((label) => (label.length > 50 ? `${label.substring(0, 47)}...` : label)), 80 | }); 81 | (0, core_1.debug)("Added all labels to issue"); 82 | await octokit.rest.issues.lock({ 83 | owner: context.issue.owner, 84 | repo: context.issue.repo, 85 | issue_number: context.issue.number, 86 | }); 87 | (0, core_1.debug)("Locked issue"); 88 | await (0, update_summary_1.updateSummary)(owner, repo, context, octokit); 89 | }; 90 | exports.onNewIssue = onNewIssue; 91 | //# sourceMappingURL=new-issue.js.map -------------------------------------------------------------------------------- /dist/features/new-issue.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"new-issue.js","sourceRoot":"","sources":["../../src/features/new-issue.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/features/update-summary.d.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "@actions/github/lib/context"; 2 | import type { GitHub } from "@actions/github/lib/utils"; 3 | export declare const updateSummary: (owner: string, repo: string, context: Context, octokit: InstanceType) => Promise; 4 | -------------------------------------------------------------------------------- /dist/features/update-summary.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.updateSummary = void 0; 7 | const core_1 = require("@actions/core"); 8 | const cosmic_1 = require("@anandchowdhary/cosmic"); 9 | const fs_1 = require("fs"); 10 | const humanize_duration_1 = __importDefault(require("humanize-duration")); 11 | const path_1 = require("path"); 12 | const prettier_1 = require("prettier"); 13 | const shelljs_1 = require("shelljs"); 14 | const github_1 = require("../github"); 15 | const updateSummary = async (owner, repo, context, octokit) => { 16 | (0, core_1.debug)("Starting updateSummary"); 17 | try { 18 | await (0, cosmic_1.cosmic)("bookshelf"); 19 | (0, core_1.debug)("Got config object"); 20 | } 21 | catch (error) { } 22 | let api = []; 23 | for await (const response of octokit.paginate.iterator(octokit.rest.issues.listForRepo, { 24 | owner: context.issue.owner, 25 | repo: context.issue.repo, 26 | labels: "kind: book", 27 | state: "all", 28 | })) { 29 | (0, core_1.debug)(`Got ${response.data.length} issues during pagination`); 30 | for (const issue of response.data) { 31 | const comments = await octokit.rest.issues.listComments({ 32 | owner: context.issue.owner, 33 | repo: context.issue.repo, 34 | issue_number: issue.number, 35 | }); 36 | (0, core_1.debug)(`Got ${comments.data.length} comments in issue ${issue.number}`); 37 | let json = undefined; 38 | try { 39 | comments.data.forEach((comment) => { 40 | if ((comment.body || "").includes("Book details (JSON)")) 41 | json = JSON.parse((comment.body || "").split("```json")[1].split("```")[0]); 42 | }); 43 | } 44 | catch (error) { 45 | console.log("JSON parsing error", error); 46 | } 47 | const isWantToRead = issue.labels.find((label) => typeof label === "string" ? label === "want to read" : label.name === "want to read"); 48 | if (isWantToRead) 49 | (0, core_1.debug)(`Book is in category "want to read"`); 50 | if (json) { 51 | (0, core_1.debug)(`Found JSON data for ${json.title}`); 52 | const currentPercentage = issue.title.match(/\(\d+\%\)/g); 53 | const overwrites = (0, cosmic_1.config)("overwrites") || {}; 54 | const openedAt = (overwrites[issue.number] || {}).started 55 | ? overwrites[issue.number].started 56 | : issue.created_at; 57 | const closedAt = (overwrites[issue.number] || {}).completed 58 | ? overwrites[issue.number].completed 59 | : issue.closed_at; 60 | api.push({ 61 | ...json, 62 | issueNumber: issue.number, 63 | progressPercent: currentPercentage && currentPercentage.length && !isNaN(parseInt(currentPercentage[0])) 64 | ? parseInt(currentPercentage[0]) 65 | : 0, 66 | state: issue.state === "open" ? (isWantToRead ? "want-to-read" : "reading") : "completed", 67 | startedAt: new Date(openedAt).toISOString(), 68 | completedAt: issue.state === "closed" ? new Date(closedAt).toISOString() : undefined, 69 | timeToComplete: issue.state === "closed" 70 | ? new Date(closedAt).getTime() - new Date(openedAt).getTime() 71 | : undefined, 72 | timeToCompleteFormatted: issue.state === "closed" 73 | ? (0, humanize_duration_1.default)(new Date(closedAt).getTime() - new Date(openedAt).getTime()).split(",")[0] 74 | : undefined, 75 | }); 76 | } 77 | else 78 | (0, core_1.debug)(`Unable to find JSON data for #${issue.id}`); 79 | } 80 | } 81 | api = api.sort((a, b) => new Date(b.completedAt ?? b.startedAt).getTime() - new Date(a.completedAt ?? a.startedAt).getTime()); 82 | await fs_1.promises.writeFile((0, path_1.join)(".", "api.json"), JSON.stringify(api, null, 2) + "\n"); 83 | (0, core_1.debug)("Written api.json file"); 84 | (0, core_1.debug)(`api has length ${api.length}`); 85 | let mdContent = ""; 86 | const apiCompleted = api.filter((i) => i.state === "completed"); 87 | const apiWantToRead = api.filter((i) => i.state === "want-to-read"); 88 | const apiReading = api.filter((i) => i.state === "reading"); 89 | if (apiReading.length) 90 | mdContent += `\n\n### ⌛ Currently reading (${apiReading.length})\n\n${apiReading 91 | .map((i) => `[![${i.title.replace(/\"/g, "")}](https://images.weserv.nl/?url=${encodeURIComponent(i.image)}&w=128&h=196&fit=contain)](https://github.com/${owner}/${repo}/issues/${i.issueNumber} "${i.title.replace(/\"/g, "")} by ${i.authors.join(", ")}")`) 92 | .join("\n")}`; 93 | if (apiCompleted.length) 94 | mdContent += `\n\n### ✅ Completed (${apiCompleted.length})\n\n${apiCompleted 95 | .map((i) => `[![${i.title.replace(/\"/g, "")}](https://images.weserv.nl/?url=${encodeURIComponent(i.image)}&w=128&h=196&fit=contain)](https://github.com/${owner}/${repo}/issues/${i.issueNumber} "${i.title.replace(/\"/g, "")} by ${i.authors 96 | .join(", ") 97 | .replace(/\"/g, "")} completed in ${i.timeToCompleteFormatted} on ${new Date(i.completedAt || "").toLocaleDateString("en-us", { 98 | month: "long", 99 | year: "numeric", 100 | })}")`) 101 | .join("\n")}`; 102 | if (apiWantToRead.length) 103 | mdContent += `\n\n### ⏭️ Want to Read (${apiWantToRead.length})\n\n${apiWantToRead 104 | .map((i) => `[![${i.title.replace(/\"/g, "")}](https://images.weserv.nl/?url=${encodeURIComponent(i.image)}&w=128&h=196&fit=contain)](https://github.com/${owner}/${repo}/issues/${i.issueNumber} "${i.title.replace(/\"/g, "")} by ${i.authors 105 | .join(", ") 106 | .replace(/\"/g, "")} completed in ${i.timeToCompleteFormatted} on ${new Date(i.completedAt || "").toLocaleDateString("en-us", { 107 | month: "long", 108 | year: "numeric", 109 | })}")`) 110 | .join("\n")}`; 111 | (0, core_1.debug)(`Generated README.md content of length ${mdContent.length}`); 112 | const content = await fs_1.promises.readFile((0, path_1.join)(".", "README.md"), "utf8"); 113 | (0, core_1.debug)(`Read README.md file of length ${content.length}`); 114 | await fs_1.promises.writeFile((0, path_1.join)(".", "README.md"), content.split("")[0] + 115 | `\n${(0, prettier_1.format)(mdContent, { 116 | parser: "markdown", 117 | })}\n` + 118 | content.split("")[1]); 119 | (0, core_1.debug)("Written README.md file"); 120 | (0, shelljs_1.exec)(`git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"`); 121 | (0, shelljs_1.exec)(`git config --global user.name "github-actions[bot]"`); 122 | (0, core_1.debug)("Added git config user details"); 123 | (0, shelljs_1.exec)("git add ."); 124 | (0, shelljs_1.exec)('git commit -m ":bento: Update API and README summary [skip ci]"'); 125 | (0, core_1.debug)("Committed to git history"); 126 | (0, shelljs_1.exec)("git push"); 127 | (0, core_1.debug)("Pushed to repository"); 128 | await (0, github_1.addDetailsToLabels)(owner, repo, octokit); 129 | (0, core_1.debug)("Updated label details"); 130 | }; 131 | exports.updateSummary = updateSummary; 132 | //# sourceMappingURL=update-summary.js.map -------------------------------------------------------------------------------- /dist/features/update-summary.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"update-summary.js","sourceRoot":"","sources":["../../src/features/update-summary.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/github.d.ts: -------------------------------------------------------------------------------- 1 | import type { GitHub } from "@actions/github/lib/utils"; 2 | export declare const addDetailsToLabels: (owner: string, repo: string, octokit: InstanceType) => Promise; 3 | -------------------------------------------------------------------------------- /dist/github.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.addDetailsToLabels = void 0; 7 | const randomcolor_1 = __importDefault(require("randomcolor")); 8 | /** 9 | * Convert a string to title case and trim it 10 | * @private 11 | * @param str - String to clean up 12 | */ 13 | const clean = (str) => str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()).trim(); 14 | const addDetailsToLabels = async (owner, repo, octokit) => { 15 | const options = octokit.rest.issues.listLabelsForRepo.endpoint.merge({ owner, repo }); 16 | for await (const labels of octokit.paginate.iterator(options)) { 17 | for await (const label of labels.data) { 18 | let color = label.color; 19 | let description = label.description; 20 | if (label.color === "ededed") 21 | color = (0, randomcolor_1.default)({ luminosity: "light" }).replace("#", ""); 22 | if (label.description === null) { 23 | if (label.name === "kind: book") 24 | description = "This issue tracks a book (reading progress)"; 25 | else if (label.name.startsWith("started: ")) 26 | description = `This book was started in ${clean(label.name.split("started: ")[1])}`; 27 | else if (label.name.startsWith("completed: ")) 28 | description = `This book was completed in ${clean(label.name.split("completed: ")[1])}`; 29 | else if (label.name.startsWith("year: ")) 30 | description = `This book was published in ${clean(label.name.split("year: ")[1])}`; 31 | else if (label.name.startsWith("decade: ")) 32 | description = `This book was published in the ${clean(label.name.split("decade: ")[1])}s`; 33 | else if (label.name.startsWith("language: ")) 34 | description = `This book was published in ${clean(label.name.split("language: ")[1])}`; 35 | else if (label.name.startsWith("publisher: ")) 36 | description = `This book was published by ${clean(label.name.split("publisher: ")[1])}`; 37 | else if (label.name.startsWith("author: ")) 38 | description = `This book was written by ${clean(label.name.split("author: ")[1])}`; 39 | else if (label.name.startsWith("category: ")) 40 | description = `This book is of the category "${clean(label.name.split("category: ")[1])}"`; 41 | } 42 | if (color !== label.color || description !== label.description) 43 | await octokit.rest.issues.updateLabel({ 44 | owner, 45 | repo, 46 | name: label.name, 47 | color, 48 | description, 49 | }); 50 | } 51 | } 52 | }; 53 | exports.addDetailsToLabels = addDetailsToLabels; 54 | //# sourceMappingURL=github.js.map -------------------------------------------------------------------------------- /dist/github.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/goodreads.d.ts: -------------------------------------------------------------------------------- 1 | export interface Book { 2 | title: string; 3 | author: string; 4 | image: string; 5 | year: number; 6 | goodreads: { 7 | id: number; 8 | image: string; 9 | ratingsCount: number; 10 | averageRating: number; 11 | authorId: number; 12 | }; 13 | } 14 | export declare const search: (key: string, secret: string, q: string) => Promise; 15 | -------------------------------------------------------------------------------- /dist/goodreads.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.search = void 0; 7 | const goodreads_api_node_1 = __importDefault(require("goodreads-api-node")); 8 | const search = async (key, secret, q) => { 9 | const gr = goodreads_api_node_1.default({ key, secret }); 10 | const results = await gr.searchBooks({ q }); 11 | const result = Array.isArray(results.search.results.work) 12 | ? results.search.results.work.sort((a, b) => (parseInt(b.ratings_count._) || 0) - (parseInt(a.ratings_count._) || 0))[0] 13 | : results.search.results.work; 14 | if (!result) 15 | throw new Error("Book not found"); 16 | return { 17 | title: result.best_book.title, 18 | author: result.best_book.author.name, 19 | year: parseInt(result.original_publication_year._), 20 | image: `https://images.weserv.nl/?url=${encodeURIComponent(!result.best_book.image_url.includes("nophoto") 21 | ? result.best_book.image_url 22 | : `https://tse2.mm.bing.net/th?q=${encodeURIComponent(`${result.best_book.title} ${result.best_book.author.name}`)}&w=128&c=7&rs=1&p=0&dpr=3&pid=1.7&mkt=en-IN&adlt=moderate`)}&w=128&h=192&fit=cover`, 23 | goodreads: { 24 | image: result.best_book.image_url, 25 | id: parseInt(result.best_book.id._), 26 | ratingsCount: parseFloat(result.ratings_count._), 27 | averageRating: parseFloat(result.average_rating), 28 | authorId: parseInt(result.best_book.author.id._), 29 | }, 30 | }; 31 | }; 32 | exports.search = search; 33 | //# sourceMappingURL=goodreads.js.map -------------------------------------------------------------------------------- /dist/goodreads.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"goodreads.js","sourceRoot":"","sources":["../src/goodreads.ts"],"names":[],"mappings":";;;;;;AAAA,4EAA2C;AAgBpC,MAAM,MAAM,GAAG,KAAK,EAAE,GAAW,EAAE,MAAc,EAAE,CAAS,EAAiB,EAAE;IACpF,MAAM,EAAE,GAAG,4BAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QACvD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAClF,CAAC,CAAC,CAAC;QACN,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC/C,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK;QAC7B,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI;QACpC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAClD,KAAK,EAAE,iCAAiC,kBAAkB,CACxD,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;YAC7C,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS;YAC5B,CAAC,CAAC,iCAAiC,kBAAkB,CACjD,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAC5D,2DAA2D,CACjE,wBAAwB;QACzB,SAAS,EAAE;YACT,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS;YACjC,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;YACnC,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;YAChD,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC;YAChD,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;SACjD;KACF,CAAC;AACJ,CAAC,CAAC;AA5BW,QAAA,MAAM,UA4BjB"} -------------------------------------------------------------------------------- /dist/google-books.d.ts: -------------------------------------------------------------------------------- 1 | export interface Book { 2 | kind: "books#volume"; 3 | id: string; 4 | volumeInfo: { 5 | title: string; 6 | authors: string[]; 7 | publisher: string; 8 | publishedDate: string; 9 | description: string; 10 | industryIdentifiers: [ 11 | { 12 | type: "ISBN_13"; 13 | identifier: string; 14 | }, 15 | { 16 | type: "ISBN_10"; 17 | identifier: string; 18 | } 19 | ]; 20 | pageCount: number; 21 | printType: "BOOK"; 22 | categories: string[]; 23 | averageRating: number; 24 | ratingsCount: number; 25 | maturityRating: "MATURE" | "NOT_MATURE"; 26 | imageLinks: { 27 | thumbnail: string; 28 | }; 29 | language: string; 30 | previewLink: string; 31 | infoLink: string; 32 | canonicalVolumeLink: string; 33 | }; 34 | } 35 | export interface BookResult { 36 | title: string; 37 | authors: string[]; 38 | publisher: string; 39 | publishedDate: string; 40 | description: string; 41 | image: string; 42 | language: string; 43 | averageRating: number; 44 | ratingsCount: number; 45 | categories: string[]; 46 | pageCount: number; 47 | isbn10?: string; 48 | isbn13?: string; 49 | googleBooks: { 50 | id: string; 51 | preview: string; 52 | info: string; 53 | canonical: string; 54 | }; 55 | } 56 | export declare const search: (q: string) => Promise; 57 | -------------------------------------------------------------------------------- /dist/google-books.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.search = void 0; 7 | const source_1 = __importDefault(require("got/dist/source")); 8 | const search = async (q) => { 9 | const results = await (0, source_1.default)(`https://www.googleapis.com/books/v1/volumes?q=intitle:${encodeURIComponent(q)}`, { 10 | responseType: "json", 11 | }); 12 | if (!results.body.items || results.body.items.length === 0) { 13 | console.error("No results.body.items", JSON.stringify(results.body)); 14 | throw new Error("Book not found"); 15 | } 16 | const result = results.body.items.sort((a, b) => (Number(b.volumeInfo.ratingsCount) || 0) - (Number(a.volumeInfo.ratingsCount) || 0))[0]; 17 | return { 18 | title: result.volumeInfo.title, 19 | authors: result.volumeInfo.authors, 20 | publisher: result.volumeInfo.publisher, 21 | publishedDate: result.volumeInfo.publishedDate, 22 | description: result.volumeInfo.description, 23 | image: (result.volumeInfo.imageLinks || {}).thumbnail || 24 | `https://tse2.mm.bing.net/th?q=${encodeURIComponent(`${result.volumeInfo.title} by ${result.volumeInfo.authors.join(", ")}`)}&w=256&c=7&rs=1&p=0&dpr=3&pid=1.7&mkt=en-IN&adlt=moderate`, 25 | language: result.volumeInfo.language, 26 | averageRating: result.volumeInfo.averageRating, 27 | ratingsCount: result.volumeInfo.ratingsCount, 28 | categories: result.volumeInfo.categories, 29 | pageCount: result.volumeInfo.pageCount, 30 | isbn10: ((result.volumeInfo.industryIdentifiers || []).find((i) => i.type === "ISBN_10") || {}) 31 | .identifier, 32 | isbn13: ((result.volumeInfo.industryIdentifiers || []).find((i) => i.type === "ISBN_13") || {}) 33 | .identifier, 34 | googleBooks: { 35 | id: result.id, 36 | preview: result.volumeInfo.previewLink, 37 | info: result.volumeInfo.infoLink, 38 | canonical: result.volumeInfo.canonicalVolumeLink, 39 | }, 40 | }; 41 | }; 42 | exports.search = search; 43 | //# sourceMappingURL=google-books.js.map -------------------------------------------------------------------------------- /dist/google-books.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"google-books.js","sourceRoot":"","sources":["../src/google-books.ts"],"names":[],"mappings":";;;;;;AAAA,6DAAkC;AA2D3B,MAAM,MAAM,GAAG,KAAK,EAAE,CAAS,EAAuB,EAAE;IAC7D,MAAM,OAAO,GAAG,MAAM,IAAA,gBAAG,EAEtB,yDAAyD,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE;QACnF,YAAY,EAAE,MAAM;KACrB,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAC1D,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;KACnC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAC9F,CAAC,CAAC,CAAC,CAAC;IAEL,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,KAAK;QAC9B,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO;QAClC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,SAAS;QACtC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,aAAa;QAC9C,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC,WAAW;QAC1C,KAAK,EACH,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,SAAS;YAC9C,iCAAiC,kBAAkB,CACjD,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxE,2DAA2D;QAC9D,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ;QACpC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,aAAa;QAC9C,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,YAAY;QAC5C,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,UAAU;QACxC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,SAAS;QACtC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;aAC5F,UAAU;QACb,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;aAC5F,UAAU;QACb,WAAW,EAAE;YACX,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,WAAW;YACtC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ;YAChC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,mBAAmB;SACjD;KACF,CAAC;AACJ,CAAC,CAAC;AAzCW,QAAA,MAAM,UAyCjB"} -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare const run: () => Promise; 2 | -------------------------------------------------------------------------------- /dist/index.spec.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnandChowdhary/bookshelf-action/d6cd83bed908785b90059fc0f24c7ecaed4eb76b/dist/index.spec.d.ts -------------------------------------------------------------------------------- /dist/index.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | test("sample", () => expect(1).toBe(1)); 3 | //# sourceMappingURL=index.spec.js.map -------------------------------------------------------------------------------- /dist/index.spec.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.spec.js","sourceRoot":"","sources":["../src/index.spec.ts"],"names":[],"mappings":";AAAA,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA"} -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | (()=>{var e={650:e=>{var r=Object.prototype.toString;var n=typeof Buffer.alloc==="function"&&typeof Buffer.allocUnsafe==="function"&&typeof Buffer.from==="function";function isArrayBuffer(e){return r.call(e).slice(8,-1)==="ArrayBuffer"}function fromArrayBuffer(e,r,t){r>>>=0;var o=e.byteLength-r;if(o<0){throw new RangeError("'offset' is out of bounds")}if(t===undefined){t=o}else{t>>>=0;if(t>o){throw new RangeError("'length' is out of bounds")}}return n?Buffer.from(e.slice(r,r+t)):new Buffer(new Uint8Array(e.slice(r,r+t)))}function fromString(e,r){if(typeof r!=="string"||r===""){r="utf8"}if(!Buffer.isEncoding(r)){throw new TypeError('"encoding" must be a valid string encoding')}return n?Buffer.from(e,r):new Buffer(e,r)}function bufferFrom(e,r,t){if(typeof e==="number"){throw new TypeError('"value" argument must not be a number')}if(isArrayBuffer(e)){return fromArrayBuffer(e,r,t)}if(typeof e==="string"){return fromString(e,r)}return n?Buffer.from(e):new Buffer(e)}e.exports=bufferFrom},274:(e,r,n)=>{var t=n(339);var o=Object.prototype.hasOwnProperty;var i=typeof Map!=="undefined";function ArraySet(){this._array=[];this._set=i?new Map:Object.create(null)}ArraySet.fromArray=function ArraySet_fromArray(e,r){var n=new ArraySet;for(var t=0,o=e.length;t=0){return r}}else{var n=t.toSetString(e);if(o.call(this._set,n)){return this._set[n]}}throw new Error('"'+e+'" is not in the set.')};ArraySet.prototype.at=function ArraySet_at(e){if(e>=0&&e{var t=n(190);var o=5;var i=1<>1;return r?-n:n}r.encode=function base64VLQ_encode(e){var r="";var n;var i=toVLQSigned(e);do{n=i&a;i>>>=o;if(i>0){n|=u}r+=t.encode(n)}while(i>0);return r};r.decode=function base64VLQ_decode(e,r,n){var i=e.length;var s=0;var l=0;var c,p;do{if(r>=i){throw new Error("Expected more digits in base 64 VLQ value.")}p=t.decode(e.charCodeAt(r++));if(p===-1){throw new Error("Invalid base64 digit: "+e.charAt(r-1))}c=!!(p&u);p&=a;s=s+(p<{var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");r.encode=function(e){if(0<=e&&e{r.GREATEST_LOWER_BOUND=1;r.LEAST_UPPER_BOUND=2;function recursiveSearch(e,n,t,o,i,a){var u=Math.floor((n-e)/2)+e;var s=i(t,o[u],true);if(s===0){return u}else if(s>0){if(n-u>1){return recursiveSearch(u,n,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return n1){return recursiveSearch(e,u,t,o,i,a)}if(a==r.LEAST_UPPER_BOUND){return u}else{return e<0?-1:e}}}r.search=function search(e,n,t,o){if(n.length===0){return-1}var i=recursiveSearch(-1,n.length,e,n,t,o||r.GREATEST_LOWER_BOUND);if(i<0){return-1}while(i-1>=0){if(t(n[i],n[i-1],true)!==0){break}--i}return i}},680:(e,r,n)=>{var t=n(339);function generatedPositionAfter(e,r){var n=e.generatedLine;var o=r.generatedLine;var i=e.generatedColumn;var a=r.generatedColumn;return o>n||o==n&&a>=i||t.compareByGeneratedPositionsInflated(e,r)<=0}function MappingList(){this._array=[];this._sorted=true;this._last={generatedLine:-1,generatedColumn:0}}MappingList.prototype.unsortedForEach=function MappingList_forEach(e,r){this._array.forEach(e,r)};MappingList.prototype.add=function MappingList_add(e){if(generatedPositionAfter(this._last,e)){this._last=e;this._array.push(e)}else{this._sorted=false;this._array.push(e)}};MappingList.prototype.toArray=function MappingList_toArray(){if(!this._sorted){this._array.sort(t.compareByGeneratedPositionsInflated);this._sorted=true}return this._array};r.H=MappingList},758:(e,r)=>{function swap(e,r,n){var t=e[r];e[r]=e[n];e[n]=t}function randomIntInRange(e,r){return Math.round(e+Math.random()*(r-e))}function doQuickSort(e,r,n,t){if(n{var t;var o=n(339);var i=n(345);var a=n(274).I;var u=n(449);var s=n(758).U;function SourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}return n.sections!=null?new IndexedSourceMapConsumer(n,r):new BasicSourceMapConsumer(n,r)}SourceMapConsumer.fromSourceMap=function(e,r){return BasicSourceMapConsumer.fromSourceMap(e,r)};SourceMapConsumer.prototype._version=3;SourceMapConsumer.prototype.__generatedMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_generatedMappings",{configurable:true,enumerable:true,get:function(){if(!this.__generatedMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__generatedMappings}});SourceMapConsumer.prototype.__originalMappings=null;Object.defineProperty(SourceMapConsumer.prototype,"_originalMappings",{configurable:true,enumerable:true,get:function(){if(!this.__originalMappings){this._parseMappings(this._mappings,this.sourceRoot)}return this.__originalMappings}});SourceMapConsumer.prototype._charIsMappingSeparator=function SourceMapConsumer_charIsMappingSeparator(e,r){var n=e.charAt(r);return n===";"||n===","};SourceMapConsumer.prototype._parseMappings=function SourceMapConsumer_parseMappings(e,r){throw new Error("Subclasses must implement _parseMappings")};SourceMapConsumer.GENERATED_ORDER=1;SourceMapConsumer.ORIGINAL_ORDER=2;SourceMapConsumer.GREATEST_LOWER_BOUND=1;SourceMapConsumer.LEAST_UPPER_BOUND=2;SourceMapConsumer.prototype.eachMapping=function SourceMapConsumer_eachMapping(e,r,n){var t=r||null;var i=n||SourceMapConsumer.GENERATED_ORDER;var a;switch(i){case SourceMapConsumer.GENERATED_ORDER:a=this._generatedMappings;break;case SourceMapConsumer.ORIGINAL_ORDER:a=this._originalMappings;break;default:throw new Error("Unknown order of iteration.")}var u=this.sourceRoot;a.map((function(e){var r=e.source===null?null:this._sources.at(e.source);r=o.computeSourceURL(u,r,this._sourceMapURL);return{source:r,generatedLine:e.generatedLine,generatedColumn:e.generatedColumn,originalLine:e.originalLine,originalColumn:e.originalColumn,name:e.name===null?null:this._names.at(e.name)}}),this).forEach(e,t)};SourceMapConsumer.prototype.allGeneratedPositionsFor=function SourceMapConsumer_allGeneratedPositionsFor(e){var r=o.getArg(e,"line");var n={source:o.getArg(e,"source"),originalLine:r,originalColumn:o.getArg(e,"column",0)};n.source=this._findSourceIndex(n.source);if(n.source<0){return[]}var t=[];var a=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,i.LEAST_UPPER_BOUND);if(a>=0){var u=this._originalMappings[a];if(e.column===undefined){var s=u.originalLine;while(u&&u.originalLine===s){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}else{var l=u.originalColumn;while(u&&u.originalLine===r&&u.originalColumn==l){t.push({line:o.getArg(u,"generatedLine",null),column:o.getArg(u,"generatedColumn",null),lastColumn:o.getArg(u,"lastGeneratedColumn",null)});u=this._originalMappings[++a]}}}return t};r.SourceMapConsumer=SourceMapConsumer;function BasicSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sources");var u=o.getArg(n,"names",[]);var s=o.getArg(n,"sourceRoot",null);var l=o.getArg(n,"sourcesContent",null);var c=o.getArg(n,"mappings");var p=o.getArg(n,"file",null);if(t!=this._version){throw new Error("Unsupported version: "+t)}if(s){s=o.normalize(s)}i=i.map(String).map(o.normalize).map((function(e){return s&&o.isAbsolute(s)&&o.isAbsolute(e)?o.relative(s,e):e}));this._names=a.fromArray(u.map(String),true);this._sources=a.fromArray(i,true);this._absoluteSources=this._sources.toArray().map((function(e){return o.computeSourceURL(s,e,r)}));this.sourceRoot=s;this.sourcesContent=l;this._mappings=c;this._sourceMapURL=r;this.file=p}BasicSourceMapConsumer.prototype=Object.create(SourceMapConsumer.prototype);BasicSourceMapConsumer.prototype.consumer=SourceMapConsumer;BasicSourceMapConsumer.prototype._findSourceIndex=function(e){var r=e;if(this.sourceRoot!=null){r=o.relative(this.sourceRoot,r)}if(this._sources.has(r)){return this._sources.indexOf(r)}var n;for(n=0;n1){v.source=l+_[1];l+=_[1];v.originalLine=i+_[2];i=v.originalLine;v.originalLine+=1;v.originalColumn=a+_[3];a=v.originalColumn;if(_.length>4){v.name=c+_[4];c+=_[4]}}m.push(v);if(typeof v.originalLine==="number"){d.push(v)}}}s(m,o.compareByGeneratedPositionsDeflated);this.__generatedMappings=m;s(d,o.compareByOriginalPositions);this.__originalMappings=d};BasicSourceMapConsumer.prototype._findMapping=function SourceMapConsumer_findMapping(e,r,n,t,o,a){if(e[n]<=0){throw new TypeError("Line must be greater than or equal to 1, got "+e[n])}if(e[t]<0){throw new TypeError("Column must be greater than or equal to 0, got "+e[t])}return i.search(e,r,o,a)};BasicSourceMapConsumer.prototype.computeColumnSpans=function SourceMapConsumer_computeColumnSpans(){for(var e=0;e=0){var t=this._generatedMappings[n];if(t.generatedLine===r.generatedLine){var i=o.getArg(t,"source",null);if(i!==null){i=this._sources.at(i);i=o.computeSourceURL(this.sourceRoot,i,this._sourceMapURL)}var a=o.getArg(t,"name",null);if(a!==null){a=this._names.at(a)}return{source:i,line:o.getArg(t,"originalLine",null),column:o.getArg(t,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}};BasicSourceMapConsumer.prototype.hasContentsOfAllSources=function BasicSourceMapConsumer_hasContentsOfAllSources(){if(!this.sourcesContent){return false}return this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some((function(e){return e==null}))};BasicSourceMapConsumer.prototype.sourceContentFor=function SourceMapConsumer_sourceContentFor(e,r){if(!this.sourcesContent){return null}var n=this._findSourceIndex(e);if(n>=0){return this.sourcesContent[n]}var t=e;if(this.sourceRoot!=null){t=o.relative(this.sourceRoot,t)}var i;if(this.sourceRoot!=null&&(i=o.urlParse(this.sourceRoot))){var a=t.replace(/^file:\/\//,"");if(i.scheme=="file"&&this._sources.has(a)){return this.sourcesContent[this._sources.indexOf(a)]}if((!i.path||i.path=="/")&&this._sources.has("/"+t)){return this.sourcesContent[this._sources.indexOf("/"+t)]}}if(r){return null}else{throw new Error('"'+t+'" is not in the SourceMap.')}};BasicSourceMapConsumer.prototype.generatedPositionFor=function SourceMapConsumer_generatedPositionFor(e){var r=o.getArg(e,"source");r=this._findSourceIndex(r);if(r<0){return{line:null,column:null,lastColumn:null}}var n={source:r,originalLine:o.getArg(e,"line"),originalColumn:o.getArg(e,"column")};var t=this._findMapping(n,this._originalMappings,"originalLine","originalColumn",o.compareByOriginalPositions,o.getArg(e,"bias",SourceMapConsumer.GREATEST_LOWER_BOUND));if(t>=0){var i=this._originalMappings[t];if(i.source===n.source){return{line:o.getArg(i,"generatedLine",null),column:o.getArg(i,"generatedColumn",null),lastColumn:o.getArg(i,"lastGeneratedColumn",null)}}}return{line:null,column:null,lastColumn:null}};t=BasicSourceMapConsumer;function IndexedSourceMapConsumer(e,r){var n=e;if(typeof e==="string"){n=o.parseSourceMapInput(e)}var t=o.getArg(n,"version");var i=o.getArg(n,"sections");if(t!=this._version){throw new Error("Unsupported version: "+t)}this._sources=new a;this._names=new a;var u={line:-1,column:0};this._sections=i.map((function(e){if(e.url){throw new Error("Support for url field in sections not implemented.")}var n=o.getArg(e,"offset");var t=o.getArg(n,"line");var i=o.getArg(n,"column");if(t{var t=n(449);var o=n(339);var i=n(274).I;var a=n(680).H;function SourceMapGenerator(e){if(!e){e={}}this._file=o.getArg(e,"file",null);this._sourceRoot=o.getArg(e,"sourceRoot",null);this._skipValidation=o.getArg(e,"skipValidation",false);this._sources=new i;this._names=new i;this._mappings=new a;this._sourcesContents=null}SourceMapGenerator.prototype._version=3;SourceMapGenerator.fromSourceMap=function SourceMapGenerator_fromSourceMap(e){var r=e.sourceRoot;var n=new SourceMapGenerator({file:e.file,sourceRoot:r});e.eachMapping((function(e){var t={generated:{line:e.generatedLine,column:e.generatedColumn}};if(e.source!=null){t.source=e.source;if(r!=null){t.source=o.relative(r,t.source)}t.original={line:e.originalLine,column:e.originalColumn};if(e.name!=null){t.name=e.name}}n.addMapping(t)}));e.sources.forEach((function(t){var i=t;if(r!==null){i=o.relative(r,t)}if(!n._sources.has(i)){n._sources.add(i)}var a=e.sourceContentFor(t);if(a!=null){n.setSourceContent(t,a)}}));return n};SourceMapGenerator.prototype.addMapping=function SourceMapGenerator_addMapping(e){var r=o.getArg(e,"generated");var n=o.getArg(e,"original",null);var t=o.getArg(e,"source",null);var i=o.getArg(e,"name",null);if(!this._skipValidation){this._validateMapping(r,n,t,i)}if(t!=null){t=String(t);if(!this._sources.has(t)){this._sources.add(t)}}if(i!=null){i=String(i);if(!this._names.has(i)){this._names.add(i)}}this._mappings.add({generatedLine:r.line,generatedColumn:r.column,originalLine:n!=null&&n.line,originalColumn:n!=null&&n.column,source:t,name:i})};SourceMapGenerator.prototype.setSourceContent=function SourceMapGenerator_setSourceContent(e,r){var n=e;if(this._sourceRoot!=null){n=o.relative(this._sourceRoot,n)}if(r!=null){if(!this._sourcesContents){this._sourcesContents=Object.create(null)}this._sourcesContents[o.toSetString(n)]=r}else if(this._sourcesContents){delete this._sourcesContents[o.toSetString(n)];if(Object.keys(this._sourcesContents).length===0){this._sourcesContents=null}}};SourceMapGenerator.prototype.applySourceMap=function SourceMapGenerator_applySourceMap(e,r,n){var t=r;if(r==null){if(e.file==null){throw new Error("SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, "+'or the source map\'s "file" property. Both were omitted.')}t=e.file}var a=this._sourceRoot;if(a!=null){t=o.relative(a,t)}var u=new i;var s=new i;this._mappings.unsortedForEach((function(r){if(r.source===t&&r.originalLine!=null){var i=e.originalPositionFor({line:r.originalLine,column:r.originalColumn});if(i.source!=null){r.source=i.source;if(n!=null){r.source=o.join(n,r.source)}if(a!=null){r.source=o.relative(a,r.source)}r.originalLine=i.line;r.originalColumn=i.column;if(i.name!=null){r.name=i.name}}}var l=r.source;if(l!=null&&!u.has(l)){u.add(l)}var c=r.name;if(c!=null&&!s.has(c)){s.add(c)}}),this);this._sources=u;this._names=s;e.sources.forEach((function(r){var t=e.sourceContentFor(r);if(t!=null){if(n!=null){r=o.join(n,r)}if(a!=null){r=o.relative(a,r)}this.setSourceContent(r,t)}}),this)};SourceMapGenerator.prototype._validateMapping=function SourceMapGenerator_validateMapping(e,r,n,t){if(r&&typeof r.line!=="number"&&typeof r.column!=="number"){throw new Error("original.line and original.column are not numbers -- you probably meant to omit "+"the original mapping entirely and only map the generated position. If so, pass "+"null for the original mapping instead of an object with empty or null values.")}if(e&&"line"in e&&"column"in e&&e.line>0&&e.column>=0&&!r&&!n&&!t){return}else if(e&&"line"in e&&"column"in e&&r&&"line"in r&&"column"in r&&e.line>0&&e.column>=0&&r.line>0&&r.column>=0&&n){return}else{throw new Error("Invalid mapping: "+JSON.stringify({generated:e,source:n,original:r,name:t}))}};SourceMapGenerator.prototype._serializeMappings=function SourceMapGenerator_serializeMappings(){var e=0;var r=1;var n=0;var i=0;var a=0;var u=0;var s="";var l;var c;var p;var f;var g=this._mappings.toArray();for(var h=0,d=g.length;h0){if(!o.compareByGeneratedPositionsInflated(c,g[h-1])){continue}l+=","}}l+=t.encode(c.generatedColumn-e);e=c.generatedColumn;if(c.source!=null){f=this._sources.indexOf(c.source);l+=t.encode(f-u);u=f;l+=t.encode(c.originalLine-1-i);i=c.originalLine-1;l+=t.encode(c.originalColumn-n);n=c.originalColumn;if(c.name!=null){p=this._names.indexOf(c.name);l+=t.encode(p-a);a=p}}s+=l}return s};SourceMapGenerator.prototype._generateSourcesContent=function SourceMapGenerator_generateSourcesContent(e,r){return e.map((function(e){if(!this._sourcesContents){return null}if(r!=null){e=o.relative(r,e)}var n=o.toSetString(e);return Object.prototype.hasOwnProperty.call(this._sourcesContents,n)?this._sourcesContents[n]:null}),this)};SourceMapGenerator.prototype.toJSON=function SourceMapGenerator_toJSON(){var e={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};if(this._file!=null){e.file=this._file}if(this._sourceRoot!=null){e.sourceRoot=this._sourceRoot}if(this._sourcesContents){e.sourcesContent=this._generateSourcesContent(e.sources,e.sourceRoot)}return e};SourceMapGenerator.prototype.toString=function SourceMapGenerator_toString(){return JSON.stringify(this.toJSON())};r.h=SourceMapGenerator},351:(e,r,n)=>{var t;var o=n(591).h;var i=n(339);var a=/(\r?\n)/;var u=10;var s="$$$isSourceNode$$$";function SourceNode(e,r,n,t,o){this.children=[];this.sourceContents={};this.line=e==null?null:e;this.column=r==null?null:r;this.source=n==null?null:n;this.name=o==null?null:o;this[s]=true;if(t!=null)this.add(t)}SourceNode.fromStringWithSourceMap=function SourceNode_fromStringWithSourceMap(e,r,n){var t=new SourceNode;var o=e.split(a);var u=0;var shiftNextLine=function(){var e=getNextLine();var r=getNextLine()||"";return e+r;function getNextLine(){return u=0;r--){this.prepend(e[r])}}else if(e[s]||typeof e==="string"){this.children.unshift(e)}else{throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+e)}return this};SourceNode.prototype.walk=function SourceNode_walk(e){var r;for(var n=0,t=this.children.length;n0){r=[];for(n=0;n{function getArg(e,r,n){if(r in e){return e[r]}else if(arguments.length===3){return n}else{throw new Error('"'+r+'" is a required argument.')}}r.getArg=getArg;var n=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;var t=/^data:.+\,.+$/;function urlParse(e){var r=e.match(n);if(!r){return null}return{scheme:r[1],auth:r[2],host:r[3],port:r[4],path:r[5]}}r.urlParse=urlParse;function urlGenerate(e){var r="";if(e.scheme){r+=e.scheme+":"}r+="//";if(e.auth){r+=e.auth+"@"}if(e.host){r+=e.host}if(e.port){r+=":"+e.port}if(e.path){r+=e.path}return r}r.urlGenerate=urlGenerate;function normalize(e){var n=e;var t=urlParse(e);if(t){if(!t.path){return e}n=t.path}var o=r.isAbsolute(n);var i=n.split(/\/+/);for(var a,u=0,s=i.length-1;s>=0;s--){a=i[s];if(a==="."){i.splice(s,1)}else if(a===".."){u++}else if(u>0){if(a===""){i.splice(s+1,u);u=0}else{i.splice(s,2);u--}}}n=i.join("/");if(n===""){n=o?"/":"."}if(t){t.path=n;return urlGenerate(t)}return n}r.normalize=normalize;function join(e,r){if(e===""){e="."}if(r===""){r="."}var n=urlParse(r);var o=urlParse(e);if(o){e=o.path||"/"}if(n&&!n.scheme){if(o){n.scheme=o.scheme}return urlGenerate(n)}if(n||r.match(t)){return r}if(o&&!o.host&&!o.path){o.host=r;return urlGenerate(o)}var i=r.charAt(0)==="/"?r:normalize(e.replace(/\/+$/,"")+"/"+r);if(o){o.path=i;return urlGenerate(o)}return i}r.join=join;r.isAbsolute=function(e){return e.charAt(0)==="/"||n.test(e)};function relative(e,r){if(e===""){e="."}e=e.replace(/\/$/,"");var n=0;while(r.indexOf(e+"/")!==0){var t=e.lastIndexOf("/");if(t<0){return r}e=e.slice(0,t);if(e.match(/^([^\/]+:\/)?\/*$/)){return r}++n}return Array(n+1).join("../")+r.substr(e.length+1)}r.relative=relative;var o=function(){var e=Object.create(null);return!("__proto__"in e)}();function identity(e){return e}function toSetString(e){if(isProtoString(e)){return"$"+e}return e}r.toSetString=o?identity:toSetString;function fromSetString(e){if(isProtoString(e)){return e.slice(1)}return e}r.fromSetString=o?identity:fromSetString;function isProtoString(e){if(!e){return false}var r=e.length;if(r<9){return false}if(e.charCodeAt(r-1)!==95||e.charCodeAt(r-2)!==95||e.charCodeAt(r-3)!==111||e.charCodeAt(r-4)!==116||e.charCodeAt(r-5)!==111||e.charCodeAt(r-6)!==114||e.charCodeAt(r-7)!==112||e.charCodeAt(r-8)!==95||e.charCodeAt(r-9)!==95){return false}for(var n=r-10;n>=0;n--){if(e.charCodeAt(n)!==36){return false}}return true}function compareByOriginalPositions(e,r,n){var t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0||n){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0){return t}t=e.generatedLine-r.generatedLine;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByOriginalPositions=compareByOriginalPositions;function compareByGeneratedPositionsDeflated(e,r,n){var t=e.generatedLine-r.generatedLine;if(t!==0){return t}t=e.generatedColumn-r.generatedColumn;if(t!==0||n){return t}t=strcmp(e.source,r.source);if(t!==0){return t}t=e.originalLine-r.originalLine;if(t!==0){return t}t=e.originalColumn-r.originalColumn;if(t!==0){return t}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsDeflated=compareByGeneratedPositionsDeflated;function strcmp(e,r){if(e===r){return 0}if(e===null){return 1}if(r===null){return-1}if(e>r){return 1}return-1}function compareByGeneratedPositionsInflated(e,r){var n=e.generatedLine-r.generatedLine;if(n!==0){return n}n=e.generatedColumn-r.generatedColumn;if(n!==0){return n}n=strcmp(e.source,r.source);if(n!==0){return n}n=e.originalLine-r.originalLine;if(n!==0){return n}n=e.originalColumn-r.originalColumn;if(n!==0){return n}return strcmp(e.name,r.name)}r.compareByGeneratedPositionsInflated=compareByGeneratedPositionsInflated;function parseSourceMapInput(e){return JSON.parse(e.replace(/^\)]}'[^\n]*\n/,""))}r.parseSourceMapInput=parseSourceMapInput;function computeSourceURL(e,r,n){r=r||"";if(e){if(e[e.length-1]!=="/"&&r[0]!=="/"){e+="/"}r=e+r}if(n){var t=urlParse(n);if(!t){throw new Error("sourceMapURL could not be parsed")}if(t.path){var o=t.path.lastIndexOf("/");if(o>=0){t.path=t.path.substring(0,o+1)}}r=join(urlGenerate(t),r)}return normalize(r)}r.computeSourceURL=computeSourceURL},997:(e,r,n)=>{n(591).h;r.SourceMapConsumer=n(952).SourceMapConsumer;n(351)},284:(e,r,n)=>{e=n.nmd(e);var t=n(997).SourceMapConsumer;var o=n(17);var i;try{i=n(147);if(!i.existsSync||!i.readFileSync){i=null}}catch(e){}var a=n(650);function dynamicRequire(e,r){return e.require(r)}var u=false;var s=false;var l=false;var c="auto";var p={};var f={};var g=/^data:application\/json[^,]+base64,/;var h=[];var d=[];function isInBrowser(){if(c==="browser")return true;if(c==="node")return false;return typeof window!=="undefined"&&typeof XMLHttpRequest==="function"&&!(window.require&&window.module&&window.process&&window.process.type==="renderer")}function hasGlobalProcessEventEmitter(){return typeof process==="object"&&process!==null&&typeof process.on==="function"}function globalProcessVersion(){if(typeof process==="object"&&process!==null){return process.version}else{return""}}function globalProcessStderr(){if(typeof process==="object"&&process!==null){return process.stderr}}function globalProcessExit(e){if(typeof process==="object"&&process!==null&&typeof process.exit==="function"){return process.exit(e)}}function handlerExec(e){return function(r){for(var n=0;n"}var n=this.getLineNumber();if(n!=null){r+=":"+n;var t=this.getColumnNumber();if(t){r+=":"+t}}}var o="";var i=this.getFunctionName();var a=true;var u=this.isConstructor();var s=!(this.isToplevel()||u);if(s){var l=this.getTypeName();if(l==="[object Object]"){l="null"}var c=this.getMethodName();if(i){if(l&&i.indexOf(l)!=0){o+=l+"."}o+=i;if(c&&i.indexOf("."+c)!=i.length-c.length-1){o+=" [as "+c+"]"}}else{o+=l+"."+(c||"")}}else if(u){o+="new "+(i||"")}else if(i){o+=i}else{o+=r;a=false}if(a){o+=" ("+r+")"}return o}function cloneCallSite(e){var r={};Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach((function(n){r[n]=/^(?:is|get)/.test(n)?function(){return e[n].call(e)}:e[n]}));r.toString=CallSiteToString;return r}function wrapCallSite(e,r){if(r===undefined){r={nextPosition:null,curPosition:null}}if(e.isNative()){r.curPosition=null;return e}var n=e.getFileName()||e.getScriptNameOrSourceURL();if(n){var t=e.getLineNumber();var o=e.getColumnNumber()-1;var i=/^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;var a=i.test(globalProcessVersion())?0:62;if(t===1&&o>a&&!isInBrowser()&&!e.isEval()){o-=a}var u=mapSourcePosition({source:n,line:t,column:o});r.curPosition=u;e=cloneCallSite(e);var s=e.getFunctionName;e.getFunctionName=function(){if(r.nextPosition==null){return s()}return r.nextPosition.name||s()};e.getFileName=function(){return u.source};e.getLineNumber=function(){return u.line};e.getColumnNumber=function(){return u.column+1};e.getScriptNameOrSourceURL=function(){return u.source};return e}var l=e.isEval()&&e.getEvalOrigin();if(l){l=mapEvalOrigin(l);e=cloneCallSite(e);e.getEvalOrigin=function(){return l};return e}return e}function prepareStackTrace(e,r){if(l){p={};f={}}var n=e.name||"Error";var t=e.message||"";var o=n+": "+t;var i={nextPosition:null,curPosition:null};var a=[];for(var u=r.length-1;u>=0;u--){a.push("\n at "+wrapCallSite(r[u],i));i.nextPosition=i.curPosition}i.curPosition=i.nextPosition=null;return o+a.reverse().join("")}function getErrorSource(e){var r=/\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(e.stack);if(r){var n=r[1];var t=+r[2];var o=+r[3];var a=p[n];if(!a&&i&&i.existsSync(n)){try{a=i.readFileSync(n,"utf8")}catch(e){a=""}}if(a){var u=a.split(/(?:\r\n|\r|\n)/)[t-1];if(u){return n+":"+t+"\n"+u+"\n"+new Array(o).join(" ")+"^"}}}return null}function printErrorAndExit(e){var r=getErrorSource(e);var n=globalProcessStderr();if(n&&n._handle&&n._handle.setBlocking){n._handle.setBlocking(true)}if(r){console.error();console.error(r)}console.error(e.stack);globalProcessExit(1)}function shimEmitUncaughtException(){var e=process.emit;process.emit=function(r){if(r==="uncaughtException"){var n=arguments[1]&&arguments[1].stack;var t=this.listeners(r).length>0;if(n&&!t){return printErrorAndExit(arguments[1])}}return e.apply(this,arguments)}}var S=h.slice(0);var _=d.slice(0);r.wrapCallSite=wrapCallSite;r.getErrorSource=getErrorSource;r.mapSourcePosition=mapSourcePosition;r.retrieveSourceMap=v;r.install=function(r){r=r||{};if(r.environment){c=r.environment;if(["node","browser","auto"].indexOf(c)===-1){throw new Error("environment "+c+" was unknown. Available options are {auto, browser, node}")}}if(r.retrieveFile){if(r.overrideRetrieveFile){h.length=0}h.unshift(r.retrieveFile)}if(r.retrieveSourceMap){if(r.overrideRetrieveSourceMap){d.length=0}d.unshift(r.retrieveSourceMap)}if(r.hookRequire&&!isInBrowser()){var n=dynamicRequire(e,"module");var t=n.prototype._compile;if(!t.__sourceMapSupport){n.prototype._compile=function(e,r){p[r]=e;f[r]=undefined;return t.call(this,e,r)};n.prototype._compile.__sourceMapSupport=true}}if(!l){l="emptyCacheBetweenOperations"in r?r.emptyCacheBetweenOperations:false}if(!u){u=true;Error.prepareStackTrace=prepareStackTrace}if(!s){var o="handleUncaughtExceptions"in r?r.handleUncaughtExceptions:true;try{var i=dynamicRequire(e,"worker_threads");if(i.isMainThread===false){o=false}}catch(e){}if(o&&hasGlobalProcessEventEmitter()){s=true;shimEmitUncaughtException()}}};r.resetRetrieveHandlers=function(){h.length=0;d.length=0;h=S.slice(0);d=_.slice(0);v=handlerExec(d);m=handlerExec(h)}},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")}};var r={};function __webpack_require__(n){var t=r[n];if(t!==undefined){return t.exports}var o=r[n]={id:n,loaded:false,exports:{}};var i=true;try{e[n](o,o.exports,__webpack_require__);i=false}finally{if(i)delete r[n]}o.loaded=true;return o.exports}(()=>{__webpack_require__.nmd=e=>{e.paths=[];if(!e.children)e.children=[];return e}})();if(typeof __webpack_require__!=="undefined")__webpack_require__.ab=__dirname+"/";var n={};(()=>{__webpack_require__(284).install()})();module.exports=n})(); -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | roots: ["/src/"], 5 | transform: { 6 | "^.+\\.tsx?$": "ts-jest", 7 | }, 8 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 9 | automock: false, 10 | }; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bookshelf-action", 3 | "version": "1.1.0", 4 | "description": "Track your reading using GitHub Actions", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "package": "ncc build --source-map", 9 | "test": "jest" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/AnandChowdhary/bookshelf-action.git" 14 | }, 15 | "keywords": [ 16 | "books", 17 | "tracker", 18 | "api", 19 | "generator", 20 | "github", 21 | "github actions", 22 | "nodejs", 23 | "typescript", 24 | "starter" 25 | ], 26 | "author": "Anand Chowdhary ", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/AnandChowdhary/bookshelf-action/issues" 30 | }, 31 | "homepage": "https://github.com/AnandChowdhary/bookshelf-action#readme", 32 | "devDependencies": { 33 | "@semantic-release/git": "^10.0.1", 34 | "@types/humanize-duration": "^3.27.1", 35 | "@types/jest": "^28.1.7", 36 | "@types/randomcolor": "^0.5.6", 37 | "@types/shelljs": "^0.8.11", 38 | "jest": "^28.1.3", 39 | "semantic-release": "^19.0.3", 40 | "semantic-release-gitmoji": "^1.4.4", 41 | "ts-jest": "^28.0.8", 42 | "typescript": "^4.7.4" 43 | }, 44 | "dependencies": { 45 | "@actions/core": "^1.9.1", 46 | "@actions/github": "^5.0.3", 47 | "@anandchowdhary/cosmic": "^1.0.1", 48 | "@koj/config": "^1.2.11", 49 | "@sindresorhus/slugify": "^1.1.0", 50 | "@vercel/ncc": "^0.38.1", 51 | "got": "^11.8.1", 52 | "humanize-duration": "^3.27.2", 53 | "locale-codes": "^1.3.1", 54 | "prettier": "^2.7.1", 55 | "randomcolor": "^0.6.2", 56 | "shelljs": "^0.8.5" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("@koj/config").releaseMaster; 2 | -------------------------------------------------------------------------------- /src/features/close-issue.ts: -------------------------------------------------------------------------------- 1 | import { debug } from "@actions/core"; 2 | import { Context } from "@actions/github/lib/context"; 3 | import type { GitHub } from "@actions/github/lib/utils"; 4 | import { config, cosmic } from "@anandchowdhary/cosmic"; 5 | import slugify from "@sindresorhus/slugify"; 6 | import HumanizeDuration from "humanize-duration"; 7 | import { updateSummary } from "./update-summary"; 8 | 9 | export const onCloseIssue = async ( 10 | owner: string, 11 | repo: string, 12 | context: Context, 13 | octokit: InstanceType 14 | ) => { 15 | debug("Started onCloseIssue"); 16 | try { 17 | await cosmic("bookshelf"); 18 | debug("Got config object"); 19 | } catch (error) {} 20 | const issue = await octokit.rest.issues.get({ 21 | owner: context.issue.owner, 22 | repo: context.issue.repo, 23 | issue_number: context.issue.number, 24 | }); 25 | debug(`Got issue #${issue.data.number}`); 26 | if (config("users") && Array.isArray(config("users"))) { 27 | if (!(config("users") as string[]).find((i) => (issue.data.user || {}).login)) 28 | return debug("User not allowed, skipping"); 29 | } 30 | await octokit.rest.issues.unlock({ 31 | owner: context.issue.owner, 32 | repo: context.issue.repo, 33 | issue_number: context.issue.number, 34 | }); 35 | debug("Unlocked issue"); 36 | if (!issue.data.closed_at) throw new Error("Closed date not found"); 37 | await octokit.rest.issues.createComment({ 38 | owner: context.issue.owner, 39 | repo: context.issue.repo, 40 | issue_number: context.issue.number, 41 | body: `You completed this book in ${HumanizeDuration( 42 | new Date(issue.data.closed_at).getTime() - new Date(issue.data.created_at).getTime() 43 | )}, great job!`, 44 | }); 45 | debug(`Created comment in issue #${issue.data.number}`); 46 | await octokit.rest.issues.lock({ 47 | owner: context.issue.owner, 48 | repo: context.issue.repo, 49 | issue_number: context.issue.number, 50 | }); 51 | debug("Locked issue"); 52 | await octokit.rest.issues.addLabels({ 53 | owner: context.issue.owner, 54 | repo: context.issue.repo, 55 | issue_number: context.issue.number, 56 | labels: [ 57 | `completed: ${slugify(new Date().toLocaleString("en", { month: "long" }))}`, 58 | `completed: ${new Date().getUTCFullYear()}`, 59 | ], 60 | }); 61 | debug(`Added "completed" labels to issue #${issue.data.number}`); 62 | const currentPercentage = issue.data.title.match(/\(\d+\%\)/g); 63 | await octokit.rest.issues.update({ 64 | owner: context.issue.owner, 65 | repo: context.issue.repo, 66 | issue_number: context.issue.number, 67 | title: 68 | currentPercentage && currentPercentage.length 69 | ? `${issue.data.title.split(currentPercentage[0])[0].trim()} (${100}%)` 70 | : `${issue.data.title.trim()} (${100}%)`, 71 | }); 72 | // Remove "want to read" label if it's there 73 | if ( 74 | issue.data.labels.find((i) => 75 | typeof i === "string" ? i === "want to read" : i.name === "want to read" 76 | ) 77 | ) { 78 | await octokit.rest.issues.removeLabel({ 79 | owner: context.issue.owner, 80 | repo: context.issue.repo, 81 | issue_number: context.issue.number, 82 | name: "want to read", 83 | }); 84 | debug("Removed 'want to read' label"); 85 | } 86 | await updateSummary(owner, repo, context, octokit); 87 | }; 88 | -------------------------------------------------------------------------------- /src/features/issue-comment.ts: -------------------------------------------------------------------------------- 1 | import { debug } from "@actions/core"; 2 | import { Context } from "@actions/github/lib/context"; 3 | import type { GitHub } from "@actions/github/lib/utils"; 4 | import { config, cosmic } from "@anandchowdhary/cosmic"; 5 | import { BookResult } from "../google-books"; 6 | import { updateSummary } from "./update-summary"; 7 | 8 | export const onIssueComment = async ( 9 | owner: string, 10 | repo: string, 11 | context: Context, 12 | octokit: InstanceType 13 | ) => { 14 | debug("Started onIssueComment"); 15 | try { 16 | await cosmic("bookshelf"); 17 | debug("Got config object"); 18 | } catch (error) {} 19 | const issue = await octokit.rest.issues.get({ 20 | owner: context.issue.owner, 21 | repo: context.issue.repo, 22 | issue_number: context.issue.number, 23 | }); 24 | debug(`Got issue #${issue.data.number}`); 25 | if (config("users") && Array.isArray(config("users"))) { 26 | if (!(config("users") as string[]).find((i) => (issue.data.user || {}).login)) 27 | return debug("User not allowed, skipping"); 28 | } 29 | if ( 30 | !issue.data.labels.find((i) => 31 | typeof i === "string" ? i === "kind: book" : i.name === "kind: book" 32 | ) 33 | ) 34 | return debug('Issue not of "kind: book", skipping'); 35 | if ((issue.data.body || "").includes("This comment is autogenerated")) 36 | return debug("Comment was autogenerated, skipping"); 37 | 38 | const comments = await octokit.rest.issues.listComments({ 39 | owner: context.issue.owner, 40 | repo: context.issue.repo, 41 | issue_number: context.issue.number, 42 | }); 43 | debug(`Got ${comments.data.length} comments in issue`); 44 | if (comments.data.length < 2) return debug("Less than 2 comments, skipping"); 45 | 46 | let json: BookResult | undefined = undefined; 47 | try { 48 | comments.data.forEach((comment) => { 49 | if ((comment.body || "").includes("Book details (JSON)")) 50 | json = JSON.parse((comment.body || "").split("```json")[1].split("```")[0]) as BookResult; 51 | }); 52 | } catch (error) { 53 | console.log("JSON parsing error", error); 54 | } 55 | debug("Got JSON data for book"); 56 | if (json) debug(`Total pages in JSON are ${(json as BookResult).pageCount}`); 57 | 58 | const lastComment = comments.data.sort( 59 | (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime() 60 | )[0]; 61 | if (!lastComment) throw new Error("Last comment not found"); 62 | debug(`Found last comment #${lastComment.id}`); 63 | let progressPercent = 0; 64 | let totalPages = json ? (json as BookResult).pageCount : 1; 65 | if ((lastComment.body || "").includes("/")) { 66 | debug("Last comment includes slash so must have length"); 67 | const num = (lastComment.body || "").split("/")[1].match(/\d+/g); 68 | if (num && num.length) { 69 | debug(`Got ${num.length} numerical matches`); 70 | const potentialPages = parseInt(num[0]); 71 | if (!isNaN(potentialPages)) { 72 | if (potentialPages) totalPages = potentialPages; 73 | debug(`Total pages from comment are ${totalPages}`); 74 | } 75 | } 76 | } else debug("Last comment doesn't have slash"); 77 | debug(`Total pages in book are ${totalPages}`); 78 | const valuesInComment = (lastComment.body || "").match(/\d+\%?/g); 79 | if (valuesInComment && valuesInComment.length) { 80 | debug(`Got ${valuesInComment.length} numerical matches`); 81 | const values = valuesInComment.map((val) => parseInt(val)).filter((val) => !isNaN(val)); 82 | const firstVal = valuesInComment[0]; 83 | debug(`Potential value is ${firstVal}`); 84 | if (values.length) 85 | if (firstVal.includes("%") && !isNaN(parseInt(firstVal))) { 86 | progressPercent = parseInt(firstVal); 87 | debug(`Potential value has % sign: ${progressPercent}`); 88 | } else { 89 | progressPercent = Math.min(Math.round((100 * values[0]) / totalPages), 100); 90 | debug(`Potential value is in pages: ${values[0]}`); 91 | debug(`Potential percent count rounded: ${Math.round((100 * values[0]) / totalPages)}`); 92 | } 93 | } 94 | debug(`Progress is ${progressPercent}%`); 95 | if (progressPercent !== 0) { 96 | try { 97 | await octokit.rest.reactions.createForIssueComment({ 98 | owner: context.issue.owner, 99 | repo: context.issue.repo, 100 | issue_number: context.issue.number, 101 | comment_id: lastComment.id, 102 | content: "+1", 103 | }); 104 | debug("Added reaction to comment"); 105 | } catch (error) { 106 | debug("Unable to add reaction to comment"); 107 | } 108 | const currentPercentage = issue.data.title.match(/\(\d+\%\)/g); 109 | await octokit.rest.issues.update({ 110 | owner: context.issue.owner, 111 | repo: context.issue.repo, 112 | issue_number: context.issue.number, 113 | title: 114 | currentPercentage && currentPercentage.length 115 | ? `${issue.data.title.split(currentPercentage[0])[0].trim()} (${progressPercent}%)` 116 | : `${issue.data.title.trim()} (${progressPercent}%)`, 117 | }); 118 | debug("Updated issue title with progress"); 119 | // Remove "want to read" label if it's there 120 | if ( 121 | issue.data.labels.find((i) => 122 | typeof i === "string" ? i === "want to read" : i.name === "want to read" 123 | ) 124 | ) { 125 | await octokit.rest.issues.removeLabel({ 126 | owner: context.issue.owner, 127 | repo: context.issue.repo, 128 | issue_number: context.issue.number, 129 | name: "want to read", 130 | }); 131 | debug("Removed 'want to read' label"); 132 | } 133 | } 134 | await updateSummary(owner, repo, context, octokit); 135 | }; 136 | -------------------------------------------------------------------------------- /src/features/new-issue.ts: -------------------------------------------------------------------------------- 1 | import { debug } from "@actions/core"; 2 | import { Context } from "@actions/github/lib/context"; 3 | import type { GitHub } from "@actions/github/lib/utils"; 4 | import { config, cosmic } from "@anandchowdhary/cosmic"; 5 | import slugify from "@sindresorhus/slugify"; 6 | import { getByTag } from "locale-codes"; 7 | import { search } from "../google-books"; 8 | import { updateSummary } from "./update-summary"; 9 | 10 | const clean = (str: string) => slugify(str, { lowercase: true, separator: " " }); 11 | 12 | export const onNewIssue = async ( 13 | owner: string, 14 | repo: string, 15 | context: Context, 16 | octokit: InstanceType 17 | ) => { 18 | debug("Started onNewIssue"); 19 | try { 20 | await cosmic("bookshelf"); 21 | debug("Got config object"); 22 | } catch (error) {} 23 | const issue = await octokit.rest.issues.get({ 24 | owner: context.issue.owner, 25 | repo: context.issue.repo, 26 | issue_number: context.issue.number, 27 | }); 28 | debug(`Got issue #${issue.data.number}`); 29 | if (config("users") && Array.isArray(config("users"))) { 30 | if (!(config("users") as string[]).find((i) => i === (issue.data.user || {}).login)) 31 | return debug("User not allowed, skipping"); 32 | } 33 | let body = 34 | "\n\n"; 35 | const labels: string[] = [ 36 | "kind: book", 37 | `started: ${clean(new Date().toLocaleString("en", { month: "long" }))}`, 38 | `started: ${new Date().getUTCFullYear()}`, 39 | ]; 40 | try { 41 | debug(`Searching for "${issue.data.title}"`); 42 | const details = await search(issue.data.title); 43 | body += `Congrats on adding **${details.title}** by ${details.authors.join( 44 | ", " 45 | )} to your bookshelf, I hope you enjoy it! It has an average of ${ 46 | details.averageRating || "unknown" 47 | }/5 stars and ${(details.ratingsCount || 0).toLocaleString()} ratings on [Google Books](${ 48 | details.googleBooks.info 49 | }).\n\n
50 | Book details (JSON) 51 | 52 | \`\`\`json 53 | ${JSON.stringify(details, null, 2)} 54 | \`\`\` 55 | 56 |
`; 57 | details.authors.forEach((i) => labels.push(`author: ${clean(i)}`)); 58 | details.categories.forEach((i) => labels.push(`category: ${clean(i)}`)); 59 | if (details.publishedDate) { 60 | const publishDate = new Date(details.publishedDate); 61 | labels.push(`year: ${publishDate.getUTCFullYear()}`); 62 | labels.push(`decade: ${Math.floor(publishDate.getUTCFullYear() / 10) * 10}s`); 63 | } 64 | if (details.language) 65 | labels.push(`language: ${clean(getByTag(details.language).name || details.language)}`); 66 | if (details.publisher) labels.push(`publisher: ${clean(details.publisher)}`); 67 | debug("Added labels from search results"); 68 | } catch (error) { 69 | console.log(error); 70 | debug(`Got an error in search results: ${String(error)}`); 71 | body += 72 | "I couldn't find details about this book using the Google Books API. Don't worry, you can still track it.\n\n"; 73 | } 74 | body += `When you're finished with reading this book, just close this issue and I'll mark it as completed. Best of luck! 👍`; 75 | await octokit.rest.issues.createComment({ 76 | owner: context.issue.owner, 77 | repo: context.issue.repo, 78 | issue_number: context.issue.number, 79 | body, 80 | }); 81 | debug("Added comment to issue"); 82 | await octokit.rest.issues.addLabels({ 83 | owner: context.issue.owner, 84 | repo: context.issue.repo, 85 | issue_number: context.issue.number, 86 | labels: labels.map((label) => (label.length > 50 ? `${label.substring(0, 47)}...` : label)), 87 | }); 88 | debug("Added all labels to issue"); 89 | await octokit.rest.issues.lock({ 90 | owner: context.issue.owner, 91 | repo: context.issue.repo, 92 | issue_number: context.issue.number, 93 | }); 94 | debug("Locked issue"); 95 | await updateSummary(owner, repo, context, octokit); 96 | }; 97 | -------------------------------------------------------------------------------- /src/features/update-summary.ts: -------------------------------------------------------------------------------- 1 | import { debug } from "@actions/core"; 2 | import { Context } from "@actions/github/lib/context"; 3 | import type { GitHub } from "@actions/github/lib/utils"; 4 | import { config, cosmic } from "@anandchowdhary/cosmic"; 5 | import { promises } from "fs"; 6 | import humanizeDuration from "humanize-duration"; 7 | import { join } from "path"; 8 | import { format } from "prettier"; 9 | import { exec } from "shelljs"; 10 | import { addDetailsToLabels } from "../github"; 11 | import { BookResult } from "../google-books"; 12 | 13 | export const updateSummary = async ( 14 | owner: string, 15 | repo: string, 16 | context: Context, 17 | octokit: InstanceType 18 | ) => { 19 | debug("Starting updateSummary"); 20 | try { 21 | await cosmic("bookshelf"); 22 | debug("Got config object"); 23 | } catch (error) {} 24 | 25 | let api: (BookResult & { 26 | state: "reading" | "completed" | "want-to-read"; 27 | issueNumber: number; 28 | startedAt: string; 29 | progressPercent: number; 30 | completedAt?: string; 31 | timeToComplete?: number; 32 | timeToCompleteFormatted?: string; 33 | })[] = []; 34 | for await (const response of octokit.paginate.iterator(octokit.rest.issues.listForRepo, { 35 | owner: context.issue.owner, 36 | repo: context.issue.repo, 37 | labels: "kind: book", 38 | state: "all", 39 | })) { 40 | debug(`Got ${response.data.length} issues during pagination`); 41 | for (const issue of response.data) { 42 | const comments = await octokit.rest.issues.listComments({ 43 | owner: context.issue.owner, 44 | repo: context.issue.repo, 45 | issue_number: issue.number, 46 | }); 47 | debug(`Got ${comments.data.length} comments in issue ${issue.number}`); 48 | let json: BookResult | undefined = undefined; 49 | try { 50 | comments.data.forEach((comment) => { 51 | if ((comment.body || "").includes("Book details (JSON)")) 52 | json = JSON.parse( 53 | (comment.body || "").split("```json")[1].split("```")[0] 54 | ) as BookResult; 55 | }); 56 | } catch (error) { 57 | console.log("JSON parsing error", error); 58 | } 59 | const isWantToRead = issue.labels.find((label) => 60 | typeof label === "string" ? label === "want to read" : label.name === "want to read" 61 | ); 62 | if (isWantToRead) debug(`Book is in category "want to read"`); 63 | if (json) { 64 | debug(`Found JSON data for ${(json as BookResult).title}`); 65 | const currentPercentage = issue.title.match(/\(\d+\%\)/g); 66 | const overwrites = 67 | config("overwrites") || ({} as Record); 68 | const openedAt = (overwrites[issue.number] || {}).started 69 | ? overwrites[issue.number].started 70 | : issue.created_at; 71 | const closedAt = (overwrites[issue.number] || {}).completed 72 | ? overwrites[issue.number].completed 73 | : issue.closed_at; 74 | api.push({ 75 | ...(json as BookResult), 76 | issueNumber: issue.number, 77 | progressPercent: 78 | currentPercentage && currentPercentage.length && !isNaN(parseInt(currentPercentage[0])) 79 | ? parseInt(currentPercentage[0]) 80 | : 0, 81 | state: issue.state === "open" ? (isWantToRead ? "want-to-read" : "reading") : "completed", 82 | startedAt: new Date(openedAt).toISOString(), 83 | completedAt: issue.state === "closed" ? new Date(closedAt).toISOString() : undefined, 84 | timeToComplete: 85 | issue.state === "closed" 86 | ? new Date(closedAt).getTime() - new Date(openedAt).getTime() 87 | : undefined, 88 | timeToCompleteFormatted: 89 | issue.state === "closed" 90 | ? humanizeDuration(new Date(closedAt).getTime() - new Date(openedAt).getTime()).split( 91 | "," 92 | )[0] 93 | : undefined, 94 | }); 95 | } else debug(`Unable to find JSON data for #${issue.id}`); 96 | } 97 | } 98 | api = api.sort((a, b) => new Date(b.completedAt ?? b.startedAt).getTime() - new Date(a.completedAt ?? a.startedAt).getTime()); 99 | await promises.writeFile(join(".", "api.json"), JSON.stringify(api, null, 2) + "\n"); 100 | debug("Written api.json file"); 101 | debug(`api has length ${api.length}`); 102 | let mdContent = ""; 103 | const apiCompleted = api.filter((i) => i.state === "completed"); 104 | const apiWantToRead = api.filter((i) => i.state === "want-to-read"); 105 | const apiReading = api.filter((i) => i.state === "reading"); 106 | if (apiReading.length) 107 | mdContent += `\n\n### ⌛ Currently reading (${apiReading.length})\n\n${apiReading 108 | .map( 109 | (i) => 110 | `[![${i.title.replace( 111 | /\"/g, 112 | "" 113 | )}](https://images.weserv.nl/?url=${encodeURIComponent( 114 | i.image 115 | )}&w=128&h=196&fit=contain)](https://github.com/${owner}/${repo}/issues/${ 116 | i.issueNumber 117 | } "${i.title.replace(/\"/g, "")} by ${i.authors.join(", ")}")` 118 | ) 119 | .join("\n")}`; 120 | if (apiCompleted.length) 121 | mdContent += `\n\n### ✅ Completed (${apiCompleted.length})\n\n${apiCompleted 122 | .map( 123 | (i) => 124 | `[![${i.title.replace( 125 | /\"/g, 126 | "" 127 | )}](https://images.weserv.nl/?url=${encodeURIComponent( 128 | i.image 129 | )}&w=128&h=196&fit=contain)](https://github.com/${owner}/${repo}/issues/${ 130 | i.issueNumber 131 | } "${i.title.replace(/\"/g, "")} by ${i.authors 132 | .join(", ") 133 | .replace(/\"/g, "")} completed in ${i.timeToCompleteFormatted} on ${new Date( 134 | i.completedAt || "" 135 | ).toLocaleDateString("en-us", { 136 | month: "long", 137 | year: "numeric", 138 | })}")` 139 | ) 140 | .join("\n")}`; 141 | if (apiWantToRead.length) 142 | mdContent += `\n\n### ⏭️ Want to Read (${apiWantToRead.length})\n\n${apiWantToRead 143 | .map( 144 | (i) => 145 | `[![${i.title.replace( 146 | /\"/g, 147 | "" 148 | )}](https://images.weserv.nl/?url=${encodeURIComponent( 149 | i.image 150 | )}&w=128&h=196&fit=contain)](https://github.com/${owner}/${repo}/issues/${ 151 | i.issueNumber 152 | } "${i.title.replace(/\"/g, "")} by ${i.authors 153 | .join(", ") 154 | .replace(/\"/g, "")} completed in ${i.timeToCompleteFormatted} on ${new Date( 155 | i.completedAt || "" 156 | ).toLocaleDateString("en-us", { 157 | month: "long", 158 | year: "numeric", 159 | })}")` 160 | ) 161 | .join("\n")}`; 162 | debug(`Generated README.md content of length ${mdContent.length}`); 163 | const content = await promises.readFile(join(".", "README.md"), "utf8"); 164 | debug(`Read README.md file of length ${content.length}`); 165 | await promises.writeFile( 166 | join(".", "README.md"), 167 | content.split("")[0] + 168 | `\n${format(mdContent, { 169 | parser: "markdown", 170 | })}\n` + 171 | content.split("")[1] 172 | ); 173 | debug("Written README.md file"); 174 | exec(`git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"`); 175 | exec(`git config --global user.name "github-actions[bot]"`); 176 | debug("Added git config user details"); 177 | exec("git add ."); 178 | exec('git commit -m ":bento: Update API and README summary [skip ci]"'); 179 | debug("Committed to git history"); 180 | exec("git push"); 181 | debug("Pushed to repository"); 182 | await addDetailsToLabels(owner, repo, octokit); 183 | debug("Updated label details"); 184 | }; 185 | -------------------------------------------------------------------------------- /src/github.ts: -------------------------------------------------------------------------------- 1 | import type { GitHub } from "@actions/github/lib/utils"; 2 | import type { IssuesListLabelsForRepoResponseData } from "@octokit/types"; 3 | import randomColor from "randomcolor"; 4 | 5 | /** 6 | * Convert a string to title case and trim it 7 | * @private 8 | * @param str - String to clean up 9 | */ 10 | const clean = (str: string) => 11 | str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()).trim(); 12 | 13 | export const addDetailsToLabels = async ( 14 | owner: string, 15 | repo: string, 16 | octokit: InstanceType 17 | ) => { 18 | const options = octokit.rest.issues.listLabelsForRepo.endpoint.merge({ owner, repo }); 19 | for await (const labels of octokit.paginate.iterator(options)) { 20 | for await (const label of labels.data as IssuesListLabelsForRepoResponseData) { 21 | let color = label.color; 22 | let description = label.description; 23 | if (label.color === "ededed") color = randomColor({ luminosity: "light" }).replace("#", ""); 24 | if (label.description === null) { 25 | if (label.name === "kind: book") 26 | description = "This issue tracks a book (reading progress)"; 27 | else if (label.name.startsWith("started: ")) 28 | description = `This book was started in ${clean(label.name.split("started: ")[1])}`; 29 | else if (label.name.startsWith("completed: ")) 30 | description = `This book was completed in ${clean(label.name.split("completed: ")[1])}`; 31 | else if (label.name.startsWith("year: ")) 32 | description = `This book was published in ${clean(label.name.split("year: ")[1])}`; 33 | else if (label.name.startsWith("decade: ")) 34 | description = `This book was published in the ${clean(label.name.split("decade: ")[1])}s`; 35 | else if (label.name.startsWith("language: ")) 36 | description = `This book was published in ${clean(label.name.split("language: ")[1])}`; 37 | else if (label.name.startsWith("publisher: ")) 38 | description = `This book was published by ${clean(label.name.split("publisher: ")[1])}`; 39 | else if (label.name.startsWith("author: ")) 40 | description = `This book was written by ${clean(label.name.split("author: ")[1])}`; 41 | else if (label.name.startsWith("category: ")) 42 | description = `This book is of the category "${clean( 43 | label.name.split("category: ")[1] 44 | )}"`; 45 | } 46 | if (color !== label.color || description !== label.description) 47 | await octokit.rest.issues.updateLabel({ 48 | owner, 49 | repo, 50 | name: label.name, 51 | color, 52 | description, 53 | }); 54 | } 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/google-books.ts: -------------------------------------------------------------------------------- 1 | import got from "got/dist/source"; 2 | 3 | export interface Book { 4 | kind: "books#volume"; 5 | id: string; 6 | volumeInfo: { 7 | title: string; 8 | authors: string[]; 9 | publisher: string; 10 | publishedDate: string; 11 | description: string; 12 | industryIdentifiers: [ 13 | { 14 | type: "ISBN_13"; 15 | identifier: string; 16 | }, 17 | { 18 | type: "ISBN_10"; 19 | identifier: string; 20 | } 21 | ]; 22 | pageCount: number; 23 | printType: "BOOK"; 24 | categories: string[]; 25 | averageRating: number; 26 | ratingsCount: number; 27 | maturityRating: "MATURE" | "NOT_MATURE"; 28 | imageLinks: { 29 | thumbnail: string; 30 | }; 31 | language: string; 32 | previewLink: string; 33 | infoLink: string; 34 | canonicalVolumeLink: string; 35 | }; 36 | } 37 | 38 | export interface BookResult { 39 | title: string; 40 | authors: string[]; 41 | publisher: string; 42 | publishedDate: string; 43 | description: string; 44 | image: string; 45 | language: string; 46 | averageRating: number; 47 | ratingsCount: number; 48 | categories: string[]; 49 | pageCount: number; 50 | isbn10?: string; 51 | isbn13?: string; 52 | googleBooks: { 53 | id: string; 54 | preview: string; 55 | info: string; 56 | canonical: string; 57 | }; 58 | } 59 | 60 | export const search = async (q: string): Promise => { 61 | const results = await got<{ 62 | items: Book[]; 63 | }>(`https://www.googleapis.com/books/v1/volumes?q=intitle:${encodeURIComponent(q)}`, { 64 | responseType: "json", 65 | }); 66 | if (!results.body.items || results.body.items.length === 0) { 67 | console.error("No results.body.items", JSON.stringify(results.body)); 68 | throw new Error("Book not found"); 69 | } 70 | const result = results.body.items.sort( 71 | (a, b) => (Number(b.volumeInfo.ratingsCount) || 0) - (Number(a.volumeInfo.ratingsCount) || 0) 72 | )[0]; 73 | 74 | return { 75 | title: result.volumeInfo.title, 76 | authors: result.volumeInfo.authors, 77 | publisher: result.volumeInfo.publisher, 78 | publishedDate: result.volumeInfo.publishedDate, 79 | description: result.volumeInfo.description, 80 | image: 81 | (result.volumeInfo.imageLinks || {}).thumbnail || 82 | `https://tse2.mm.bing.net/th?q=${encodeURIComponent( 83 | `${result.volumeInfo.title} by ${result.volumeInfo.authors.join(", ")}` 84 | )}&w=256&c=7&rs=1&p=0&dpr=3&pid=1.7&mkt=en-IN&adlt=moderate`, 85 | language: result.volumeInfo.language, 86 | averageRating: result.volumeInfo.averageRating, 87 | ratingsCount: result.volumeInfo.ratingsCount, 88 | categories: result.volumeInfo.categories, 89 | pageCount: result.volumeInfo.pageCount, 90 | isbn10: ((result.volumeInfo.industryIdentifiers || []).find((i) => i.type === "ISBN_10") || {}) 91 | .identifier, 92 | isbn13: ((result.volumeInfo.industryIdentifiers || []).find((i) => i.type === "ISBN_13") || {}) 93 | .identifier, 94 | googleBooks: { 95 | id: result.id, 96 | preview: result.volumeInfo.previewLink, 97 | info: result.volumeInfo.infoLink, 98 | canonical: result.volumeInfo.canonicalVolumeLink, 99 | }, 100 | }; 101 | }; 102 | -------------------------------------------------------------------------------- /src/index.spec.ts: -------------------------------------------------------------------------------- 1 | test("sample", () => expect(1).toBe(1)) 2 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { debug, getInput, setFailed } from "@actions/core"; 2 | import { context, getOctokit } from "@actions/github"; 3 | import { onCloseIssue } from "./features/close-issue"; 4 | import { onIssueComment } from "./features/issue-comment"; 5 | import { onNewIssue } from "./features/new-issue"; 6 | import { updateSummary } from "./features/update-summary"; 7 | 8 | const token = getInput("token") || process.env.GH_PAT || process.env.GITHUB_TOKEN; 9 | const [owner, repo] = (process.env.GITHUB_REPOSITORY || "").split("/"); 10 | 11 | export const run = async () => { 12 | const COMMAND = getInput("command"); 13 | debug(`Got command: ${COMMAND}`); 14 | if (!COMMAND) throw new Error("Command not found"); 15 | if (!token) throw new Error("GitHub token not found"); 16 | 17 | const octokit = getOctokit(token); 18 | if (COMMAND === "onNewIssue") return onNewIssue(owner, repo, context, octokit); 19 | if (COMMAND === "onCloseIssue") return onCloseIssue(owner, repo, context, octokit); 20 | if (COMMAND === "onIssueComment") return onIssueComment(owner, repo, context, octokit); 21 | if (COMMAND === "updateSummary") return updateSummary(owner, repo, context, octokit); 22 | throw new Error("Command not recognized"); 23 | }; 24 | 25 | run() 26 | .then(() => {}) 27 | .catch((error) => { 28 | console.error("ERROR", error); 29 | setFailed(error.message); 30 | }); 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "esnext", 5 | "module": "commonjs", 6 | "lib": ["dom", "esnext"], 7 | "strict": true, 8 | "sourceMap": true, 9 | "declaration": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "experimentalDecorators": true, 13 | "emitDecoratorMetadata": true, 14 | "declarationDir": "./dist", 15 | "outDir": "./dist", 16 | "typeRoots": ["node_modules/@types", "@types"] 17 | }, 18 | "include": ["src", "tooling"], 19 | "exclude": ["node_modules"] 20 | } 21 | --------------------------------------------------------------------------------