+ Imię: + {name} +
++ Zasługi: + {translatedContributions.join(", ")} +
+diff --git a/.all-contributorsrc b/.all-contributorsrc index 2661aa0b..f0fe22b7 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -112,9 +112,38 @@ "contributions": [ "doc" ] + }, + { + "login": "AdiPol1359", + "name": "Adrian Polak", + "avatar_url": "https://avatars.githubusercontent.com/u/27779154?v=4", + "profile": "https://projectcode.pl/", + "contributions": [ + "code" + ] + }, + { + "login": "xStrixU", + "name": "xStrixU", + "avatar_url": "https://avatars.githubusercontent.com/u/41890821?v=4", + "profile": "https://github.com/xStrixU", + "contributions": [ + "code" + ] + }, + { + "login": "grzegorzpokorski", + "name": "Grzegorz Pokorski", + "avatar_url": "https://avatars.githubusercontent.com/u/27455716?v=4", + "profile": "https://github.com/grzegorzpokorski", + "contributions": [ + "doc", + "bug", + "code" + ] } ], - "contributorsPerLine": 7, + "contributorsPerLine": 3, "skipCi": true, "badgeTemplate": "[![All Contributors](https://img.shields.io/badge/Contributors-<%= contributors.length %>-673ab7.svg)](#contributors-)" } diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index c25ab495..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,84 +0,0 @@ -version: 2.1 -orbs: - node: circleci/node@1.1.6 - -jobs: - dangerfile: - docker: - - image: circleci/node:12-browsers - steps: - - run: | - if [ "$CIRCLE_BRANCH" = "develop" ] || [ "$CIRCLE_BRANCH" = "main" ]; then - circleci-agent step halt - fi - - - checkout - - restore_cache: - name: Restore Yarn Package Cache - keys: - - yarn-packages-{{ checksum "yarn.lock" }} - - yarn-packages- - - run: yarn install --frozen-lockfile - - run: yarn cache dir - - - run: yarn get-base-branch - - run: git status - - run: cat /tmp/.basebranch - - run: git fetch && git checkout $CIRCLE_BRANCH && git reset --hard origin/$CIRCLE_BRANCH - - run: git diff --name-only HEAD $(cat /tmp/.basebranch) - - when: - condition: git diff --name-only HEAD $(cat /tmp/.basebranch) | grep -q "apps/www" - steps: - - run: cp apps/www/.env apps/www/.env.staging - - run: cp apps/www/.env apps/www/.env.production - - run: yarn workspace www build > analyze.next - - run: rm apps/www/.env.staging - - run: rm apps/www/.env.production - - run: cat analyze.next - - run: yarn create-size && mv size-snapshot.json /tmp/current-size-snapshot.json - - run: rm analyze.next && rm -rf apps/www/.next - - - run: git checkout $(cat /tmp/.basebranch) && git reset --hard origin/$(cat /tmp/.basebranch) - - run: git status - - run: yarn install --frozen-lockfile - - run: cp apps/www/.env apps/www/.env.staging - - run: cp apps/www/.env apps/www/.env.production - - run: yarn workspace www build > analyze.next - - run: rm apps/www/.env.staging - - run: rm apps/www/.env.production - - run: cat analyze.next - - run: mv analyze.next /tmp/ - - - run: git checkout $CIRCLE_BRANCH && git reset --hard origin/$CIRCLE_BRANCH - - run: git status - - run: yarn install --frozen-lockfile - - run: cp apps/www/.env apps/www/.env.staging - - run: cp apps/www/.env apps/www/.env.production - - - run: mv /tmp/analyze.next ./ - - run: yarn create-size && mv size-snapshot.json previous-size-snapshot.json - - run: mv /tmp/current-size-snapshot.json ./ - - # - run: mkdir -p /tmp/lighthouse/ - - run: yarn danger ci - - - save_cache: - name: Save Yarn Package Cache - key: yarn-packages-{{ checksum "yarn.lock" }} - paths: - - ~/.cache/yarn - - /home/circleci/.cache/yarn/v6 - - - store_artifacts: - path: ./current-size-snapshot.json - # - store_artifacts: - # path: /tmp/lighthouse - -workflows: - dangerfile: - jobs: - - dangerfile: - filters: - branches: - ignore: - - /dependabot\/*/ diff --git a/apps/www/.editorconfig b/.editorconfig similarity index 100% rename from apps/www/.editorconfig rename to .editorconfig diff --git a/.eslintignore b/.eslintignore deleted file mode 120000 index 3e4e48b0..00000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -.gitignore \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index a0a954dd..00000000 --- a/.eslintrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "sourceType": "module" - }, - "plugins": [], - "extends": ["prettier", "plugin:import/typescript"], - "rules": { - "no-const-assign": "error", - "import/no-anonymous-default-export": "error", - "import/dynamic-import-chunkname": "error", - "import/order": ["error", { "newlines-between": "always", "alphabetize": { "order": "asc" } }], - "import/no-duplicates": "error", - "import/no-cycle": "error", - "@typescript-eslint/no-unused-vars": "off" - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..5bc6cff8 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + root: true, + // This tells ESLint to load the config from the package `eslint-config-devfaq` + extends: ["devfaq"], + settings: { + next: { + rootDir: ["apps/*/"], + }, + }, +}; diff --git a/.fossa.yml b/.fossa.yml deleted file mode 100755 index 546a93fd..00000000 --- a/.fossa.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli) -# Visit https://fossa.com to learn more - -version: 2 -cli: - server: https://app.fossa.com - fetcher: custom - project: git@github.com:typeofweb/devfaq.git -analyze: - modules: - - name: api - type: npm - target: apps/api - path: apps/api - - name: www - type: npm - target: apps/www - path: apps/www - - name: . - type: npm - target: . - path: . diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 62db841e..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,9 +0,0 @@ -apps/api/app.js @mmiszy -apps/api/src @mmiszy - -apps/www/app.js @mmiszy -apps/www/pages @mmiszy -apps/www/components @mmiszy -apps/www/public @mmiszy - -scripts @mmiszy diff --git a/.github/workflows/auto-approve-dependabot.yml b/.github/workflows/auto-approve-dependabot.yml deleted file mode 100644 index 0c4d9b11..00000000 --- a/.github/workflows/auto-approve-dependabot.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Auto approve dependabot - -on: - pull_request: - branches: [develop] - -jobs: - auto-approve: - runs-on: ubuntu-latest - steps: - - uses: hmarr/auto-approve-action@v2.0.0 - if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]' - with: - github-token: '${{ secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 7e8b529f..00000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [develop, main] - pull_request: - # The branches below must be a subset of the branches above - branches: [develop] - schedule: - - cron: '0 19 * * 3' - -jobs: - analyse: - name: Analyse - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..8e1d8816 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,73 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["develop", main] + pull_request: + # The branches below must be a subset of the branches above + branches: ["develop"] + schedule: + - cron: "41 18 * * 2" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["javascript"] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/deploy-api.yml b/.github/workflows/deploy-api.yml new file mode 100644 index 00000000..654e0523 --- /dev/null +++ b/.github/workflows/deploy-api.yml @@ -0,0 +1,66 @@ +name: Fly Deploy +on: + workflow_dispatch: + push: + branches: + - develop +jobs: + deploy: + name: Deploy API + runs-on: ubuntu-latest + environment: staging-api + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: Fail if branch is not main + if: github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/develop' + run: | + echo "This workflow should not be triggered with workflow_dispatch on a branch other than develop" + exit 1 + + - name: Verify if deploy is needed + id: should_run + if: github.event_name != 'workflow_dispatch' + shell: bash + run: | + HAS_CHANGES=$(npx -y turbo run build --filter='api...[HEAD^]' --dry=json | jq '.packages | length > 0') + echo "HAS_CHANGES=$HAS_CHANGES" >> $GITHUB_OUTPUT + + - name: Create GitHub deployment + if: steps.should_run.outputs.HAS_CHANGES != 'false' + uses: chrnorm/deployment-action@v2 + id: deployment + with: + token: "${{ github.token }}" + environment-url: https://staging-api.devfaq.pl + environment: staging-api + + - name: Prepare flyctl + if: steps.should_run.outputs.HAS_CHANGES != 'false' + uses: superfly/flyctl-actions/setup-flyctl@master + + - name: Deploy to fly.io + if: steps.should_run.outputs.HAS_CHANGES != 'false' + run: flyctl deploy --config apps/api/fly.toml --remote-only -e GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -e GIT_COMMIT_HASH=$(git rev-parse HEAD) + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} + + - name: Update deployment status (success) + if: steps.should_run.outputs.HAS_CHANGES != 'false' && success() + uses: chrnorm/deployment-status@v2 + with: + token: "${{ github.token }}" + environment-url: ${{ steps.deployment.outputs.environment_url }} + deployment-id: ${{ steps.deployment.outputs.deployment_id }} + state: "success" + + - name: Update deployment status (failure) + if: steps.should_run.outputs.HAS_CHANGES != 'false' && failure() + uses: chrnorm/deployment-status@v2 + with: + token: "${{ github.token }}" + environment-url: ${{ steps.deployment.outputs.environment_url }} + deployment-id: ${{ steps.deployment.outputs.deployment_id }} + state: "failure" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 5ee86cd9..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Deploy to staging and production - -on: - push: - branches: [main, develop] - -jobs: - deploy: - runs-on: ubuntu-latest - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - SENTRY_LOG_LEVEL: debug - - steps: - - uses: actions/checkout@v2 - - - name: Setup SSH Keys and known_hosts - env: - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - run: | - mkdir -p ~/.ssh - ssh-keyscan -H github.com >> ~/.ssh/known_hosts - ssh-keyscan -H s18.mydevil.net >> ~/.ssh/known_hosts - ssh-agent -a $SSH_AUTH_SOCK > /dev/null - ssh-add - <<< "${{ secrets.SSH_PRIVATE_KEY }}" - if [[ "${GITHUB_REF##*/}" == 'develop' ]]; then ENV="staging"; fi - if [[ "${GITHUB_REF##*/}" == 'main' ]]; then ENV="production"; fi - ssh typeofweb@s18.mydevil.net 'source ~/.bashrc && ssh-add ~/.ssh/github && bash -s' < ./scripts/ssh-script-deploy.sh $ENV - - - name: Create Sentry Release - run: | - if [[ "${GITHUB_REF##*/}" == 'develop' ]]; then ENV="staging"; fi - if [[ "${GITHUB_REF##*/}" == 'main' ]]; then ENV="production"; fi - - # Install Sentry CLI - curl -sL https://sentry.io/get-cli/ | bash - - # Create new Sentry release - export SENTRY_VERSION=$(sentry-cli releases propose-version) - - sentry-cli releases --org=typeofweb --project=devfaq-api new $SENTRY_VERSION - sentry-cli releases --org=typeofweb --project=devfaq-api set-commits --auto $SENTRY_VERSION - sentry-cli releases --org=typeofweb --project=devfaq-api finalize $SENTRY_VERSION - sentry-cli releases --org=typeofweb --project=devfaq-api deploys $SENTRY_VERSION new -e $ENV - - sentry-cli releases --org=typeofweb --project=devfaq-www new $SENTRY_VERSION - sentry-cli releases --org=typeofweb --project=devfaq-www set-commits --auto $SENTRY_VERSION - sentry-cli releases --org=typeofweb --project=devfaq-www finalize $SENTRY_VERSION - sentry-cli releases --org=typeofweb --project=devfaq-www deploys $SENTRY_VERSION new -e $ENV diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml new file mode 100644 index 00000000..792004db --- /dev/null +++ b/.github/workflows/lighthouse.yml @@ -0,0 +1,33 @@ +name: Lighthouse + +concurrency: + group: lighthouse-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +on: [pull_request] +jobs: + lighthouse: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Wait for Vercel preview deployment + uses: patrickedqvist/wait-for-vercel-preview@v1.2.0 + id: waitForVercelPreviewDeployment + with: + token: ${{ secrets.GITHUB_TOKEN }} + max_timeout: 600 + check_interval: 15 + + - name: Warm-up devfaq cache + run: | + curl ${{ steps.waitForVercelPreviewDeployment.outputs.url }} + curl ${{ steps.waitForVercelPreviewDeployment.outputs.url }}/questions/js/1 + + - name: Lighthouse + uses: foo-software/lighthouse-check-action@v9.1.0 + with: + urls: ${{ steps.waitForVercelPreviewDeployment.outputs.url }} + gitHubAccessToken: ${{ secrets.GITHUB_TOKEN }} + locale: pl + prCommentEnabled: true diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml new file mode 100644 index 00000000..1bc2c73a --- /dev/null +++ b/.github/workflows/nextjs_bundle_analysis.yml @@ -0,0 +1,138 @@ +name: "Next.js Bundle Analysis" + +concurrency: + group: analyze-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +on: + pull_request: + push: + branches: + - develop + workflow_dispatch: + +defaults: + run: + working-directory: ./ + +jobs: + analyze: + runs-on: ubuntu-latest + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + NEXT_PUBLIC_API_URL: https://staging-api.devfaq.pl + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + + - uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + + - uses: pnpm/action-setup@v2 + with: + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: node-cache-${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + node-cache-${{ runner.os }}-pnpm- + + - name: Install dependencies + run: pnpm --version && pnpm install --frozen-lockfile + + - name: Restore next build + uses: actions/cache@v3 + id: restore-build-cache + env: + cache-name: cache-next-build + with: + path: apps/app/.next/cache + key: ${{ runner.os }}-build-${{ env.cache-name }} + + - name: Build next.js app + run: pnpm build --filter=app + + - name: Analyze bundle + run: cd apps/app && npx -p nextjs-bundle-analysis report + + - name: Upload bundle + uses: actions/upload-artifact@v3 + with: + name: bundle + path: apps/app/.next/analyze/__bundle_analysis.json + + - name: Download base branch bundle stats + uses: dawidd6/action-download-artifact@v2 + if: success() && github.event.number + with: + workflow: nextjs_bundle_analysis.yml + # branch: ${{ github.event.pull_request.base.ref }} + commit: ${{ github.event.pull_request.base.sha }} + path: apps/app/.next/analyze/base + + # And here's the second place - this runs after we have both the current and + # base branch bundle stats, and will compare them to determine what changed. + # There are two configurable arguments that come from package.json: + # + # - budget: optional, set a budget (bytes) against which size changes are measured + # it's set to 350kb here by default, as informed by the following piece: + # https://infrequently.org/2021/03/the-performance-inequality-gap/ + # + # - red-status-percentage: sets the percent size increase where you get a red + # status indicator, defaults to 20% + # + # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` + # entry in your package.json file. + - name: Compare with base branch bundle + if: success() && github.event.number + run: ls -laR apps/app/.next/analyze/base && cd apps/app && npx -p nextjs-bundle-analysis compare + + - name: Get comment body + id: get-comment-body + if: success() && github.event.number + uses: actions/github-script@v6 + with: + result-encoding: string + script: | + const fs = require('fs') + const comment = fs.readFileSync('apps/app/.next/analyze/__bundle_analysis_comment.txt', 'utf8') + core.setOutput('body', comment) + + - name: Find Comment + uses: peter-evans/find-comment@v2 + if: success() && github.event.number + id: fc + with: + issue-number: ${{ github.event.number }} + body-includes: "" + + - name: Create Comment + uses: peter-evans/create-or-update-comment@v2 + if: success() && github.event.number && steps.fc.outputs.comment-id == 0 + with: + issue-number: ${{ github.event.number }} + body: ${{ steps.get-comment-body.outputs.body }} + + - name: Update Comment + uses: peter-evans/create-or-update-comment@v2 + if: success() && github.event.number && steps.fc.outputs.comment-id != 0 + with: + issue-number: ${{ github.event.number }} + body: ${{ steps.get-comment-body.outputs.body }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace diff --git a/.github/workflows/test-PR.yml b/.github/workflows/test-PR.yml deleted file mode 100644 index caa8aa22..00000000 --- a/.github/workflows/test-PR.yml +++ /dev/null @@ -1,119 +0,0 @@ -name: Test and Build - -on: - pull_request: - branches: [develop, main] - -jobs: - test_www: - if: "! contains(toJSON(github.event.commits.*.message), '[skip-ci]')" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 100 - - - uses: marceloprado/has-changed-path@master - id: changed-www - with: - paths: apps/www - - - name: Read .nvmrc - if: steps.changed-www.outputs.changed == 'true' - run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" - id: nvm - - name: Use Node.js - if: steps.changed-www.outputs.changed == 'true' - uses: actions/setup-node@v1 - with: - node-version: '${{ steps.nvm.outputs.NVMRC }}' - - - name: Get yarn cache directory path - if: steps.changed-www.outputs.changed == 'true' - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Cache Node.js modules - if: steps.changed-www.outputs.changed == 'true' - uses: actions/cache@v1 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - ${{ runner.OS }}- - - - run: cp apps/www/.env apps/www/.env.staging - - run: cp apps/www/.env apps/www/.env.production - - - name: Install dependencies - if: steps.changed-www.outputs.changed == 'true' - run: yarn workspace www install --frozen-lockfile - - - name: Run tests - if: steps.changed-www.outputs.changed == 'true' - run: yarn workspace www test - - - name: Run build - if: steps.changed-www.outputs.changed == 'true' - run: yarn workspace www build - - test_api: - if: "! contains(toJSON(github.event.commits.*.message), '[skip-ci]')" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 100 - - - uses: marceloprado/has-changed-path@master - id: changed-api - with: - paths: apps/api - - - name: Setup PostgreSQL - if: steps.changed-api.outputs.changed == 'true' - uses: Harmon758/postgresql-action@v1.0.0 - with: - postgresql version: 12-alpine - postgresql db: database_development - postgresql user: postgres - postgresql password: -api2018 - - - name: Read .nvmrc - if: steps.changed-api.outputs.changed == 'true' - run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" - id: nvm - - name: Use Node.js - if: steps.changed-api.outputs.changed == 'true' - uses: actions/setup-node@v1 - with: - node-version: '${{ steps.nvm.outputs.NVMRC }}' - - name: Get yarn cache directory path - if: steps.changed-api.outputs.changed == 'true' - id: yarn-cache-dir-path - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Cache Node.js modules - if: steps.changed-api.outputs.changed == 'true' - uses: actions/cache@v1 - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - ${{ runner.OS }}- - - - name: Install dependencies - if: steps.changed-api.outputs.changed == 'true' - run: yarn workspace api install --frozen-lockfile - - - name: Run tests - if: steps.changed-api.outputs.changed == 'true' - run: yarn workspace api test - - - name: Run build for dependabot - if: steps.changed-api.outputs.changed == 'true' && (github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]') - run: yarn workspace api build diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..b45c8135 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,97 @@ +name: Tests + +concurrency: + group: tests-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +on: [pull_request] + +jobs: + build_and_test: + runs-on: ubuntu-latest + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + NEXT_PUBLIC_API_URL: https://staging-api.devfaq.pl + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + + - uses: pnpm/action-setup@v2 + with: + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: node-cache-${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + node-cache-${{ runner.os }}-pnpm- + + - name: Install dependencies + run: pnpm --version && pnpm install --frozen-lockfile + + - name: Turbo Cache + uses: actions/cache@v3 + with: + path: .turbo + key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + turbo-${{ github.job }}-${{ github.ref_name }}- + + - name: Build + run: pnpm run build --cache-dir=".turbo" + + - name: Check linters + run: pnpm run lint --cache-dir=".turbo" + + - name: Run tests + run: pnpm run test --cache-dir=".turbo" + + - name: Check TypeScript + run: pnpm run check-types --cache-dir=".turbo" + + storybook: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + + - uses: pnpm/action-setup@v2 + with: + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: node-cache-${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + node-cache-${{ runner.os }}-pnpm- + + - name: Install dependencies + run: pnpm --version && pnpm install --frozen-lockfile + + - name: Build Storybook + run: pnpm --filter=app run build-storybook diff --git a/.gitignore b/.gitignore index d6c45f29..c524296a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,91 +1,35 @@ -npm-debug.log -.next -out -previous-size-snapshot.json -current-size-snapshot.json -size-snapshot.json -analyze.next -.deployment-url -.basebranch -package-lock.json -spmdb/ -spmlogs/ -newrelic.js - +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# dependencies node_modules -.tmp -.idea -.DS_Store -.version -dist -.history - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* +.pnp +.pnp.js -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -junit -test-results.xml - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul +# testing coverage -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript +# next.js +.next/ +out/ +build -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz +# misc +.DS_Store +*.pem -# Yarn Integrity file -.yarn-integrity +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* -# dotenv environment variables file .env -.env.dev -apps/www/.env.staging -apps/www/.env.production +.env.local +.env.development.local +.env.test.local +.env.production.local -*.tsbuildinfo - -# cypress +# turbo +.turbo -apps/www/cypress/screenshots -apps/www/cypress/videos +*.tsbuildinfo diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..a5a29d9f --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +pnpm lint-staged diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 00000000..c8932c05 --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,4 @@ +module.exports = { + "*.{js,jsx,ts,tsx,md,mdx,graphql,yml,yaml,css,scss,json}": ["pnpm prettier --write"], + "*.{js,jsx,ts,tsx}": [() => "pnpm lint:fix"], +}; diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..daefc04d --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +auto-install-peers=true +strict-peer-dependencies=false +save-exact=true diff --git a/.nvmrc b/.nvmrc index 48082f72..3c032078 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12 +18 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..3ae76f13 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +apps/app/.next +pnpm-lock.yaml diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index cbd1fe37..00000000 --- a/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "semi": true, - "singleQuote": true, - "trailingComma": "es5", - "printWidth": 100 -} diff --git a/.vscode/settings.json b/.vscode/settings.json index 65266697..1b6500b0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,44 +1,14 @@ { - "editor.formatOnSave": true, - "editor.formatOnType": true, - "prettier.disableLanguages": ["json", "scss", "markdown"], - "[json]": { - "editor.formatOnSave": false, - "editor.formatOnType": false - }, - "[markdown]": { - "editor.formatOnSave": false, - "editor.formatOnType": false - }, - "[scss]": { - "editor.formatOnSave": false, - "editor.formatOnType": false - }, - "search.exclude": { - "**/node_modules": true, - "**/bower_components": true, - ".next": true, - "**/dist": true - }, - "typescript.tsdk": "node_modules/typescript/lib", - "typescript.preferences.importModuleSpecifier": "relative", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - }, - "workbench.colorCustomizations": { - "titleBar.activeBackground": "#673ab7", - "titleBar.inactiveBackground": "#401886", - "titleBar.activeForeground": "#ffffff", - "titleBar.inactiveForeground": "#ffffff" - }, - "tslint.autoFixOnSave": true, - "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/dist": true - }, - "prettier.configPath": "./.prettierrc" + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "workbench.colorCustomizations": { + "titleBar.activeBackground": "#673ab7", + "titleBar.inactiveBackground": "#401886", + "titleBar.activeForeground": "#ffffff", + "titleBar.inactiveForeground": "#ffffff" + } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 85c6dd10..e977a31b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,18 +6,19 @@ ## Introduction -DevFAQ is organised into a monorepo with lerna and yarn workspaces. You'll find frontend ([www](./apps/www)) and backend ([api](./apps/api)) in the [apps](./apps) directory. +DevFAQ is organised into a monorepo with Turborepo. You'll find frontend ([app](./apps/app)) and backend ([api](./apps/api)) in the [apps](./apps) directory. - Frontend is written in **Next.js (React) with TypeScript**. -- Backend is a REST API, and uses **HapiJS, PostgreSQL, and TypeScript**. +- Backend is a REST API, and uses **Fastify, PostgreSQL, and TypeScript**. ## Project setup -0. Make sure you have Docker installed and `docker-compose` command is available. +0. Make sure you have Docker installed and `docker compose` command is available. 1. Fork and clone the repo. `develop` is the default branch and you should base your work off of it. -2. Run `yarn` inside the repo to install all the dependencies. -3. Run `yarn dev` to start both frontend and backend locally. +2. Run `pnpm install` inside the repo to install all the dependencies. +3. Run `pnpm dev` to start both frontend and backend locally. 4. In order for everything to work smoothly, you'll need to add two entries to your `/etc/hosts`. See [Configuring localhost domain](#configuring-localhost-domain) section. +5. Remember to add `.env*` files to each app located in `apps` directory. For `apps/api` it will be `.env` - example file with variables is named `.env-example` and you can find it in `apps/api`. For `apps/app`, example env file is named `.env.local-example` and it is located in `apps/app`. ### Configuring localhost domain @@ -35,14 +36,14 @@ Now you should be able to access your app at [app.devfaq.localhost:3000](http:// There are only a few tests and we definitely need more! To run all tests execute the following command: ``` -yarn test +pnpm test ``` If you need to run only www or only api tests, you can do it as follows: ``` -yarn workspace www test -yarn workspace api test +pnpm test --filter=www +pnpm test --filter=api ``` ## Creating a PR diff --git a/README.md b/README.md index 0ddec95c..828d9f21 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # DevFAQ -[![All Contributors](https://img.shields.io/badge/Contributors-11-673ab7.svg)](#contributors-) + +[![All Contributors](https://img.shields.io/badge/Contributors-14-673ab7.svg)](#contributors-) + [![Sponsor Type of Web](https://badgen.net/badge/icon/Sponsor%20%E2%9D%A4?icon=github&label&color=ea4aaa)](https://github.com/sponsors/typeofweb) ![Test and Build](https://github.com/typeofweb/devfaq/workflows/Test%20and%20Build/badge.svg) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=typeofweb_devfaq&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=typeofweb_devfaq) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftypeofweb%2Fdevfaq.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftypeofweb%2Fdevfaq?ref=badge_shield) [![Discord](https://img.shields.io/discord/440163731704643589?color=738ADB&label=Discord&logo=discord&logoColor=white)](https://discord.typeofweb.com/) @@ -14,7 +16,6 @@ See [opencollective.com/typeofweb](https://opencollective.com/typeofweb) or [git - ## Contributors ✨ **See [CONTRIBUTING](./CONTRIBUTING.md).** @@ -25,21 +26,32 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Michał Miszczyszyn 💻 🚧 📦 🤔 |
- Tomasz Nastały 💻 🤔 |
- Bartosz Cytrowski 🖋 |
- Pawel Pawlowski 🎨 |
- Survikrowa 💻 |
- mczeplowski 💻 |
- Bartosz Dryl 💻 |
-
Kuba Domański 👀 |
- Jakub Kisielewski 👀 |
- KonradNojman 👀 |
- Patryk Górka 📖 |
- |||
Michał Miszczyszyn 💻 🚧 📦 🤔 |
+ Tomasz Nastały 💻 🤔 |
+ Bartosz Cytrowski 🖋 |
+ ||||
Pawel Pawlowski 🎨 |
+ Survikrowa 💻 |
+ mczeplowski 💻 |
+ ||||
Bartosz Dryl 💻 |
+ Kuba Domański 👀 |
+ Jakub Kisielewski 👀 |
+ ||||
KonradNojman 👀 |
+ Patryk Górka 📖 |
+ Adrian Polak 💻 |
+ ||||
xStrixU 💻 |
+ Grzegorz Pokorski 📖 🐛 💻 |
+
+ DevFAQ.pl jest serwisem internetowym służącym do udostępniania i wymiany pytań + rekrutacyjnych na stanowiska developerów oraz inne pokrewne. Został stworzony przez + programistów dla programistów, a jego celem jest wymiana wiedzy oraz możliwość przygotowania + się do rozmów rekrutacyjnych. +
+ ++ Każdy użytkownik DevFAQ może dodać treść pytania, przydzielić mu kategorię oraz poziom + trudności. Następnie po kliknięciu „Dodaj” pytanie trafia do moderacji. Po zaakceptowaniu + przez administratorów, pojawi się na stronie. Może to zająć kilka dni! +
+ +Tak! Możesz skorzystać z powszechnie znanego Markdown:
+Przykładowe pytanie napisane w Markdown może wyglądać tak:
+ ++ Czy funkcja `sayHello` zwraca **string**?{"\n"} + ```javascript + {` +function sayHello() { + return 'Hello World'; +} +`} + ``` ++ +
+ Więcej informacji na temat Markdown oraz kompletną dokumentację znajdziesz na stronie{" "} + + CommonMark + + . +
+
+ Jeszcze momencik… a Twoje pytanie pojawi się na liście dostępnych pytań. Najpierw musimy
+ rzucić na nie okiem i zatwierdzić.
+
W międzyczasie zajrzyj na bloga ❤️
+
+ {status === "accepted" + ? "Nie znaleziono żadnego pytania" + : "Brak pytań do zaakceptowania"} +
+ )} + > + ); +}; diff --git a/apps/app/src/components/AdminPanel/AdminPanelHeader.tsx b/apps/app/src/components/AdminPanel/AdminPanelHeader.tsx new file mode 100644 index 00000000..b920b15e --- /dev/null +++ b/apps/app/src/components/AdminPanel/AdminPanelHeader.tsx @@ -0,0 +1,81 @@ +import { useRouter } from "next/navigation"; +import { ChangeEvent, ReactNode } from "react"; +import { useDevFAQRouter } from "../../hooks/useDevFAQRouter"; +import { levels } from "../../lib/level"; +import { QuestionStatus, statuses } from "../../lib/question"; +import { technologies, technologiesLabels, Technology } from "../../lib/technologies"; +import { Level } from "../QuestionItem/QuestionLevel"; +import { Select } from "../Select/Select"; + +type AdminPanelHeaderProps = Readonly<{ + status: QuestionStatus; + technology: Technology | null; + levels: Level[] | null; +}>; + +const SelectLabel = ({ children }: { readonly children: ReactNode }) => ( + +); + +export const AdminPanelHeader = ({ + status, + technology, + levels: selectedLevels, +}: AdminPanelHeaderProps) => { + const { mergeQueryParams } = useDevFAQRouter(); + const router = useRouter(); + + const handleSelectChange = (param: string) => (event: ChangeEvent+ Zasługi: + {translatedContributions.join(", ")} +
++ ⚠️ Wystąpił nieoczekiwany błąd. Spróbuj ponownie, a jeśli problem będzie się powtarzał,{" "} + + skontaktuj się z administracją. + +
+); diff --git a/apps/app/src/components/Footer.tsx b/apps/app/src/components/Footer.tsx new file mode 100644 index 00000000..7d1cc528 --- /dev/null +++ b/apps/app/src/components/Footer.tsx @@ -0,0 +1,48 @@ +import Link from "next/link"; +import { Container } from "./Container"; + +export const Footer = () => ( + +); diff --git a/apps/app/src/components/GitHubAvatar.tsx b/apps/app/src/components/GitHubAvatar.tsx new file mode 100644 index 00000000..1f1a15de --- /dev/null +++ b/apps/app/src/components/GitHubAvatar.tsx @@ -0,0 +1,24 @@ +import Image from "next/image"; +import { ComponentProps } from "react"; +import { User } from "../types"; + +type GitHubAvatarProps = Readonly<{ + user: Pick+ Stwórz konto już dzisiaj i korzystaj z dodatkowych funkcji serwisu DevFAQ! +
++ Jeżeli podczas udzielania odpowiedzi korzystałeś z dodatkowych źródeł, lub chcesz + podlinkować dodatkowe materiały do komentarza, dodaj je do swojej odpowiedzi: +
++ Chcesz dodać odpowiedź? Najpierw musisz się zalogować! +
+ + + ++ Nikt nie udzielił jeszcze odpowiedzi na to pytanie! +
+ )} +Nie ma żadnych pytań do zaakceptowania!
-{auth.error.message}
} -Stwórz konto już dzisiaj i korzystaj z dodatkowych funkcji serwisu DevFAQ!
- - -
- Jeszcze momencik… a Twoje pytanie pojawi się na liście dostępnych pytań. Najpierw musimy
- rzucić na nie okiem i zatwierdzić.
-
W międzyczasie zajrzyj na bloga ❤️
-
Usunąłeś pytanie ze swojej listy!
- - {questionRemovalTimer && } -Najpierw zaznacz jakieś pytania, a następnie wróć tutaj aby zobaczyć podgląd!
-