diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..faadfb3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,138 @@ +name: Release + +on: + push: + tags: + - 'v*' # Trigger on version tags like v1.0.0, v0.1.0, etc. + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-release: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.x' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + - name: Build TypeScript + run: npm run build + + - name: Verify build output + run: | + if [ ! -d "dist" ]; then + echo "Error: dist directory not found after build" + exit 1 + fi + echo "Build successful, dist directory contains:" + ls -la dist/ + + - name: Create build artifact + run: | + mkdir -p release-artifacts + tar -czf release-artifacts/odette-${{ github.ref_name }}.tar.gz \ + dist/ \ + views/ \ + public/ \ + package.json \ + package-lock.json \ + README.md \ + LICENSE.txt + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + files: release-artifacts/* + generate_release_notes: true + draft: false + prerelease: ${{ contains(github.ref_name, '-') }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Optional: Publish to Docker Hub + # Uncomment this job and add DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets + # docker-hub: + # runs-on: ubuntu-latest + # needs: build-and-release + # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + # + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v3 + # + # - name: Log in to Docker Hub + # uses: docker/login-action@v3 + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + # + # - name: Extract metadata for Docker + # id: meta + # uses: docker/metadata-action@v5 + # with: + # images: ${{ secrets.DOCKERHUB_USERNAME }}/odette + # tags: | + # type=semver,pattern={{version}} + # type=semver,pattern={{major}}.{{minor}} + # type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }} + # + # - name: Build and push to Docker Hub + # uses: docker/build-push-action@v5 + # with: + # context: . + # push: true + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} + # cache-from: type=gha + # platforms: linux/amd64,linux/arm64 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 837c9a4..f1b6731 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,6 +29,26 @@ npm run dev See [README.md](README.md) for more details. +## Release Process + +Releases are automated via GitHub Actions: + +1. Update version in `package.json` (follow [semantic versioning](https://semver.org/)) +2. Commit the version change +3. Create and push a git tag: + ```bash + git tag -a v0.2.0 -m "Release v0.2.0" + git push origin v0.2.0 + ``` +4. GitHub Actions will automatically: + - Run tests + - Build the application + - Create a GitHub release with build artifacts + - Build and push Docker images to `ghcr.io/cdanis/odette` + - Tag Docker images with the version number (and `latest` for stable releases only) + +Release artifacts include a compressed tarball with the built application files. + ## Code Style - Use TypeScript diff --git a/README.md b/README.md index 6b23d52..1865c4d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,19 @@ npm start ### Docker +**Using pre-built image:** + +```bash +docker run -p 3000:3000 \ + -v /path/to/data:/data \ + -e SMTP_USER=your-email@gmail.com \ + -e SMTP_PASS=your-app-password \ + -e SESSION_SECRET=random-secret-here \ + ghcr.io/cdanis/odette:latest +``` + +**Building locally:** + ```bash docker build -t odette . docker run -p 3000:3000 \ @@ -66,6 +79,8 @@ docker run -p 3000:3000 \ Database and uploaded files persist in the `/data` volume. +Docker images are automatically built and published to GitHub Container Registry on each release. + ## Configuration Environment variables: