Compare commits
23 Commits
bdd9e663b9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 26df70f9f5 | |||
| 96e66be50e | |||
| c0b566fc70 | |||
| bdcb3d1d20 | |||
| cc2df21796 | |||
| f546ee450e | |||
| 6d165a3912 | |||
| 3edb5c33ee | |||
| ab87e943f3 | |||
| 39f85a3900 | |||
| af0f03758a | |||
| dee7c95542 | |||
| c7a3690129 | |||
| 0d8cddb9be | |||
| 9bca886629 | |||
| edc6d5acf3 | |||
| 4473dc9164 | |||
| 29a984934d | |||
| ef49f30c88 | |||
| 89e7729f2c | |||
| 1ad993b9d1 | |||
| 27f4e1fd2c | |||
| 657855bd41 |
@@ -9,24 +9,26 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CONVERGE_HASKELL_TOOLS_IMAGE: ghcr.io/flipstone/haskell-tools:debian-ghc-9.10.3-5d6640d
|
||||
STACK_ROOT: ${{ github.workspace }}/.stack-root
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: .
|
||||
|
||||
- name: Install Stack
|
||||
run: |
|
||||
curl -sSL https://get.haskellstack.org/ | sh
|
||||
|
||||
- name: Cache Stack
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .stack-root
|
||||
key: stack-${{ runner.os }}-${{ hashFiles('stack.yaml', 'package.yaml') }}
|
||||
restore-keys: stack-${{ runner.os }}-
|
||||
key: stack-v2-${{ runner.os }}-${{ hashFiles('stack.yaml', 'package.yaml') }}
|
||||
restore-keys: stack-v2-${{ runner.os }}-
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir -p .stack-root build
|
||||
./hs stack build --copy-bins --local-bin-path /work/build
|
||||
mkdir -p build
|
||||
stack build --copy-bins --local-bin-path ./build
|
||||
|
||||
- name: Compress with UPX
|
||||
run: |
|
||||
@@ -39,9 +41,55 @@ jobs:
|
||||
fi
|
||||
${UPX_DIR}/upx build/converge
|
||||
|
||||
- name: Build Arch package
|
||||
run: |
|
||||
# Build the package inside an Arch Linux container.
|
||||
# Pipe workspace via stdin to avoid Docker-in-Docker volume mount issues.
|
||||
# All build output goes to stderr (visible in logs); only the package
|
||||
# tar goes to stdout so it can be captured cleanly.
|
||||
tar cf - --exclude=.stack-root --exclude=.stack-work . | \
|
||||
docker run --rm -i -w /build archlinux:latest bash -c "
|
||||
mkdir -p /build &&
|
||||
cd /build &&
|
||||
tar xf - &&
|
||||
pacman -Syu --noconfirm >&2 &&
|
||||
pacman -S --noconfirm git fakeroot debugedit >&2 &&
|
||||
useradd -m build &&
|
||||
chown -R build:build . &&
|
||||
runuser -u build -- makepkg --noconfirm --nodeps --nocheck >&2 &&
|
||||
tar cf /dev/stdout converge-*.pkg.tar.zst
|
||||
" > /tmp/packages.tar
|
||||
tar xf /tmp/packages.tar
|
||||
echo "pkgfile=$(ls converge-[0-9]*.pkg.tar.zst)" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Publish to Arch repo
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
SSH_AUTH_SOCK: /dev/null
|
||||
run: |
|
||||
# Set up SSH
|
||||
mkdir -p "$HOME/.ssh"
|
||||
echo "${{ secrets.ARCH_REPO_SSH_KEY }}" > "$HOME/.ssh/id_ed25519"
|
||||
chmod 600 "$HOME/.ssh/id_ed25519"
|
||||
ssh-keyscan -H "${{ vars.ARCH_REPO_HOST }}" >> "$HOME/.ssh/known_hosts" 2>/dev/null
|
||||
|
||||
PKGFILE="${{ env.pkgfile }}"
|
||||
echo "Uploading $PKGFILE to ${{ vars.ARCH_REPO_HOST }}..."
|
||||
|
||||
# Upload the package
|
||||
scp -v -i "$HOME/.ssh/id_ed25519" \
|
||||
"$PKGFILE" \
|
||||
"${{ vars.ARCH_REPO_USER }}@${{ vars.ARCH_REPO_HOST }}:${{ vars.ARCH_REPO_PATH }}/"
|
||||
|
||||
# Add to repo database
|
||||
ssh -v -i "$HOME/.ssh/id_ed25519" \
|
||||
"${{ vars.ARCH_REPO_USER }}@${{ vars.ARCH_REPO_HOST }}" \
|
||||
"cd '${{ vars.ARCH_REPO_PATH }}' && \
|
||||
repo-add '${{ vars.ARCH_REPO_DB }}' '$PKGFILE' && \
|
||||
rm -f '$PKGFILE.old'"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: converge
|
||||
path: build/converge
|
||||
compression-level: 0
|
||||
|
||||
@@ -12,3 +12,5 @@ dist-newstyle/
|
||||
.pi/
|
||||
converge-relay/.go-cache/
|
||||
converge-relay/build/
|
||||
*.pkg.tar
|
||||
pkg/
|
||||
|
||||
@@ -18,9 +18,9 @@ test/TestHelper.hs # Shared test utilities (temp repos, sentinel files)
|
||||
test/GitCommitSpec.hs # Commit behaviour tests
|
||||
test/GitPullSpec.hs # Pull/rebase tests
|
||||
test/GitSafetySpec.hs # Operation-in-progress detection tests
|
||||
SPEC.md # Human-readable specifications
|
||||
converge.example.yaml # Example config file
|
||||
converge.service # systemd unit file
|
||||
SPEC.md # Human-readable specifications
|
||||
converge.example.yaml # Example config file
|
||||
converge.service # systemd user service (daemon mode)
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Maintainer: James Brechtel <james@leonard-brechtel.com.com>
|
||||
# Contributor: James Brechtel <james@leonard-brechtel.com.com>
|
||||
|
||||
pkgname=converge
|
||||
_pkgver=0.2.0.0
|
||||
pkgver=${_pkgver//-/_}
|
||||
pkgrel=1
|
||||
pkgdesc="Auto-sync git repositories by watching for changes, committing, pulling, and pushing"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/jbrechtel/converge"
|
||||
license=('BSD')
|
||||
makedepends=('stack' 'git')
|
||||
depends=('git' 'libnotify' 'gcc-libs')
|
||||
optdepends=('converge-relay: realtime push notifications via SSE relay server')
|
||||
backup=('etc/converge/config.example.yaml')
|
||||
source=(
|
||||
"converge.service"
|
||||
"converge.example.yaml"
|
||||
)
|
||||
md5sums=(
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
)
|
||||
|
||||
build() {
|
||||
cd "$startdir"
|
||||
echo "$startdir"
|
||||
|
||||
# Use pre-built binary if available (e.g. from scripts/build), otherwise build from source
|
||||
if [[ -x build/converge ]]; then
|
||||
msg "Using pre-built binary from build/converge"
|
||||
install -Dm755 build/converge "$srcdir/bin/converge"
|
||||
else
|
||||
export STACK_ROOT="$srcdir/.stack-root"
|
||||
msg "Building converge with stack (resolver: $(awk '/^resolver:/ {print $2}' stack.yaml))..."
|
||||
stack build \
|
||||
--copy-bins \
|
||||
--local-bin-path "$srcdir/bin" \
|
||||
--ghc-options '-O2'
|
||||
fi
|
||||
}
|
||||
|
||||
check() {
|
||||
cd "$startdir"
|
||||
export STACK_ROOT="$srcdir/.stack-root"
|
||||
msg "Running tests..."
|
||||
stack test
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$startdir"
|
||||
|
||||
# Binary
|
||||
install -Dm755 "$srcdir/bin/converge" \
|
||||
"$pkgdir/usr/bin/converge"
|
||||
|
||||
# User systemd services
|
||||
install -Dm644 converge.service \
|
||||
"$pkgdir/usr/lib/systemd/user/converge.service"
|
||||
|
||||
# Example config
|
||||
install -Dm644 converge.example.yaml \
|
||||
"$pkgdir/etc/converge/config.example.yaml"
|
||||
|
||||
# Documentation
|
||||
install -Dm644 README.md \
|
||||
"$pkgdir/usr/share/doc/converge/README.md"
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
## Supports logging to a file instead of stderr via --log-file or log_file config
|
||||
## Can notify on pull: per-repo notify_on_pull setting sends a desktop notification when new commits are pulled from the remote
|
||||
|
||||
## --sync / -s flag runs a single sync cycle (commit + pull + push) and exits, useful for wake-from-sleep hooks
|
||||
## --sync / -s flag runs a single sync cycle (commit + pull + push) and exits
|
||||
|
||||
## Can connect to a converge-relay SSE endpoint and automatically pull when push events arrive
|
||||
### Configured via --relay-url CLI flag or relay_url config file entry
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
cabal-version: 2.2
|
||||
|
||||
-- This file has been generated from package.yaml by hpack version 0.38.1.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: converge
|
||||
version: 0.1.0.1
|
||||
synopsis: Auto-sync a git repository by watching for changes, committing, and pulling
|
||||
description: Converge watches a git repository for file changes, automatically
|
||||
commits them, and pulls from the remote. It notifies the user via
|
||||
libnotify/notify-send when merge conflicts arise.
|
||||
author: James Leonard-Brechtel
|
||||
maintainer: james@leonard-brechtel.com
|
||||
copyright: 2026 James Leonard-Brechtel
|
||||
license: BSD-3-Clause
|
||||
build-type: Simple
|
||||
|
||||
library
|
||||
exposed-modules:
|
||||
Converge
|
||||
other-modules:
|
||||
Paths_converge
|
||||
autogen-modules:
|
||||
Paths_converge
|
||||
hs-source-dirs:
|
||||
src
|
||||
default-extensions:
|
||||
OverloadedStrings
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
TupleSections
|
||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
|
||||
build-depends:
|
||||
aeson
|
||||
, async
|
||||
, base >=4.7 && <5
|
||||
, bytestring
|
||||
, directory
|
||||
, filepath
|
||||
, fsnotify
|
||||
, http-client
|
||||
, http-client-tls
|
||||
, http-types
|
||||
, optparse-applicative
|
||||
, process
|
||||
, text
|
||||
, time
|
||||
, unix
|
||||
, yaml
|
||||
default-language: Haskell2010
|
||||
|
||||
executable converge
|
||||
main-is: Main.hs
|
||||
other-modules:
|
||||
Paths_converge
|
||||
autogen-modules:
|
||||
Paths_converge
|
||||
hs-source-dirs:
|
||||
app
|
||||
default-extensions:
|
||||
OverloadedStrings
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
TupleSections
|
||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
aeson
|
||||
, async
|
||||
, base >=4.7 && <5
|
||||
, bytestring
|
||||
, converge
|
||||
, directory
|
||||
, filepath
|
||||
, fsnotify
|
||||
, http-client
|
||||
, http-client-tls
|
||||
, http-types
|
||||
, optparse-applicative
|
||||
, process
|
||||
, text
|
||||
, time
|
||||
, unix
|
||||
, yaml
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite converge-test
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Spec.hs
|
||||
other-modules:
|
||||
GitCommitSpec
|
||||
GitPullSpec
|
||||
GitSafetySpec
|
||||
RelaySpec
|
||||
TestHelper
|
||||
Paths_converge
|
||||
autogen-modules:
|
||||
Paths_converge
|
||||
hs-source-dirs:
|
||||
test
|
||||
default-extensions:
|
||||
OverloadedStrings
|
||||
RecordWildCards
|
||||
ScopedTypeVariables
|
||||
TupleSections
|
||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
aeson
|
||||
, async
|
||||
, base >=4.7 && <5
|
||||
, bytestring
|
||||
, converge
|
||||
, directory
|
||||
, filepath
|
||||
, fsnotify
|
||||
, hspec
|
||||
, http-client
|
||||
, http-client-tls
|
||||
, http-types
|
||||
, optparse-applicative
|
||||
, process
|
||||
, temporary
|
||||
, text
|
||||
, time
|
||||
, unix
|
||||
, yaml
|
||||
default-language: Haskell2010
|
||||
+1
-1
@@ -6,7 +6,7 @@ Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=%h/.local/bin/converge --config %h/.config/converge/config.yaml
|
||||
ExecStart=/usr/bin/converge --config %h/.config/converge/config.yaml
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
|
||||
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
name: converge
|
||||
version: 0.1.0.0
|
||||
version: 0.1.0.1
|
||||
synopsis: Auto-sync a git repository by watching for changes, committing, and pulling
|
||||
description: |
|
||||
Converge watches a git repository for file changes, automatically
|
||||
commits them, and pulls from the remote. It notifies the user via
|
||||
libnotify/notify-send when merge conflicts arise.
|
||||
author: James Brechtel
|
||||
maintainer: james@flipstone.com
|
||||
copyright: 2026 James Brechtel
|
||||
author: James Leonard-Brechtel
|
||||
maintainer: james@leonard-brechtel.com
|
||||
copyright: 2026 James Leonard-Brechtel
|
||||
license: BSD-3-Clause
|
||||
|
||||
default-extensions:
|
||||
|
||||
@@ -20,3 +20,15 @@ echo "Compressing with UPX..."
|
||||
'
|
||||
|
||||
echo "Done: $(ls -lh build/converge | awk '{print $5}')"
|
||||
|
||||
# Build Arch Linux package (if makepkg is available)
|
||||
if command -v makepkg &>/dev/null; then
|
||||
echo "Building Arch package with makepkg..."
|
||||
if makepkg -f 2>&1; then
|
||||
echo "Package: $(ls -1 converge-*.pkg.tar.zst 2>/dev/null)"
|
||||
else
|
||||
echo "WARNING: makepkg failed (see above)" >&2
|
||||
fi
|
||||
else
|
||||
echo "Skipping package build (makepkg not found)"
|
||||
fi
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../.pi/skills/gitea-actions/scripts/gitea-actions.sh
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build an Arch Linux package for converge using makepkg.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/makepkg # Build the package (no install)
|
||||
# ./scripts/makepkg -i # Build and install
|
||||
# ./scripts/makepkg -s # Build and install missing deps
|
||||
#
|
||||
# The resulting .pkg.tar.zst will be placed in the project root.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
makepkg -f "$@"
|
||||
+4
-2
@@ -447,7 +447,9 @@ gitCommitAll logger repoPath = do
|
||||
then pure addResult
|
||||
else do
|
||||
hostname <- init <$> readProcess "hostname" [] ""
|
||||
loggedGit logger repoPath ["commit", "-m", "converge: auto-commit from " <> hostname]
|
||||
timestamp <- formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S" <$> getCurrentTime
|
||||
let msg = "converge: auto-commit at " <> timestamp <> " from " <> hostname
|
||||
loggedGit logger repoPath ["commit", "-m", msg]
|
||||
|
||||
-- | Pull from the configured remote, rebasing onto the tracked upstream branch.
|
||||
gitPull :: Logger -> RepoConfig -> IO (ExitCode, Text, Text)
|
||||
@@ -585,7 +587,7 @@ connectRelay :: Text -> Logger -> [RepoConfig] -> IO ()
|
||||
connectRelay url logger repos = do
|
||||
logMsg logger Info ("relay: connecting to " <> url)
|
||||
req <- parseRequest (T.unpack url)
|
||||
manager <- newManager tlsManagerSettings
|
||||
manager <- newManager tlsManagerSettings{managerResponseTimeout = responseTimeoutNone}
|
||||
let loop delay = do
|
||||
let delaySec = min delay (60 :: Int)
|
||||
result <- try $
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=Converge - sync repos after waking from sleep
|
||||
Documentation=https://github.com/jbrechtel/converge
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/converge --sync
|
||||
# Small delay as a safety net for environments (e.g. netctl) where
|
||||
# network-online.target may not gate properly on resume, giving the
|
||||
# network stack time to reconnect before converge attempts to pull.
|
||||
ExecStartPre=/bin/sleep 5
|
||||
|
||||
# Allow notify-send to reach the desktop session
|
||||
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/work/personal/converge/converge.example.yaml
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/work/personal/converge/converge.service
|
||||
Reference in New Issue
Block a user