diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ee0decf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +name: CI - Build and Test + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +permissions: # ADD THIS BLOCK + contents: read # ADD + packages: write # ADD + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build the Docker image + run: docker build -t tutorial-app:ci . + + - name: Create a shared network + run: docker network create test-net + + - name: Start a PostgreSQL database + run: | + docker run -d --name test-db --network test-net \ + -e POSTGRES_USER=tutorial_user \ + -e POSTGRES_PASSWORD=tutorial_password \ + -e POSTGRES_DB=tutorial_db \ + postgres:15-alpine + + - name: Wait for the database to be ready + run: | + for i in $(seq 1 30); do + if docker exec test-db pg_isready -U tutorial_user; then + echo "Database is ready!" + break + fi + echo "Waiting for database... ($i)" + sleep 2 + done + + - name: Run the app container + run: | + docker run -d --name test-app --network test-net \ + -e DB_HOST=test-db \ + -e DB_USER=tutorial_user \ + -e DB_PASSWORD=tutorial_password \ + -e DB_NAME=tutorial_db \ + -p 8080:8080 \ + tutorial-app:ci + + - name: Wait for the app to start + run: sleep 15 + + - name: Health check (the actual test) + run: | + curl --fail http://localhost:8080/api/tutorials || exit 1 + echo "API is responding correctly!" + + # ===== NEW: publish image to GHCR ===== + - name: Log in to GitHub Container Registry + if: github.event_name == 'push' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set lowercase image name + if: github.event_name == 'push' + run: echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV + + - name: Push image to GHCR + if: github.event_name == 'push' + run: | + docker tag tutorial-app:ci $IMAGE:latest + docker tag tutorial-app:ci $IMAGE:${{ github.sha }} + docker push $IMAGE:latest + docker push $IMAGE:${{ github.sha }} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6c2ff60 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "master" + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8877fbc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM node:18-alpine + +WORKDIR /app + +COPY package*.json ./ + +RUN npm install --production + +COPY . . + +ENV NODE_ENV=production +ENV PORT=8080 + +EXPOSE 8080 + +CMD ["node", "server.js"] diff --git a/app/config/db.config.js b/app/config/db.config.js index 64ba9c5..f187962 100644 --- a/app/config/db.config.js +++ b/app/config/db.config.js @@ -1,8 +1,8 @@ module.exports = { - HOST: "localhost", - USER: "postgres", - PASSWORD: "123", - DB: "testdb", + HOST: process.env.DB_HOST || "localhost", + USER: process.env.DB_USER || "postgres", + PASSWORD: process.env.DB_PASSWORD || "123456", + DB: process.env.DB_NAME || "testdb", dialect: "postgres", pool: { max: 5, diff --git a/app/routes/turorial.routes.js b/app/routes/turorial.routes.js index 674d3aa..fa40fd0 100644 --- a/app/routes/turorial.routes.js +++ b/app/routes/turorial.routes.js @@ -6,6 +6,9 @@ module.exports = app => { // Create a new Tutorial router.post("/", tutorials.create); + // Create a new Tutorial + router.post("/health", tutorials.create); + // Retrieve all Tutorials router.get("/", tutorials.findAll); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6d450f1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ + +services: + backend: + build: . + container_name: tutorial-api + ports: + - "8080:8080" + environment: + DB_HOST: postgres + DB_USER: tutorial_user + DB_PASSWORD: tutorial_password + DB_NAME: tutorial_db + DB_PORT: 5432 + depends_on: + - postgres + + postgres: + image: postgres:15-alpine + container_name: tutorial-db + environment: + POSTGRES_USER: tutorial_user + POSTGRES_PASSWORD: tutorial_password + POSTGRES_DB: tutorial_db + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: + diff --git a/render.yaml b/render.yaml new file mode 100644 index 0000000..493391f --- /dev/null +++ b/render.yaml @@ -0,0 +1,31 @@ +services: + - type: web + name: tutorial-api + runtime: docker + dockerfilePath: ./Dockerfile + plan: free + envVars: + - key: DB_HOST + fromDatabase: + name: tutorial-db + property: host + - key: DB_PORT + fromDatabase: + name: tutorial-db + property: port + - key: DB_USER + fromDatabase: + name: tutorial-db + property: user + - key: DB_PASSWORD + fromDatabase: + name: tutorial-db + property: password + - key: DB_NAME + fromDatabase: + name: tutorial-db + property: database + +databases: + - name: tutorial-db + plan: free