diff --git a/.gitea/release-template.md b/.gitea/release-template.md new file mode 100644 index 0000000..a72bb69 --- /dev/null +++ b/.gitea/release-template.md @@ -0,0 +1,26 @@ +## MAILER {{VERSION}} + +Pre-compiled binaries for multiple platforms. + +### Installation + +#### Option 1: Via npm (recommended) +```bash +npm install -g @serve.zone/mailer +``` + +#### Option 2: Direct binary download +Download the appropriate binary for your platform from the assets below and make it executable. + +### Supported Platforms +- Linux x86_64 (x64) +- Linux ARM64 (aarch64) +- macOS x86_64 (Intel) +- macOS ARM64 (Apple Silicon) +- Windows x86_64 + +### Checksums +SHA256 checksums are provided in `SHA256SUMS.txt` for binary verification. + +### npm Package +The npm package includes automatic binary detection and installation for your platform. diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..9c419f8 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,84 @@ +name: CI + +on: + push: + branches: + - main + - 'migration/**' + pull_request: + branches: + - main + +jobs: + check: + name: Type Check & Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Check TypeScript types + run: deno check mod.ts + + - name: Lint code + run: deno lint + continue-on-error: true + + - name: Format check + run: deno fmt --check + continue-on-error: true + + build: + name: Build Test (Current Platform) + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Compile for current platform + run: | + echo "Testing compilation for Linux x86_64..." + deno compile --allow-all --no-check \ + --output mailer-test \ + --target x86_64-unknown-linux-gnu mod.ts + + - name: Test binary execution + run: | + chmod +x mailer-test + ./mailer-test --version + ./mailer-test help + + build-all: + name: Build All Platforms + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Compile all platform binaries + run: bash scripts/compile-all.sh + + - name: Upload all binaries as artifact + uses: actions/upload-artifact@v3 + with: + name: mailer-binaries.zip + path: dist/binaries/* + retention-days: 30 diff --git a/.gitea/workflows/npm-publish.yml b/.gitea/workflows/npm-publish.yml new file mode 100644 index 0000000..d4abc2b --- /dev/null +++ b/.gitea/workflows/npm-publish.yml @@ -0,0 +1,129 @@ +name: Publish to npm + +on: + push: + tags: + - 'v*' + +jobs: + npm-publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Setup Node.js for npm publishing + uses: actions/setup-node@v4 + with: + node-version: '18.x' + registry-url: 'https://registry.npmjs.org/' + + - name: Get version from tag + id: version + run: | + VERSION=${GITHUB_REF#refs/tags/} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT + echo "Publishing version: $VERSION" + + - name: Verify deno.json version matches tag + run: | + DENO_VERSION=$(grep -o '"version": "[^"]*"' deno.json | cut -d'"' -f4) + TAG_VERSION="${{ steps.version.outputs.version_number }}" + echo "deno.json version: $DENO_VERSION" + echo "Tag version: $TAG_VERSION" + if [ "$DENO_VERSION" != "$TAG_VERSION" ]; then + echo "ERROR: Version mismatch!" + echo "deno.json has version $DENO_VERSION but tag is $TAG_VERSION" + exit 1 + fi + + - name: Compile binaries for npm package + run: | + echo "Compiling binaries for npm package..." + deno task compile + echo "" + echo "Binary sizes:" + ls -lh dist/binaries/ + + - name: Generate SHA256 checksums + run: | + cd dist/binaries + sha256sum * > SHA256SUMS + cat SHA256SUMS + cd ../.. + + - name: Sync package.json version + run: | + VERSION="${{ steps.version.outputs.version_number }}" + echo "Syncing package.json to version ${VERSION}..." + npm version ${VERSION} --no-git-tag-version --allow-same-version + echo "package.json version: $(grep '"version"' package.json | head -1)" + + - name: Create npm package + run: | + echo "Creating npm package..." + npm pack + echo "" + echo "Package created:" + ls -lh *.tgz + + - name: Test local installation + run: | + echo "Testing local package installation..." + PACKAGE_FILE=$(ls *.tgz) + npm install -g ${PACKAGE_FILE} + echo "" + echo "Testing mailer command:" + mailer --version || echo "Note: Binary execution may fail in CI environment" + echo "" + echo "Checking installed files:" + npm ls -g @serve.zone/mailer || true + + - name: Publish to npm + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + echo "Publishing to npm registry..." + npm publish --access public + echo "" + echo "✅ Successfully published @serve.zone/mailer to npm!" + echo "" + echo "Package info:" + npm view @serve.zone/mailer + + - name: Verify npm package + run: | + echo "Waiting for npm propagation..." + sleep 30 + echo "" + echo "Verifying published package..." + npm view @serve.zone/mailer + echo "" + echo "Testing installation from npm:" + npm install -g @serve.zone/mailer + echo "" + echo "Package installed successfully!" + which mailer || echo "Binary location check skipped" + + - name: Publish Summary + run: | + echo "================================================" + echo " npm Publish Complete!" + echo "================================================" + echo "" + echo "✅ Package: @serve.zone/mailer" + echo "✅ Version: ${{ steps.version.outputs.version }}" + echo "" + echo "Installation:" + echo " npm install -g @serve.zone/mailer" + echo "" + echo "Registry:" + echo " https://www.npmjs.com/package/@serve.zone/mailer" + echo "" diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..864b213 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,249 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + build-and-release: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v2.x + + - name: Get version from tag + id: version + run: | + VERSION=${GITHUB_REF#refs/tags/} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT + echo "Building version: $VERSION" + + - name: Verify deno.json version matches tag + run: | + DENO_VERSION=$(grep -o '"version": "[^"]*"' deno.json | cut -d'"' -f4) + TAG_VERSION="${{ steps.version.outputs.version_number }}" + echo "deno.json version: $DENO_VERSION" + echo "Tag version: $TAG_VERSION" + if [ "$DENO_VERSION" != "$TAG_VERSION" ]; then + echo "ERROR: Version mismatch!" + echo "deno.json has version $DENO_VERSION but tag is $TAG_VERSION" + exit 1 + fi + + - name: Compile binaries for all platforms + run: | + echo "================================================" + echo " MAILER Release Compilation" + echo " Version: ${{ steps.version.outputs.version }}" + echo "================================================" + echo "" + + # Clean up old binaries and create fresh directory + rm -rf dist/binaries + mkdir -p dist/binaries + echo "→ Cleaned old binaries from dist/binaries" + echo "" + + # Linux x86_64 + echo "→ Compiling for Linux x86_64..." + deno compile --allow-all --no-check \ + --output dist/binaries/mailer-linux-x64 \ + --target x86_64-unknown-linux-gnu mod.ts + echo " ✓ Linux x86_64 complete" + + # Linux ARM64 + echo "→ Compiling for Linux ARM64..." + deno compile --allow-all --no-check \ + --output dist/binaries/mailer-linux-arm64 \ + --target aarch64-unknown-linux-gnu mod.ts + echo " ✓ Linux ARM64 complete" + + # macOS x86_64 + echo "→ Compiling for macOS x86_64..." + deno compile --allow-all --no-check \ + --output dist/binaries/mailer-macos-x64 \ + --target x86_64-apple-darwin mod.ts + echo " ✓ macOS x86_64 complete" + + # macOS ARM64 + echo "→ Compiling for macOS ARM64..." + deno compile --allow-all --no-check \ + --output dist/binaries/mailer-macos-arm64 \ + --target aarch64-apple-darwin mod.ts + echo " ✓ macOS ARM64 complete" + + # Windows x86_64 + echo "→ Compiling for Windows x86_64..." + deno compile --allow-all --no-check \ + --output dist/binaries/mailer-windows-x64.exe \ + --target x86_64-pc-windows-msvc mod.ts + echo " ✓ Windows x86_64 complete" + + echo "" + echo "All binaries compiled successfully!" + ls -lh dist/binaries/ + + - name: Generate SHA256 checksums + run: | + cd dist/binaries + sha256sum * > SHA256SUMS.txt + cat SHA256SUMS.txt + cd ../.. + + - name: Extract changelog for this version + id: changelog + run: | + VERSION="${{ steps.version.outputs.version }}" + + # Check if CHANGELOG.md exists + if [ ! -f CHANGELOG.md ]; then + echo "No CHANGELOG.md found, using default release notes" + cat > /tmp/release_notes.md << EOF + ## MAILER $VERSION + + Pre-compiled binaries for multiple platforms. + + ### Installation + + Use the installation script: + \`\`\`bash + curl -sSL https://code.foss.global/serve.zone/mailer/raw/branch/main/install.sh | sudo bash + \`\`\` + + Or download the binary for your platform and make it executable. + + ### Supported Platforms + - Linux x86_64 (x64) + - Linux ARM64 (aarch64) + - macOS x86_64 (Intel) + - macOS ARM64 (Apple Silicon) + - Windows x86_64 + + ### Checksums + SHA256 checksums are provided in SHA256SUMS.txt + EOF + else + # Try to extract section for this version from CHANGELOG.md + # This is a simple extraction - adjust based on your CHANGELOG format + awk "/## \[$VERSION\]/,/## \[/" CHANGELOG.md | sed '$d' > /tmp/release_notes.md || cat > /tmp/release_notes.md << EOF + ## MAILER $VERSION + + See CHANGELOG.md for full details. + + ### Installation + + Use the installation script: + \`\`\`bash + curl -sSL https://code.foss.global/serve.zone/mailer/raw/branch/main/install.sh | sudo bash + \`\`\` + EOF + fi + + echo "Release notes:" + cat /tmp/release_notes.md + + - name: Delete existing release if it exists + run: | + VERSION="${{ steps.version.outputs.version }}" + + echo "Checking for existing release $VERSION..." + + # Try to get existing release by tag + EXISTING_RELEASE_ID=$(curl -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/mailer/releases/tags/$VERSION" \ + | jq -r '.id // empty') + + if [ -n "$EXISTING_RELEASE_ID" ]; then + echo "Found existing release (ID: $EXISTING_RELEASE_ID), deleting..." + curl -X DELETE -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/mailer/releases/$EXISTING_RELEASE_ID" + echo "Existing release deleted" + sleep 2 + else + echo "No existing release found, proceeding with creation" + fi + + - name: Create Gitea Release + run: | + VERSION="${{ steps.version.outputs.version }}" + RELEASE_NOTES=$(cat /tmp/release_notes.md) + + # Create the release + echo "Creating release for $VERSION..." + RELEASE_ID=$(curl -X POST -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Content-Type: application/json" \ + "https://code.foss.global/api/v1/repos/serve.zone/mailer/releases" \ + -d "{ + \"tag_name\": \"$VERSION\", + \"name\": \"MAILER $VERSION\", + \"body\": $(jq -Rs . /tmp/release_notes.md), + \"draft\": false, + \"prerelease\": false + }" | jq -r '.id') + + echo "Release created with ID: $RELEASE_ID" + + # Upload binaries as release assets + for binary in dist/binaries/*; do + filename=$(basename "$binary") + echo "Uploading $filename..." + curl -X POST -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@$binary" \ + "https://code.foss.global/api/v1/repos/serve.zone/mailer/releases/$RELEASE_ID/assets?name=$filename" + done + + echo "All assets uploaded successfully" + + - name: Clean up old releases + run: | + echo "Cleaning up old releases (keeping only last 3)..." + + # Fetch all releases sorted by creation date + RELEASES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/mailer/releases" | \ + jq -r 'sort_by(.created_at) | reverse | .[3:] | .[].id') + + # Delete old releases + if [ -n "$RELEASES" ]; then + echo "Found releases to delete:" + for release_id in $RELEASES; do + echo " Deleting release ID: $release_id" + curl -X DELETE -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://code.foss.global/api/v1/repos/serve.zone/mailer/releases/$release_id" + done + echo "Old releases deleted successfully" + else + echo "No old releases to delete (less than 4 releases total)" + fi + echo "" + + - name: Release Summary + run: | + echo "================================================" + echo " Release ${{ steps.version.outputs.version }} Complete!" + echo "================================================" + echo "" + echo "Binaries published:" + ls -lh dist/binaries/ + echo "" + echo "Release URL:" + echo "https://code.foss.global/serve.zone/mailer/releases/tag/${{ steps.version.outputs.version }}" + echo "" + echo "Installation command:" + echo "curl -sSL https://code.foss.global/serve.zone/mailer/raw/branch/main/install.sh | sudo bash" + echo "" diff --git a/changelog.md b/changelog.md index bab9120..4b28418 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ # Changelog +## 2025-10-24 - 1.1.0 - feat(ci) +Add CI, release and npm-publish automation; introduce release template and local settings + +- Add CI workflow (.gitea/workflows/ci.yml) to run TypeScript checks, linting, formatting and platform compilation tests +- Add release workflow (.gitea/workflows/release.yml) to compile binaries for multiple platforms, generate checksums, create/update Gitea releases and upload assets +- Add npm publish workflow (.gitea/workflows/npm-publish.yml) to build package from a tag and publish precompiled binaries to npm (tag-triggered) +- Add a Gitea release template (.gitea/release-template.md) describing platforms, checksums and installation options +- Add local tool permission settings (.claude/settings.local.json) used by local tooling +- No API or runtime source changes — this commit is focused on CI/CD, release automation and packaging + ## 2025-10-24 - 1.0.1 - fix(dev) Add local development settings file to grant tooling permissions diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index f0885d5..4d469cc 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/mailer', - version: '1.0.1', + version: '1.1.0', description: 'Enterprise mail server with SMTP, HTTP API, and DNS management - built for serve.zone infrastructure' }