diff --git a/.github/FUNDING.yml b/.github/FUNDING.y similarity index 100% rename from .github/FUNDING.yml rename to .github/FUNDING.y diff --git a/.github/actionlint.yaml b/.github/actionlint.ya similarity index 100% rename from .github/actionlint.yaml rename to .github/actionlint.ya diff --git a/.github/labeler.yml b/.github/labeler.y similarity index 100% rename from .github/labeler.yml rename to .github/labeler.y diff --git a/.github/workflow/cron-translations.yml b/.github/workflow/cron-translations.yml new file mode 100644 index 0000000000000..e776a0d5dc713 --- /dev/null +++ b/.github/workflow/cron-translations.yml @@ -0,0 +1,38 @@ +# name: cron-translations + +# on: +# schedule: +# - cron: "7 0 * * *" # every day at 00:07 UTC +# workflow_dispatch: + +# jobs: +# crowdin-pull: +# runs-on: ubuntu-latest +# if: github.repository == 'go-gitea/gitea' +# steps: +# - uses: actions/checkout@v4 +# - uses: crowdin/github-action@v1 +# with: +# upload_sources: true +# upload_translations: false +# download_sources: false +# download_translations: true +# push_translations: false +# push_sources: false +# create_pull_request: false +# config: crowdin.yml +# env: +# CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} +# CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} +# - name: update locales +# run: ./build/update-locales.sh +# - name: push translations to repo +# uses: appleboy/git-push-action@v0.0.3 +# with: +# author_email: "teabot@gitea.io" +# author_name: GiteaBot +# branch: main +# commit: true +# commit_message: "[skip ci] Updated translations via Crowdin" +# remote: "git@github.com:go-gitea/gitea.git" +# ssh_key: ${{ secrets.DEPLOY_KEY }} diff --git a/.github/workflows/Pre-Production.yml b/.github/workflows/Pre-Production.yml new file mode 100644 index 0000000000000..32fb398a41663 --- /dev/null +++ b/.github/workflows/Pre-Production.yml @@ -0,0 +1,37 @@ +name: Pre-Production Performance Testing + +on: + push: + branches: + - main # Runs after PR is merged into main + +jobs: + preprod-perf-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Java (required by JMeter) + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '21' + + - name: Install JMeter + run: | + sudo apt update + sudo apt install -y jmeter + jmeter --version + + - name: Run JMeter Test + run: | + mkdir -p reports/jmeter + jmeter -n -t tests/perf_test.jmx -l reports/jmeter/results.jtl -e -o reports/jmeter/report + + - name: Upload JMeter HTML Report + uses: actions/upload-artifact@bcb6a651d2b8c4fdb17bcf0d2581a3ad16f58aa9 # Pin to known good SHA + with: + name: jmeter-report + path: reports/jmeter/report diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000000..deb5c945815ab --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,66 @@ +name: Gitea Build Environment Workflow + +on: + push: + branches: + - feature_branch + # Trigger on push to the dev branch just + +jobs: + build: + runs-on: ubuntu-latest + + steps: + # Step 1: Checkout the code from the repository + - name: Checkout repository + uses: actions/checkout@v2 + + # Step 2: Set up Go (Gitea is written in Go) yes yesy se + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: '1.24.0' # Use the Go version that Gitea supports + + # Step 3: Install dependencies + - name: Install dependencies + run: go mod tidy + + - name: Run unit tests + run: go test ./... -v + continue-on-error: true + + - name: Run linting + run: | + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + golangci-lint run + continue-on-error: true + + docker: + runs-on: ubuntu-latest + needs: build # This will wait until the 'build' job is finished + + steps: + # Step 1: Checkout the repository + - name: Checkout repository + uses: actions/checkout@v2 + + # Step 2: Set up Docker + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Step 3: Log in to Docker Hub + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} # Store your Docker username as a secret in GitHub + password: ${{ secrets.DOCKER_PASSWORD }} # Store your Docker password as a secret in GitHub + + # Step 4: Build the Docker image + - name: Build Docker image + run: | + docker build -t maias816/gitea:latest . + + # Step 5: Push the Docker image to Docker Hub + - name: Push Docker image + run: | + docker push maias816/gitea:latest diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml index 33cbc507d9677..c392a0e4982ef 100644 --- a/.github/workflows/cron-licenses.yml +++ b/.github/workflows/cron-licenses.yml @@ -1,8 +1,35 @@ +# name: cron-licenses + +# on: +# # schedule: +# # - cron: "7 0 * * 1" # every Monday at 00:07 UTC +# workflow_dispatch: + +# jobs: +# cron-licenses: +# runs-on: ubuntu-latest +# if: github.repository == 'go-gitea/gitea' +# steps: +# - uses: actions/checkout@v4 +# - uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# check-latest: true +# - run: make generate-license generate-gitignore +# timeout-minutes: 40 +# - name: push translations to repo +# uses: appleboy/git-push-action@v0.0.3 +# with: +# author_email: "teabot@gitea.io" +# author_name: GiteaBot +# branch: main +# commit: true +# commit_message: "[skip ci] Updated licenses and gitignores" +# remote: "git@github.com:go-gitea/gitea.git" +# ssh_key: ${{ secrets.DEPLOY_KEY }} name: cron-licenses on: - # schedule: - # - cron: "7 0 * * 1" # every Monday at 00:07 UTC workflow_dispatch: jobs: diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml deleted file mode 100644 index f1b51debf1223..0000000000000 --- a/.github/workflows/cron-translations.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: cron-translations - -on: - schedule: - - cron: "7 0 * * *" # every day at 00:07 UTC - workflow_dispatch: - -jobs: - crowdin-pull: - runs-on: ubuntu-latest - if: github.repository == 'go-gitea/gitea' - steps: - - uses: actions/checkout@v4 - - uses: crowdin/github-action@v1 - with: - upload_sources: true - upload_translations: false - download_sources: false - download_translations: true - push_translations: false - push_sources: false - create_pull_request: false - config: crowdin.yml - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} - - name: update locales - run: ./build/update-locales.sh - - name: push translations to repo - uses: appleboy/git-push-action@v0.0.3 - with: - author_email: "teabot@gitea.io" - author_name: GiteaBot - branch: main - commit: true - commit_message: "[skip ci] Updated translations via Crowdin" - remote: "git@github.com:go-gitea/gitea.git" - ssh_key: ${{ secrets.DEPLOY_KEY }} diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index 7c1fb024421bc..60bbb085bf38c 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -1,3 +1,101 @@ +# name: files-changed + +# on: +# workflow_call: +# outputs: +# backend: +# value: ${{ jobs.detect.outputs.backend }} +# frontend: +# value: ${{ jobs.detect.outputs.frontend }} +# docs: +# value: ${{ jobs.detect.outputs.docs }} +# actions: +# value: ${{ jobs.detect.outputs.actions }} +# templates: +# value: ${{ jobs.detect.outputs.templates }} +# docker: +# value: ${{ jobs.detect.outputs.docker }} +# swagger: +# value: ${{ jobs.detect.outputs.swagger }} +# yaml: +# value: ${{ jobs.detect.outputs.yaml }} + +# jobs: +# detect: +# runs-on: ubuntu-latest +# timeout-minutes: 3 +# outputs: +# backend: ${{ steps.changes.outputs.backend }} +# frontend: ${{ steps.changes.outputs.frontend }} +# docs: ${{ steps.changes.outputs.docs }} +# actions: ${{ steps.changes.outputs.actions }} +# templates: ${{ steps.changes.outputs.templates }} +# docker: ${{ steps.changes.outputs.docker }} +# swagger: ${{ steps.changes.outputs.swagger }} +# yaml: ${{ steps.changes.outputs.yaml }} +# steps: +# - uses: actions/checkout@v4 +# - uses: dorny/paths-filter@v3 +# id: changes +# with: +# filters: | +# backend: +# - "**/*.go" +# - "templates/**/*.tmpl" +# - "assets/emoji.json" +# - "go.mod" +# - "go.sum" +# - "Makefile" +# - ".golangci.yml" +# - ".editorconfig" +# - "options/locale/locale_en-US.ini" + +# frontend: +# - "**/*.js" +# - "web_src/**" +# - "assets/emoji.json" +# - "package.json" +# - "package-lock.json" +# - "Makefile" +# - ".eslintrc.yaml" +# - "stylelint.config.js" +# - ".npmrc" + +# docs: +# - "**/*.md" +# - ".markdownlint.yaml" +# - "package.json" +# - "package-lock.json" + +# actions: +# - ".github/workflows/*" +# - "Makefile" + +# templates: +# - "tools/lint-templates-*.js" +# - "templates/**/*.tmpl" +# - "pyproject.toml" +# - "poetry.lock" + +# docker: +# - "Dockerfile" +# - "Dockerfile.rootless" +# - "docker/**" +# - "Makefile" + +# swagger: +# - "templates/swagger/v1_json.tmpl" +# - "Makefile" +# - "package.json" +# - "package-lock.json" +# - ".spectral.yaml" + +# yaml: +# - "**/*.yml" +# - "**/*.yaml" +# - ".yamllint.yaml" +# - "pyproject.toml" +# - "poetry.lock" name: files-changed on: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000000000..2c7c10f78d3ca --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,56 @@ +name: Gitea Setup and Testing + +on: + pull_request: + + + workflow_dispatch: + +jobs: + setup-and-test: + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:13 + options: --health-cmd="pg_isready -U gitea_user" --health-timeout=30s --health-retries=3 + ports: + - 5432:5432 + env: + POSTGRES_DB: gitea + POSTGRES_USER: gitea_user + POSTGRES_PASSWORD: gitea_pass + + redis: + image: redis:alpine + ports: + - 6379:6379 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} # GitHub Secrets for Docker username + password: ${{ secrets.DOCKER_PASSWORD }} # GitHub Secrets for Docker password + + - name: Pull Test Docker Image for API tests + run: | + docker pull maias816/api_ui_tests:latest + # Pull the existing image from docker hub1 + - name: Run API and UI Tests + run: | + docker run --rm maias816/api_ui_tests:latest + + # - name: pull feature image # pull and feature image ok k + # run: | + # docker pull maias816/code-formatter:latest + # - name : run feature tests + # run: | + # docker run maias816/code-formatter:latest + + + + diff --git a/.golangci.yml b/.golangci.yml index c39d7ac5f2f5b..67560db4b902c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -37,9 +37,11 @@ output: linters-settings: testifylint: - disable: - - go-require - - require-error + disable: + - go-require + - require-error + + stylecheck: checks: ["all", "-ST1005", "-ST1003"] nakedret: diff --git a/MaiasREADME.md b/MaiasREADME.md new file mode 100644 index 0000000000000..4010e161ae96d --- /dev/null +++ b/MaiasREADME.md @@ -0,0 +1,102 @@ + +# 🐳 Run Gitea using Docker + +This guide explains how to run **Gitea**, a self-hosted Git service, using **Docker**. + +--- + +## βœ… 1. Install Docker + +Download and install Docker from the official website: +πŸ‘‰ [https://www.docker.com/products/docker-desktop](https://www.docker.com/products/docker-desktop) + +--- + +## βœ… 2. Create Required Folders + +Create directories for persistent Gitea data: + +### On Linux / macOS: +```bash +mkdir -p ~/gitea/{data,config} +``` + +### On Windows PowerShell: +```powershell +mkdir gitea\data +mkdir gitea\config +``` + +--- + +## βœ… 3. Run Gitea Docker Container + +Use this command to run Gitea with **SQLite** (simplest setup): + +```bash +docker run -d --name=gitea \ + -p 3000:3000 -p 222:22 \ + -v ~/gitea/data:/data \ + gitea/gitea:latest +``` + +- `-p 3000:3000`: maps web interface to `http://localhost:3000` +- `-p 222:22`: maps SSH (optional) +- `-v ~/gitea/data:/data`: mounts persistent data volume + +> ⚠️ On Windows, use full path like `C:/Users/YourName/gitea/data` instead of `~/gitea/data`. + +--- + +## βœ… 4. Access Gitea mm + +After a few seconds, go to: +``` +http://localhost:3000 +``` + +Follow the setup wizard: +- Choose **SQLite** (or MySQL/PostgreSQL) +- Set admin user credentials +- Complete setup + +--- + +## βœ… 5. (Optional) Docker Compose Setup + +Create a `docker-compose.yml` file: + +```yaml +version: "3" + +services: + gitea: + image: gitea/gitea:latest + container_name: gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always + volumes: + - ./gitea/data:/data + ports: + - "3000:3000" + - "222:22" +``` + +Then run: + +```bash +docker-compose up -d +``` + +--- + +## βœ… Common URLs + +- Web UI: `http://localhost:3000` +- SSH (if enabled): `ssh -p 222 git@localhost` + +--- + +Let me know if you want to use a specific database (e.g. MySQL, PostgreSQL) or encounter any issues. diff --git a/README.md b/README.md index f747d993d7984..5852f44639f52 100644 --- a/README.md +++ b/README.md @@ -1,159 +1 @@ -# Gitea - -[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly") -[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea") -[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card") -[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc") -[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release") -[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") -[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") -[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT") -[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea) -[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") - -[View this document in Chinese](./README_ZH.md) - -## Purpose - -The goal of this project is to make the easiest, fastest, and most -painless way of setting up a self-hosted Git service. - -As Gitea is written in Go, it works across **all** the platforms and -architectures that are supported by Go, including Linux, macOS, and -Windows on x86, amd64, ARM and PowerPC architectures. -This project has been -[forked](https://blog.gitea.com/welcome-to-gitea/) from -[Gogs](https://gogs.io) since November of 2016, but a lot has changed. - -For online demonstrations, you can visit [demo.gitea.com](https://demo.gitea.com). - -For accessing free Gitea service (with a limited number of repositories), you can visit [gitea.com](https://gitea.com/user/login). - -To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com). - -## Documentation - -You can find comprehensive documentation on our official [documentation website](https://docs.gitea.com/). - -It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively. - -If you have any suggestions or would like to contribute to it, you can visit the [documentation repository](https://gitea.com/gitea/docs) - -## Building - -From the root of the source tree, run: - - TAGS="bindata" make build - -or if SQLite support is required: - - TAGS="bindata sqlite sqlite_unlock_notify" make build - -The `build` target is split into two sub-targets: - -- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod). -- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater. - -Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js. - -More info: https://docs.gitea.com/installation/install-from-source - -## Using - -After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use: - - ./gitea web - -> [!NOTE] -> If you're interested in using our APIs, we have experimental support with [documentation](https://docs.gitea.com/api). - -## Contributing - -Expected workflow is: Fork -> Patch -> Push -> Pull Request - -> [!NOTE] -> -> 1. **YOU MUST READ THE [CONTRIBUTORS GUIDE](CONTRIBUTING.md) BEFORE STARTING TO WORK ON A PULL REQUEST.** -> 2. If you have found a vulnerability in the project, please write privately to **security@gitea.io**. Thanks! - -## Translating - -[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com) - -Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there. - -You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up. - -Get more information from [documentation](https://docs.gitea.com/contributing/localization). - -## Official and Third-Party Projects - -We provide an official [go-sdk](https://gitea.com/gitea/go-sdk), a CLI tool called [tea](https://gitea.com/gitea/tea) and an [action runner](https://gitea.com/gitea/act_runner) for Gitea Action. - -We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea), where you can discover more third-party projects, including SDKs, plugins, themes, and more. - -## Communication - -[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea") - -If you have questions that are not covered by the [documentation](https://docs.gitea.com/), you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/). - -## Authors - -- [Maintainers](https://github.com/orgs/go-gitea/people) -- [Contributors](https://github.com/go-gitea/gitea/graphs/contributors) -- [Translators](options/locale/TRANSLATORS) - -## Backers - -Thank you to all our backers! πŸ™ [[Become a backer](https://opencollective.com/gitea#backer)] - - - -## Sponsors - -Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/gitea#sponsor)] - - - - - - - - - - - - -## FAQ - -**How do you pronounce Gitea?** - -Gitea is pronounced [/Ι‘Ιͺ’ti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea" with a hard g. - -**Why is this not hosted on a Gitea instance?** - -We're [working on it](https://github.com/go-gitea/gitea/issues/1029). - -**Where can I find the security patches?** - -In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches. - -## License - -This project is licensed under the MIT License. -See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file -for the full license text. - -## Further information - -
-Looking for an overview of the interface? Check it out! - -|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)| -|:---:|:---:|:---:| -|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)| -|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)| -|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)| - -
+Initial commit diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000000000..515481709c086 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,15 @@ +version: '3' + +services: + gitea: + image: gitea/gitea:1.23.0 + container_name: gitea + ports: + - "3000:3000" + - "222:22" + volumes: + - ./gitea:/data + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000..5ed0c7a6435f6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +version: '3.7' + +services: + gitea: + image: gitea/gitea:latest # Gitea Docker image + container_name: gitea + ports: + - "3000:3000" # Expose Gitea web interface on port 3000 + - "22:22" # Expose SSH port for Git operations + environment: + - USER_UID=1000 + - USER_GID=1000 + - GITEA__database__DB_TYPE=postgres + - GITEA__database__HOST=db:5432 # PostgreSQL database service + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea_user + - GITEA__database__PASSWD=gitea_pass + - GITEA__server__DOMAIN=localhost:3000 + - GITEA__server__SSH_PORT=22 + depends_on: + - db + - redis + volumes: + - ./data:/data # Persistent storage for Gitea data + + db: + image: postgres:alpine # PostgreSQL Docker image + container_name: db + environment: + - POSTGRES_DB=gitea + - POSTGRES_USER=gitea_user + - POSTGRES_PASSWORD=gitea_pass + volumes: + - ./db-data:/var/lib/postgresql/data # Persistent storage for database + + redis: + image: redis:alpine # Redis Docker image + container_name: redis + + ports: + - "6379:6379" # Expose Redis default port + volumes: + - ./redis-data:/data # Persistent storage for Redis diff --git a/main/pom.xml b/main/pom.xml new file mode 100644 index 0000000000000..bfa4f5321b3e8 --- /dev/null +++ b/main/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + org.example + main + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + + org.seleniumhq.selenium + selenium-java + 4.27.0 + + + + + org.junit.jupiter + junit-jupiter-api + 5.10.5 + + + org.junit.jupiter + junit-jupiter-engine + 5.10.5 + test + + + + + io.rest-assured + rest-assured + 5.4.0 + + + io.rest-assured + json-path + 5.4.0 + + + io.rest-assured + xml-path + 5.4.0 + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.0 + + + + + diff --git a/main/src/main/java/org/example/DriverFactory.java b/main/src/main/java/org/example/DriverFactory.java new file mode 100644 index 0000000000000..442e5c5ab5f60 --- /dev/null +++ b/main/src/main/java/org/example/DriverFactory.java @@ -0,0 +1,62 @@ +package org.example; + +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxOptions; +import org.openqa.selenium.remote.RemoteWebDriver; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Optional; + +public class DriverFactory { + + private static final String grid_url = System.getenv("GRID_URL"); + + private static final String browser = Optional + .ofNullable(System.getenv("BROWSER")) + .orElse("chrome"); + + public static WebDriver getDriver() { + if (grid_url != null) { + return getRemoteDriver(browser); + } else { + return getLocalDriver(browser); + } + } + + private static WebDriver getRemoteDriver(String browser) { + URL hubUrl; + try { + hubUrl = new URI(grid_url).toURL(); + } catch (URISyntaxException | MalformedURLException err) { + throw new IllegalArgumentException("Invalid grid URL"); + } + + if (browser.equalsIgnoreCase("chrome")) { + ChromeOptions options = new ChromeOptions(); + options.addArguments("--headless"); + return new RemoteWebDriver(hubUrl, options); + } else if (browser.equalsIgnoreCase("firefox")) { + FirefoxOptions options = new FirefoxOptions(); + options.addArguments("-headless"); + return new RemoteWebDriver(hubUrl, options); + } else { + throw new IllegalArgumentException("Unsupported browser: " + browser); + } + } + + private static WebDriver getLocalDriver(String browser) { + if (browser.equalsIgnoreCase("chrome")) { + return new ChromeDriver(); + } else if (browser.equalsIgnoreCase("firefox")) { + return new FirefoxDriver(); + } else { + throw new IllegalArgumentException("Unsupported browser: " + browser); + } + } +} diff --git a/main/src/main/java/org/example/HomePageGit.java b/main/src/main/java/org/example/HomePageGit.java new file mode 100644 index 0000000000000..1ccc77b272a1e --- /dev/null +++ b/main/src/main/java/org/example/HomePageGit.java @@ -0,0 +1,66 @@ +package org.example; + +import org.junit.jupiter.api.Assertions; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.LoadableComponent; +import org.openqa.selenium.support.ui.Wait; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.time.Duration; +import java.util.List; + +public class HomePageGit extends LoadableComponent { + private WebDriver driver; + private List elements; + private final String baseURL = "http://localhost:3000/user/login"; + //String baseURL2="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login"; + //String baseURL = System.getenv("URL"); + + @Override + protected void load() { + this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); + driver.get(baseURL + "/"); + System.out.println(driver.getCurrentUrl()); + + } + + // @Override + protected void isLoaded() throws Error { + Assertions.assertTrue(driver.getTitle().contains("Dashboard")); + + } + + // Constructor + public HomePageGit(WebDriver driver) { + this.driver = driver; + PageFactory.initElements(driver, this); + + } + + // Method to initialize the elements list (called after the driver is initialized) + public void initializeElements() { + elements = driver.findElements(By.cssSelector("img.avatar, #_aria_auto_id_5")); // Adjust selectors accordingly + } + + public boolean isLoggedInSuccessfully() { + System.out.println(driver.getTitle()); + return driver.getTitle().contains("maias"); + } + + // Method to click on the image and then the profile button + public ProfilePage goToProfilePage() { + WebElement profileImage = driver.findElement(By.xpath("//*[@id=\"navbar\"]/div[2]/div[2]/span/img")); + profileImage.click(); + WebElement profilebtn=driver.findElement(By.xpath("//*[@id=\"_aria_auto_id_5\"]")); + profilebtn.click(); + + return new ProfilePage(driver); + } +} + + + diff --git a/main/src/main/java/org/example/LoginGit.java b/main/src/main/java/org/example/LoginGit.java new file mode 100644 index 0000000000000..796c69ae28e13 --- /dev/null +++ b/main/src/main/java/org/example/LoginGit.java @@ -0,0 +1,61 @@ +package org.example; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.LoadableComponent; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertTrue; + + +public class LoginGit extends LoadableComponent { + private WebDriver driver; + private final String baseURL="http://localhost:3000"; + //String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app"; + private By userNameFieldBy = By.cssSelector("input[name=\"user_name\"]"); + public By passwordFieldBy = By.cssSelector("input[name=\"password\"]"); + private By signinButtonBy = By.cssSelector("button.ui.primary.button.tw-w-full"); + + public LoginGit(WebDriver driver) { + this.driver = driver; + PageFactory.initElements(driver,this); + + } + public HomePageGit loginAsValidUser(String userName, String password) { + + driver.findElement(userNameFieldBy).sendKeys(userName); + driver.findElement(passwordFieldBy).sendKeys(password); + driver.findElement(signinButtonBy).click(); + + return new HomePageGit(driver); + } + public LoginGit loginWithInvalidCredentials(String userName, String password){ + driver.findElement(userNameFieldBy).clear(); + driver.findElement(userNameFieldBy).sendKeys(userName); + driver.findElement(passwordFieldBy).clear(); + driver.findElement(passwordFieldBy).sendKeys(password); + driver.findElement(signinButtonBy).click(); + return new LoginGit(driver) ; + } + public boolean isLoginFailed(){ + + return driver.getTitle().contains("Sign In"); + } + + @Override + protected void load() { + this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); + driver.get(baseURL+"/user/login"); + System.out.println(driver.getCurrentUrl()); + + } + + @Override + protected void isLoaded() throws Error { + assertTrue(driver.getTitle().contains("Sign In")); + + } +} + diff --git a/main/src/main/java/org/example/Main.java b/main/src/main/java/org/example/Main.java new file mode 100644 index 0000000000000..03adefcf12528 --- /dev/null +++ b/main/src/main/java/org/example/Main.java @@ -0,0 +1,17 @@ +package org.example; + +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + //TIP Press with your caret at the highlighted text + // to see how IntelliJ IDEA suggests fixing it. + System.out.printf("Hello and welcome!"); + + for (int i = 1; i <= 5; i++) { + //TIP Press to start debugging your code. We have set one breakpoint + // for you, but you can always add more by pressing . + System.out.println("i = " + i); + } + } +} diff --git a/main/src/main/java/org/example/NewProjectPage.java b/main/src/main/java/org/example/NewProjectPage.java new file mode 100644 index 0000000000000..b537d0ac174cc --- /dev/null +++ b/main/src/main/java/org/example/NewProjectPage.java @@ -0,0 +1,131 @@ +package org.example; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.LoadableComponent; +import org.openqa.selenium.support.ui.Wait; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertTrue; + + +public class NewProjectPage extends LoadableComponent { + private WebDriver driver; + private final String baseURL="http://localhost:3000/user/login"; + //private static final String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login"; + + // Locators for New Project Fields + private By titleField = By.id("_aria_auto_id_0"); + private By descriptionField = By.id("_combo_markdown_editor_1"); + private By templateDropdown = By.id("_aria_auto_id_13"); + private By cardPreviewsDropdown = By.id("_aria_auto_id_17"); + private By createProjectButton = By.cssSelector(".ui.primary.button"); + private By cancelButton = By.cssSelector(".ui.cancel.button"); + + // Locators for Description Buttons + private By boldButton = By.cssSelector("md-bold.markdown-toolbar-button[aria-label='Add bold text']"); + private By numberProjects=By.cssSelector("div.ui.small.label"); + + + // Constructor + public NewProjectPage(WebDriver driver) { + this.driver = driver; + + // This call sets the WebElement fields. + PageFactory.initElements(driver, this); + } + + // Actions for New Project Fields + public void enterTitle(String title) { + driver.findElement(titleField).sendKeys(title); + } + + public void enterDescription(String description) { + Wait wait = new WebDriverWait(driver, Duration.ofSeconds(5), Duration.ofMillis(500)); + wait.until(driver -> driver.findElement(descriptionField).isDisplayed()); + driver.findElement(descriptionField).sendKeys(description); + } + + public void selectTemplate(String templateName) { + Actions actions = new Actions(driver); + + // Click the dropdown + WebElement dropdown = driver.findElement(By.xpath("//div[@class='ui selection dropdown']")); + actions.moveToElement(dropdown).click().perform(); + + // Click the option + WebElement option = driver.findElement(By.xpath("//div[@role='option' and text()='" + templateName + "']")); + actions.moveToElement(option).click().perform(); + } + + + public void selectCardPreview(String cardPreviewOption) { + + Actions actions=new Actions(driver); + + WebElement dropdown= driver.findElement(By.xpath("//div[@class='ui selection dropdown']")); + actions.moveToElement(dropdown).click().perform(); + + WebElement option=driver.findElement(By.xpath("//div[@role='option' and text()='" + cardPreviewOption + "']")); + actions.moveToElement(option).click().perform(); + + } + + public void clickCreateProject() { + driver.findElement(createProjectButton).click(); + } + + public void clickCancel() { + driver.findElement(cancelButton).click(); + } + + // Actions for Description Buttons + public void clickBoldButton() { + driver.findElement(boldButton).click(); + } + + + + // Getter for Description Content + public String getDescriptionContent() { + WebElement previewElement = driver.findElement(descriptionField); + String content = previewElement.getAttribute("value"); + return content; + } + public int getNumberOfProjects(){ + WebElement numberElement = driver.findElement(numberProjects); + + + + String numberText = numberElement.getText(); + int number = Integer.parseInt(numberText); + return number; + + + } + + public boolean isSuccessfulProjectPage(){ + + + return driver.getTitle().equals("Projects - Gitea: Git with a cup of tea"); + + } + + @Override + protected void load() { + this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2)); + driver.get(baseURL+"/maias/-/projects/new"); + } + + @Override + protected void isLoaded() throws Error { + + assertTrue(driver.getTitle().contains("New Project")); + + } +} diff --git a/main/src/main/java/org/example/ProfilePage.java b/main/src/main/java/org/example/ProfilePage.java new file mode 100644 index 0000000000000..1e31a32286ad9 --- /dev/null +++ b/main/src/main/java/org/example/ProfilePage.java @@ -0,0 +1,61 @@ +package org.example; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.LoadableComponent; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.time.Duration; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertTrue; + + +public class ProfilePage extends LoadableComponent { + private WebDriver driver; + private final String baseURL="http://localhost:3000/user/login"; + //private static final String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login"; + + // Locator for the list of project links + private By projectLinksBy = By.cssSelector("div.overflow-menu-items a[href='/maias/-/projects']"); + + public ProfilePage(WebDriver driver) { + this.driver = driver; + // This call sets the WebElement fields. + PageFactory.initElements(driver, this); + + } + + // Method to click on the Projects link (choosing from the list) + public ProjectPage goToProjectsPage() { + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); + + // Wait until at least one project link is visible (lambda function for custom condition) + List projectLinks = wait.until(driver -> driver.findElements(projectLinksBy)); + System.out.println(projectLinks); + // Select and click on the first available project link (or you can choose any specific link) + if (!projectLinks.isEmpty()) { + WebElement SecondProjectLink = projectLinks.get(0); // Choose based on index (0 for the first link) + SecondProjectLink.click(); + } + + // Return a new ProjectPage object + return new ProjectPage(driver); + } + + @Override + protected void load() { + this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2)); + driver.get(baseURL+"/maias"); + + + } + + @Override + protected void isLoaded() throws Error { + assertTrue(driver.getTitle().contains("maias - Gitea")); + + } +} diff --git a/main/src/main/java/org/example/ProjectPage.java b/main/src/main/java/org/example/ProjectPage.java new file mode 100644 index 0000000000000..a5d52d5bd533e --- /dev/null +++ b/main/src/main/java/org/example/ProjectPage.java @@ -0,0 +1,51 @@ +package org.example; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.LoadableComponent; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ProjectPage extends LoadableComponent { + private WebDriver driver; + private final String baseURL="http://localhost:3000/user/login"; + //private static final String baseURL1="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login"; + + // CSS selector for the "New Project" button + private By newProjectButtonBy = By.linkText("New Project"); + + public ProjectPage(WebDriver driver) { + this.driver = driver; + // This call sets the WebElement fields. + PageFactory.initElements(driver, this); + + } + + // Method to click the "New Project" button and go to the New Project page + public NewProjectPage goToNewProjectPage() { + // Find the "New Project" button + WebElement newProjectButton = driver.findElement(newProjectButtonBy); + + // Click the "New Project" button + newProjectButton.click(); + + // Return a new instance of the NewProjectPage class (you need to create this class) + return new NewProjectPage(driver); + } + + @Override + protected void load() { + this.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2)); + driver.get(baseURL+"/maias/-/projects"); + } + + @Override + protected void isLoaded() throws Error { + assertTrue(driver.getTitle().contains("Projects")); + + } +} diff --git a/main/src/test/java/APITests/APITestGiteaTest.java b/main/src/test/java/APITests/APITestGiteaTest.java new file mode 100644 index 0000000000000..66a1940330cfd --- /dev/null +++ b/main/src/test/java/APITests/APITestGiteaTest.java @@ -0,0 +1,63 @@ +package APITests; + +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import java.net.URL; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.equalTo; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class APITestGiteaTest { + + private static final String owner = "maias"; + private static final String apiToken = "30d8417411cb86e107307f3abaa3639954bdaf12"; + private static final String projectName = "newRepoAPITest"; + + @BeforeAll + public static void setup() { + String dbUrl = "http://localhost:3000"; + //String baseURL="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app"; + RestAssured.baseURI =dbUrl + "/api/v1"; + //System.out.println(dbUrl); + } + + @Test + @Order(1) + public void testCreateRepo() { + given() + .log().all() + .header("Authorization", "token " + apiToken) + .contentType(ContentType.JSON) + .body("{ \"name\": \"" + projectName + "\", \"private\": false }") + .when() + .post("/user/repos") + .then() + .log().all() + .statusCode(201) + .body("name", equalTo(projectName)) + .body("private", equalTo(false)); + + } + + @Test + @Order(2) + public void testDeleteRepo() { + given() + .log().all() + .header("Authorization", "token " + apiToken) + .when() + .delete("/repos/" + owner + "/" + projectName) + .then() + .log().all() + .statusCode(204); + } + + +} diff --git a/main/src/test/java/UITests/LoginGitTest.java b/main/src/test/java/UITests/LoginGitTest.java new file mode 100644 index 0000000000000..a9053da815f3f --- /dev/null +++ b/main/src/test/java/UITests/LoginGitTest.java @@ -0,0 +1,81 @@ +package UITests; + +import org.example.HomePageGit; +import org.example.LoginGit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Wait; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.net.MalformedURLException; +import java.time.Duration; + +import static org.example.DriverFactory.getDriver; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class LoginGitTest { + WebDriver driver; + private LoginGit login; + private final String URL="http://localhost:3000/user/login"; + //String URL="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login"; + + + @BeforeEach + public void setUp() throws MalformedURLException { + driver= getDriver(); + driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15)); + driver.manage().window().maximize(); + driver.get(URL); + + try{ + Wait wait=new WebDriverWait(driver, Duration.ofSeconds(5)); + WebElement visitButton= wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[text()='Visit Site']"))); + visitButton.click(); + } + catch (TimeoutException err){ + System.out.println("Ngrok warning page was not loaded"); + } + login = new LoginGit(driver).get(); + + } + @Test + public void testInvalidLogin() { + LoginGit page = login.loginWithInvalidCredentials("wrong", "wrong"); + assertTrue(page.isLoginFailed(), "Login should fail with invalid credentials"); + } + + @Test + public void testValidLogin() { + HomePageGit home = login.loginAsValidUser("maias", "Maias123"); + assertTrue(home.isLoggedInSuccessfully(), "Login should be successful with valid credentials"); + } + + @Test + public void testEmptyUsername() { + LoginGit page = login.loginWithInvalidCredentials("", "Maias123"); + assertTrue(page.isLoginFailed(), "Login should fail when the username is empty"); + } + + @Test + public void testEmptyPassword() { + LoginGit page = login.loginWithInvalidCredentials("maias", ""); + assertTrue(page.isLoginFailed(), "Login should fail when the password is empty"); + } + + @Test + public void testEmptyUsernameAndPassword() { + LoginGit page = login.loginWithInvalidCredentials("", ""); + assertTrue(page.isLoginFailed(), "Login should fail when both username and password are empty"); + } + @AfterEach + public void tearDown() { + driver.quit(); + } + +} diff --git a/main/src/test/java/UITests/NewProjectPageTest.java b/main/src/test/java/UITests/NewProjectPageTest.java new file mode 100644 index 0000000000000..c20f35dd6fea4 --- /dev/null +++ b/main/src/test/java/UITests/NewProjectPageTest.java @@ -0,0 +1,160 @@ +package UITests; + +import org.example.*; +import org.junit.jupiter.api.*; +import org.openqa.selenium.By; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Wait; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.net.MalformedURLException; +import java.time.Duration; + +import static org.example.DriverFactory.getDriver; +import static org.junit.jupiter.api.Assertions.*; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class NewProjectPageTest { + private WebDriver driver; + private ProjectPage projectPage; + private LoginGit login; + private HomePageGit home; + private ProfilePage profile; + private NewProjectPage newProjectPage; + private final String URL = "http://localhost:3000/user/login"; + String URL2="https://a7bd-2a06-c701-78fb-bc00-e162-b721-5502-6b4b.ngrok-free.app/user/login"; + + @BeforeEach + public void setUp() throws MalformedURLException { + driver = getDriver(); + driver.manage().window().maximize(); + driver.get(URL); + try { + Wait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + WebElement visitButton = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[text()='Visit Site']"))); + visitButton.click(); + } catch (TimeoutException err) { + System.out.println("Ngrok warning page was not loaded"); + } + login = new LoginGit(driver).get(); + } + + @Test + @Order(1) + public void testCreateProject() { + //the bot pattern + newProjectPage = login.loginAsValidUser("maias", "Maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle("Test1 Project"); + newProjectPage.enterDescription("This is a test project description."); + newProjectPage.selectTemplate("None"); + newProjectPage.selectCardPreview("Images and Text"); + newProjectPage.clickCreateProject(); + assertTrue(newProjectPage.isSuccessfulProjectPage()); + } + @Test + @Order(2)//if we have emty title the project will not create + public void testEmptyFields() { + //the bot pattern + newProjectPage=login.loginAsValidUser("maias", "Maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle(""); + newProjectPage.enterDescription("this is Description"); + newProjectPage.clickCreateProject(); + assertFalse(newProjectPage.isSuccessfulProjectPage()); + + + } + @Test + @Order(3) + //if we have emty title the project will not create + public void testTitleOnly() { + //the bot pattern + newProjectPage=login.loginAsValidUser("maias", "Maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle("Test 3 Project2"); + newProjectPage.clickCreateProject(); + assertTrue(newProjectPage.isSuccessfulProjectPage()); + + + } + /* @Test //if we have emty title the project will not create + public void testCancelButton() { + newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle("Test 4 Project"); + newProjectPage.enterDescription("This is a test project description."); + newProjectPage.selectTemplate("None"); + newProjectPage.selectCardPreview("Images and Text"); + int numberProjectBefore= newProjectPage.getNumberOfProjects(); + newProjectPage.clickCancel(); + int numberProjectafter=newProjectPage.getNumberOfProjects(); + assertEquals(numberProjectBefore,numberProjectafter); + + + } + + @Test// test BoldStyle after we write the description + public void testBoldStyleInDescription() { + newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle("Test5 Project"); + newProjectPage.enterDescription("This is a test description."); + newProjectPage.selectTemplate("Basic Kanban"); + newProjectPage.selectCardPreview("Text Only"); + // Apply bold styling + newProjectPage.clickBoldButton(); + // Get the HTML content after applying bold + String afterBoldHtml = newProjectPage.getDescriptionContent(); + // Verify that bold tags are added in the HTML + assertTrue(afterBoldHtml.contains("****") , + "Bold styling was not applied in the description preview."); + //Verify the content inside the bold tags is as expected + assertTrue(afterBoldHtml.contains("This is a test description."), + "Description content is incorrect after applying bold styling."); + // Create the project + newProjectPage.clickCreateProject(); + // Verify that the project was created successfully + assertTrue(newProjectPage.isSuccessfulProjectPage()); + } + @Test// test BoldStyle before we write the description + public void testBoldStyleInDescription2() { + newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle("Test6 Project"); + newProjectPage.clickBoldButton(); + newProjectPage.enterDescription("This is a test description."); + newProjectPage.selectTemplate("Basic Kanban"); + newProjectPage.selectCardPreview("Text Only"); + // Get the HTML content after applying bold + String afterBoldHtml = newProjectPage.getDescriptionContent(); + // Verify that bold tags are added in the HTML + assertTrue(afterBoldHtml.equals("**This is a test description.**") , + "Bold styling was not applied in the description preview."); + //Verify the content inside the bold tags is as expected + assertTrue(afterBoldHtml.contains("This is a test description."), + "Description content is incorrect after applying bold styling."); + // Create the project + newProjectPage.clickCreateProject(); + // Verify that the project was created successfully + assertTrue(newProjectPage.isSuccessfulProjectPage()); + } + @Test// test BoldStyle for some words we write the description + public void testBoldStyleInDescription3() { + newProjectPage=login.loginAsValidUser("maias", "maias123").goToProfilePage().goToProjectsPage().goToNewProjectPage(); + newProjectPage.enterTitle("Test 7 Project"); + newProjectPage.enterDescription("This is a test description."); + newProjectPage.clickBoldButton(); + newProjectPage.enterDescription("maias "); + newProjectPage.selectTemplate("Basic Kanban"); + newProjectPage.selectCardPreview("Text Only"); + newProjectPage.enterDescription("This not Bold"); + String afterAdditionalText=newProjectPage.getDescriptionContent(); + assertTrue(afterAdditionalText.equals("This is a test description.**maias **This not Bold"),"Bold styling was not applied in the description preview."); + newProjectPage.clickCreateProject(); + assertTrue(newProjectPage.isSuccessfulProjectPage()); + }*/ + @AfterEach + public void tearDown() { + driver.quit(); + } + +} + diff --git a/main/target/classes/org/example/DriverFactory.class b/main/target/classes/org/example/DriverFactory.class new file mode 100644 index 0000000000000..d6f1dd2c519b1 Binary files /dev/null and b/main/target/classes/org/example/DriverFactory.class differ diff --git a/main/target/classes/org/example/HomePageGit.class b/main/target/classes/org/example/HomePageGit.class new file mode 100644 index 0000000000000..bf74e9c03ab5a Binary files /dev/null and b/main/target/classes/org/example/HomePageGit.class differ diff --git a/main/target/classes/org/example/LoginGit.class b/main/target/classes/org/example/LoginGit.class new file mode 100644 index 0000000000000..8d65a046b0f80 Binary files /dev/null and b/main/target/classes/org/example/LoginGit.class differ diff --git a/main/target/classes/org/example/Main.class b/main/target/classes/org/example/Main.class new file mode 100644 index 0000000000000..4426061088818 Binary files /dev/null and b/main/target/classes/org/example/Main.class differ diff --git a/main/target/classes/org/example/NewProjectPage.class b/main/target/classes/org/example/NewProjectPage.class new file mode 100644 index 0000000000000..0cbfc091cc81b Binary files /dev/null and b/main/target/classes/org/example/NewProjectPage.class differ diff --git a/main/target/classes/org/example/ProfilePage.class b/main/target/classes/org/example/ProfilePage.class new file mode 100644 index 0000000000000..2a421a31c6be2 Binary files /dev/null and b/main/target/classes/org/example/ProfilePage.class differ diff --git a/main/target/classes/org/example/ProjectPage.class b/main/target/classes/org/example/ProjectPage.class new file mode 100644 index 0000000000000..78e6b877ad19d Binary files /dev/null and b/main/target/classes/org/example/ProjectPage.class differ diff --git a/main/target/test-classes/APITests/APITestGiteaTest.class b/main/target/test-classes/APITests/APITestGiteaTest.class new file mode 100644 index 0000000000000..a8789a6390de4 Binary files /dev/null and b/main/target/test-classes/APITests/APITestGiteaTest.class differ diff --git a/main/target/test-classes/UITests/LoginGitTest.class b/main/target/test-classes/UITests/LoginGitTest.class new file mode 100644 index 0000000000000..2d236a7e52c74 Binary files /dev/null and b/main/target/test-classes/UITests/LoginGitTest.class differ diff --git a/main/target/test-classes/UITests/NewProjectPageTest.class b/main/target/test-classes/UITests/NewProjectPageTest.class new file mode 100644 index 0000000000000..935e370265f00 Binary files /dev/null and b/main/target/test-classes/UITests/NewProjectPageTest.class differ diff --git a/newfile.txt b/newfile.txt new file mode 100644 index 0000000000000..e69de29bb2d1d