├── .circleci └── config.yml ├── .env.template ├── .github ├── actions │ ├── create-dotenv │ │ └── action.yml │ ├── setup-aws │ │ └── action.yml │ ├── setup-go-task │ │ └── action.yml │ ├── setup-go │ │ └── action.yml │ └── setup-node │ │ └── action.yml └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── README └── architecture.jpg ├── Taskfile.yml ├── events ├── updateDaily │ ├── input.dev.json │ └── input.prod.json ├── updateDailyByTag │ ├── android.dev.json │ ├── android.prod.json │ ├── aws.dev.json │ ├── aws.prod.json │ ├── beginner.dev.json │ ├── beginner.prod.json │ ├── docker.dev.json │ ├── docker.prod.json │ ├── git.dev.json │ ├── git.prod.json │ ├── go.dev.json │ ├── go.prod.json │ ├── ios.dev.json │ ├── ios.prod.json │ ├── java.dev.json │ ├── java.prod.json │ ├── javascript.dev.json │ ├── javascript.prod.json │ ├── linux.dev.json │ ├── linux.prod.json │ ├── nodejs.dev.json │ ├── nodejs.prod.json │ ├── php.dev.json │ ├── php.prod.json │ ├── python.dev.json │ ├── python.prod.json │ ├── rails.dev.json │ ├── rails.prod.json │ ├── react.dev.json │ ├── react.prod.json │ ├── ruby.dev.json │ ├── ruby.prod.json │ ├── swift.dev.json │ ├── swift.prod.json │ ├── typescript.dev.json │ ├── typescript.prod.json │ ├── vim.dev.json │ ├── vim.prod.json │ ├── vuejs.dev.json │ └── vuejs.prod.json ├── updateWeekly │ ├── input.dev.json │ └── input.prod.json └── updateWeeklyByTag │ ├── android.dev.json │ ├── android.prod.json │ ├── aws.dev.json │ ├── aws.prod.json │ ├── beginner.dev.json │ ├── beginner.prod.json │ ├── docker.dev.json │ ├── docker.prod.json │ ├── git.dev.json │ ├── git.prod.json │ ├── go.dev.json │ ├── go.prod.json │ ├── ios.dev.json │ ├── ios.prod.json │ ├── java.dev.json │ ├── java.prod.json │ ├── javascript.dev.json │ ├── javascript.prod.json │ ├── linux.dev.json │ ├── linux.prod.json │ ├── nodejs.dev.json │ ├── nodejs.prod.json │ ├── php.dev.json │ ├── php.prod.json │ ├── python.dev.json │ ├── python.prod.json │ ├── rails.dev.json │ ├── rails.prod.json │ ├── react.dev.json │ ├── react.prod.json │ ├── ruby.dev.json │ ├── ruby.prod.json │ ├── swift.dev.json │ ├── swift.prod.json │ ├── typescript.dev.json │ ├── typescript.prod.json │ ├── vim.dev.json │ ├── vim.prod.json │ ├── vuejs.dev.json │ └── vuejs.prod.json ├── go.mod ├── go.sum ├── package.json ├── pkg ├── controllers │ └── reports.go ├── handlers │ ├── daily │ │ └── main.go │ ├── dailybytag │ │ └── main.go │ ├── weekly │ │ └── main.go │ └── weeklybytag │ │ └── main.go └── infrastructures │ ├── qiita │ ├── client.go │ ├── entities.go │ └── http.go │ └── report │ └── builder.go ├── renovate.json ├── serverless.yml ├── templates └── template.md └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | aws-cli: circleci/aws-cli@3.1.3 5 | go: circleci/go@1.7.1 6 | node: circleci/node@5.0.2 7 | 8 | executors: 9 | ubuntu: 10 | machine: 11 | image: ubuntu-2004:current 12 | 13 | commands: 14 | setup-go: 15 | steps: 16 | - go/install: 17 | version: '1.18' 18 | - go/mod-download-cached 19 | 20 | setup-go-task: 21 | steps: 22 | - run: 23 | name: install go-task 24 | command: go install github.com/go-task/task/v3/cmd/task@latest 25 | 26 | setup-node: 27 | steps: 28 | - node/install: 29 | install-yarn: true 30 | node-version: '14' 31 | - node/install-packages: 32 | pkg-manager: yarn 33 | 34 | setup-aws: 35 | steps: 36 | - aws-cli/install 37 | - aws-cli/assume-role-with-web-identity: 38 | role-arn: ${AWS_IAM_ROLE_ARN} 39 | 40 | create-dotenv: 41 | steps: 42 | - run: 43 | name: create .env 44 | command: | 45 | echo "QIITA_ACCESS_TOKEN=${QIITA_ACCESS_TOKEN}" > .env 46 | 47 | jobs: 48 | build: 49 | executor: ubuntu 50 | steps: 51 | - checkout 52 | - setup-node 53 | - setup-go 54 | - setup-go-task 55 | - run: 56 | name: go test 57 | command: task test 58 | - run: 59 | name: build 60 | command: task build 61 | - run: 62 | name: sls package 63 | command: yarn run serverless package --stage prod 64 | 65 | deploy: 66 | executor: ubuntu 67 | parameters: 68 | stage: 69 | type: string 70 | steps: 71 | - checkout 72 | - setup-aws 73 | - create-dotenv 74 | - setup-node 75 | - setup-go 76 | - setup-go-task 77 | - run: 78 | name: deploy 79 | command: task deploy -- --stage << parameters.stage >> --force 80 | 81 | workflows: 82 | build: 83 | jobs: 84 | - build 85 | 86 | - approval_deploy: 87 | type: approval 88 | requires: [build] 89 | 90 | - deploy: 91 | context: aws 92 | name: deploy_dev 93 | stage: dev 94 | requires: [approval_deploy] 95 | filters: 96 | branches: 97 | ignore: main 98 | 99 | - deploy: 100 | context: aws 101 | name: deploy_prod 102 | stage: prod 103 | requires: [approval_deploy] 104 | filters: 105 | branches: 106 | only: main 107 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | QIITA_ACCESS_TOKEN= 2 | -------------------------------------------------------------------------------- /.github/actions/create-dotenv/action.yml: -------------------------------------------------------------------------------- 1 | name: create-dotenv 2 | runs: 3 | using: composite 4 | steps: 5 | - name: create .env 6 | run: echo "QIITA_ACCESS_TOKEN=${QIITA_ACCESS_TOKEN}" > .env 7 | shell: bash -------------------------------------------------------------------------------- /.github/actions/setup-aws/action.yml: -------------------------------------------------------------------------------- 1 | name: setup-aws 2 | runs: 3 | using: composite 4 | steps: 5 | - uses: aws-actions/configure-aws-credentials@v1 6 | with: 7 | aws-region: 'us-east-1' 8 | role-to-assume: '${{ env.AWS_IAM_ROLE_ARN }}' 9 | 10 | # # This item has no matching transformer 11 | # - circleci_aws_cli_assume_role_with_web_identity: 12 | -------------------------------------------------------------------------------- /.github/actions/setup-go-task/action.yml: -------------------------------------------------------------------------------- 1 | name: setup-go-task 2 | runs: 3 | using: composite 4 | steps: 5 | - name: install go-task 6 | run: go install github.com/go-task/task/v3/cmd/task@latest 7 | shell: bash -------------------------------------------------------------------------------- /.github/actions/setup-go/action.yml: -------------------------------------------------------------------------------- 1 | name: setup-go 2 | runs: 3 | using: composite 4 | steps: 5 | - uses: actions/setup-go@v3.5.0 6 | with: 7 | cache: true 8 | go-version: '1.18' 9 | # # This item has no matching transformer 10 | # - circleci_go_mod_download_cached: -------------------------------------------------------------------------------- /.github/actions/setup-node/action.yml: -------------------------------------------------------------------------------- 1 | name: setup-node 2 | runs: 3 | using: composite 4 | steps: 5 | - uses: actions/setup-node@v3.6.0 6 | with: 7 | node-version: '14' 8 | - id: yarn-cache-dir-path 9 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 10 | shell: bash 11 | - uses: actions/cache@v3.2.2 12 | with: 13 | path: "${{ steps.yarn-cache-dir-path.outputs.dir }}" 14 | key: "${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}" 15 | restore-keys: "${{ runner.os }}-yarn-" 16 | - run: yarn install --frozen-lockfile 17 | shell: bash -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: koki-develop/qiita-lgtm-ranking/build 2 | on: 3 | push: 4 | branches: 5 | - develop 6 | - main 7 | env: 8 | AWS_IAM_ROLE_ARN: ${{ secrets.AWS_IAM_ROLE_ARN }} 9 | QIITA_ACCESS_TOKEN: ${{ secrets.QIITA_ACCESS_TOKEN }} 10 | jobs: 11 | build: 12 | runs-on: ubuntu-20.04 13 | steps: 14 | - uses: actions/checkout@v3.3.0 15 | - uses: "./.github/actions/setup-node" 16 | - uses: "./.github/actions/setup-go" 17 | - uses: "./.github/actions/setup-go-task" 18 | - name: go test 19 | run: task test 20 | - name: build 21 | run: task build 22 | - name: sls package 23 | run: yarn run serverless package --stage prod 24 | approval_deploy: 25 | environment: 26 | name: approval 27 | runs-on: ubuntu-latest 28 | needs: 29 | - build 30 | steps: 31 | - run: echo 'approved' 32 | deploy: 33 | permissions: 34 | id-token: write 35 | contents: read 36 | if: github.ref != 'refs/heads/main' 37 | runs-on: ubuntu-20.04 38 | needs: 39 | - approval_deploy 40 | env: 41 | stage: dev 42 | steps: 43 | - uses: actions/checkout@v3.3.0 44 | - uses: "./.github/actions/setup-aws" 45 | - uses: "./.github/actions/create-dotenv" 46 | - uses: "./.github/actions/setup-node" 47 | - uses: "./.github/actions/setup-go" 48 | - uses: "./.github/actions/setup-go-task" 49 | - name: deploy 50 | run: task deploy -- --stage ${{ env.stage }} --force 51 | deploy_1: 52 | permissions: 53 | id-token: write 54 | contents: read 55 | if: github.ref == 'refs/heads/main' 56 | runs-on: ubuntu-20.04 57 | needs: 58 | - approval_deploy 59 | env: 60 | stage: prod 61 | steps: 62 | - uses: actions/checkout@v3.3.0 63 | - uses: "./.github/actions/setup-aws" 64 | - uses: "./.github/actions/create-dotenv" 65 | - uses: "./.github/actions/setup-node" 66 | - uses: "./.github/actions/setup-go" 67 | - uses: "./.github/actions/setup-go-task" 68 | - name: deploy 69 | run: task deploy -- --stage ${{ env.stage }} --force 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Serverless directories 2 | .serverless 3 | 4 | # golang output binary directory 5 | build/ 6 | 7 | # golang vendor (dependencies) directory 8 | vendor 9 | 10 | # Binaries for programs and plugins 11 | *.exe 12 | *.exe~ 13 | *.dll 14 | *.so 15 | *.dylib 16 | 17 | # Test binary, build with `go test -c` 18 | *.test 19 | 20 | # Output of the go coverage tool, specifically when used with LiteIDE 21 | *.out 22 | /cover.html 23 | 24 | # npm 25 | /node_modules 26 | 27 | # dotenv 28 | /.env 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 koki sato 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 | [koki-develop/qiita-ranking](https://github.com/koki-develop/qiita-ranking) に移動しました。 2 | -------------------------------------------------------------------------------- /README/architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koki-develop/qiita-lgtm-ranking/0a109f126997a7a77063ec2c201371ec2c9c491a/README/architecture.jpg -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | tasks: 4 | test: 5 | cmds: 6 | - go test ./pkg/... 7 | 8 | invokeDailyAll: 9 | vars: 10 | STAGE: '{{ default "dev" .STAGE }}' 11 | cmds: 12 | - | 13 | yarn run serverless invoke -f updateDaily \ 14 | --stage {{ .STAGE }} \ 15 | --log \ 16 | --path ./events/updateDaily/input.{{ .STAGE }}.json 17 | - | 18 | for path in $(ls ./events/updateDailyByTag/*.{{ .STAGE }}.json); do 19 | yarn run serverless invoke -f updateDailyByTag \ 20 | --stage {{ .STAGE }} \ 21 | --log \ 22 | --path "${path}" 23 | done 24 | 25 | clean: 26 | cmds: 27 | - rm -rf ./build/ 28 | 29 | build: 30 | deps: [clean] 31 | env: 32 | GO111MODULE: on 33 | GOOS: linux 34 | GOARCH: amd64 35 | cmds: 36 | - go build -ldflags="-s -w" -o build/updateDaily ./pkg/handlers/daily 37 | - go build -ldflags="-s -w" -o build/updateDailyByTag ./pkg/handlers/dailybytag 38 | - go build -ldflags="-s -w" -o build/updateWeekly ./pkg/handlers/weekly 39 | - go build -ldflags="-s -w" -o build/updateWeeklyByTag ./pkg/handlers/weeklybytag 40 | 41 | diff: 42 | vars: 43 | STAGE: '{{ default "dev" .STAGE }}' 44 | cmds: 45 | - yarn run serverless package --stage {{ .STAGE }} 46 | - yarn run serverless diff --stage {{ .STAGE }} 47 | 48 | deploy: 49 | deps: [build] 50 | cmds: 51 | - yarn run serverless deploy --verbose {{.CLI_ARGS}} 52 | -------------------------------------------------------------------------------- /events/updateDaily/input.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "921b3bbbc51e0c511d67" 3 | } 4 | -------------------------------------------------------------------------------- /events/updateDaily/input.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "fa223e1fa0ab057a54bc" 3 | } 4 | -------------------------------------------------------------------------------- /events/updateDailyByTag/android.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "bbf37017d3748ce7846a", 3 | "tag": "Android" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/android.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9c6bf21a9880e242a0d6", 3 | "tag": "Android" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/aws.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "b827777f9ace9630eff2", 3 | "tag": "AWS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/aws.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "8c4aeec4fc98e4b1ba0e", 3 | "tag": "AWS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/beginner.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "ba66b02ebabf0fb88047", 3 | "tag": "初心者" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/beginner.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "4107350b0914837836af", 3 | "tag": "初心者" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/docker.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "0af3a92ecd06d6d07768", 3 | "tag": "Docker" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/docker.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "70aa655b580ed4f91756", 3 | "tag": "Docker" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/git.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "6fad6945d755ec442099", 3 | "tag": "Git" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/git.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "36cfb2318aabe8b3f8df", 3 | "tag": "Git" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/go.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "5a89c6f4142de12e031c", 3 | "tag": "Go" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/go.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "16809f8444e0329bed8a", 3 | "tag": "Go" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/ios.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "ba76a9c15773e7ef59ca", 3 | "tag": "iOS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/ios.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "da7fabcf41ed103528ae", 3 | "tag": "iOS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/java.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9baaa35d9a25019a7e1b", 3 | "tag": "Java" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/java.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9003b8beb47a46292028", 3 | "tag": "Java" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/javascript.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "1c8628833fef5a6b34d2", 3 | "tag": "JavaScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/javascript.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "31e7365a838b890f7cc3", 3 | "tag": "JavaScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/linux.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9aac5f46bf2e1f709939", 3 | "tag": "Linux" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/linux.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "7bcae94b268bff253eef", 3 | "tag": "Linux" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/nodejs.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "66e52b056b9c9cfce3f1", 3 | "tag": "Node.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/nodejs.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "17556a2356938fdf489c", 3 | "tag": "Node.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/php.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "38175b99ebc13f53b281", 3 | "tag": "PHP" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/php.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "42476b629e2d655d9803", 3 | "tag": "PHP" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/python.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "014a82df8219c17def81", 3 | "tag": "Python" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/python.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "45e8c5b0017008c62fac", 3 | "tag": "Python" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/rails.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "731bc05d58a19290bc8a", 3 | "tag": "Rails" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/rails.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "6835d21664b6e36a1efa", 3 | "tag": "Rails" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/react.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "a9dd6223168a31b67d20", 3 | "tag": "React" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/react.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "d17e403386f316d0d96e", 3 | "tag": "React" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/ruby.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "27a5219b8b8b3bc2a7b3", 3 | "tag": "Ruby" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/ruby.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "effb08232a286c91b814", 3 | "tag": "Ruby" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/swift.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9a8dde568fe8ca2f8441", 3 | "tag": "Swift" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/swift.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "4b45f7a2308597b362e6", 3 | "tag": "Swift" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/typescript.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "046ec5a844e5508f1dfe", 3 | "tag": "TypeScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/typescript.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "3442ef41f83064dafb64", 3 | "tag": "TypeScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/vim.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "7d2b0492b5c2d3968992", 3 | "tag": "Vim" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/vim.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "cb67a3dd7a37eee8f8d9", 3 | "tag": "Vim" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/vuejs.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "ac10995b3054e6c77f22", 3 | "tag": "Vue.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateDailyByTag/vuejs.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "a0d7b0334c58e658c7a0", 3 | "tag": "Vue.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeekly/input.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "32f2d520a2c362bdeaf5" 3 | } 4 | -------------------------------------------------------------------------------- /events/updateWeekly/input.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "b6cfc81906990b3a3e72" 3 | } 4 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/android.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "c9e01ace1c9ea80758e7", 3 | "tag": "Android" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/android.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "8b3af051428d746f26c5", 3 | "tag": "Android" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/aws.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9d88aa90990b220ab454", 3 | "tag": "AWS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/aws.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "e24b6279326a462d456c", 3 | "tag": "AWS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/beginner.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "0dd863619e85b4cdd07a", 3 | "tag": "初心者" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/beginner.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "402899ec543aff109505", 3 | "tag": "初心者" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/docker.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "28189490e70fdd55791d", 3 | "tag": "Docker" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/docker.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "ae11fca7d2eba445b037", 3 | "tag": "Docker" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/git.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "cbdc22a84887af1cc270", 3 | "tag": "Git" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/git.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "74eacdbf363e260981c3", 3 | "tag": "Git" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/go.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "517d1abc903893e5b35d", 3 | "tag": "Go" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/go.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "49d4537d95f878b3e91a", 3 | "tag": "Go" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/ios.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "a343a776baa89e7ccbfd", 3 | "tag": "iOS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/ios.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "e61a29a383d0403e92fc", 3 | "tag": "iOS" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/java.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "101f5e4c9a9f7b60ea40", 3 | "tag": "Java" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/java.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "4c3f84836bfdbb137226", 3 | "tag": "Java" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/javascript.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "a6dab8547a042d4c4c9c", 3 | "tag": "JavaScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/javascript.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "eaa7ac5b62a0a723edbb", 3 | "tag": "JavaScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/linux.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "8258a9a6ceedf4c4d727", 3 | "tag": "Linux" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/linux.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "362e81e53c3f9dee22f1", 3 | "tag": "Linux" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/nodejs.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "e14a4287701cbb339e9d", 3 | "tag": "Node.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/nodejs.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "66ed7ad8f7c9673e9d50", 3 | "tag": "Node.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/php.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "1f6bba863d0494c6e885", 3 | "tag": "PHP" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/php.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "3318cbdbc45c6ebd4014", 3 | "tag": "PHP" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/python.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9c515415a8cba944d575", 3 | "tag": "Python" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/python.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "9d7f2ffeafb36cf59a77", 3 | "tag": "Python" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/rails.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "370598ab6e1383b8dabd", 3 | "tag": "Rails" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/rails.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "93b9e7f7d143e9ce650e", 3 | "tag": "Rails" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/react.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "945a52ea6458fd873f3d", 3 | "tag": "React" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/react.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "f9712f8acace22815b99", 3 | "tag": "React" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/ruby.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "104d83bf7474c1077b56", 3 | "tag": "Ruby" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/ruby.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "72c3d2e896bdc3e1a6b3", 3 | "tag": "Ruby" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/swift.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "036b9f4ab2e44815ffbe", 3 | "tag": "Swift" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/swift.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "e2b6f0645e29f0e2b761", 3 | "tag": "Swift" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/typescript.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "7cbd1bd49c4f90ed8980", 3 | "tag": "TypeScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/typescript.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "25b7c0870afa6d41d19b", 3 | "tag": "TypeScript" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/vim.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "1c6e122c3f1ccb5bf4bd", 3 | "tag": "Vim" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/vim.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "f5361177baef95e447d1", 3 | "tag": "Vim" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/vuejs.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "bb9ce3bbd891512c18d1", 3 | "tag": "Vue.js" 4 | } 5 | -------------------------------------------------------------------------------- /events/updateWeeklyByTag/vuejs.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "report_id": "2774e02c6eea5c830d99", 3 | "tag": "Vue.js" 4 | } 5 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/koki-develop/qiita-lgtm-ranking 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/aws/aws-lambda-go v1.34.1 7 | github.com/fnproject/fdk-go v0.0.19 8 | github.com/pkg/errors v0.9.1 9 | github.com/tencentyun/scf-go-lib v0.0.0-20211123032342-f972dcd16ff6 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/aws/aws-lambda-go v1.34.1 h1:M3a/uFYBjii+tDcOJ0wL/WyFi2550FHoECdPf27zvOs= 2 | github.com/aws/aws-lambda-go v1.34.1/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/fnproject/fdk-go v0.0.19 h1:2O7+hXO1uLeFaKszKLSH8ha8qxuqePaGogH1ldV9s2w= 5 | github.com/fnproject/fdk-go v0.0.19/go.mod h1:I1vcgeMhAypxJ4pxIgq/pERZJvmanYYSlZaScO+oSps= 6 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 7 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 9 | github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= 10 | github.com/tencentyun/scf-go-lib v0.0.0-20211123032342-f972dcd16ff6 h1:5owXVztD4wNP6bhJzA5UNQyYsIKk5YWbA2EJnnMD/sg= 11 | github.com/tencentyun/scf-go-lib v0.0.0-20211123032342-f972dcd16ff6/go.mod h1:K3DbqPpP2WE/9MWokWWzgFZcbgtMb9Wd5CYk9AAbEN8= 12 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "scripts": { 4 | "predeploy": "./bin/build", 5 | "deploy": "serverless deploy --verbose" 6 | }, 7 | "devDependencies": { 8 | "serverless": "2.72.3", 9 | "serverless-plugin-diff": "3.0.0", 10 | "serverless-prune-plugin": "2.0.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pkg/controllers/reports.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "time" 9 | 10 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/infrastructures/qiita" 11 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/infrastructures/report" 12 | "github.com/pkg/errors" 13 | ) 14 | 15 | type ReportController struct { 16 | builder *report.Builder 17 | qiitaClient *qiita.Client 18 | } 19 | 20 | type ReportControllerConfig struct { 21 | QiitaAccessToken string 22 | } 23 | 24 | func NewReportController(cfg *ReportControllerConfig) *ReportController { 25 | return &ReportController{ 26 | builder: report.NewBuilder(), 27 | qiitaClient: qiita.New(cfg.QiitaAccessToken), 28 | } 29 | } 30 | 31 | func (ctrl *ReportController) UpdateDaily(rptID string) error { 32 | now := time.Now() 33 | from := now.AddDate(0, 0, -1) 34 | query := fmt.Sprintf("created:>=%s stocks:>=2", from.Format("2006-01-02")) 35 | 36 | items, err := ctrl.getAllItems(query) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | tags, err := ctrl.loadDailyTags() 42 | if err != nil { 43 | return err 44 | } 45 | 46 | rpt, err := ctrl.builder.Build(&report.BuildOptions{ 47 | Tags: tags, 48 | Conditions: report.Conditions{ 49 | {Key: "期間", Value: fmt.Sprintf("%s ~ %s", from.Format("2006-01-02"), now.Format("2006-01-02"))}, 50 | {Key: "条件", Value: "ストック数が **2** 以上の記事"}, 51 | }, 52 | Items: items, 53 | }) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | if err := ctrl.qiitaClient.UpdateItem(rptID, &qiita.UpdateItemPayload{ 59 | Title: "Qiita デイリーいいね数ランキング【自動更新】", 60 | Body: rpt, 61 | Tags: qiita.Tags{ 62 | {Name: "Qiita"}, 63 | {Name: "lgtm"}, 64 | {Name: "いいね"}, 65 | {Name: "ランキング"}, 66 | }, 67 | }); err != nil { 68 | return err 69 | } 70 | 71 | return nil 72 | } 73 | 74 | func (ctrl *ReportController) UpdateDailyByTag(rptID, tag string) error { 75 | now := time.Now() 76 | from := now.AddDate(0, 0, -1) 77 | query := fmt.Sprintf("created:>=%s tag:%s", from.Format("2006-01-02"), tag) 78 | 79 | items, err := ctrl.getAllItems(query) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | tags, err := ctrl.loadDailyTags() 85 | if err != nil { 86 | return err 87 | } 88 | 89 | rpt, err := ctrl.builder.Build(&report.BuildOptions{ 90 | Tags: tags, 91 | Conditions: report.Conditions{ 92 | {Key: "期間", Value: fmt.Sprintf("%s ~ %s", from.Format("2006-01-02"), now.Format("2006-01-02"))}, 93 | }, 94 | Items: items, 95 | }) 96 | if err != nil { 97 | return err 98 | } 99 | 100 | if err := ctrl.qiitaClient.UpdateItem(rptID, &qiita.UpdateItemPayload{ 101 | Title: fmt.Sprintf("【%s】Qiita デイリーいいね数ランキング【自動更新】", tag), 102 | Body: rpt, 103 | Tags: qiita.Tags{ 104 | {Name: "Qiita"}, 105 | {Name: "lgtm"}, 106 | {Name: "いいね"}, 107 | {Name: "ランキング"}, 108 | {Name: tag}, 109 | }, 110 | }); err != nil { 111 | return err 112 | } 113 | 114 | return nil 115 | } 116 | 117 | func (ctrl *ReportController) UpdateWeekly(rptID string) error { 118 | now := time.Now() 119 | from := now.AddDate(0, 0, -7) 120 | query := fmt.Sprintf("created:>=%s stocks:>=10", from.Format("2006-01-02")) 121 | 122 | items, err := ctrl.getAllItems(query) 123 | if err != nil { 124 | return err 125 | } 126 | 127 | tags, err := ctrl.loadWeeklyTags() 128 | if err != nil { 129 | return err 130 | } 131 | 132 | rpt, err := ctrl.builder.Build(&report.BuildOptions{ 133 | Tags: tags, 134 | Conditions: report.Conditions{ 135 | {Key: "期間", Value: fmt.Sprintf("%s ~ %s", from.Format("2006-01-02"), now.Format("2006-01-02"))}, 136 | {Key: "条件", Value: "ストック数が **10** 以上の記事"}, 137 | }, 138 | Items: items, 139 | }) 140 | if err != nil { 141 | return err 142 | } 143 | 144 | if err := ctrl.qiitaClient.UpdateItem(rptID, &qiita.UpdateItemPayload{ 145 | Title: "Qiita 週間いいね数ランキング【自動更新】", 146 | Body: rpt, 147 | Tags: qiita.Tags{ 148 | {Name: "Qiita"}, 149 | {Name: "lgtm"}, 150 | {Name: "いいね"}, 151 | {Name: "ランキング"}, 152 | }, 153 | }); err != nil { 154 | return err 155 | } 156 | 157 | return nil 158 | } 159 | 160 | func (ctrl *ReportController) UpdateWeeklyByTag(rptID, tag string) error { 161 | now := time.Now() 162 | from := now.AddDate(0, 0, -7) 163 | query := fmt.Sprintf("created:>=%s stocks:>=2 tag:%s", from.Format("2006-01-02"), tag) 164 | 165 | items, err := ctrl.getAllItems(query) 166 | if err != nil { 167 | return err 168 | } 169 | 170 | tags, err := ctrl.loadWeeklyTags() 171 | if err != nil { 172 | return err 173 | } 174 | 175 | rpt, err := ctrl.builder.Build(&report.BuildOptions{ 176 | Tags: tags, 177 | Conditions: report.Conditions{ 178 | {Key: "期間", Value: fmt.Sprintf("%s ~ %s", from.Format("2006-01-02"), now.Format("2006-01-02"))}, 179 | {Key: "条件", Value: "ストック数が **2** 以上の記事"}, 180 | }, 181 | Items: items, 182 | }) 183 | if err != nil { 184 | return err 185 | } 186 | 187 | if err := ctrl.qiitaClient.UpdateItem(rptID, &qiita.UpdateItemPayload{ 188 | Title: fmt.Sprintf("【%s】Qiita 週間いいね数ランキング【自動更新】", tag), 189 | Body: rpt, 190 | Tags: qiita.Tags{ 191 | {Name: "Qiita"}, 192 | {Name: "lgtm"}, 193 | {Name: "いいね"}, 194 | {Name: "ランキング"}, 195 | {Name: tag}, 196 | }, 197 | }); err != nil { 198 | return err 199 | } 200 | 201 | return nil 202 | } 203 | 204 | func (ctrl *ReportController) getAllItems(query string) (qiita.Items, error) { 205 | var items qiita.Items 206 | for i := 0; i < 100; i++ { 207 | rslt, err := ctrl.qiitaClient.GetItems(&qiita.GetItemsOptions{Page: i + 1, PerPage: 100, Query: query}) 208 | if err != nil { 209 | return nil, err 210 | } 211 | if len(rslt) == 0 { 212 | break 213 | } 214 | 215 | items = append(items, rslt.FilterWithMinLiked(1)...) 216 | if len(rslt) < 100 { 217 | break 218 | } 219 | } 220 | 221 | return items, nil 222 | } 223 | 224 | func (ctrl *ReportController) setStockersCount(items qiita.Items) error { 225 | for _, item := range items { 226 | cnt, err := ctrl.qiitaClient.GetStockersCount(item.ID) 227 | if err != nil { 228 | return err 229 | } 230 | item.StockersCount = cnt 231 | } 232 | 233 | return nil 234 | } 235 | 236 | func (ctrl *ReportController) loadTags(glob string) (report.Tags, error) { 237 | files, err := filepath.Glob(glob) 238 | if err != nil { 239 | return nil, errors.WithStack(err) 240 | } 241 | 242 | var tags report.Tags 243 | for _, file := range files { 244 | f, err := os.Open(file) 245 | if err != nil { 246 | return nil, errors.WithStack(err) 247 | } 248 | defer f.Close() 249 | var tag report.Tag 250 | if err := json.NewDecoder(f).Decode(&tag); err != nil { 251 | return nil, errors.WithStack(err) 252 | } 253 | tags = append(tags, &tag) 254 | } 255 | 256 | return tags, nil 257 | } 258 | 259 | func (ctrl *ReportController) loadDailyTags() (report.Tags, error) { 260 | return ctrl.loadTags("./events/updateDailyByTag/*.prod.json") 261 | } 262 | 263 | func (ctrl *ReportController) loadWeeklyTags() (report.Tags, error) { 264 | return ctrl.loadTags("./events/updateWeeklyByTag/*.prod.json") 265 | } 266 | -------------------------------------------------------------------------------- /pkg/handlers/daily/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/aws/aws-lambda-go/lambda" 8 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/controllers" 9 | ) 10 | 11 | type Event struct { 12 | ReportID string `json:"report_id"` 13 | } 14 | 15 | func Handler(e *Event) error { 16 | ctrl := controllers.NewReportController(&controllers.ReportControllerConfig{ 17 | QiitaAccessToken: os.Getenv("QIITA_ACCESS_TOKEN"), 18 | }) 19 | 20 | if err := ctrl.UpdateDaily(e.ReportID); err != nil { 21 | fmt.Printf("err: %+v\n", err) 22 | return err 23 | } 24 | 25 | return nil 26 | } 27 | 28 | func main() { 29 | lambda.Start(Handler) 30 | } 31 | -------------------------------------------------------------------------------- /pkg/handlers/dailybytag/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/aws/aws-lambda-go/lambda" 8 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/controllers" 9 | ) 10 | 11 | type Event struct { 12 | ReportID string `json:"report_id"` 13 | Tag string `json:"tag"` 14 | } 15 | 16 | func Handler(e *Event) error { 17 | ctrl := controllers.NewReportController(&controllers.ReportControllerConfig{ 18 | QiitaAccessToken: os.Getenv("QIITA_ACCESS_TOKEN"), 19 | }) 20 | 21 | if err := ctrl.UpdateDailyByTag(e.ReportID, e.Tag); err != nil { 22 | fmt.Printf("err: %+v\n", err) 23 | return err 24 | } 25 | 26 | return nil 27 | } 28 | 29 | func main() { 30 | lambda.Start(Handler) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/handlers/weekly/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/aws/aws-lambda-go/lambda" 8 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/controllers" 9 | ) 10 | 11 | type Event struct { 12 | ReportID string `json:"report_id"` 13 | } 14 | 15 | func Handler(e *Event) error { 16 | ctrl := controllers.NewReportController(&controllers.ReportControllerConfig{ 17 | QiitaAccessToken: os.Getenv("QIITA_ACCESS_TOKEN"), 18 | }) 19 | 20 | if err := ctrl.UpdateWeekly(e.ReportID); err != nil { 21 | fmt.Printf("err: %+v\n", err) 22 | return err 23 | } 24 | 25 | return nil 26 | } 27 | 28 | func main() { 29 | lambda.Start(Handler) 30 | } 31 | -------------------------------------------------------------------------------- /pkg/handlers/weeklybytag/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/aws/aws-lambda-go/lambda" 8 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/controllers" 9 | ) 10 | 11 | type Event struct { 12 | ReportID string `json:"report_id"` 13 | Tag string `json:"tag"` 14 | } 15 | 16 | func Handler(e *Event) error { 17 | ctrl := controllers.NewReportController(&controllers.ReportControllerConfig{ 18 | QiitaAccessToken: os.Getenv("QIITA_ACCESS_TOKEN"), 19 | }) 20 | 21 | if err := ctrl.UpdateWeeklyByTag(e.ReportID, e.Tag); err != nil { 22 | fmt.Printf("err: %+v\n", err) 23 | return err 24 | } 25 | 26 | return nil 27 | } 28 | 29 | func main() { 30 | lambda.Start(Handler) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/infrastructures/qiita/client.go: -------------------------------------------------------------------------------- 1 | package qiita 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "net/http" 10 | "net/url" 11 | "path" 12 | "strconv" 13 | 14 | "github.com/pkg/errors" 15 | ) 16 | 17 | type Client struct { 18 | token string 19 | httpAPI HTTPAPI 20 | } 21 | 22 | func New(token string) *Client { 23 | return &Client{ 24 | token: token, 25 | httpAPI: new(http.Client), 26 | } 27 | } 28 | 29 | type GetItemsOptions struct { 30 | Page int 31 | PerPage int 32 | Query string 33 | } 34 | 35 | func (cl *Client) GetItems(opts *GetItemsOptions) (Items, error) { 36 | req, err := cl.newRequest(http.MethodGet, "/items", nil) 37 | if err != nil { 38 | return nil, errors.WithStack(err) 39 | } 40 | 41 | q := req.URL.Query() 42 | q.Add("page", strconv.Itoa(opts.Page)) 43 | q.Add("per_page", strconv.Itoa(opts.PerPage)) 44 | q.Add("query", opts.Query) 45 | req.URL.RawQuery = q.Encode() 46 | 47 | resp, err := cl.sendRequest(req) 48 | if err != nil { 49 | return nil, err 50 | } 51 | defer resp.Body.Close() 52 | 53 | var items Items 54 | if err := json.NewDecoder(resp.Body).Decode(&items); err != nil { 55 | return nil, errors.WithStack(err) 56 | } 57 | 58 | return items, nil 59 | } 60 | 61 | func (cl *Client) GetStockersCount(itemid string) (int, error) { 62 | req, err := cl.newRequest(http.MethodGet, fmt.Sprintf("/items/%s/stockers", itemid), nil) 63 | if err != nil { 64 | return 0, errors.WithStack(err) 65 | } 66 | 67 | resp, err := cl.sendRequest(req) 68 | if err != nil { 69 | return 0, err 70 | } 71 | defer resp.Body.Close() 72 | 73 | cstr := resp.Header.Get("total-count") 74 | c, err := strconv.Atoi(cstr) 75 | if err != nil { 76 | return 0, errors.WithStack(err) 77 | } 78 | 79 | return c, nil 80 | } 81 | 82 | type UpdateItemPayload struct { 83 | Title string `json:"title"` 84 | Body string `json:"body"` 85 | Tags Tags `json:"tags"` 86 | } 87 | 88 | func (cl *Client) UpdateItem(id string, p *UpdateItemPayload) error { 89 | b, err := json.Marshal(p) 90 | if err != nil { 91 | return errors.WithStack(err) 92 | } 93 | 94 | req, err := cl.newRequest(http.MethodPatch, fmt.Sprintf("/items/%s", id), bytes.NewReader(b)) 95 | if err != nil { 96 | return errors.WithStack(err) 97 | } 98 | 99 | resp, err := cl.sendRequest(req) 100 | if err != nil { 101 | return err 102 | } 103 | defer resp.Body.Close() 104 | 105 | return nil 106 | } 107 | 108 | func (cl *Client) newRequest(method, p string, body io.Reader) (*http.Request, error) { 109 | u, err := url.Parse("https://qiita.com/api/v2") 110 | if err != nil { 111 | return nil, errors.WithStack(err) 112 | } 113 | u.Path = path.Join(u.Path, p) 114 | 115 | req, err := http.NewRequest(method, u.String(), body) 116 | if err != nil { 117 | return nil, errors.WithStack(err) 118 | } 119 | req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", cl.token)) 120 | 121 | if body != nil { 122 | req.Header.Set("Content-Type", "application/json") 123 | } 124 | 125 | return req, nil 126 | } 127 | 128 | func (cl *Client) sendRequest(req *http.Request) (*http.Response, error) { 129 | resp, err := cl.httpAPI.Do(req) 130 | if err != nil { 131 | return nil, errors.WithStack(err) 132 | } 133 | 134 | fmt.Printf("rate limit remaining: %s\n", resp.Header.Get("rate-remaining")) 135 | 136 | if resp.StatusCode != http.StatusOK { 137 | defer resp.Body.Close() 138 | 139 | b, err := ioutil.ReadAll(resp.Body) 140 | if err != nil { 141 | return nil, errors.WithStack(err) 142 | } 143 | return nil, errors.New(string(b)) 144 | } 145 | 146 | return resp, nil 147 | } 148 | -------------------------------------------------------------------------------- /pkg/infrastructures/qiita/entities.go: -------------------------------------------------------------------------------- 1 | package qiita 2 | 3 | import ( 4 | "sort" 5 | "time" 6 | ) 7 | 8 | type Item struct { 9 | ID string `json:"id"` 10 | Title string `json:"title"` 11 | LikesCount int `json:"likes_count"` 12 | StockersCount int `json:"stocks_count"` 13 | URL string `json:"url"` 14 | User User `json:"user"` 15 | Tags Tags `json:"tags"` 16 | CreatedAt time.Time `json:"created_at"` 17 | } 18 | 19 | type Items []*Item 20 | 21 | func (items Items) FilterWithMinLiked(min int) Items { 22 | var rslt Items 23 | for _, item := range items { 24 | if item.LikesCount >= min { 25 | rslt = append(rslt, item) 26 | } 27 | } 28 | return rslt 29 | } 30 | 31 | func (items Items) Sort() { 32 | sort.SliceStable(items, func(i, j int) bool { 33 | if items[i].LikesCount > items[j].LikesCount { 34 | return true 35 | } 36 | if items[i].LikesCount == items[j].LikesCount { 37 | if items[i].StockersCount > items[j].StockersCount { 38 | return true 39 | } 40 | if items[i].StockersCount == items[j].StockersCount { 41 | if items[i].CreatedAt.After(items[j].CreatedAt) { 42 | return true 43 | } 44 | } 45 | } 46 | 47 | return false 48 | }) 49 | } 50 | 51 | type User struct { 52 | ID string `json:"id"` 53 | ProfileImageURL string `json:"profile_image_url"` 54 | } 55 | 56 | type Users []*User 57 | 58 | type Tag struct { 59 | Name string `json:"name"` 60 | } 61 | 62 | type Tags []*Tag 63 | -------------------------------------------------------------------------------- /pkg/infrastructures/qiita/http.go: -------------------------------------------------------------------------------- 1 | package qiita 2 | 3 | import "net/http" 4 | 5 | type HTTPAPI interface { 6 | Do(req *http.Request) (*http.Response, error) 7 | } 8 | -------------------------------------------------------------------------------- /pkg/infrastructures/report/builder.go: -------------------------------------------------------------------------------- 1 | package report 2 | 3 | import ( 4 | "bytes" 5 | "html/template" 6 | 7 | "github.com/koki-develop/qiita-lgtm-ranking/pkg/infrastructures/qiita" 8 | "github.com/pkg/errors" 9 | ) 10 | 11 | type Builder struct{} 12 | 13 | func NewBuilder() *Builder { 14 | return &Builder{} 15 | } 16 | 17 | type BuildOptions struct { 18 | Tags Tags 19 | Conditions Conditions 20 | Items qiita.Items 21 | } 22 | 23 | func (b *Builder) Build(opts *BuildOptions) (string, error) { 24 | tpl, err := template.New("template.md").Funcs(template.FuncMap{ 25 | "inc": func(i int) int { 26 | return i + 1 27 | }, 28 | }).ParseFiles("./templates/template.md") 29 | if err != nil { 30 | return "", errors.WithStack(err) 31 | } 32 | 33 | buf := new(bytes.Buffer) 34 | opts.Items.Sort() 35 | if err := tpl.Execute(buf, map[string]interface{}{ 36 | "tags": opts.Tags, 37 | "conditions": opts.Conditions, 38 | "items": opts.Items, 39 | }); err != nil { 40 | return "", errors.WithStack(err) 41 | } 42 | 43 | return buf.String(), nil 44 | } 45 | 46 | type Tag struct { 47 | ReportID string `json:"report_id"` 48 | Name string `json:"tag"` 49 | } 50 | 51 | type Tags []*Tag 52 | 53 | type Condition struct { 54 | Key string 55 | Value string 56 | } 57 | 58 | type Conditions []*Condition 59 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: qiita-lgtm-ranking 2 | 3 | frameworkVersion: '2' 4 | useDotenv: true 5 | 6 | plugins: 7 | - serverless-plugin-diff 8 | - serverless-prune-plugin 9 | 10 | custom: 11 | prefix: ${self:service}-${self:provider.stage} 12 | schedule: 13 | enabled: 14 | dev: false 15 | prod: true 16 | prune: 17 | automatic: true 18 | includeLayers: true 19 | number: 3 20 | 21 | provider: 22 | name: aws 23 | region: us-east-1 24 | runtime: go1.x 25 | lambdaHashingVersion: 20201221 26 | memorySize: 128 27 | timeout: 900 28 | stage: ${opt:stage, "dev"} 29 | stackTags: 30 | App: qiita-lgtm-ranking 31 | environment: 32 | QIITA_ACCESS_TOKEN: ${env:QIITA_ACCESS_TOKEN} 33 | 34 | package: 35 | individually: true 36 | 37 | functions: 38 | updateDaily: 39 | handler: build/updateDaily 40 | package: 41 | patterns: 42 | - "!./**" 43 | - ./build/updateDaily 44 | - ./events/updateDailyByTag/*.prod.json 45 | - ./templates/** 46 | events: 47 | - schedule: 48 | name: ${self:custom.prefix}-daily 49 | rate: cron(0 6,18 * * ? *) 50 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 51 | input: ${file(./events/updateDaily/input.${self:provider.stage}.json)} 52 | 53 | updateDailyByTag: 54 | handler: build/updateDailyByTag 55 | package: 56 | patterns: 57 | - "!./**" 58 | - ./build/updateDailyByTag 59 | - ./events/updateDailyByTag/*.prod.json 60 | - ./templates/** 61 | events: 62 | # AWS 63 | - schedule: 64 | name: ${self:custom.prefix}-daily-aws 65 | rate: cron(0 0,6,12,18 * * ? *) 66 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 67 | input: ${file(./events/updateDailyByTag/aws.${self:provider.stage}.json)} 68 | 69 | # Android 70 | - schedule: 71 | name: ${self:custom.prefix}-daily-android 72 | rate: cron(0 1,7,13,19 * * ? *) 73 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 74 | input: ${file(./events/updateDailyByTag/android.${self:provider.stage}.json)} 75 | 76 | # Docker 77 | - schedule: 78 | name: ${self:custom.prefix}-daily-docker 79 | rate: cron(0 2,8,14,20 * * ? *) 80 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 81 | input: ${file(./events/updateDailyByTag/docker.${self:provider.stage}.json)} 82 | 83 | # Go 84 | - schedule: 85 | name: ${self:custom.prefix}-daily-go 86 | rate: cron(0 3,9,15,21 * * ? *) 87 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 88 | input: ${file(./events/updateDailyByTag/go.${self:provider.stage}.json)} 89 | 90 | # Git 91 | - schedule: 92 | name: ${self:custom.prefix}-daily-git 93 | rate: cron(0 4,10,16,22 * * ? *) 94 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 95 | input: ${file(./events/updateDailyByTag/git.${self:provider.stage}.json)} 96 | 97 | # iOS 98 | - schedule: 99 | name: ${self:custom.prefix}-daily-ios 100 | rate: cron(0 5,11,17,23 * * ? *) 101 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 102 | input: ${file(./events/updateDailyByTag/ios.${self:provider.stage}.json)} 103 | 104 | # Java 105 | - schedule: 106 | name: ${self:custom.prefix}-daily-java 107 | rate: cron(0 0,6,12,18 * * ? *) 108 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 109 | input: ${file(./events/updateDailyByTag/java.${self:provider.stage}.json)} 110 | 111 | # JavaScript 112 | - schedule: 113 | name: ${self:custom.prefix}-daily-javascript 114 | rate: cron(0 1,7,13,19 * * ? *) 115 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 116 | input: ${file(./events/updateDailyByTag/javascript.${self:provider.stage}.json)} 117 | 118 | # Linux 119 | - schedule: 120 | name: ${self:custom.prefix}-daily-linux 121 | rate: cron(0 2,8,14,20 * * ? *) 122 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 123 | input: ${file(./events/updateDailyByTag/linux.${self:provider.stage}.json)} 124 | 125 | # Node.js 126 | - schedule: 127 | name: ${self:custom.prefix}-daily-nodejs 128 | rate: cron(0 3,9,15,21 * * ? *) 129 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 130 | input: ${file(./events/updateDailyByTag/nodejs.${self:provider.stage}.json)} 131 | 132 | # PHP 133 | - schedule: 134 | name: ${self:custom.prefix}-daily-php 135 | rate: cron(0 4,10,16,22 * * ? *) 136 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 137 | input: ${file(./events/updateDailyByTag/php.${self:provider.stage}.json)} 138 | 139 | # Python 140 | - schedule: 141 | name: ${self:custom.prefix}-daily-python 142 | rate: cron(0 5,11,17,23 * * ? *) 143 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 144 | input: ${file(./events/updateDailyByTag/python.${self:provider.stage}.json)} 145 | 146 | # Rails 147 | - schedule: 148 | name: ${self:custom.prefix}-daily-rails 149 | rate: cron(0 0,6,12,18 * * ? *) 150 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 151 | input: ${file(./events/updateDailyByTag/rails.${self:provider.stage}.json)} 152 | 153 | # React 154 | - schedule: 155 | name: ${self:custom.prefix}-daily-react 156 | rate: cron(0 1,7,13,19 * * ? *) 157 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 158 | input: ${file(./events/updateDailyByTag/react.${self:provider.stage}.json)} 159 | 160 | # Ruby 161 | - schedule: 162 | name: ${self:custom.prefix}-daily-ruby 163 | rate: cron(0 2,8,14,20 * * ? *) 164 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 165 | input: ${file(./events/updateDailyByTag/ruby.${self:provider.stage}.json)} 166 | 167 | # Swift 168 | - schedule: 169 | name: ${self:custom.prefix}-daily-swift 170 | rate: cron(0 3,9,15,21 * * ? *) 171 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 172 | input: ${file(./events/updateDailyByTag/swift.${self:provider.stage}.json)} 173 | 174 | # TypeScript 175 | - schedule: 176 | name: ${self:custom.prefix}-daily-typescript 177 | rate: cron(0 4,10,16,22 * * ? *) 178 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 179 | input: ${file(./events/updateDailyByTag/typescript.${self:provider.stage}.json)} 180 | 181 | # Vim 182 | - schedule: 183 | name: ${self:custom.prefix}-daily-vim 184 | rate: cron(0 5,11,17,23 * * ? *) 185 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 186 | input: ${file(./events/updateDailyByTag/vim.${self:provider.stage}.json)} 187 | 188 | # Vue.js 189 | - schedule: 190 | name: ${self:custom.prefix}-daily-vuejs 191 | rate: cron(0 0,6,12,18 * * ? *) 192 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 193 | input: ${file(./events/updateDailyByTag/vuejs.${self:provider.stage}.json)} 194 | 195 | # 初心者 196 | - schedule: 197 | name: ${self:custom.prefix}-daily-beginner 198 | rate: cron(0 1,7,13,19 * * ? *) 199 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 200 | input: ${file(./events/updateDailyByTag/beginner.${self:provider.stage}.json)} 201 | 202 | updateWeekly: 203 | handler: build/updateWeekly 204 | package: 205 | patterns: 206 | - "!./**" 207 | - ./build/updateWeekly 208 | - ./events/updateWeeklyByTag/*.prod.json 209 | - ./templates/** 210 | events: 211 | - schedule: 212 | name: ${self:custom.prefix}-weekly 213 | rate: cron(0 0,12 * * ? *) 214 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 215 | input: ${file(./events/updateWeekly/input.${self:provider.stage}.json)} 216 | 217 | updateWeeklyByTag: 218 | handler: build/updateWeeklyByTag 219 | package: 220 | patterns: 221 | - "!./**" 222 | - ./build/updateWeeklyByTag 223 | - ./events/updateWeeklyByTag/*.prod.json 224 | - ./templates/** 225 | events: 226 | # AWS 227 | - schedule: 228 | name: ${self:custom.prefix}-weekly-aws 229 | rate: cron(0 0,6,12,18 * * ? *) 230 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 231 | input: ${file(./events/updateWeeklyByTag/aws.${self:provider.stage}.json)} 232 | 233 | # Android 234 | - schedule: 235 | name: ${self:custom.prefix}-weekly-android 236 | rate: cron(0 1,7,13,19 * * ? *) 237 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 238 | input: ${file(./events/updateWeeklyByTag/android.${self:provider.stage}.json)} 239 | 240 | # Docker 241 | - schedule: 242 | name: ${self:custom.prefix}-weekly-docker 243 | rate: cron(0 2,8,14,20 * * ? *) 244 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 245 | input: ${file(./events/updateWeeklyByTag/docker.${self:provider.stage}.json)} 246 | 247 | # Go 248 | - schedule: 249 | name: ${self:custom.prefix}-weekly-go 250 | rate: cron(0 3,9,15,21 * * ? *) 251 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 252 | input: ${file(./events/updateWeeklyByTag/go.${self:provider.stage}.json)} 253 | 254 | # Git 255 | - schedule: 256 | name: ${self:custom.prefix}-weekly-git 257 | rate: cron(0 4,10,16,22 * * ? *) 258 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 259 | input: ${file(./events/updateWeeklyByTag/git.${self:provider.stage}.json)} 260 | 261 | # iOS 262 | - schedule: 263 | name: ${self:custom.prefix}-weekly-ios 264 | rate: cron(0 5,11,17,23 * * ? *) 265 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 266 | input: ${file(./events/updateWeeklyByTag/ios.${self:provider.stage}.json)} 267 | 268 | # Java 269 | - schedule: 270 | name: ${self:custom.prefix}-weekly-java 271 | rate: cron(0 0,6,12,18 * * ? *) 272 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 273 | input: ${file(./events/updateWeeklyByTag/java.${self:provider.stage}.json)} 274 | 275 | # JavaScript 276 | - schedule: 277 | name: ${self:custom.prefix}-weekly-javascript 278 | rate: cron(0 1,7,13,19 * * ? *) 279 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 280 | input: ${file(./events/updateWeeklyByTag/javascript.${self:provider.stage}.json)} 281 | 282 | # Linux 283 | - schedule: 284 | name: ${self:custom.prefix}-weekly-linux 285 | rate: cron(0 2,8,14,20 * * ? *) 286 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 287 | input: ${file(./events/updateWeeklyByTag/linux.${self:provider.stage}.json)} 288 | 289 | # Node.js 290 | - schedule: 291 | name: ${self:custom.prefix}-weekly-nodejs 292 | rate: cron(0 3,9,15,21 * * ? *) 293 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 294 | input: ${file(./events/updateWeeklyByTag/nodejs.${self:provider.stage}.json)} 295 | 296 | # PHP 297 | - schedule: 298 | name: ${self:custom.prefix}-weekly-php 299 | rate: cron(0 4,10,16,22 * * ? *) 300 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 301 | input: ${file(./events/updateWeeklyByTag/php.${self:provider.stage}.json)} 302 | 303 | # Python 304 | - schedule: 305 | name: ${self:custom.prefix}-weekly-python 306 | rate: cron(0 5,11,17,23 * * ? *) 307 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 308 | input: ${file(./events/updateWeeklyByTag/python.${self:provider.stage}.json)} 309 | 310 | # Rails 311 | - schedule: 312 | name: ${self:custom.prefix}-weekly-rails 313 | rate: cron(0 0,6,12,18 * * ? *) 314 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 315 | input: ${file(./events/updateWeeklyByTag/rails.${self:provider.stage}.json)} 316 | 317 | # React 318 | - schedule: 319 | name: ${self:custom.prefix}-weekly-react 320 | rate: cron(0 1,7,13,19 * * ? *) 321 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 322 | input: ${file(./events/updateWeeklyByTag/react.${self:provider.stage}.json)} 323 | 324 | # Ruby 325 | - schedule: 326 | name: ${self:custom.prefix}-weekly-ruby 327 | rate: cron(0 2,8,14,20 * * ? *) 328 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 329 | input: ${file(./events/updateWeeklyByTag/ruby.${self:provider.stage}.json)} 330 | 331 | # Swift 332 | - schedule: 333 | name: ${self:custom.prefix}-weekly-swift 334 | rate: cron(0 3,9,15,21 * * ? *) 335 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 336 | input: ${file(./events/updateWeeklyByTag/swift.${self:provider.stage}.json)} 337 | 338 | # TypeScript 339 | - schedule: 340 | name: ${self:custom.prefix}-weekly-typescript 341 | rate: cron(0 4,10,16,22 * * ? *) 342 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 343 | input: ${file(./events/updateWeeklyByTag/typescript.${self:provider.stage}.json)} 344 | 345 | # Vim 346 | - schedule: 347 | name: ${self:custom.prefix}-weekly-vim 348 | rate: cron(0 5,11,17,23 * * ? *) 349 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 350 | input: ${file(./events/updateWeeklyByTag/vim.${self:provider.stage}.json)} 351 | 352 | # Vue.js 353 | - schedule: 354 | name: ${self:custom.prefix}-weekly-vuejs 355 | rate: cron(0 0,6,12,18 * * ? *) 356 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 357 | input: ${file(./events/updateWeeklyByTag/vuejs.${self:provider.stage}.json)} 358 | 359 | # 初心者 360 | - schedule: 361 | name: ${self:custom.prefix}-weekly-beginner 362 | rate: cron(0 1,7,13,19 * * ? *) 363 | enabled: ${self:custom.schedule.enabled.${self:provider.stage}} 364 | input: ${file(./events/updateWeeklyByTag/beginner.${self:provider.stage}.json)} 365 | -------------------------------------------------------------------------------- /templates/template.md: -------------------------------------------------------------------------------- 1 | # タグ別 2 | 3 | {{ range .tags }}[`{{ .Name }}`](https://qiita.com/items/{{ .ReportID }}) {{ end }} 4 | 5 | # 集計について 6 | 7 | {{ range .conditions -}} 8 | - {{ .Key }}: {{ .Value }} 9 | {{ end -}} 10 | 11 | # GitHub 12 | 13 | 14 | スターをもらえるととっても励みになります :bow: 15 | 16 | # いいね数ランキング 17 | 18 | {{ if .items -}} 19 | {{ range $i, $item := .items -}} 20 | ## {{ inc $i }} 位: [{{ $item.Title }}]({{ $item.URL }}) 21 | 22 | {{ range $item.Tags }}[`{{ .Name }}`](https://qiita.com/tags/{{ .Name }}) {{ end }} 23 | **{{ $item.LikesCount }}** いいね **{{ $item.StockersCount }}** ストック 24 | [@{{ $item.User.ID }}](https://qiita.com/{{ $item.User.ID }}) さん ( {{ $item.CreatedAt.Format "2006-01-02 15:04" }} に投稿 ) 25 | {{ end -}} 26 | {{ else -}} 27 | ランキングに入る記事が見つかりませんでした。 28 | {{ end -}} 29 | --------------------------------------------------------------------------------