Automation & CI/CD
Logsmith is designed for automation-first workflows. Integrate changelog generation seamlessly into your CI/CD pipelines, release processes, and development workflows.
Overview
Logsmith excels in automated environments because it:
- Runs headless without user interaction
- Provides consistent output across environments
- Supports multiple formats for different consumers
- Handles errors gracefully with proper exit codes
- Includes verbose logging for debugging automation issues
GitHub Actions
Basic Changelog Generation
yaml
# .github/workflows/changelog.yml
name: Generate Changelog
on:
push:
tags: ['v*']
jobs:
changelog:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Generate Changelog
run: |
bun add -g logsmith
logsmith --theme github --output CHANGELOG.md
- name: Commit Changes
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add CHANGELOG.md
git commit -m "docs: update changelog" || exit 0
git push
Release Workflow
Complete release workflow with changelog generation:
yaml
# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Install Dependencies
run: |
bun install
bun add -g logsmith
- name: Extract Version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Generate Release Changelog
run: |
# Generate changelog for this release only
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -n "$PREVIOUS_TAG" ]; then
logsmith --from "$PREVIOUS_TAG" --to "${{ steps.version.outputs.VERSION }}" \
--theme github --format markdown --output RELEASE_NOTES.md
else
logsmith --to "${{ steps.version.outputs.VERSION }}" \
--theme github --format markdown --output RELEASE_NOTES.md
fi
- name: Update Full Changelog
run: |
logsmith --theme github --output CHANGELOG.md
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add CHANGELOG.md
git commit -m "docs: update changelog for ${{ steps.version.outputs.VERSION }}" || exit 0
git push origin HEAD:main
- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.version.outputs.VERSION }}
release_name: Release ${{ steps.version.outputs.VERSION }}
body_path: RELEASE_NOTES.md
draft: false
prerelease: false
Pull Request Previews
Generate changelog previews for pull requests:
yaml
# .github/workflows/pr-changelog.yml
name: PR Changelog Preview
on:
pull_request:
types: [opened, synchronize]
jobs:
preview:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Install logsmith
run: bun add -g logsmith
- name: Generate Preview
id: changelog
run: |
# Generate changelog for commits in this PR
BASE_SHA=${{ github.event.pull_request.base.sha }}
HEAD_SHA=${{ github.event.pull_request.head.sha }}
logsmith --from "$BASE_SHA" --to "$HEAD_SHA" \
--theme github --no-output > changelog_preview.md || echo "No conventional commits found" > changelog_preview.md
- name: Comment PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const changelog = fs.readFileSync('changelog_preview.md', 'utf8');
const body = `## 📋 Changelog Preview
Changes that would be included in the next release:
${changelog}
<sub>Generated by logsmith</sub>`;
// Update existing comment or create new one
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' && comment.body.includes('📋 Changelog Preview')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
Repository Statistics
Automated repository insights and reporting:
yaml
# .github/workflows/stats.yml
name: Repository Statistics
on:
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
workflow_dispatch:
jobs:
stats:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Install logsmith
run: bun add -g logsmith
- name: Generate Statistics
run: |
# Generate stats for last week
logsmith stats --from "1 week ago" --json > weekly-stats.json
logsmith stats --from "1 week ago" > weekly-stats.txt
# Generate stats for last month
logsmith stats --from "1 month ago" --json > monthly-stats.json
logsmith stats --from "1 month ago" > monthly-stats.txt
- name: Create Issue Report
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const weeklyStats = fs.readFileSync('weekly-stats.txt', 'utf8');
const date = new Date().toISOString().split('T')[0];
const body = `# 📊 Weekly Repository Statistics - ${date}
## Summary
${weeklyStats}
## 📈 Trends
- View detailed trends in the [monthly report]
- Compare with [previous weeks]
<sub>Automated report generated by logsmith</sub>`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `📊 Weekly Stats Report - ${date}`,
body: body,
labels: ['statistics', 'automated']
});
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: repository-statistics
path: |
weekly-stats.json
weekly-stats.txt
monthly-stats.json
monthly-stats.txt
GitLab CI/CD
Basic Pipeline
yaml
# .gitlab-ci.yml
stages:
- generate
- deploy
variables:
BUN_VERSION: 1.2.0
generate-changelog:
stage: generate
image: oven/bun:${BUN_VERSION}
before_script:
- bun add -g logsmith
script:
- logsmith --theme github --output CHANGELOG.md
- logsmith stats --json > stats.json
artifacts:
paths:
- CHANGELOG.md
- stats.json
expire_in: 1 week
only:
- tags
- main
release-notes:
stage: generate
image: oven/bun:${BUN_VERSION}
before_script:
- bun add -g logsmith
script:
- |
if [ -n "$CI_COMMIT_TAG" ]; then
# Generate release notes for this tag
PREVIOUS_TAG=$(git describe --tags --abbrev=0 $CI_COMMIT_TAG~1 2>/dev/null || echo "")
if [ -n "$PREVIOUS_TAG" ]; then
logsmith --from "$PREVIOUS_TAG" --to "$CI_COMMIT_TAG" \
--theme github --format markdown --output RELEASE_NOTES.md
else
logsmith --to "$CI_COMMIT_TAG" \
--theme github --format markdown --output RELEASE_NOTES.md
fi
fi
artifacts:
paths:
- RELEASE_NOTES.md
expire_in: 1 day
only:
- tags
Jenkins Pipeline
Declarative Pipeline
groovy
// Jenkinsfile
pipeline {
agent any
environment {
BUN_VERSION = '1.2.0'
}
stages {
stage('Setup') {
steps {
// Install Bun
sh '''
curl -fsSL https://bun.sh/install | bash
export PATH="$HOME/.bun/bin:$PATH"
bun add -g logsmith
'''
}
}
stage('Generate Changelog') {
when {
anyOf {
tag 'v*'
branch 'main'
}
}
steps {
sh '''
export PATH="$HOME/.bun/bin:$PATH"
logsmith --theme corporate --output CHANGELOG.md --verbose
'''
archiveArtifacts artifacts: 'CHANGELOG.md', fingerprint: true
}
}
stage('Repository Statistics') {
steps {
sh '''
export PATH="$HOME/.bun/bin:$PATH"
logsmith stats --json > repository-stats.json
logsmith stats > repository-stats.txt
'''
archiveArtifacts artifacts: 'repository-stats.*', fingerprint: true
// Publish stats to external system
script {
def stats = readJSON file: 'repository-stats.json'
echo "Total commits: ${stats.totalCommits}"
echo "Contributors: ${stats.contributors}"
}
}
}
stage('Release') {
when {
tag 'v*'
}
steps {
sh '''
export PATH="$HOME/.bun/bin:$PATH"
# Generate release notes
PREVIOUS_TAG=$(git describe --tags --abbrev=0 ${TAG_NAME}~1 2>/dev/null || echo "")
if [ -n "$PREVIOUS_TAG" ]; then
logsmith --from "$PREVIOUS_TAG" --to "${TAG_NAME}" \
--theme github --format markdown --output RELEASE_NOTES.md
fi
'''
// Create GitHub release
script {
def releaseNotes = readFile 'RELEASE_NOTES.md'
// Use GitHub API or plugin to create release
}
}
}
}
post {
always {
cleanWs()
}
success {
// Notify team of successful changelog generation
slackSend(
channel: '#dev-notifications',
message: "✅ Changelog generated successfully for ${env.BUILD_TAG}"
)
}
failure {
slackSend(
channel: '#dev-notifications',
message: "❌ Changelog generation failed for ${env.BUILD_TAG}"
)
}
}
}
Docker Integration
Dockerfile for Automation
dockerfile
# Dockerfile.logsmith
FROM oven/bun:1.2.0-alpine
WORKDIR /app
# Install logsmith globally
RUN bun add -g logsmith
# Copy git repository (or mount as volume)
COPY . .
# Default command
CMD ["logsmith", "--help"]
Docker Compose for Development
yaml
# docker-compose.yml
version: '3.8'
services:
changelog:
build:
context: .
dockerfile: Dockerfile.logsmith
volumes:
- .:/app
- ./output:/output
environment:
- LOGSMITH_OUTPUT=/output/CHANGELOG.md
- LOGSMITH_THEME=github
command: logsmith --output /output/CHANGELOG.md --theme github --verbose
stats:
build:
context: .
dockerfile: Dockerfile.logsmith
volumes:
- .:/app
- ./output:/output
command: logsmith stats --json --output /output/stats.json
multi-format:
build:
context: .
dockerfile: Dockerfile.logsmith
volumes:
- .:/app
- ./output:/output
command: >
sh -c "
logsmith --output /output/CHANGELOG.md --theme github &&
logsmith --output /output/changelog.json --format json &&
logsmith --output /output/changelog.html --format html --theme colorful
"
Custom Automation Scripts
Pre-commit Hook
bash
#!/bin/bash
# .git/hooks/pre-commit
# Generate changelog preview for staging area
if command -v logsmith >/dev/null 2>&1; then
echo "Generating changelog preview..."
# Check if there are conventional commits
if git log --oneline | grep -E "^[a-f0-9]+\s+(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\(.+\))?:" >/dev/null; then
logsmith --no-output --verbose 2>&1 | head -20
echo ""
echo "💡 Tip: Your changes will appear in the next changelog!"
fi
fi
exit 0
Release Script
bash
#!/bin/bash
# scripts/release.sh
set -e
# Configuration
THEME="github"
CHANGELOG_FILE="CHANGELOG.md"
RELEASE_NOTES_FILE="RELEASE_NOTES.md"
# Check if logsmith is installed
if ! command -v logsmith >/dev/null 2>&1; then
echo "❌ logsmith not found. Installing..."
bun add -g logsmith
fi
# Get version from tag or ask user
if [ -z "$1" ]; then
echo "Usage: $0 <version-tag>"
echo "Example: $0 v1.2.0"
exit 1
fi
VERSION_TAG="$1"
echo "🚀 Preparing release $VERSION_TAG"
# Generate full changelog
echo "📝 Generating full changelog..."
logsmith --theme "$THEME" --output "$CHANGELOG_FILE" --verbose
# Generate release notes for this version
echo "📋 Generating release notes..."
PREVIOUS_TAG=$(git describe --tags --abbrev=0 "$VERSION_TAG"~1 2>/dev/null || echo "")
if [ -n "$PREVIOUS_TAG" ]; then
echo "📈 Changes from $PREVIOUS_TAG to $VERSION_TAG"
logsmith --from "$PREVIOUS_TAG" --to "$VERSION_TAG" \
--theme "$THEME" --output "$RELEASE_NOTES_FILE" --verbose
else
echo "📈 All changes up to $VERSION_TAG"
logsmith --to "$VERSION_TAG" \
--theme "$THEME" --output "$RELEASE_NOTES_FILE" --verbose
fi
# Commit changelog
echo "💾 Committing changelog..."
git add "$CHANGELOG_FILE"
git commit -m "docs: update changelog for $VERSION_TAG" || echo "No changelog changes to commit"
# Show release notes
echo ""
echo "📋 Release Notes Preview:"
echo "========================="
cat "$RELEASE_NOTES_FILE"
echo ""
echo "✅ Release preparation complete!"
echo ""
echo "Next steps:"
echo "1. Review the generated files: $CHANGELOG_FILE, $RELEASE_NOTES_FILE"
echo "2. Push changes: git push"
echo "3. Create and push tag: git tag $VERSION_TAG && git push origin $VERSION_TAG"
echo "4. Create GitHub release with notes from $RELEASE_NOTES_FILE"
Monorepo Automation
bash
#!/bin/bash
# scripts/monorepo-changelogs.sh
# Generate changelogs for each package in a monorepo
set -e
PACKAGES_DIR="packages"
THEME="minimal"
echo "🏗️ Generating changelogs for monorepo packages..."
# Find all packages
for package_dir in "$PACKAGES_DIR"/*; do
if [ -d "$package_dir" ] && [ -f "$package_dir/package.json" ]; then
package_name=$(basename "$package_dir")
echo ""
echo "📦 Processing package: $package_name"
# Generate package-specific changelog
logsmith --dir "$package_dir" \
--output "$package_dir/CHANGELOG.md" \
--theme "$THEME" \
--include-scopes "$package_name" \
--verbose
# Generate package statistics
logsmith stats --dir "$package_dir" \
--json > "$package_dir/stats.json"
echo "✅ Completed $package_name"
fi
done
# Generate root changelog
echo ""
echo "📋 Generating root changelog..."
logsmith --output CHANGELOG.md --theme "$THEME" --verbose
echo ""
echo "✅ All monorepo changelogs generated!"
Environment Configuration
Environment Variables
Configure logsmith behavior through environment variables:
bash
# Set default theme
export LOGSMITH_THEME="corporate"
# Set default output format
export LOGSMITH_FORMAT="markdown"
# Set verbosity level
export LOGSMITH_VERBOSE="true"
# Set default exclude authors
export LOGSMITH_EXCLUDE_AUTHORS="dependabot[bot],renovate[bot]"
# GitHub token for enhanced features
export GITHUB_TOKEN="ghp_your_token_here"
Configuration for CI
typescript
// logsmith.config.ci.ts
import { defineConfig } from 'logsmith'
export default defineConfig({
theme: 'corporate',
verbose: process.env.CI_DEBUG === 'true',
excludeAuthors: ['dependabot[bot]', 'renovate[bot]'],
repo: process.env.GITHUB_REPOSITORY
? `https://github.com/${process.env.GITHUB_REPOSITORY}`
: undefined,
})
Best Practices for Automation
General Guidelines
- Always fetch full Git history in CI/CD (use
fetch-depth: 0
) - Pin logsmith version for reproducible builds
- Use configuration files instead of CLI arguments for complex setups
- Implement proper error handling and notifications
- Cache dependencies when possible to speed up builds
- Test automation locally before deploying to CI/CD
Security Considerations
- Protect GitHub tokens and other secrets
- Use least-privilege permissions for automation accounts
- Validate inputs and sanitize outputs
- Audit automation logs for security issues
- Rotate tokens regularly and monitor usage
Performance Optimization
- Use specific Git ranges instead of full history when possible
- Filter out unnecessary commits early
- Parallelize multiple format generation
- Cache Git operations when running multiple logsmith commands
- Use appropriate verbosity levels (verbose only for debugging)
Next Steps
- Learn about cross-platform compatibility for deployment considerations
- Explore theming options for automation-friendly styles
- Check repository insights for automated reporting
- Review the API reference for programmatic automation