Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Dependencies
node_modules
npm-debug.log

# Git
.git
.gitignore
.github

# Build outputs
dist/index.js
dist/index.js.map

# Development
.vscode
.idea

# Testing
coverage
test

# Documentation
README.md
LICENSE

# Misc
*.md
.DS_Store
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# API Configuration
# The base URL for the Purdue.io API
API_URL=https://api.purdue.io/odata
46 changes: 46 additions & 0 deletions .github/workflows/docker-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Docker PR Verification

on:
pull_request:
branches: [ main ]
paths:
- 'Dockerfile'
- 'docker-compose.yml'
- 'nginx.conf'
- '.dockerignore'
- 'src/**'
- 'package*.json'
- 'webpack.config.js'
- 'tsconfig.json'

jobs:
verify:
name: Verify Docker Build
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: false
load: true
tags: purdueio-browser:pr-${{ github.event.pull_request.number }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Test image runs
run: |
docker run -d --name test-container -p 8080:80 purdueio-browser:pr-${{ github.event.pull_request.number }}
sleep 5
curl -f http://localhost:8080 || exit 1
docker stop test-container
58 changes: 58 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Docker Publish

on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Tag to build and push'
required: true
default: 'latest'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
24 changes: 13 additions & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,28 @@ on:
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Checkout code
uses: actions/checkout@v4

- name: Use Node.js 14.x
uses: actions/setup-node@v1
- name: Use Node.js 18.x
uses: actions/setup-node@v4
with:
node-version: 14.x
node-version: 18.x
cache: 'npm'

- name: Restore Packages
run: npm install
- name: Install dependencies
run: npm ci

- name: Build and Publish
- name: Build
run: npm run publish

- name: Test
run: npm run test

- name: Upload Artifact
uses: actions/upload-artifact@v2
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: Browser
path: dist
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/index.js
dist/index.js.map
node_modules
node_modules
.env
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Stage 1: Build the application
FROM node:18-alpine AS builder

# Build argument for API URL
ARG API_URL=https://api.purdue.io/odata

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production=false

# Copy source code
COPY . .

# Build the application with API_URL environment variable
ENV API_URL=${API_URL}
RUN npm run publish

# Stage 2: Serve with nginx
FROM nginx:alpine

# Copy nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy built application from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html

# Expose port 80
EXPOSE 80

# Start nginx
CMD ["nginx", "-g", "daemon off;"]
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: '3.8'

services:
web:
build:
context: .
dockerfile: Dockerfile
args:
- API_URL=${API_URL:-https://api.purdue.io/odata}
ports:
- "8080:80"
restart: unless-stopped
container_name: purdueio-browser
28 changes: 28 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;

# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

# Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

# SPA fallback - serve index.html for all routes
location / {
try_files $uri $uri/ /index.html;
}
}
3 changes: 2 additions & 1 deletion src/ts/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export class Application

public static run(): Application
{
let dataSource = new PurdueApiDataSource("https://api.purdue.io/odata");
const apiUrl = process.env.API_URL || "https://api.purdue.io/odata";
let dataSource = new PurdueApiDataSource(apiUrl);
let returnVal = new Application(dataSource);
returnVal.start();
return returnVal;
Expand Down
8 changes: 7 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require('path');
const webpack = require('webpack');

var config = {
entry: './src/index.ts',
Expand All @@ -18,7 +19,12 @@ var config = {
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
}
},
plugins: [
new webpack.DefinePlugin({
'process.env.API_URL': JSON.stringify(process.env.API_URL || 'https://api.purdue.io/odata')
})
]
};

module.exports = (env, argv) => {
Expand Down