diff --git a/Jenkinsfile b/.github/deprecated/Jenkinsfile-archived-24-07-2026 similarity index 100% rename from Jenkinsfile rename to .github/deprecated/Jenkinsfile-archived-24-07-2026 diff --git a/.github/workflows/ci.yml b/.github/deprecated/ci-archived-24-07-2026.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/deprecated/ci-archived-24-07-2026.yml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f19f09cab..990f0dc4d 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -6,9 +6,10 @@ on: - main - dev - MikhailDeriabin/feature/670-migrate-ci-gh-actions -# pull_request: -# branches: -# - '**' + - MikhailDeriabin/feature/670-migrate-ci-gh-actions-new + pull_request: + branches: + - '**' defaults: run: @@ -17,7 +18,8 @@ defaults: jobs: test: name: Run tests - runs-on: [ self-hosted, gh-runner-common ] +# runs-on: [self-hosted, gh-runner-common] + runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v7 @@ -62,96 +64,97 @@ jobs: files: ./frontend-next-migration/coverage/coverage-final.json fail_ci_if_error: true -# build-and-push: -# name: Build and Push Docker Image -## needs: test -# if: github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'MikhailDeriabin/feature/670-migrate-ci-gh-actions' -# runs-on: [self-hosted, gh-runner-common] -# steps: -# - name: Checkout code -# uses: actions/checkout@v7 -# -# - name: Log in to Docker Hub -# uses: docker/login-action@v4 -# with: -# username: ${{ secrets.DOCKERHUB_USERNAME }} -# password: ${{ secrets.DOCKERHUB_TOKEN }} -# -# - name: Write build env file -# env: -# ENV_LOCAL_BUILD: ${{ secrets.SITE_ENV_LOCAL_BUILD }} -# run: printf '%s' "$ENV_LOCAL_BUILD" > .env.local -# -# - name: Build and push image -# uses: docker/build-push-action@v7 -# env: -# DOCKER_BUILD_RECORD_UPLOAD: false -# with: -# context: frontend-next-migration -# push: true -# load: true -# tags: | -# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-27 -# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-latest -## ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} -## ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-latest -# -# - name: Clean up build env file -# if: always() -# run: rm -f .env.local -# -# - name: Scan image for vulnerabilities -# uses: aquasecurity/trivy-action@v0.36.0 -# with: -# image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-27 -## image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} -# format: json -# ignore-unfixed: true -# exit-code: '0' -# output: frontend-next-migration/trivy-results.json -# -# - name: Upload vulnerabilities to summary tab -# if: always() -# run: | -# { -# echo "## Vulnerability scan results" -# echo "" -# echo "| Target | Package | CVE | Severity | Installed | Fixed |" -# echo "|---|---|---|---|---|---|" -# jq -r ' -# .Results[]? -# | select(.Vulnerabilities != null) -# | .Target as $t -# | .Vulnerabilities[] -# | "| \($t) | \(.PkgName) | \(.VulnerabilityID) | \(.Severity) | \(.InstalledVersion) | \(.FixedVersion // "-") |" -# ' trivy-results.json -# } >> "$GITHUB_STEP_SUMMARY" -# -# - name: Convert scan results to SARIF format -# if: always() -# run: trivy convert --format sarif --output trivy-results.sarif trivy-results.json -# -# - name: Upload vulnerabilities to Security tab -# uses: github/codeql-action/upload-sarif@v4 -# with: -# sarif_file: frontend-next-migration/trivy-results.sarif - -# notify: -# name: Notify server about new image build -# needs: build-and-push -# if: github.ref_name == 'main' || github.ref_name == 'dev' -# runs-on: [self-hosted, gh-runner-common] -# steps: -# - name: Notify server -# env: -# WEBHOOK_SECRET: ${{ secrets.SERVER_WEBHOOK_NOTIFY_SECRET }} -# WEBHOOK_URL: ${{ secrets.SERVER_WEBHOOK_NOTIFY_URL }} + build-and-push: + name: Build and Push Docker Image + needs: test + if: github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'MikhailDeriabin/feature/670-migrate-ci-gh-actions' + runs-on: [self-hosted, gh-runner-common] + steps: + - name: Checkout code + uses: actions/checkout@v7 + + - name: Log in to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Write build env file + env: + ENV_LOCAL_BUILD: ${{ secrets.SITE_ENV_LOCAL_BUILD }} + run: printf '%s' "$ENV_LOCAL_BUILD" > .env.local + + - name: Build and push image + uses: docker/build-push-action@v7 + env: + DOCKER_BUILD_RECORD_UPLOAD: false + with: + context: frontend-next-migration + push: true + load: true + tags: | + ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-${{ github.run_number }} + ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-latest +# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} +# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-latest + + - name: Clean up build env file + if: always() + run: rm -f .env.local + + - name: Scan image for vulnerabilities + uses: aquasecurity/trivy-action@v0.36.0 + with: + image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-${{ github.run_number }} +# image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} + format: json + ignore-unfixed: true + exit-code: '0' + output: frontend-next-migration/trivy-results.json + + - name: Upload vulnerabilities to summary tab + if: always() + run: | + { + echo "## Vulnerability scan results" + echo "" + echo "| Target | Package | CVE | Severity | Installed | Fixed |" + echo "|---|---|---|---|---|---|" + jq -r ' + .Results[]? + | select(.Vulnerabilities != null) + | .Target as $t + | .Vulnerabilities[] + | "| \($t) | \(.PkgName) | \(.VulnerabilityID) | \(.Severity) | \(.InstalledVersion) | \(.FixedVersion // "-") |" + ' trivy-results.json + } >> "$GITHUB_STEP_SUMMARY" + + - name: Convert scan results to SARIF format + if: always() + run: trivy convert --format sarif --output trivy-results.sarif trivy-results.json + + - name: Upload vulnerabilities to Security tab + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: frontend-next-migration/trivy-results.sarif + + notify: + name: Notify server about new image build + needs: build-and-push + if: github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'MikhailDeriabin/feature/670-migrate-ci-gh-actions' + runs-on: [self-hosted, gh-runner-common] + steps: + - name: Notify server + env: + WEBHOOK_SECRET: ${{ secrets.SERVER_WEBHOOK_NOTIFY_SECRET }} + WEBHOOK_URL: ${{ secrets.SERVER_WEBHOOK_NOTIFY_URL }} + PAYLOAD: '{"name": "site", "tag": "dev"}' # PAYLOAD: '{"name": "site", "tag": "${{ github.ref_name }}"}' -# run: | -# SIGNATURE=$(echo "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | sed 's/^.* //') -# -# curl -s -o /dev/null -X POST "$WEBHOOK_URL" \ -# -H "Content-Type: application/json" \ -# -H "X-Hub-Signature: sha256=$SIGNATURE" \ -# -d "$PAYLOAD" \ -# --insecure \ No newline at end of file + run: | + SIGNATURE=$(echo "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | sed 's/^.* //') + + curl -s -o /dev/null -X POST "$WEBHOOK_URL" \ + -H "Content-Type: application/json" \ + -H "X-Hub-Signature: sha256=$SIGNATURE" \ + -d "$PAYLOAD" \ + --insecure \ No newline at end of file diff --git a/README.md b/README.md index ca2806556..1530477d2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![codecov](https://yrfbcpxonsco.mikhail.com.de/github/Alt-Org/Altzone-WebPages/graph/badge.svg?token=HYZVADVM8S)](https://yrfbcpxonsco.mikhail.com.de/github/Alt-Org/Altzone-WebPages) + # Altzone-WebPages Welcome to the **Altzone-WebPages** repository! 🎉 diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..9f3ea4b6e --- /dev/null +++ b/codecov.yml @@ -0,0 +1,11 @@ +coverage: + status: + project: + default: + target: 1 + patch: + default: + target: 1 + +codecov: + branch: dev \ No newline at end of file diff --git a/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx b/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx index 8ec96f7cc..56f42d4a7 100644 --- a/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx +++ b/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx @@ -23,7 +23,7 @@ export const NewClanForm = ({ onSuccess, className = '' }: Props) => { className={classNames(cls.Form, {}, [className])} onSubmit={handleSubmit(onFormSubmit)} > - Luo Klaani. Changed + Luo Klaani ({ - useForm: jest.fn(), -})); - -jest.mock('react-redux', () => ({ - useDispatch: jest.fn(), - useSelector: jest.fn(), -})); - -jest.mock('@hookform/resolvers/yup', () => ({ - yupResolver: jest.fn(), -})); - -jest.mock('@/entities/Clan', () => ({ - useCreateClanMutation: jest.fn(), -})); - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); - -describe('onFormSubmit', () => { - const mockCreate = jest.fn(); - const mockOnSuccess = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - (useForm as jest.Mock).mockReturnValue({ - register: jest.fn(), - handleSubmit: jest.fn(), - formState: { errors: {} }, - setValue: jest.fn(), - }); - (useCreateClanMutation as jest.Mock).mockReturnValue([ - mockCreate, - { data: null, isLoading: false, error: null }, - ]); - }); - - it('should check that onSubmitForm correctly convert data for api', async () => { - const { result } = renderHook(() => useNewClanForm({ onSuccess: mockOnSuccess })); - - const mockValues = { - isOpen: true, - name: 'mandoliini', - tag: 'mandoliini', - phrase: 'phrase', - labels: [ - { - label: 'test1', - value: 'TEST1', - }, - { - label: 'test2', - value: 'TEST2', - }, - ], - }; - - const newMockValues = { - isOpen: true, - name: 'mandoliini', - tag: 'mandoliini', - phrase: 'phrase', - labels: ['test1', 'test2'], - }; - - await act(async () => { - await result.current.onFormSubmit(mockValues); - }); - - expect(mockCreate).toHaveBeenCalledWith(newMockValues); - }); -}); diff --git a/frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts b/frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts deleted file mode 100644 index 486977274..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts +++ /dev/null @@ -1,88 +0,0 @@ -'use client'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { useEffect } from 'react'; -import { FieldValues, useForm } from 'react-hook-form'; -import { useDispatch, useSelector } from 'react-redux'; -import { toast } from 'react-toastify'; -import { IClanCreateDto, useCreateClanMutation } from '@/entities/Clan'; -import { profileActions, selectProfile } from '@/entities/Profile/model/profileSlice/profileSlice'; -import { ValidationAddNewClan } from '../validations'; -import { ProfileSchema } from '@/entities/Profile/types/profile'; - -type Props = { - onSuccess?: () => void; -}; - -export const useNewClanForm = ({ onSuccess }: Props) => { - const { - register, - handleSubmit, - formState: { errors }, - setValue, - } = useForm({ - resolver: yupResolver(ValidationAddNewClan), - }); - - const [ - create, - { - data, - isLoading, - // isError, - error, - }, - ] = useCreateClanMutation(); - - const profile = useSelector((state: ProfileSchema) => selectProfile(state)); - const dispatch = useDispatch(); - - //update store profile after creating new clan - const handleUpdateClanId = (newClanId: string) => { - if (profile) { - const updatedProfile = { - ...profile, - Player: { - ...profile.Player, - clan_id: newClanId, - }, - }; - dispatch(profileActions.setProfile(updatedProfile)); - } else { - console.error('No Profile found in store'); - } - }; - - async function onFormSubmit(fieldValues: FieldValues) { - //converting label to array of lowercase strings - const newFieldValues = { - ...fieldValues, - labels: fieldValues.labels.map((item: any) => item.value.toLowerCase()), - }; - - await create(newFieldValues as IClanCreateDto); - } - - useEffect(() => { - if (data) { - const clanId = data.data.Clan?._id; - handleUpdateClanId(clanId); - toast.success('Klaani oli luotu!'); - onSuccess?.(); - return; - } - - if (error) { - // @ts-ignore todo it works but ts for some reason doesnt recognise the type, figure our why fix - toast.error(error?.data?.message); - return; - } - }, [isLoading, data, error, onSuccess]); - - return { - register, - handleSubmit, - onFormSubmit, - errors, - setValue, - }; -}; diff --git a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss b/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss deleted file mode 100644 index b8f96b9ae..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.Form { - //width: 40%; - //background-color: var(--inverted-bg-color); -} diff --git a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx b/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx deleted file mode 100644 index abf66b960..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { StoryObj, Meta } from '@storybook/nextjs'; -import { NewClanForm } from './NewClanForm'; - -export default { - title: 'features/NewClanForm', - component: NewClanForm, - args: { - className: '', - }, -} as Meta; - -export const Default: StoryObj = {}; diff --git a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx b/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx deleted file mode 100644 index 8ec96f7cc..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx +++ /dev/null @@ -1,90 +0,0 @@ -'use client'; -import { CustomForm } from '@/shared/ui/CustomForm'; -import { classNames } from '@/shared/lib/classNames/classNames'; -import { useNewClanForm } from '../../model/useNewClanForm'; -import cls from './NewClanForm.module.scss'; -import { ClanLabel } from '@/entities/Clan/enum/clanLabel.enum'; -import { useState } from 'react'; - -type Props = { - onSuccess?: () => void; - className?: string; -}; - -export const NewClanForm = ({ onSuccess, className = '' }: Props) => { - const { register, handleSubmit, onFormSubmit, errors, setValue } = useNewClanForm({ - onSuccess, - }); - - const [selected, setSelected] = useState<{ label: any; value: string }[]>([]); - - return ( - - Luo Klaani. Changed - - - - - - - - { - setSelected(newSelection); - setValue('labels', newSelection); - }} - /> - - { - - } - - Vahvista - - ); -}; diff --git a/frontend-next-migration/src/features/AddNewClan1/validations/index.ts b/frontend-next-migration/src/features/AddNewClan1/validations/index.ts deleted file mode 100644 index ba2cd1d33..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/validations/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as yup from 'yup'; - -//todo add i18n -export const ValidationAddNewClan = yup.object().shape({ - name: yup - .string() - .required('Vaadittu') - .min(3, 'Klaanin nimen on oltava vähintään 3 merkkiä pitkä') - .max(15, 'Klaanin nimen on oltava enintään 15 merkkiä pitkä') - .matches(/^[A-Za-z]+$/, 'Klaanin nimi saa sisältää vain kirjaimia'), - - tag: yup - .string() - .required('Tagi on vaadittu') - .min(3, 'Tagin on oltava vähintään 3 merkkiä pitkä') - .max(10, 'Tagin on oltava enintään 10 merkkiä pitkä') - .matches(/^[A-Za-z0-9_]+$/, 'Tagi voi sisältää vain kirjaimia, numeroita ja alaviivoja'), - - phrase: yup - .string() - .required() - .min(3, 'Moton on oltava vähintään 3 merkkiä pitkä') - .max(30, 'Moton on oltava enintään 30 merkkiä pitkä') - .matches(/^[A-Za-z0-9_]+$/, 'Motto voi sisältää vain kirjaimia, numeroita ja alaviivoja'), - - labels: yup - .array() - .of( - yup.object({ - label: yup.string(), - value: yup.string(), - }), - ) - .required() - .min(1, 'Valitse vähintään 1'), - - isOpen: yup.boolean(), -}); diff --git a/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx b/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx index effc885c7..e4c7cd182 100644 --- a/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx +++ b/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx @@ -67,7 +67,7 @@ const About = (props: Props) => { >