diff --git a/.github/.workflows/docker-publish.yml b/.github/.workflows/docker-publish.yml new file mode 100644 index 0000000..ff8a58e --- /dev/null +++ b/.github/.workflows/docker-publish.yml @@ -0,0 +1,96 @@ +name: Docker + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +on: + push: + branches: [ "master" ] + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} + + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Install the cosign tool except on PR + # https://github.com/sigstore/cosign-installer + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb #v3.8.2 + with: + cosign-release: 'v2.2.4' + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=raw,value=${{ github.run_number }} + + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # Sign the resulting Docker image digest except on PRs. + # This will only write to the public Rekor transparency log when the Docker + # repository is public to avoid leaking data. If you would like to publish + # transparency data even for private images, pass --force to cosign below. + # https://github.com/sigstore/cosign + - name: Sign the published Docker image + if: ${{ github.event_name != 'pull_request' }} + env: + # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + # This step uses the identity token to provision an ephemeral certificate + # against the sigstore community Fulcio instance. + run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} \ No newline at end of file diff --git a/InsightsBackend/Dockerfile b/InsightsBackend/Dockerfile new file mode 100644 index 0000000..0f9a8e4 --- /dev/null +++ b/InsightsBackend/Dockerfile @@ -0,0 +1,20 @@ +FROM maven:3.9.7-eclipse-temurin-21 AS build + +WORKDIR /app + +COPY pom.xml ./ +RUN mvn dependency:go-offline -B + +COPY src ./src + +RUN mvn clean package -DskipTests + +FROM eclipse-temurin:21-jdk-alpine + +WORKDIR /app + +COPY --from=build /app/target/*.jar app.jar + +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=production"] diff --git a/InsightsBackend/pom.xml b/InsightsBackend/pom.xml index e30af42..3402fa4 100644 --- a/InsightsBackend/pom.xml +++ b/InsightsBackend/pom.xml @@ -143,6 +143,7 @@ org.apache.maven.plugins maven-surefire-plugin + --enable-preview local @@ -189,7 +190,6 @@ ${checkstyle.version} checkstyle.xml - UTF-8 true diff --git a/InsightsBackend/src/main/resources/application-local.properties b/InsightsBackend/src/main/resources/application-local.properties index 7063346..de50937 100644 --- a/InsightsBackend/src/main/resources/application-local.properties +++ b/InsightsBackend/src/main/resources/application-local.properties @@ -7,3 +7,6 @@ spring.datasource.password=postgres github.secret=dummytoken github.fetch=false github.projectId= + +cors.allowed.origins[0]=http://localhost:4200 +cors.allowed.origins[1]=http://localhost diff --git a/InsightsBackend/src/main/resources/application-production.properties b/InsightsBackend/src/main/resources/application-production.properties index f4cf918..2b48c9a 100644 --- a/InsightsBackend/src/main/resources/application-production.properties +++ b/InsightsBackend/src/main/resources/application-production.properties @@ -8,3 +8,6 @@ spring.datasource.password=${DATABASE_PASSWORD} github.secret=${GITHUB_API_SECRET} github.fetch=true github.projectId=${GITHUB_PROJECT_ID} + +cors.allowed.origins[0]=http://localhost +cors.allowed.origins[1]=https://insights.frankframework.org diff --git a/InsightsBackend/src/main/resources/application.properties b/InsightsBackend/src/main/resources/application.properties index d9fa8af..69547b2 100644 --- a/InsightsBackend/src/main/resources/application.properties +++ b/InsightsBackend/src/main/resources/application.properties @@ -3,7 +3,8 @@ spring.application.name=insights spring.jpa.show-sql=true spring.datasource.driver-class-name=org.postgresql.Driver -spring.datasource.hikari.auto-commit=false + +spring.sql.init.mode=always github.url=https://api.github.com/graphql github.branchProtectionRegexes[0]=master @@ -12,5 +13,3 @@ github.priorityLabels[0]=FEF2C0 github.priorityLabels[1]=D4C5F9 github.priorityLabels[2]=006B75 github.ignoredLabels[0]=FBCA04 - -cors.allowed.origins=http://localhost:4200 diff --git a/InsightsFrontend/Dockerfile b/InsightsFrontend/Dockerfile new file mode 100644 index 0000000..801bbfe --- /dev/null +++ b/InsightsFrontend/Dockerfile @@ -0,0 +1,17 @@ +FROM node:23-alpine AS build + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +FROM nginx:alpine + +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/InsightsFrontend/angular.json b/InsightsFrontend/angular.json index 64e5dba..a657d95 100644 --- a/InsightsFrontend/angular.json +++ b/InsightsFrontend/angular.json @@ -56,7 +56,13 @@ "development": { "optimization": false, "extractLicenses": false, - "sourceMap": true + "sourceMap": true, + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.development.ts" + } + ] } }, "defaultConfiguration": "production" diff --git a/InsightsFrontend/src/app/app.service.ts b/InsightsFrontend/src/app/app.service.ts index 5c4126c..6d8a95c 100644 --- a/InsightsFrontend/src/app/app.service.ts +++ b/InsightsFrontend/src/app/app.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; import { Observable } from 'rxjs'; import { TimeSpanParameters } from './services/issue.service'; +import { environment } from '../environments/environment.development'; export const GitHubStates = { OPEN: 0, @@ -15,9 +16,9 @@ export type GitHubState = (typeof GitHubStates)[keyof typeof GitHubStates]; providedIn: 'root', }) export class AppService { - private static readonly API_BASE_URL: string = 'http://localhost:8080/api'; + private static readonly API_BASE_URL: string = environment.backendUrl; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) { } /** * Performs a GET request to the given URL with optional query parameters. diff --git a/InsightsFrontend/src/environments/environment.development.ts b/InsightsFrontend/src/environments/environment.development.ts new file mode 100644 index 0000000..2f2657e --- /dev/null +++ b/InsightsFrontend/src/environments/environment.development.ts @@ -0,0 +1,3 @@ +export const environment = { + backendUrl: "http://localhost:8080/api" +}; diff --git a/InsightsFrontend/src/environments/environment.ts b/InsightsFrontend/src/environments/environment.ts new file mode 100644 index 0000000..77ebaac --- /dev/null +++ b/InsightsFrontend/src/environments/environment.ts @@ -0,0 +1,3 @@ +export const environment = { + backendUrl: "http://backend:8080/api" +}; diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..16a3113 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,55 @@ +services: + frontend: + build: ./InsightsFrontend + # image: ghcr.io/frankframework/insights:${VERSION:-frontend} + restart: always + volumes: + - ./InsightsFrontend/dist/insights-frontend/browser:/usr/share/nginx/html + networks: + - FFInsightsNetwork + depends_on: + - backend + ports: + - "80:80" + container_name: frontend + + backend: + build: ./InsightsBackend + # image: ghcr.io/frankframework/insights:${VERSION:-backend} + restart: always + environment: + SPRING_PROFILES_ACTIVE: production + DATABASE_HOST: db + DATABASE_PORT: 5432 + DATABASE_NAME: insights + DATABASE_USERNAME: postgres + DATABASE_PASSWORD: postgres + GITHUB_API_SECRET: dummytoken + networks: + - FFInsightsNetwork + depends_on: + - db + ports: + - "8080:8080" + container_name: backend + + db: + image: postgres:17 + restart: always + environment: + POSTGRES_DB: insights + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + volumes: + - pg-data:/var/lib/postgresql/data + networks: + - FFInsightsNetwork + ports: + - "5432:5432" + +networks: + FFInsightsNetwork: + driver: bridge + +volumes: + pg-data: