diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..a8776de75 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +secrets filter=git-crypt diff=git-crypt diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 000000000..bdad52c24 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,128 @@ +name: CI + +on: + workflow_call: + inputs: + registry: + description: OCI registry for image publishing + required: true + type: string + tag: + description: OCI image tag to use for publishing + required: true + type: string + secrets: + mail_server: + description: Server address for sending mail + required: true + mail_server_port: + description: Server port for sending mail + required: true + mail_targets: + description: Target addresses for sending mail + required: true + mail_username: + description: Username on the mail server + required: true + mail_password: + description: Password on the mail server + required: true + +jobs: + image: + runs-on: ubuntu-latest + defaults: + run: + working-directory: angular + permissions: + contents: read + packages: write + steps: + - name: Check out the repository + id: checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Set up node + id: setup-node + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: current + cache: npm + cache-dependency-path: angular/package-lock.json + + - name: Run clean install + id: npm-ci + run: npm ci + + - name: Run tests + id: npm-test + run: npm run test -- --browsers ChromeHeadless --no-watch --no-progress + + - name: Build the project + id: npm-build + run: npm run build -- --configuration production + + - name: Set up buildx plugin + id: setup-buildx + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 + + - name: Log into registry ${{ inputs.registry }} as ${{ github.actor }} + id: docker-login + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ${{ inputs.registry }} + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Extract metadata + id: docker-meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 + with: + images: ${{ inputs.registry }}/${{ github.repository }} + tags: | + type=raw,value=${{ inputs.tag }} + + - name: Build and push the image + id: docker-build-push + uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6.7.0 + with: + context: . + push: true + tags: ${{ steps.docker-meta.outputs.tags }} + labels: ${{ steps.docker-meta.outputs.labels }} + + - name: Retrieve the execution time + id: exec-time + if: always() + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "time=$(gh api /repos/${{ github.repository }}/actions/runs/${{ github.run_id }} \ + --jq '(.updated_at | fromdate) - (.created_at | fromdate)')" >> "$GITHUB_OUTPUT" + + - name: Send summary + if: always() + uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0 + with: + server_address: ${{ secrets.mail_server }} + server_port: ${{ secrets.mail_server_port }} + username: ${{ secrets.mail_username }} + password: ${{ secrets.mail_password }} + subject: GitHub Actions Job Summary for ${{ github.repository }} (${{ job.status }}) + to: ${{ secrets.mail_targets }} + from: GitHub Actions (on behalf of ${{ github.actor }}) + body: |- + Job status: ${{ job.status }}. + Workflow took approximately ${{ steps.exec-time.outputs.time }} seconds to execute. + Summary: + - Check out the repository: ${{ steps.checkout.outcome }} + - Set up node: ${{ steps.setup-node.outcome }} + - Run clean install: ${{ steps.npm-ci.outcome }} + - Run tests: ${{ steps.npm-test.outcome }} + - Build the project: ${{ steps.npm-build.outcome }} + - Set up buildx plugin: ${{ steps.setup-buildx.outcome }} + - Log into ${{ inputs.registry }} as ${{ github.actor }}: ${{ steps.docker-login.outcome }} + - Extract metadata: ${{ steps.docker-meta.outcome }} + - Build and push the image: ${{ steps.docker-build-push.outcome }} + - Retrieve the execution time: ${{ steps.exec-time.outcome }} + - Send summary via email: one can only hope diff --git a/.github/workflows/trigger.yaml b/.github/workflows/trigger.yaml new file mode 100644 index 000000000..74ce6b83e --- /dev/null +++ b/.github/workflows/trigger.yaml @@ -0,0 +1,43 @@ +name: Run CI on push + +on: + push: + branches: + - master + - feature/* + +jobs: + secrets: + runs-on: ubuntu-latest + outputs: + server: ${{ steps.secrets.outputs.MAIL_SERVER }} + port: ${{ steps.secrets.outputs.MAIL_SERVER_PORT }} + targets: ${{ steps.secrets.outputs.MAIL_TARGETS }} + username: ${{ steps.secrets.outputs.MAIL_USERNAME }} + password: ${{ steps.secrets.outputs.MAIL_PASSWORD }} + steps: + - name: Check out the repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Unlock secrets with git-crypt + uses: sliteteam/github-action-git-crypt-unlock@f99c0c6b60bb7ec30dcec033a8f0a3b3d48f21e1 # v1.3.0 + env: + GIT_CRYPT_KEY: ${{ secrets.GIT_CRYPT_KEY }} + + - name: Extract the unlocked secrets + id: secrets + run: | + cat secrets >> "$GITHUB_OUTPUT" + + ci: + uses: ./.github/workflows/ci.yaml + needs: secrets + with: + registry: ghcr.io + tag: latest + secrets: + mail_server: ${{ needs.secrets.outputs.server }} + mail_server_port: ${{ needs.secrets.outputs.port }} + mail_targets: ${{ needs.secrets.outputs.targets }} + mail_username: ${{ needs.secrets.outputs.username }} + mail_password: ${{ needs.secrets.outputs.password }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f9f2bdb06 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.git-crypt/ +.idea/ +.vscode/ +git-crypt-key diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..2f9fb12ac --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +repos: + - repo: https://github.com/adrienverge/yamllint + rev: v1.35.1 + hooks: + - id: yamllint + + - repo: https://github.com/lyz-code/yamlfix + rev: 1.17.0 + hooks: + - id: yamlfix + args: [--config-file, .yamlfix.toml] + + - repo: https://github.com/petalmd/git-crypt-pre-commit + rev: v0.1 + hooks: + - id: git-crypt + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + - id: check-merge-conflict + - id: check-symlinks + - id: end-of-file-fixer + - id: forbid-new-submodules + - id: mixed-line-ending + - id: no-commit-to-branch + - id: trailing-whitespace + + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: v0.10.0.1 + hooks: + - id: shellcheck + args: [--check-sourced] diff --git a/.yamlfix.toml b/.yamlfix.toml new file mode 100644 index 000000000..424ad87cf --- /dev/null +++ b/.yamlfix.toml @@ -0,0 +1,4 @@ +whitelines = 1 +section_whitelines = 1 +explicit_start = false +sequence_style = "keep_style" diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 000000000..ce61e8ea8 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,11 @@ +extends: default + +yaml-files: + - '*.yaml' + - '*.yml' + - .yamllint + +rules: + comments: disable + document-start: disable + line-length: disable diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..fee747036 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +# Tagged as 1.27.2-alpine3.20 +# https://github.com/nginxinc/docker-nginx-unprivileged/pkgs/container/nginx-unprivileged/299640275?tag=1.27.2-alpine3.20 +FROM ghcr.io/nginxinc/nginx-unprivileged@sha256:add866cd510386edb5a7e878f6566ede993a374d6abfd1e653a49b6e74562e31 + +COPY ./nginx.conf /etc/nginx/nginx.conf +COPY ./angular/dist/angular-starter/browser/ /usr/share/nginx/html/ + +CMD ["nginx"] diff --git a/README.md b/README.md index ad8ba255d..dffb9668f 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Here is a working Angular live demo : https://angular.ganatan.com

- Angular 16 Example 
+      <img src=

@@ -59,7 +59,7 @@ git clone https://gitlab.com/ganatan/angular-react-starter.git # change directory cd angular-react-starter -cd angular +cd angular # install the repo with npm npm install @@ -68,7 +68,7 @@ npm install npm start ``` -in your browser go to [http://localhost:4200](http://localhost:4200) +in your browser go to [http://localhost:4200](http://localhost:4200) @@ -95,7 +95,7 @@ npm start ``` -in your browser go to [http://localhost:3000](http://localhost:3000) +in your browser go to [http://localhost:3000](http://localhost:3000) # [Node Quick start](#node-quick-start) @@ -121,7 +121,7 @@ npm start ``` -in your browser go to [http://localhost:5000](http://localhost:5000) +in your browser go to [http://localhost:5000](http://localhost:5000) # [Angular Tutorial](#angular-quick-start) @@ -143,9 +143,9 @@ Here is a step by step Tutorial : https://www.ganatan.com/tutorials/getting-sta ## Development * `npm run start` -* in your browser go to [http://localhost:4200](http://localhost:4200) +* in your browser go to [http://localhost:4200](http://localhost:4200) -## Production +## Production * `npm run build` ## Linter @@ -166,9 +166,9 @@ Here is a step by step Tutorial : https://www.ganatan.com/tutorials/getting-sta ## Development * `npm run start` -* in your browser go to [http://localhost:3000](http://localhost:3000) +* in your browser go to [http://localhost:3000](http://localhost:3000) -## Production +## Production * `npm run build` ## Linter @@ -188,9 +188,9 @@ Here is a step by step Tutorial : https://www.ganatan.com/tutorials/getting-sta ## Development * `npm run start` -* in your browser go to [http://localhost:5000](http://localhost:5000) +* in your browser go to [http://localhost:5000](http://localhost:5000) -## Production +## Production * `npm run build` ## Linter @@ -217,4 +217,3 @@ Here is a step by step Tutorial : https://www.ganatan.com/tutorials/getting-sta ## [Tutoriels React en français](#french-tutorials) - Installation - https://www.ganatan.com/tutorials/demarrer-avec-react - Tutoriels Etape par étape - https://www.ganatan.com/tutorials - diff --git a/angular/LICENSE b/angular/LICENSE index d3a987df8..e18c26332 100644 --- a/angular/LICENSE +++ b/angular/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/angular/README.md b/angular/README.md index e91c11a76..f47af655b 100644 --- a/angular/README.md +++ b/angular/README.md @@ -5,7 +5,7 @@ ### Developpement * `npm run start` -* in your browser [http://localhost:4200](http://localhost:4200) +* in your browser [http://localhost:4200](http://localhost:4200) ## Linter * `npm run lint` @@ -19,7 +19,7 @@ ### Production * `npm run serve` -* in your browser [http://localhost:4000](http://localhost:4000) +* in your browser [http://localhost:4000](http://localhost:4000) ### Author diff --git a/angular/eslint.config.js b/angular/eslint.config.js index 7558b47ec..fd5f218b2 100644 --- a/angular/eslint.config.js +++ b/angular/eslint.config.js @@ -2,7 +2,7 @@ const eslint = require("@eslint/js"); const tseslint = require("typescript-eslint"); const angular = require("angular-eslint"); - + module.exports = tseslint.config( { files: ["**/*.ts"], @@ -37,7 +37,7 @@ module.exports = tseslint.config( "id-length": "error", "newline-before-return": "error", "space-before-blocks": "error", - "no-alert": "error" + "no-alert": "error" }, }, { diff --git a/angular/nginx.conf b/angular/nginx.conf index 544b710f9..064d882d8 100644 --- a/angular/nginx.conf +++ b/angular/nginx.conf @@ -34,4 +34,4 @@ http { } } -} \ No newline at end of file +} diff --git a/angular/package.json b/angular/package.json index d7cf58907..9de9213e8 100644 --- a/angular/package.json +++ b/angular/package.json @@ -42,4 +42,4 @@ "typescript": "5.5.4", "typescript-eslint": "8.2.0" } -} \ No newline at end of file +} diff --git a/angular/server.js b/angular/server.js index ff66ad41f..3747c347f 100644 --- a/angular/server.js +++ b/angular/server.js @@ -12,4 +12,3 @@ const port = 4000; app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) - diff --git a/angular/src/app/app.component.html b/angular/src/app/app.component.html index f51f01c06..85e2f1f57 100644 --- a/angular/src/app/app.component.html +++ b/angular/src/app/app.component.html @@ -259,4 +259,4 @@

Hello, {{ title }}

- \ No newline at end of file + diff --git a/angular/src/index.html b/angular/src/index.html index 2c054d69b..1c8998d77 100644 --- a/angular/src/index.html +++ b/angular/src/index.html @@ -24,4 +24,4 @@ - \ No newline at end of file + diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..09b0de3b8 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,6 @@ +services: + app: + image: ghcr.io/kuwairo/angular-react-starter:latest + restart: on-failure + ports: + - 127.0.0.1:8087:8080 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 000000000..0f2f04e94 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,44 @@ +# Run NGINX in foreground +daemon off; + +pid /tmp/nginx.pid; +worker_processes auto; + +events { + worker_connections 1024; +} + +error_log /var/log/nginx/error.log notice; + +http { + # Change temp paths to work in unprivileged mode + client_body_temp_path /tmp/client_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + proxy_temp_path /tmp/proxy_temp; + scgi_temp_path /tmp/scgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + keepalive_timeout 65; + + server { + listen 8080 default_server; + + location / { + root /usr/share/nginx/html; + index index.html; + + gzip on; + try_files $uri $uri/ =404; + } + } +} diff --git a/node/.dockerignore b/node/.dockerignore index db1a1aa75..1249e7fcd 100644 --- a/node/.dockerignore +++ b/node/.dockerignore @@ -1,3 +1,3 @@ **/node_modules node_modules -dist \ No newline at end of file +dist diff --git a/node/.eslintrc.json b/node/.eslintrc.json index 675cc715a..1c0967f5a 100644 --- a/node/.eslintrc.json +++ b/node/.eslintrc.json @@ -62,4 +62,4 @@ "newline-before-return": "error", "space-before-blocks": "error" } -} \ No newline at end of file +} diff --git a/node/Dockerfile b/node/Dockerfile index 6706aed30..8a6e01e18 100644 --- a/node/Dockerfile +++ b/node/Dockerfile @@ -9,4 +9,4 @@ RUN rm -rf node_modules EXPOSE 5000 -CMD ["node", "dist/app.js"] \ No newline at end of file +CMD ["node", "dist/app.js"] diff --git a/node/README.md b/node/README.md index eb47d7291..dac40a17c 100644 --- a/node/README.md +++ b/node/README.md @@ -12,9 +12,9 @@ * docker run -it node-starter:1.0.0 /bin/bash -* in your browser [http://localhost:5000](http://localhost:5000) +* in your browser [http://localhost:5000](http://localhost:5000) ### Swagger / Api Documentation -* in your browser [http://localhost:5000/api-docs](http://localhost:5000/api-docs) \ No newline at end of file +* in your browser [http://localhost:5000/api-docs](http://localhost:5000/api-docs) diff --git a/node/babel.config.json b/node/babel.config.json index ae719f311..623ee01c5 100644 --- a/node/babel.config.json +++ b/node/babel.config.json @@ -12,4 +12,4 @@ } ] ] -} \ No newline at end of file +} diff --git a/node/swagger.yaml b/node/swagger.yaml index a849063c4..cc98186fe 100644 --- a/node/swagger.yaml +++ b/node/swagger.yaml @@ -1,29 +1,32 @@ openapi: 3.0.0 + info: title: Node Backend Title version: 1.1.1 description: Node Backend Documentation + servers: - url: http://localhost:5000 + paths: /: get: summary: index Summary description: Index Description responses: - "200": + '200': description: responses Index Description /countries: get: summary: Countries Summary description: Countries Description responses: - "200": + '200': description: responses Countries Description /continents: get: summary: Continents Summary description: Continents Description responses: - "200": + '200': description: responses Continents Description diff --git a/react/.eslintrc.json b/react/.eslintrc.json index 29dfeaa01..bc77f9afb 100644 --- a/react/.eslintrc.json +++ b/react/.eslintrc.json @@ -40,4 +40,4 @@ "version": "detect" } } -} \ No newline at end of file +} diff --git a/react/nginx.conf b/react/nginx.conf index ca9adbf52..093817b8b 100644 --- a/react/nginx.conf +++ b/react/nginx.conf @@ -41,4 +41,3 @@ http { } } - diff --git a/react/package.json b/react/package.json index 6c8f54ff5..367b4e636 100644 --- a/react/package.json +++ b/react/package.json @@ -44,4 +44,4 @@ "eslint-plugin-jsx-a11y": "6.9.0", "eslint-plugin-react": "7.35.0" } -} \ No newline at end of file +} diff --git a/react/server.js b/react/server.js index 5c15f6487..1facbed16 100644 --- a/react/server.js +++ b/react/server.js @@ -12,4 +12,3 @@ const port = 3000; app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) - diff --git a/react/src/logo.svg b/react/src/logo.svg index 9dfc1c058..716947603 100644 --- a/react/src/logo.svg +++ b/react/src/logo.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/secrets b/secrets new file mode 100644 index 000000000..939833641 Binary files /dev/null and b/secrets differ