diff --git a/.github/workflows/weather-app-ci-build.yml b/.github/workflows/weather-app-ci-build.yml new file mode 100644 index 0000000..6c67195 --- /dev/null +++ b/.github/workflows/weather-app-ci-build.yml @@ -0,0 +1,63 @@ +name: Weather App CI + +on: + push: + branches: [ "master", "development" ] + pull_request: + branches: [ "master", "development" ] + +jobs: + + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Docker Login + env: + DOCKER_USER: ${{ secrets.DOCKER_USER }} + DOCKER_KEY: ${{ secrets.DOCKER_KEY }} + run: | + docker login -u $DOCKER_USER -p $DOCKER_KEY + + # Script Permissions + - name: Setting up Permissions + run: | + chmod +x -R ./scripts/*.sh + mkdir -p ./storage/logs/ ./bootstrap/cache/ + chmod 777 ./storage/ ./bootstrap/cache -R + + # Docker Images + - name: Building the Docker Images + run: ./scripts/build.sh + + # Docker Containers + - name: Start Docker Containers + run: ./scripts/up.sh -d + + # Composer + - name: Run Composer + run: | + ./scripts/composer.sh install + ./scripts/composer.sh dump-autoload + + # NPM + - name: Run NPM + run: | + ./scripts/run.sh npm install + ./scripts/run.sh npm run build + + # Code Quality Check + - name: Run PhpStan + run: ./scripts/composer.sh run phpstan + + - name: Run Easy Coding Sandards + run: ./scripts/composer.sh run ecs-all + + - name: Run Automated Test with PhpUnit + run: ./scripts/composer.sh run phpunit + + # Teardown + - name: Stop container and remove images + run: ./scripts/down.sh -v diff --git a/README.md b/README.md index a088f61..7e4c841 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,138 @@ # Bizmates Ph Weather App Coding Exam +![Weather APP BUILD](https://github.com/nspalo/bizmates-weather-app-exam/actions/workflows/weather-app-ci-build.yml/badge.svg) + A simple weather forecasting application built with Laravel that can display weather update from Japan as a coding exam for Bizmates Ph + +---- + +# About the Weather App +- Is a simple web application built with laravel that can search a for a given location's coordinates and get the weather update and forecast. +- Uses Geoapify geocoding Api to get the geolocation and Open Weather Map Api to get weather data +- This project observes: + - PSR Coding Standards + - Object-Oriented Principles / DRY / KISS + - SOLID Principles / Clean Code + - Automated coding standard checking using PhpStan & Easy Coding Standard + - Automated testing using PhpUnit + +![Weather App](https://github.com/nspalo/bizmates-weather-app-exam/blob/feature/BWA-9-weather-app-readme/docker/documents/weather-app-sample-image.jpg) + +## Web Stack +- Docker +- NginX stable-alpine +- PHP 8.1 fpm-alpine +- Composer 2.6.1 +- Node 20.6-alpine +- Laravel 9 +- Bootstrap 5 + +### Pre-requisite +- Docker +- Geoapify Account + - Generate API Key +- Open Weather Map Account + - Generate API Key +- Configure the API Keys in the `.env` file + - `See: /src/.env` + - For more info, check `/src/config/services.php` + +## Set Up Procedure +### Step 1: Service containers - Building, Starting, and Stopping +``` +// Building the services/containers +> ./scripts/build.sh + +// Starting the services/containers +// - optionally add the -d (detach) flag to run in the background +> ./scripts/up.sh -d + +// Or do a one-liner command for the build and start process +> ./scripts/up.sh -d --build + +// Stoping the services/containers +// - To stop a specific service add the continer name +> ./scripts/stop.sh <_ContainerName_> + +// Tear down routine +// - optionally add the -v to remove the images +> ./scripts/down.sh -v +``` + +### Step 2: Packages and Dependencies +``` +// Running composer install +> ./scripts/composer.sh install +> ./scripts/composer.sh dump-autoload + +// Running NPM +> ./scripts/run.sh npm install +> ./scripts/run.sh npm run build + +// Copying Laravel .env file +> ./scripts/composer.sh run post-root-package-install + +// Generating Key +> ./scripts/artisan.sh key:generate + +``` + +### Step 3: Accessing the site +Hit the browser at `localhost:8080` + +### API Endpoint +`localhost:8080/api/weather-update?location=Some-Location` + +where `?location=` is query string for the location to check for weather update/forecast + + +---- + +## Code Quality and Testing +``` +// Running PhpStan +> ./scripts/composer.sh run phpstan + +// Running Easy Coding Standards for the entire project +./scripts/composer.sh run ecs-all + +// Running Easy Coding Standards for App or Test ONLY +./scripts/composer.sh run ecs-app +./scripts/composer.sh run ecs-test + +// Running Auto-Fix for ecs +./scripts/composer.sh run ecs-fix-app +./scripts/composer.sh run ecs-fix-test + +// Running Automated Test with PhpUnit +./scripts/composer.sh run phpunit + +``` + +---- + +## BizmatesPh Coding Exam Requirements +### Background +- This page aims to provide travel information of Japan for foreign tourists visiting Japan for the first time. + +### Tech Stack +- PHP (version 8+ preferred) +- Framework Laravel (any version) +- HTML5, CSS3, Javascript ES5/ES6 or any JS Library preferred (VueJS is a plus) +- Responsive Design (Desktop and Mobile) +- API Endpoints +- Automated Testing + +### Submission method +- Provide a github repository once finished +- Development should be within 4 - 5days + +### API Service +- Open Weather Map's Daily API +- Foursquare Search Venue API + +### Code Quality +- PSR Coding Standards 1,2,4 & 12 +- Object-Oriented Principles + Clean Code & SOLID Principles +- Google JavaScript Style Guide +- Google HTML/CSS Style Guide diff --git a/docker/documents/weather-app-sample-image.jpg b/docker/documents/weather-app-sample-image.jpg new file mode 100644 index 0000000..3ebb589 Binary files /dev/null and b/docker/documents/weather-app-sample-image.jpg differ diff --git a/src/composer.json b/src/composer.json index 96260a5..7e4b2d1 100644 --- a/src/composer.json +++ b/src/composer.json @@ -37,6 +37,7 @@ }, "scripts": { "post-autoload-dump": [ + "mkdir -p ./bootstrap/cache/", "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover --ansi" ], diff --git a/src/config/services.php b/src/config/services.php index 88edfc4..752d825 100644 --- a/src/config/services.php +++ b/src/config/services.php @@ -37,7 +37,7 @@ 'max_output' => env('OPEN_WEATHER_MAX_OUTPUT', '5'), 'unit' => env('OPEN_WEATHER_UNIT', 'metric'), 'lang' => env('OPEN_WEATHER_LANG', 'en'), - 'uri' => env('OPEN_WEATHER_API_URI', ''), + 'uri' => env('OPEN_WEATHER_API_URI', 'api.openweathermap.org/data/2.5'), ], 'geoapify' => [ 'filter' => env('GEOAPIFY_FILTER', 'countrycode:jp'), @@ -46,7 +46,7 @@ 'lang' => env('GEOAPIFY_LANG', 'en'), 'max_output' => env('GEOAPIFY_MAX_OUTPUT', '1'), 'type' => env('GEOAPIFY_TYPE', 'city'), - 'uri' => env('GEOAPIFY_API_URI', ''), + 'uri' => env('GEOAPIFY_API_URI', 'api.geoapify.com/v1/geocode/search'), 'default_search' => env('GEOAPIFY_DEFAULT', 'Tokyo, Japan'), ], ], diff --git a/src/tests/Unit/CreatesApplication.php b/src/tests/CreatesApplication.php similarity index 81% rename from src/tests/Unit/CreatesApplication.php rename to src/tests/CreatesApplication.php index 079f015..df084d1 100644 --- a/src/tests/Unit/CreatesApplication.php +++ b/src/tests/CreatesApplication.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Unit; +namespace Tests; use Illuminate\Contracts\Console\Kernel; @@ -15,7 +15,7 @@ trait CreatesApplication */ public function createApplication() { - $app = require __DIR__ . '/../../bootstrap/app.php'; + $app = require __DIR__ . '/../bootstrap/app.php'; $app->make(Kernel::class)->bootstrap(); diff --git a/src/tests/Feature/ExampleTest.php b/src/tests/Feature/ExampleTest.php deleted file mode 100644 index e17d7b6..0000000 --- a/src/tests/Feature/ExampleTest.php +++ /dev/null @@ -1,23 +0,0 @@ -get('/'); - - $response->assertStatus(200); - } -} diff --git a/src/tests/Unit/TestCase.php b/src/tests/TestCase.php similarity index 93% rename from src/tests/Unit/TestCase.php rename to src/tests/TestCase.php index 1e4d375..c7a1aa3 100644 --- a/src/tests/Unit/TestCase.php +++ b/src/tests/TestCase.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Unit; +namespace Tests; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; diff --git a/src/tests/Unit/Enums/DirectionTest.php b/src/tests/Unit/Enums/DirectionTest.php index 6698fc1..150c599 100644 --- a/src/tests/Unit/Enums/DirectionTest.php +++ b/src/tests/Unit/Enums/DirectionTest.php @@ -5,7 +5,7 @@ namespace Unit\Enums; use App\Enums\Direction; -use Unit\TestCase; +use Tests\TestCase; class DirectionTest extends TestCase { diff --git a/src/tests/Unit/ExampleTest.php b/src/tests/Unit/ExampleTest.php deleted file mode 100644 index 18d3bcb..0000000 --- a/src/tests/Unit/ExampleTest.php +++ /dev/null @@ -1,20 +0,0 @@ -assertTrue(true); - } -} diff --git a/src/tests/Unit/Services/ConfigurationMapper/ServiceConfigurationMapperTest.php b/src/tests/Unit/Services/ConfigurationMapper/ServiceConfigurationMapperTest.php index a896a53..b42af13 100644 --- a/src/tests/Unit/Services/ConfigurationMapper/ServiceConfigurationMapperTest.php +++ b/src/tests/Unit/Services/ConfigurationMapper/ServiceConfigurationMapperTest.php @@ -6,7 +6,7 @@ use App\Services\ConfigurationMapper\Exceptions\UnknownServiceConfigurationException; use App\Services\ConfigurationMapper\ServiceConfigurationMapper; -use Unit\TestCase; +use Tests\TestCase; class ServiceConfigurationMapperTest extends TestCase { diff --git a/src/tests/Unit/Services/GeoapifyApi/GeocodingServiceTest.php b/src/tests/Unit/Services/GeoapifyApi/GeocodingServiceTest.php index 5cb2ba3..a2e4d7d 100644 --- a/src/tests/Unit/Services/GeoapifyApi/GeocodingServiceTest.php +++ b/src/tests/Unit/Services/GeoapifyApi/GeocodingServiceTest.php @@ -9,7 +9,7 @@ use App\Services\UrlQueryStringBuilder\Interfaces\UrlQueryStringBuilderServiceInterface; use Illuminate\Http\Client\RequestException; use Illuminate\Support\Facades\Http; -use Unit\TestCase; +use Tests\TestCase; class GeocodingServiceTest extends TestCase { diff --git a/src/tests/Unit/Services/GeoapifyApi/Resources/GeolocationResourceTest.php b/src/tests/Unit/Services/GeoapifyApi/Resources/GeolocationResourceTest.php index 8c1c8b1..4495049 100644 --- a/src/tests/Unit/Services/GeoapifyApi/Resources/GeolocationResourceTest.php +++ b/src/tests/Unit/Services/GeoapifyApi/Resources/GeolocationResourceTest.php @@ -5,7 +5,7 @@ namespace Unit\Services\GeoapifyApi\Resources; use App\Services\GeoapifyApi\Resources\GeolocationResource; -use Unit\TestCase; +use Tests\TestCase; class GeolocationResourceTest extends TestCase { diff --git a/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourceTest.php b/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourceTest.php index 735ba08..e6ebd46 100644 --- a/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourceTest.php +++ b/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourceTest.php @@ -5,7 +5,7 @@ namespace Unit\Services\OpenWeatherApi\Resources; use App\Services\OpenWeatherApi\Resources\WeatherResource; -use Unit\TestCase; +use Tests\TestCase; class WeatherResourceTest extends TestCase { diff --git a/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourcesTest.php b/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourcesTest.php index c48fd38..860e31e 100644 --- a/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourcesTest.php +++ b/src/tests/Unit/Services/OpenWeatherApi/Resources/WeatherResourcesTest.php @@ -5,7 +5,7 @@ namespace Unit\Services\OpenWeatherApi\Resources; use App\Services\OpenWeatherApi\Resources\WeatherResources; -use Unit\TestCase; +use Tests\TestCase; class WeatherResourcesTest extends TestCase { diff --git a/src/tests/Unit/Services/UrlQueryStringBuilder/UrlQueryStringBuilderServiceTest.php b/src/tests/Unit/Services/UrlQueryStringBuilder/UrlQueryStringBuilderServiceTest.php index af547b8..42a93ae 100644 --- a/src/tests/Unit/Services/UrlQueryStringBuilder/UrlQueryStringBuilderServiceTest.php +++ b/src/tests/Unit/Services/UrlQueryStringBuilder/UrlQueryStringBuilderServiceTest.php @@ -5,7 +5,7 @@ namespace Unit\Services\UrlQueryStringBuilder; use App\Services\UrlQueryStringBuilder\UrlQueryStringBuilderService; -use Unit\TestCase; +use Tests\TestCase; class UrlQueryStringBuilderServiceTest extends TestCase {