From dc28b4e587a126959fd539b7c487a4938145fdef Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Mon, 30 Dec 2024 21:44:40 +0000 Subject: [PATCH] Revert "Bump react-router-dom from 6.28.1 to 7.1.0 (#323)" (#328) * Revert "Bump react-router-dom from 6.28.1 to 7.1.0 (#323)" This reverts commit 2d9bb1e32f744f4b105d294038cbdc76921f7b8d. * Update sonarcloud.yml * . * chore - add pre-commit hooks for branch name validation * chore - update package-lock.json to revert react-router-dom changes * feat - modify routing configuration for new features * chore - add @babel/plugin-proposal-private-property-in-object dependency * refactor - update GitHub workflow for sonar-cloud configuration * test - add unit tests for AuthorItem component * refactor - removed unused import from test file --- .githooks/pre-commit | 16 +++ .githooks/prepare-commit-msg | 39 ++++++ .../{sonarcloud.yml => sonar-cloud.yml} | 29 ++-- package-lock.json | 103 +++++++------- package.json | 3 +- src/App.js | 26 ++-- src/Components/Authors/AuthorItem.test.js | 130 ++++++++++++++++++ 7 files changed, 267 insertions(+), 79 deletions(-) create mode 100644 .githooks/pre-commit create mode 100644 .githooks/prepare-commit-msg rename .github/workflows/{sonarcloud.yml => sonar-cloud.yml} (65%) create mode 100644 src/Components/Authors/AuthorItem.test.js diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 0000000..91cbd3c --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +LC_ALL=C + +local_branch="$(git rev-parse --abbrev-ref HEAD)" + +valid_branch_regex="^(penify|gitauto|dependabot|feature|fix|docs|style|refactor|perf|hotfix|test|chore|create)(\/[a-zA-Z0-9#._-]+)+$" + +message="There is something wrong with your branch name. Branch names in this project must adhere to this contract: $valid_branch_regex. Your commit will be rejected. You should rename your branch to a valid name and try again." + +if [[ ! $local_branch =~ $valid_branch_regex ]] +then + echo "$message" + exit 1 +fi + +#npm run lint \ No newline at end of file diff --git a/.githooks/prepare-commit-msg b/.githooks/prepare-commit-msg new file mode 100644 index 0000000..fc9f2e7 --- /dev/null +++ b/.githooks/prepare-commit-msg @@ -0,0 +1,39 @@ +#!/bin/sh + +# This script generates an AI-powered commit message using dotnet-aicommitmessage. +# It can be bypassed by setting the GIT_AICOMMIT_SKIP environment variable. + +# Exit immediately if GIT_AICOMMIT_SKIP is set +if [ -n "$GIT_AICOMMIT_SKIP" ]; then + exit 0 +fi + +if ! command -v dotnet-aicommitmessage &> /dev/null; then + echo "Error: dotnet-aicommitmessage is not installed or not in PATH" >&2 + echo "Please install it by running 'dotnet tool install -g aicommitmessage'" >&2 + exit 1 +fi + +COMMIT_MSG_FILE=$1 +CURRENT_MESSAGE=$(cat "$COMMIT_MSG_FILE") + +# From version 0.6.1, this is not needed anymore. +# GIT_DIFF=$(git diff --staged) +# GIT_BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD) + +# Run dotnet-aicommitmessage with error handling +# From version 0.6.1 branch and diff are now retrieved by the tool and don't need to be passed manually. +# Version 0.6.1 and higher: dotnet-aicommitmessage generate-message -m "$CURRENT_MESSAGE" +# Version 0.6.0 and lower: dotnet-aicommitmessage generate-message -m "$CURRENT_MESSAGE" -b "$GIT_BRANCH_NAME" -d "$GIT_DIFF" + +if ! AI_MESSAGE=$(dotnet-aicommitmessage generate-message -m "$CURRENT_MESSAGE"); then + echo "Error: Failed to generate AI commit message. Using original message." >&2 + exit 0 +fi + +if [[ -z "$AI_MESSAGE" || "$AI_MESSAGE" =~ ^[[:space:]]*$ ]]; then + echo "Error: Generated commit message is empty." >&2 + exit 1 +fi +echo "$AI_MESSAGE" > "$COMMIT_MSG_FILE" +exit 0 diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonar-cloud.yml similarity index 65% rename from .github/workflows/sonarcloud.yml rename to .github/workflows/sonar-cloud.yml index c2e4244..d0599b5 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonar-cloud.yml @@ -5,8 +5,6 @@ on: - main pull_request: types: [opened, synchronize, reopened] - pull_request_target: - types: [opened, synchronize, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -17,26 +15,31 @@ jobs: name: SonarCloud runs-on: ubuntu-latest steps: - - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Node.js 22 + uses: actions/setup-node@v4 with: - fetch-depth: 0 - + node-version: 22.x + - name: Install dependencies - run: npm install + run: npm ci + + - name: Build + run: npm run build - - name: Test and coverage - run: npm run test -- --coverage --watchAll=false - + - name: Test + run: npm test -- --coverage --watchAll=false + - name: SonarCloud Scan uses: SonarSource/sonarcloud-github-action@master if: >- ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository - ) || ( - github.event_name == 'pull_request_target' && - github.event.pull_request.head.repo.full_name != github.repository ) || ( github.event_name == 'workflow_dispatch' ) diff --git a/package-lock.json b/package-lock.json index 162651c..00fdf68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "react": "^19.0.0", "react-cookie-consent": "^9.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^6.28.1", "react-scripts": "^5.0.1", "react-select": "^5.9.0", "react-string-replace": "^1.1.1", @@ -24,7 +25,7 @@ "web-vitals": "^4.2.4" }, "devDependencies": { - "react-router-dom": "^7.1.0" + "@babel/plugin-proposal-private-property-in-object": "^7.21.11" } }, "node_modules/@adobe/css-tools": { @@ -725,9 +726,18 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { "node": ">=6.9.0" }, @@ -1970,6 +1980,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2967,6 +2989,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", + "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3450,12 +3480,6 @@ "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true - }, "node_modules/@types/eslint": { "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", @@ -12651,52 +12675,33 @@ } }, "node_modules/react-router": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.0.tgz", - "integrity": "sha512-VcFhWqkNIcojDRYaUO8qV0Jib52s9ULpCp3nkBbmrvtoCVFRp6tmk3tJ2w9BZauVctA1YRnJlFYDn9iJRuCpGA==", - "dev": true, + "version": "6.28.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.1.tgz", + "integrity": "sha512-2omQTA3rkMljmrvvo6WtewGdVh45SpL9hGiCI9uUrwGGfNFDIvGK4gYJsKlJoNVi6AQZcopSCballL+QGOm7fA==", "dependencies": { - "@types/cookie": "^0.6.0", - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0", - "turbo-stream": "2.4.0" + "@remix-run/router": "1.21.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.0.tgz", - "integrity": "sha512-F4/nYBC9e4s0/ZjxM8GkZ9a68DpX76LN1a9W9mfPl2GfbDJ9/vzJro6MThNR5qGBH6KkgcK1BziyEzXhHV46Xw==", - "dev": true, + "version": "6.28.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.1.tgz", + "integrity": "sha512-YraE27C/RdjcZwl5UCqF/ffXnZDxpJdk9Q6jw38SZHjXs7NNdpViq2l2c7fO7+4uWaEfcwfGCv3RSg4e1By/fQ==", "dependencies": { - "react-router": "7.1.0" + "@remix-run/router": "1.21.0", + "react-router": "6.28.1" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, - "node_modules/react-router/node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "dev": true, - "engines": { - "node": ">=18" + "react": ">=16.8", + "react-dom": ">=16.8" } }, "node_modules/react-scripts": { @@ -14510,12 +14515,6 @@ "node": ">= 0.8" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "dev": true - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -15695,12 +15694,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/turbo-stream": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", - "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index e82692e..dfafcc7 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "react": "^19.0.0", "react-cookie-consent": "^9.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^6.28.1", "react-scripts": "^5.0.1", "react-select": "^5.9.0", "react-string-replace": "^1.1.1", @@ -44,6 +45,6 @@ ] }, "devDependencies": { - "react-router-dom": "^7.1.0" + "@babel/plugin-proposal-private-property-in-object": "^7.21.11" } } diff --git a/src/App.js b/src/App.js index f655e04..6034485 100644 --- a/src/App.js +++ b/src/App.js @@ -10,16 +10,22 @@ import ErrorBoundary from "./Helpers/ErrorBoundary"; function App() { return ( - - - }> - } /> - } /> - } /> - } /> - - - + + + }> + } /> + } /> + } /> + } /> + + + ); } diff --git a/src/Components/Authors/AuthorItem.test.js b/src/Components/Authors/AuthorItem.test.js new file mode 100644 index 0000000..0fce303 --- /dev/null +++ b/src/Components/Authors/AuthorItem.test.js @@ -0,0 +1,130 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import { BrowserRouter as Router } from "react-router-dom"; +import AuthorItem from "./AuthorItem"; +import FormatDate from "../../Helpers/FormatDate"; + +jest.mock("../../Helpers/FormatDate"); + +const mockAuthor = { + login: "testuser", + name: "Test User", + avatar_url: "https://avatars.githubusercontent.com/u/1?v=4", + lastIssue_at: "2023-10-01T00:00:00Z", + issues: 5, + followers: 10, + bio: "This is a test bio", + repositories: [ + { id: 1, name: "repo1", organization: { login: "tes-repo1" } }, + { id: 2, name: "repo2", organization: { login: "test-repo2" } }, + ], +}; + +describe("AuthorItem Component", () => { + beforeEach(() => { + FormatDate.mockReturnValue("October 1, 2023"); + }); + + it("renders without crashing", () => { + render( + + + + ); + }); + + it("displays the author's name", () => { + const { getByText } = render( + + + + ); + expect(getByText("Test User")).toBeInTheDocument(); + }); + + it("displays the author's avatar", () => { + const { getByAltText } = render( + + + + ); + const avatar = getByAltText("testuser"); + expect(avatar).toHaveAttribute( + "src", + "https://avatars.githubusercontent.com/u/1?v=4&size=48" + ); + }); + + it("displays the correct number of issues and followers", () => { + const { getByText } = render( + + + + ); + expect(getByText("5 vagas publicadas")).toBeInTheDocument(); + expect(getByText("10 seguidores")).toBeInTheDocument(); + }); + + it("displays the formatted last issue date", () => { + const { getByText } = render( + + + + ); + expect(getByText("Ăšltima vaga em: October 1, 2023")).toBeInTheDocument(); + }); + + it("displays the author's bio", () => { + const { getByText } = render( + + + + ); + expect(getByText("This is a test bio")).toBeInTheDocument(); + }); + + it("displays the GitHub profile link", () => { + const { getByText } = render( + + + + ); + const profileLink = getByText("Ver perfil no GitHub"); + expect(profileLink).toHaveAttribute("href", "https://github.com/testuser"); + }); +});