From 454b9164eeef8b27ccee2cdaa29272e02739ca75 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 27 Dec 2025 10:32:18 +0000 Subject: [PATCH 1/3] Add GitHub Actions workflows for CI and publishing - CI workflow runs tests on push to main and PRs - Tests run on multiple Elixir/OTP versions - Includes formatting check and compilation warnings check - Publish workflow publishes to Hex.pm on merge to main --- .github/workflows/ci.yml | 48 +++++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 39 ++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a3473d8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Test (Elixir ${{ matrix.elixir }} / OTP ${{ matrix.otp }}) + runs-on: ubuntu-latest + + strategy: + matrix: + elixir: ['1.14', '1.15', '1.16'] + otp: ['25', '26'] + exclude: + - elixir: '1.14' + otp: '26' + + steps: + - uses: actions/checkout@v4 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.elixir }} + otp-version: ${{ matrix.otp }} + + - name: Restore dependencies cache + uses: actions/cache@v4 + with: + path: deps + key: ${{ runner.os }}-mix-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix-${{ matrix.otp }}-${{ matrix.elixir }}- + + - name: Install dependencies + run: mix deps.get + + - name: Check formatting + run: mix format --check-formatted + + - name: Run tests + run: mix test + + - name: Check compilation warnings + run: mix compile --warnings-as-errors diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..6708b25 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,39 @@ +name: Publish to Hex.pm + +on: + push: + branches: [main] + +jobs: + publish: + name: Publish to Hex.pm + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + + steps: + - uses: actions/checkout@v4 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: '1.16' + otp-version: '26' + + - name: Restore dependencies cache + uses: actions/cache@v4 + with: + path: deps + key: ${{ runner.os }}-mix-26-1.16-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix-26-1.16- + + - name: Install dependencies + run: mix deps.get + + - name: Run tests + run: mix test + + - name: Publish to Hex + env: + HEX_API_KEY: ${{ secrets.HEX_API_KEY }} + run: | + mix hex.publish --yes From e2c3d1b4cab7e24dc526ac93219ce5f30963c538 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 27 Dec 2025 10:51:02 +0000 Subject: [PATCH 2/3] Add release automation and documentation - Add [Unreleased] section to CHANGELOG with HTTP client changes - Create scripts/release.sh for automated version bumps - Update publish workflow to trigger on version tags (v*.*.*) instead of main pushes - Add CONTRIBUTING.md with development and release process documentation --- .github/workflows/publish.yml | 4 +- CHANGELOG.md | 14 ++++ CONTRIBUTING.md | 153 ++++++++++++++++++++++++++++++++++ scripts/release.sh | 119 ++++++++++++++++++++++++++ 4 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100755 scripts/release.sh diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6708b25..f8f7971 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,13 +2,13 @@ name: Publish to Hex.pm on: push: - branches: [main] + tags: + - 'v*.*.*' jobs: publish: name: Publish to Hex.pm runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f183b9..bb42c94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- **Automatic HTTP retries** - `FYI.Client` module with exponential backoff for sink delivery + - Retries transient failures (network errors, 5xx status codes) up to 3 times + - Exponential backoff with delays of 1s, 2s, 4s + - Respects `Retry-After` response headers + - Configurable via `:http_client` config (max_retries, retry_delay) + +### Changed + +- Sinks now use `FYI.Client.post/2` for HTTP requests instead of raw `Req.post/2` + ## [1.0.0] - 2024-12-26 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..46a25d1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,153 @@ +# Contributing to FYI + +Thank you for your interest in contributing to FYI! This guide will help you get started. + +## Development Setup + +1. **Clone the repository** + ```bash + git clone https://github.com/chrisgreg/fyi.git + cd fyi + ``` + +2. **Install dependencies** + ```bash + mix deps.get + ``` + +3. **Run tests** + ```bash + mix test + ``` + +4. **Check formatting** + ```bash + mix format --check-formatted + ``` + +## Making Changes + +1. **Create a branch** for your changes + ```bash + git checkout -b your-feature-name + ``` + +2. **Make your changes** and write tests + +3. **Update the CHANGELOG** + - Add your changes to the `[Unreleased]` section in `CHANGELOG.md` + - Use the existing format: `- **Feature name** - Description` + - Categorize under `### Added`, `### Changed`, `### Fixed`, or `### Removed` + +4. **Ensure tests pass and code is formatted** + ```bash + mix test + mix format + ``` + +5. **Commit your changes** + ```bash + git add . + git commit -m "Add feature X" + ``` + +6. **Push and create a pull request** + ```bash + git push origin your-feature-name + ``` + +## Release Process + +> **Note**: Only maintainers can create releases. + +Releases are managed using semantic versioning (MAJOR.MINOR.PATCH): +- **PATCH** (1.0.1): Bug fixes, no breaking changes +- **MINOR** (1.1.0): New features, backwards compatible +- **MAJOR** (2.0.0): Breaking changes + +### Steps to Release + +1. **Ensure you're on main with latest changes** + ```bash + git checkout main + git pull origin main + ``` + +2. **Verify the CHANGELOG has an [Unreleased] section with changes** + - Check that all changes since the last release are documented + - Ensure changes are categorized properly (Added/Changed/Fixed/Removed) + +3. **Run the release script** + ```bash + ./scripts/release.sh patch # For bug fixes (1.0.0 -> 1.0.1) + ./scripts/release.sh minor # For new features (1.0.0 -> 1.1.0) + ./scripts/release.sh major # For breaking changes (1.0.0 -> 2.0.0) + ``` + + The script will: + - Bump the version in `mix.exs` + - Move `[Unreleased]` to the new version with today's date in `CHANGELOG.md` + - Create a new empty `[Unreleased]` section + - Commit the changes + - Create a git tag (e.g., `v1.0.1`) + +4. **Review the changes** + ```bash + git show # Review the commit + git show v1.0.1 # Review the tag + ``` + +5. **Push to GitHub** (this triggers the publish workflow) + ```bash + git push origin main --tags + ``` + +6. **GitHub Actions will automatically**: + - Run the full test suite + - Publish the new version to Hex.pm (using the `HEX_API_KEY` secret) + +### If Something Goes Wrong + +If you need to undo a release before pushing: + +```bash +git reset --hard HEAD~1 # Undo the commit +git tag -d v1.0.1 # Delete the tag +``` + +If you already pushed, you'll need to: +1. Yank the version from Hex.pm if it was published +2. Delete the tag from GitHub +3. Revert the commit + +### First-Time Release Setup + +The `HEX_API_KEY` secret must be configured in GitHub: + +1. Generate a Hex API key: + ```bash + mix hex.user key generate + ``` + +2. Add it to GitHub: + - Go to repository Settings → Secrets and variables → Actions + - Click "New repository secret" + - Name: `HEX_API_KEY` + - Value: Your generated key + +## Code Style + +- Follow the existing code style +- Run `mix format` before committing +- Write descriptive commit messages +- Add tests for new features +- Update documentation as needed + +## Questions? + +If you have questions or need help, feel free to: +- Open an issue +- Start a discussion +- Reach out to the maintainers + +Thank you for contributing! 🎉 diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..e95d190 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,119 @@ +#!/bin/bash +set -e + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Get current version from mix.exs +CURRENT_VERSION=$(grep '@version' mix.exs | sed 's/.*"\(.*\)".*/\1/') + +echo -e "${GREEN}Current version: ${CURRENT_VERSION}${NC}" +echo "" + +# Parse version +IFS='.' read -r -a VERSION_PARTS <<< "$CURRENT_VERSION" +MAJOR="${VERSION_PARTS[0]}" +MINOR="${VERSION_PARTS[1]}" +PATCH="${VERSION_PARTS[2]}" + +# Determine new version based on argument +case "${1:-}" in + major) + NEW_MAJOR=$((MAJOR + 1)) + NEW_VERSION="${NEW_MAJOR}.0.0" + ;; + minor) + NEW_MINOR=$((MINOR + 1)) + NEW_VERSION="${MAJOR}.${NEW_MINOR}.0" + ;; + patch) + NEW_PATCH=$((PATCH + 1)) + NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" + ;; + *) + echo -e "${RED}Usage: $0 {major|minor|patch}${NC}" + echo "" + echo "Examples:" + echo " $0 patch # ${CURRENT_VERSION} -> ${MAJOR}.${MINOR}.$((PATCH + 1))" + echo " $0 minor # ${CURRENT_VERSION} -> ${MAJOR}.$((MINOR + 1)).0" + echo " $0 major # ${CURRENT_VERSION} -> $((MAJOR + 1)).0.0" + exit 1 + ;; +esac + +echo -e "${YELLOW}Releasing version ${NEW_VERSION}${NC}" +echo "" + +# Check for uncommitted changes +if ! git diff-index --quiet HEAD --; then + echo -e "${RED}Error: You have uncommitted changes. Please commit or stash them first.${NC}" + exit 1 +fi + +# Check if on main branch +CURRENT_BRANCH=$(git branch --show-current) +if [ "$CURRENT_BRANCH" != "main" ]; then + echo -e "${YELLOW}Warning: You're not on the main branch (current: ${CURRENT_BRANCH})${NC}" + read -p "Continue anyway? [y/N] " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi +fi + +# Check if [Unreleased] section exists +if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then + echo -e "${RED}Error: No [Unreleased] section found in CHANGELOG.md${NC}" + echo "Please add your changes to an [Unreleased] section first." + exit 1 +fi + +# Check if there are actual changes in [Unreleased] +if grep -A 3 "## \[Unreleased\]" CHANGELOG.md | grep -q "^## \["; then + echo -e "${RED}Error: [Unreleased] section appears to be empty${NC}" + echo "Please add your changes to the [Unreleased] section first." + exit 1 +fi + +echo "📝 Updating mix.exs..." +sed -i.bak "s/@version \"${CURRENT_VERSION}\"/@version \"${NEW_VERSION}\"/" mix.exs +rm mix.exs.bak + +echo "📝 Updating CHANGELOG.md..." +TODAY=$(date +%Y-%m-%d) +sed -i.bak "s/## \[Unreleased\]/## [${NEW_VERSION}] - ${TODAY}/" CHANGELOG.md +rm CHANGELOG.md.bak + +# Add a new [Unreleased] section at the top +sed -i.bak "/^## \[${NEW_VERSION}\]/i\\ +## [Unreleased]\\ +\\ +" CHANGELOG.md +rm CHANGELOG.md.bak + +echo "✅ Committing changes..." +git add mix.exs CHANGELOG.md +git commit -m "Release v${NEW_VERSION}" + +echo "🏷️ Creating git tag..." +git tag "v${NEW_VERSION}" + +echo "" +echo -e "${GREEN}✨ Release ${NEW_VERSION} prepared successfully!${NC}" +echo "" +echo "Next steps:" +echo " 1. Review the commit and tag:" +echo " git show" +echo " git show v${NEW_VERSION}" +echo "" +echo " 2. Push to GitHub (this will trigger the publish workflow):" +echo " git push origin main --tags" +echo "" +echo " 3. The GitHub Action will automatically publish to Hex.pm" +echo "" +echo -e "${YELLOW}Note: You can undo this release with:${NC}" +echo " git reset --hard HEAD~1" +echo " git tag -d v${NEW_VERSION}" From aa234328e627dc4f40da089dd2d981b7693a20c4 Mon Sep 17 00:00:00 2001 From: Chris Gregori Date: Sat, 27 Dec 2025 11:03:05 +0000 Subject: [PATCH 3/3] Change OTP versions for CI tests --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3473d8..56fdddb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,11 +13,11 @@ jobs: strategy: matrix: - elixir: ['1.14', '1.15', '1.16'] - otp: ['25', '26'] + elixir: ["1.16", "1.19"] + otp: ["26", "27", "28"] exclude: - - elixir: '1.14' - otp: '26' + - elixir: "1.16" + otp: "28" steps: - uses: actions/checkout@v4