Compare commits
4 Commits
ac343050a8
...
074a2b1f5f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
074a2b1f5f | ||
|
|
3f9acb08ec | ||
|
|
56bc1cb21b | ||
|
|
43a408d962 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
|
||||
### Quick Install (Linux/macOS)
|
||||
```bash
|
||||
curl -sSL https://git.appmodel.nl/Tour/finish/main/docs/install.sh | bash
|
||||
curl -sSL https://git.appmodel.nl/tour/finish/main/docs/install.sh | bash
|
||||
```
|
||||
|
||||
### Homebrew (macOS)
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
# finish.sh Test Container
|
||||
FROM ubuntu:22.04
|
||||
|
||||
LABEL maintainer="finish contributors"
|
||||
LABEL description="Test environment for finish.sh"
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install dependencies including BATS for testing
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
bash \
|
||||
bash-completion \
|
||||
curl \
|
||||
wget \
|
||||
jq \
|
||||
bc \
|
||||
vim \
|
||||
git \
|
||||
bats \
|
||||
&& apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /opt/finish
|
||||
|
||||
# Copy all files
|
||||
COPY . .
|
||||
|
||||
# Make scripts executable
|
||||
RUN chmod +x finish.sh
|
||||
|
||||
# Run tests by default
|
||||
ENTRYPOINT ["bats"]
|
||||
CMD ["tests"]
|
||||
365
PUBLISHING.md
365
PUBLISHING.md
@@ -1,365 +0,0 @@
|
||||
# Publishing Guide for finish.sh
|
||||
|
||||
This guide explains how to publish and distribute finish.sh through various channels.
|
||||
|
||||
## Overview
|
||||
|
||||
finish.sh can be distributed through multiple channels:
|
||||
1. **Direct installation script** - One-line curl install
|
||||
2. **Debian/Ubuntu packages** - APT repository
|
||||
3. **Homebrew** - macOS package manager
|
||||
4. **Docker** - Container images
|
||||
5. **GitHub Releases** - Direct downloads
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before publishing, ensure:
|
||||
- [ ] All tests pass (`./run_tests.sh`)
|
||||
- [ ] Version numbers are updated in all files
|
||||
- [ ] CHANGELOG.md is updated
|
||||
- [ ] Documentation is complete and accurate
|
||||
|
||||
## Version Management
|
||||
|
||||
Update version numbers in these files:
|
||||
1. `finish.sh` - Line 34: `export ACSH_VERSION=0.5.0`
|
||||
2. `debian/changelog` - Add new entry
|
||||
3. `homebrew/finish.rb` - Line 6: `version "0.5.0"`
|
||||
4. `docs/install.sh` - Line 7: `ACSH_VERSION="v0.5.0"`
|
||||
5. `Dockerfile` - Line 6: `LABEL version="0.5.0"`
|
||||
|
||||
## 1. Direct Installation Script
|
||||
|
||||
The install script at `docs/install.sh` enables one-line installation:
|
||||
|
||||
```bash
|
||||
curl -sSL https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
```
|
||||
|
||||
### Setup:
|
||||
- Host the script on a reliable server or GitHub/GitLab
|
||||
- Ensure the URL is accessible and supports HTTPS
|
||||
- Test the installation on clean systems
|
||||
|
||||
### Testing:
|
||||
```bash
|
||||
# Test in Docker
|
||||
docker run --rm -it ubuntu:22.04 bash
|
||||
curl -sSL YOUR_URL/install.sh | bash
|
||||
```
|
||||
|
||||
## 2. Debian/Ubuntu Packages
|
||||
|
||||
### Building the Package
|
||||
|
||||
```bash
|
||||
# Install build tools
|
||||
sudo apt-get install debhelper devscripts
|
||||
|
||||
# Build the package
|
||||
dpkg-buildpackage -us -uc -b
|
||||
|
||||
# This creates:
|
||||
# ../finish_0.5.0-1_all.deb
|
||||
```
|
||||
|
||||
### Testing the Package
|
||||
|
||||
```bash
|
||||
# Install locally
|
||||
sudo dpkg -i ../finish_*.deb
|
||||
sudo apt-get install -f # Fix dependencies
|
||||
|
||||
# Test installation
|
||||
finish --help
|
||||
finish install
|
||||
```
|
||||
|
||||
### Creating an APT Repository
|
||||
|
||||
#### Option A: Using Packagecloud (Recommended for beginners)
|
||||
|
||||
1. Sign up at https://packagecloud.io
|
||||
2. Create a repository
|
||||
3. Upload your .deb file:
|
||||
```bash
|
||||
gem install package_cloud
|
||||
package_cloud push yourname/finish/ubuntu/jammy ../finish_*.deb
|
||||
```
|
||||
|
||||
Users install with:
|
||||
```bash
|
||||
curl -s https://packagecloud.io/install/repositories/yourname/finish/script.deb.sh | sudo bash
|
||||
sudo apt-get install finish
|
||||
```
|
||||
|
||||
#### Option B: Using GitHub Pages + reprepro
|
||||
|
||||
1. Create a repository structure:
|
||||
```bash
|
||||
mkdir -p apt-repo/{conf,pool,dists}
|
||||
```
|
||||
|
||||
2. Create `apt-repo/conf/distributions`:
|
||||
```
|
||||
Origin: finish.sh
|
||||
Label: finish
|
||||
Codename: stable
|
||||
Architectures: all
|
||||
Components: main
|
||||
Description: APT repository for finish.sh
|
||||
```
|
||||
|
||||
3. Add packages:
|
||||
```bash
|
||||
reprepro -b apt-repo includedeb stable ../finish_*.deb
|
||||
```
|
||||
|
||||
4. Host on GitHub Pages or your server
|
||||
|
||||
Users install with:
|
||||
```bash
|
||||
echo "deb https://your-domain.com/apt-repo stable main" | sudo tee /etc/apt/sources.list.d/finish.list
|
||||
curl -fsSL https://your-domain.com/apt-repo/key.gpg | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install finish
|
||||
```
|
||||
|
||||
## 3. Homebrew Formula
|
||||
|
||||
### Creating a Homebrew Tap
|
||||
|
||||
1. Create a GitHub repository: `homebrew-finish`
|
||||
|
||||
2. Add the formula to `Formula/finish.rb`
|
||||
|
||||
3. Create a release tarball and calculate SHA256:
|
||||
```bash
|
||||
git archive --format=tar.gz --prefix=finish-0.5.0/ v0.5.0 > finish-0.5.0.tar.gz
|
||||
sha256sum finish-0.5.0.tar.gz
|
||||
```
|
||||
|
||||
4. Update the formula with the correct URL and SHA256
|
||||
|
||||
5. Test the formula:
|
||||
```bash
|
||||
brew install --build-from-source ./homebrew/finish.rb
|
||||
brew test finish
|
||||
brew audit --strict finish
|
||||
```
|
||||
|
||||
### Publishing the Tap
|
||||
|
||||
Users can install with:
|
||||
```bash
|
||||
brew tap yourname/finish
|
||||
brew install finish
|
||||
```
|
||||
|
||||
Or directly:
|
||||
```bash
|
||||
brew install yourname/finish/finish
|
||||
```
|
||||
|
||||
## 4. Docker Images
|
||||
|
||||
### Building Images
|
||||
|
||||
```bash
|
||||
# Production image
|
||||
docker build -t finish:0.5.0 -t finish:latest .
|
||||
|
||||
# Test image
|
||||
docker build -f Dockerfile.test -t finish:test .
|
||||
```
|
||||
|
||||
### Publishing to GitHub Container Registry
|
||||
|
||||
The GitHub Actions workflow automatically publishes Docker images when you push a tag:
|
||||
|
||||
```bash
|
||||
git tag -a v0.5.0 -m "Release v0.5.0"
|
||||
git push origin v0.5.0
|
||||
```
|
||||
|
||||
Images will be available at:
|
||||
```
|
||||
ghcr.io/appmodel/finish:0.5.0
|
||||
ghcr.io/appmodel/finish:latest
|
||||
```
|
||||
|
||||
### Publishing to Docker Hub
|
||||
|
||||
```bash
|
||||
# Login
|
||||
docker login
|
||||
|
||||
# Tag and push
|
||||
docker tag finish:latest yourname/finish:0.5.0
|
||||
docker tag finish:latest yourname/finish:latest
|
||||
docker push yourname/finish:0.5.0
|
||||
docker push yourname/finish:latest
|
||||
```
|
||||
|
||||
## 5. GitHub Releases
|
||||
|
||||
### Automated Release Process
|
||||
|
||||
The `.github/workflows/release.yml` workflow automatically:
|
||||
1. Creates release artifacts when you push a tag
|
||||
2. Builds Debian packages
|
||||
3. Publishes Docker images
|
||||
4. Creates a GitHub release with downloads
|
||||
|
||||
### Manual Release Process
|
||||
|
||||
1. Create a release tarball:
|
||||
```bash
|
||||
git archive --format=tar.gz --prefix=finish-0.5.0/ v0.5.0 > finish-0.5.0.tar.gz
|
||||
```
|
||||
|
||||
2. Create release on GitHub:
|
||||
- Go to Releases → Draft a new release
|
||||
- Tag: `v0.5.0`
|
||||
- Title: `finish.sh v0.5.0`
|
||||
- Upload: tarball and .deb file
|
||||
- Write release notes
|
||||
|
||||
## Release Checklist
|
||||
|
||||
Before releasing a new version:
|
||||
|
||||
- [ ] Update all version numbers
|
||||
- [ ] Update CHANGELOG.md
|
||||
- [ ] Run all tests
|
||||
- [ ] Test installation script
|
||||
- [ ] Build and test Debian package
|
||||
- [ ] Test Docker images
|
||||
- [ ] Update documentation
|
||||
- [ ] Create git tag
|
||||
- [ ] Push tag to trigger CI/CD
|
||||
- [ ] Verify GitHub release created
|
||||
- [ ] Verify Docker images published
|
||||
- [ ] Update Homebrew formula with new SHA256
|
||||
- [ ] Test installation from all sources
|
||||
- [ ] Announce release (if applicable)
|
||||
|
||||
## Distribution URLs
|
||||
|
||||
After publishing, users can install from:
|
||||
|
||||
**Quick Install:**
|
||||
```bash
|
||||
curl -sSL https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
```
|
||||
|
||||
**Homebrew:**
|
||||
```bash
|
||||
brew tap appmodel/finish
|
||||
brew install finish
|
||||
```
|
||||
|
||||
**APT (if configured):**
|
||||
```bash
|
||||
sudo apt-get install finish
|
||||
```
|
||||
|
||||
**Docker:**
|
||||
```bash
|
||||
docker pull ghcr.io/appmodel/finish:latest
|
||||
```
|
||||
|
||||
**Direct Download:**
|
||||
```
|
||||
https://git.appmodel.nl/Tour/finish/releases/latest
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Debian Package Issues
|
||||
|
||||
**Problem:** Package won't install
|
||||
```bash
|
||||
# Check dependencies
|
||||
dpkg-deb -I finish_*.deb
|
||||
# Test installation
|
||||
sudo dpkg -i finish_*.deb
|
||||
sudo apt-get install -f
|
||||
```
|
||||
|
||||
**Problem:** Lintian warnings
|
||||
```bash
|
||||
lintian finish_*.deb
|
||||
# Fix issues in debian/ files
|
||||
```
|
||||
|
||||
### Homebrew Issues
|
||||
|
||||
**Problem:** Formula audit fails
|
||||
```bash
|
||||
brew audit --strict ./homebrew/finish.rb
|
||||
# Fix issues reported
|
||||
```
|
||||
|
||||
**Problem:** Installation fails
|
||||
```bash
|
||||
brew install --verbose --debug ./homebrew/finish.rb
|
||||
```
|
||||
|
||||
### Docker Issues
|
||||
|
||||
**Problem:** Build fails
|
||||
```bash
|
||||
docker build --no-cache -t finish:test .
|
||||
```
|
||||
|
||||
**Problem:** Image too large
|
||||
```bash
|
||||
# Use multi-stage builds
|
||||
# Remove unnecessary files
|
||||
# Combine RUN commands
|
||||
```
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
The project includes three GitHub Actions workflows:
|
||||
|
||||
1. **test.yml** - Runs on every push/PR
|
||||
- Runs BATS tests
|
||||
- Tests installation
|
||||
- Runs shellcheck
|
||||
- Tests Docker builds
|
||||
|
||||
2. **docker.yml** - Builds and publishes Docker images
|
||||
- Triggered by tags and main branch
|
||||
- Publishes to GitHub Container Registry
|
||||
|
||||
3. **release.yml** - Creates releases
|
||||
- Triggered by version tags
|
||||
- Builds all artifacts
|
||||
- Creates GitHub release
|
||||
- Publishes packages
|
||||
|
||||
## Support and Documentation
|
||||
|
||||
- Update the README.md with installation instructions
|
||||
- Maintain CHANGELOG.md with version history
|
||||
- Create issue templates for bug reports and feature requests
|
||||
- Set up discussions for community support
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Always use HTTPS for installation scripts
|
||||
- Sign Debian packages with GPG
|
||||
- Use checksums for release artifacts
|
||||
- Regularly update dependencies
|
||||
- Monitor for security vulnerabilities
|
||||
|
||||
## Next Steps
|
||||
|
||||
After initial publication:
|
||||
1. Monitor GitHub issues for user feedback
|
||||
2. Set up analytics if desired
|
||||
3. Create documentation site
|
||||
4. Announce on relevant forums/communities
|
||||
5. Consider submitting to package manager directories
|
||||
16
README.md
16
README.md
@@ -7,13 +7,13 @@ Command-line completion powered by local LLMs. Press `Tab` twice and get intelli
|
||||
### One-Line Install (Recommended)
|
||||
|
||||
```bash
|
||||
curl -sSL https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
curl -sSL https://git.appmodel.nl/tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
```
|
||||
|
||||
### Manual Installation
|
||||
|
||||
```bash
|
||||
git clone https://git.appmodel.nl/Tour/finish.git finish
|
||||
git clone https://git.appmodel.nl/tour/finish.git finish
|
||||
cd finish
|
||||
./finish.sh install
|
||||
source ~/.bashrc
|
||||
@@ -59,7 +59,7 @@ finish config
|
||||
Change the endpoint or model:
|
||||
|
||||
```bash
|
||||
finish config set endpoint http://192.168.1.100:1234/v1/chat/completions
|
||||
finish config set endpoint http://plato.lan:1234/v1/chat/completions
|
||||
finish config set model your-model-name
|
||||
```
|
||||
|
||||
@@ -100,7 +100,7 @@ finish command --dry-run "your command"
|
||||
The fastest way to get started:
|
||||
|
||||
```bash
|
||||
curl -sSL https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
curl -sSL https://git.appmodel.nl/tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
source ~/.bashrc # or ~/.zshrc for zsh
|
||||
finish model
|
||||
```
|
||||
@@ -118,7 +118,7 @@ source ~/.bashrc
|
||||
|
||||
#### APT (Debian/Ubuntu)
|
||||
|
||||
Download the `.deb` package from [releases](https://git.appmodel.nl/Tour/finish/releases):
|
||||
Download the `.deb` package from [releases](https://git.appmodel.nl/tour/finish/releases):
|
||||
|
||||
```bash
|
||||
sudo dpkg -i finish_*.deb
|
||||
@@ -153,7 +153,7 @@ finish model # Configure your LLM endpoint
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://git.appmodel.nl/Tour/finish.git finish
|
||||
git clone https://git.appmodel.nl/tour/finish.git finish
|
||||
cd finish
|
||||
chmod +x finish.sh
|
||||
sudo ln -s $PWD/finish.sh /usr/local/bin/finish
|
||||
@@ -210,7 +210,7 @@ Add custom providers by editing `finish.sh` and adding entries to `_finish_model
|
||||
Clone and link for development:
|
||||
|
||||
```bash
|
||||
git clone https://git.appmodel.nl/Tour/finish.git finish
|
||||
git clone https://git.appmodel.nl/tour/finish.git finish
|
||||
cd finish
|
||||
ln -s $PWD/finish.sh $HOME/.local/bin/finish
|
||||
finish install
|
||||
@@ -284,7 +284,7 @@ After creating a release, update the Homebrew formula:
|
||||
|
||||
1. Calculate SHA256 of the release tarball:
|
||||
```bash
|
||||
curl -sL https://git.appmodel.nl/Tour/finish/archive/v0.5.0.tar.gz | sha256sum
|
||||
curl -sL https://git.appmodel.nl/tour/finish/archive/v0.5.0.tar.gz | sha256sum
|
||||
```
|
||||
|
||||
2. Update `homebrew/finish.rb` with the new SHA256 and version
|
||||
|
||||
201
SUMMARY.md
201
SUMMARY.md
@@ -1,201 +0,0 @@
|
||||
# Publication Setup Summary
|
||||
|
||||
This document summarizes the publication setup completed for finish.sh.
|
||||
|
||||
## Files Created
|
||||
|
||||
### 1. Installation Script
|
||||
- **`docs/install.sh`** - Enhanced one-line installer with:
|
||||
- Dependency checking
|
||||
- Shell detection (bash/zsh)
|
||||
- Color-coded output
|
||||
- Error handling
|
||||
- PATH management
|
||||
- Usage: `curl -sSL <URL>/install.sh | bash`
|
||||
|
||||
### 2. Debian Package Structure
|
||||
Complete Debian packaging in `debian/` directory:
|
||||
- **`control`** - Package metadata and dependencies
|
||||
- **`rules`** - Build instructions
|
||||
- **`changelog`** - Version history
|
||||
- **`copyright`** - License information
|
||||
- **`compat`** - Debhelper compatibility level
|
||||
- **`postinst`** - Post-installation script
|
||||
- **`source/format`** - Package format specification
|
||||
|
||||
Build command: `dpkg-buildpackage -us -uc -b`
|
||||
|
||||
### 3. Homebrew Formula
|
||||
- **`homebrew/finish.rb`** - Homebrew formula for macOS
|
||||
- Includes dependencies, installation steps, and caveats
|
||||
- Update SHA256 after creating releases
|
||||
|
||||
### 4. Docker Configuration
|
||||
- **`Dockerfile`** - Production container image
|
||||
- **`Dockerfile.test`** - Testing container with BATS
|
||||
- **`docker-compose.yml`** - Multi-service Docker setup
|
||||
- **`.dockerignore`** - Excludes unnecessary files from builds
|
||||
|
||||
### 5. GitHub Actions Workflows
|
||||
CI/CD automation in `.github/workflows/`:
|
||||
- **`test.yml`** - Runs tests on every push/PR
|
||||
- **`release.yml`** - Creates releases and builds packages
|
||||
- **`docker.yml`** - Builds and publishes Docker images
|
||||
|
||||
### 6. Documentation
|
||||
- **`PUBLISHING.md`** - Comprehensive publishing guide
|
||||
- **`README.md`** - Updated with installation methods
|
||||
- **`.gitignore`** - Updated to exclude build artifacts
|
||||
|
||||
## Distribution Channels
|
||||
|
||||
### 1. Quick Install (Recommended)
|
||||
```bash
|
||||
curl -sSL https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
```
|
||||
|
||||
### 2. Debian/Ubuntu Package
|
||||
Users can install the `.deb` file:
|
||||
```bash
|
||||
sudo dpkg -i finish_*.deb
|
||||
sudo apt-get install -f
|
||||
```
|
||||
|
||||
Or from an APT repository (when configured):
|
||||
```bash
|
||||
sudo apt-get install finish
|
||||
```
|
||||
|
||||
### 3. Homebrew (macOS)
|
||||
```bash
|
||||
brew tap closedloop-technologies/finish
|
||||
brew install finish
|
||||
```
|
||||
|
||||
### 4. Docker
|
||||
```bash
|
||||
docker pull ghcr.io/closedloop-technologies/finish:latest
|
||||
docker run -it ghcr.io/closedloop-technologies/finish:latest
|
||||
```
|
||||
|
||||
### 5. From Source
|
||||
```bash
|
||||
git clone https://git.appmodel.nl/Tour/finish.git
|
||||
cd finish
|
||||
./finish.sh install
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate Actions
|
||||
1. **Test the installation script** on clean systems
|
||||
2. **Build and test the Debian package**:
|
||||
```bash
|
||||
dpkg-buildpackage -us -uc -b
|
||||
sudo dpkg -i ../finish_*.deb
|
||||
```
|
||||
3. **Test Docker builds**:
|
||||
```bash
|
||||
docker build -t finish:test .
|
||||
docker run -it finish:test
|
||||
```
|
||||
|
||||
### For First Release
|
||||
1. **Update version numbers** in:
|
||||
- `finish.sh` (line 34)
|
||||
- `debian/changelog`
|
||||
- `homebrew/finish.rb`
|
||||
- `docs/install.sh`
|
||||
- `Dockerfile`
|
||||
|
||||
2. **Create release tarball**:
|
||||
```bash
|
||||
git archive --format=tar.gz --prefix=finish-0.5.0/ v0.5.0 > finish-0.5.0.tar.gz
|
||||
```
|
||||
|
||||
3. **Calculate SHA256** for Homebrew:
|
||||
```bash
|
||||
sha256sum finish-0.5.0.tar.gz
|
||||
```
|
||||
|
||||
4. **Create and push tag**:
|
||||
```bash
|
||||
git tag -a v0.5.0 -m "Release v0.5.0"
|
||||
git push origin v0.5.0
|
||||
```
|
||||
This triggers GitHub Actions to build everything automatically.
|
||||
|
||||
### Setting Up Package Repositories
|
||||
|
||||
#### APT Repository Options:
|
||||
1. **Packagecloud** (easiest):
|
||||
- Sign up at https://packagecloud.io
|
||||
- Upload .deb file
|
||||
- Users get one-line install
|
||||
|
||||
2. **GitHub Pages** (free):
|
||||
- Use `reprepro` to create repository
|
||||
- Host on GitHub Pages
|
||||
- Users add your repository to sources
|
||||
|
||||
See `PUBLISHING.md` for detailed instructions.
|
||||
|
||||
#### Homebrew Tap:
|
||||
1. Create GitHub repo: `homebrew-finish`
|
||||
2. Add formula to `Formula/finish.rb`
|
||||
3. Users install with: `brew tap yourname/finish && brew install finish`
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
Before releasing:
|
||||
- [ ] Test install script on Ubuntu 22.04
|
||||
- [ ] Test install script on Debian 12
|
||||
- [ ] Test install script on macOS
|
||||
- [ ] Build Debian package successfully
|
||||
- [ ] Install and test Debian package
|
||||
- [ ] Build Docker image successfully
|
||||
- [ ] Run BATS tests in Docker
|
||||
- [ ] Test Homebrew formula (if applicable)
|
||||
- [ ] Verify all version numbers match
|
||||
- [ ] Test GitHub Actions workflows
|
||||
|
||||
## Automation
|
||||
|
||||
The GitHub Actions workflows handle:
|
||||
- **On every push/PR**: Run tests, lint code, build Docker images
|
||||
- **On version tag push**: Build packages, create release, publish Docker images
|
||||
|
||||
This means once set up, releasing a new version is as simple as:
|
||||
```bash
|
||||
git tag -a v0.5.1 -m "Release v0.5.1"
|
||||
git push origin v0.5.1
|
||||
```
|
||||
|
||||
Everything else happens automatically!
|
||||
|
||||
## Support Channels
|
||||
|
||||
Consider setting up:
|
||||
- GitHub Issues for bug reports
|
||||
- GitHub Discussions for Q&A
|
||||
- Documentation website (GitHub Pages)
|
||||
- Discord/Slack community (optional)
|
||||
|
||||
## Resources
|
||||
|
||||
- Debian Packaging Guide: https://www.debian.org/doc/manuals/maint-guide/
|
||||
- Homebrew Formula Cookbook: https://docs.brew.sh/Formula-Cookbook
|
||||
- GitHub Actions Documentation: https://docs.github.com/en/actions
|
||||
- Docker Best Practices: https://docs.docker.com/develop/dev-best-practices/
|
||||
|
||||
## Conclusion
|
||||
|
||||
Your project is now fully set up for publication with:
|
||||
- ✅ One-line installation script
|
||||
- ✅ Debian/Ubuntu package support
|
||||
- ✅ Homebrew formula for macOS
|
||||
- ✅ Docker containers
|
||||
- ✅ Automated CI/CD with GitHub Actions
|
||||
- ✅ Comprehensive documentation
|
||||
|
||||
All distribution channels are ready. Follow the "Next Steps" section above to test and publish your first release!
|
||||
140
USAGE.md
140
USAGE.md
@@ -1,140 +0,0 @@
|
||||
# Usage Guide
|
||||
|
||||
## Installation
|
||||
|
||||
Install and set up finish:
|
||||
|
||||
```bash
|
||||
finish install
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
View current settings:
|
||||
|
||||
```bash
|
||||
finish config
|
||||
```
|
||||
|
||||
Change settings:
|
||||
|
||||
```bash
|
||||
finish config set temperature 0.5
|
||||
finish config set endpoint http://plato.lan:1234/v1/chat/completions
|
||||
finish config set model your-model-name
|
||||
```
|
||||
|
||||
Reset to defaults:
|
||||
|
||||
```bash
|
||||
finish config reset
|
||||
```
|
||||
|
||||
## Model Selection
|
||||
|
||||
Select a model interactively:
|
||||
|
||||
```bash
|
||||
finish model
|
||||
```
|
||||
|
||||
Use arrow keys to navigate, Enter to select, or 'q' to quit.
|
||||
|
||||
## Basic Commands
|
||||
|
||||
Show help:
|
||||
|
||||
```bash
|
||||
finish --help
|
||||
```
|
||||
|
||||
Test completions without caching:
|
||||
|
||||
```bash
|
||||
finish command "your command here"
|
||||
```
|
||||
|
||||
Preview the prompt sent to the model:
|
||||
|
||||
```bash
|
||||
finish command --dry-run "your command here"
|
||||
```
|
||||
|
||||
View system information:
|
||||
|
||||
```bash
|
||||
finish system
|
||||
```
|
||||
|
||||
## Usage Statistics
|
||||
|
||||
Check your usage stats and costs:
|
||||
|
||||
```bash
|
||||
finish usage
|
||||
```
|
||||
|
||||
## Cache Management
|
||||
|
||||
Clear cached completions and logs:
|
||||
|
||||
```bash
|
||||
finish clear
|
||||
```
|
||||
|
||||
## Enable/Disable
|
||||
|
||||
Temporarily disable:
|
||||
|
||||
```bash
|
||||
finish disable
|
||||
```
|
||||
|
||||
Re-enable:
|
||||
|
||||
```bash
|
||||
finish enable
|
||||
```
|
||||
|
||||
## Uninstallation
|
||||
|
||||
Remove finish completely:
|
||||
|
||||
```bash
|
||||
finish remove
|
||||
```
|
||||
|
||||
## Using finish
|
||||
|
||||
Once enabled, just type a command and press `Tab` twice to get suggestions:
|
||||
|
||||
```bash
|
||||
git <TAB><TAB>
|
||||
docker <TAB><TAB>
|
||||
find <TAB><TAB>
|
||||
```
|
||||
|
||||
Natural language also works:
|
||||
|
||||
```bash
|
||||
# convert video to mp4 <TAB><TAB>
|
||||
# list all processes using port 8080 <TAB><TAB>
|
||||
# compress this folder to tar.gz <TAB><TAB>
|
||||
```
|
||||
|
||||
## Configuration File
|
||||
|
||||
The config file is located at `~/.finish/config` and contains:
|
||||
|
||||
- `provider`: Model provider (lmstudio, ollama)
|
||||
- `model`: Model name
|
||||
- `temperature`: Response randomness (0.0 - 1.0)
|
||||
- `endpoint`: API endpoint URL
|
||||
- `api_prompt_cost`: Cost per input token
|
||||
- `api_completion_cost`: Cost per output token
|
||||
- `max_history_commands`: Number of recent commands to include in context
|
||||
- `max_recent_files`: Number of recent files to include in context
|
||||
- `cache_dir`: Directory for cached completions
|
||||
- `cache_size`: Maximum number of cached items
|
||||
- `log_file`: Path to usage log file
|
||||
4
debian/control
vendored
4
debian/control
vendored
@@ -4,8 +4,8 @@ Priority: optional
|
||||
Maintainer: finish.sh Contributors <noreply@finish.sh>
|
||||
Build-Depends: debhelper (>= 10)
|
||||
Standards-Version: 4.5.0
|
||||
Homepage: https://git.appmodel.nl/Tour/finish/finish
|
||||
Vcs-Git: https://git.appmodel.nl/Tour/finish.git
|
||||
Homepage: https://git.appmodel.nl/tour/finish/finish
|
||||
Vcs-Git: https://git.appmodel.nl/tour/finish.git
|
||||
|
||||
Package: finish
|
||||
Architecture: all
|
||||
|
||||
4
debian/copyright
vendored
4
debian/copyright
vendored
@@ -1,7 +1,7 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: finish
|
||||
Upstream-Contact: https://git.appmodel.nl/Tour/finish/finish
|
||||
Source: https://git.appmodel.nl/Tour/finish
|
||||
Upstream-Contact: https://git.appmodel.nl/tour/finish/finish
|
||||
Source: https://git.appmodel.nl/tour/finish
|
||||
|
||||
Files: *
|
||||
Copyright: 2024-2025 finish.sh Contributors
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#!/bin/sh
|
||||
# finish.sh installer
|
||||
# Usage: curl -sSL https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
# Usage: curl -sSL https://git.appmodel.nl/tour/finish/raw/branch/main/docs/install.sh | bash
|
||||
|
||||
set -e
|
||||
|
||||
ACSH_VERSION="v0.5.0"
|
||||
BRANCH_OR_VERSION=${1:-main}
|
||||
REPO_URL="https://git.appmodel.nl/Tour/finish/raw/branch"
|
||||
REPO_URL="https://git.appmodel.nl/tour/finish/raw/branch"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
@@ -121,6 +121,11 @@ main() {
|
||||
echo ""
|
||||
|
||||
# Determine installation location
|
||||
# Prefer local user install at ~/.local/bin, create it if missing
|
||||
if [ ! -d "$HOME/.local/bin" ]; then
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
fi
|
||||
|
||||
if [ -d "$HOME/.local/bin" ]; then
|
||||
INSTALL_LOCATION="$HOME/.local/bin/finish"
|
||||
# Add to PATH if not already there
|
||||
@@ -134,8 +139,8 @@ main() {
|
||||
elif [ -w "/usr/local/bin" ]; then
|
||||
INSTALL_LOCATION="/usr/local/bin/finish"
|
||||
else
|
||||
echo_error "Cannot write to /usr/local/bin and $HOME/.local/bin doesn't exist"
|
||||
echo "Please create $HOME/.local/bin or run with sudo"
|
||||
echo_error "Cannot determine installation location"
|
||||
echo "Please ensure either $HOME/.local/bin exists and is writable, or run with sudo for /usr/local/bin"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -154,6 +159,13 @@ main() {
|
||||
echo_green "✓ Installed to $INSTALL_LOCATION"
|
||||
echo ""
|
||||
|
||||
# Ensure current shell PATH includes the install dir for immediate use
|
||||
INSTALL_DIR="$(dirname "$INSTALL_LOCATION")"
|
||||
case ":$PATH:" in
|
||||
*":$INSTALL_DIR:"*) ;;
|
||||
*) export PATH="$INSTALL_DIR:$PATH" ;;
|
||||
esac
|
||||
|
||||
# Check bash-completion
|
||||
if [ "$SHELL_TYPE" = "bash" ]; then
|
||||
if ! command -v _init_completion > /dev/null 2>&1; then
|
||||
@@ -188,7 +200,7 @@ main() {
|
||||
echo ""
|
||||
echo " 3. Start using by pressing Tab twice after any command"
|
||||
echo ""
|
||||
echo "Documentation: https://git.appmodel.nl/Tour/finish"
|
||||
echo "Documentation: https://git.appmodel.nl/tour/finish"
|
||||
else
|
||||
echo_error "Installation failed. Please check the output above."
|
||||
exit 1
|
||||
|
||||
12
finish.iml
Normal file
12
finish.iml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.git" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tests" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
59
finish.sh
59
finish.sh
@@ -228,7 +228,10 @@ $prompt"
|
||||
}')
|
||||
;;
|
||||
*)
|
||||
payload=$(echo "$base_payload" | jq '. + {response_format: {type: "json_object"}}')
|
||||
# Default OpenAI-compatible providers increasingly expect
|
||||
# response_format.type to be either "text" or a json_schema.
|
||||
# Use "text" for maximum compatibility to avoid 400 errors.
|
||||
payload=$(echo "$base_payload" | jq '. + {response_format: {type: "text"}}')
|
||||
;;
|
||||
esac
|
||||
echo "$payload"
|
||||
@@ -256,16 +259,21 @@ log_request() {
|
||||
openai_completion() {
|
||||
local content status_code response_body default_user_input user_input api_key payload endpoint timeout attempt max_attempts
|
||||
local log_file debug_log
|
||||
|
||||
# Ensure configuration (provider, endpoint, etc.) is loaded before checks
|
||||
acsh_load_config
|
||||
|
||||
log_file=${ACSH_LOG_FILE:-"$HOME/.finish/finish.log"}
|
||||
debug_log="$HOME/.finish/debug.log"
|
||||
endpoint=${ACSH_ENDPOINT:-"http://plato.lan:1234/v1/chat/completions"}
|
||||
timeout=${ACSH_TIMEOUT:-30}
|
||||
default_user_input="Write two to six most likely commands given the provided information"
|
||||
user_input=${*:-$default_user_input}
|
||||
log_file=${ACSH_LOG_FILE:-"$HOME/.finish/finish.log"}
|
||||
debug_log="$HOME/.finish/debug.log"
|
||||
|
||||
# Only check for API key if not using local providers that don't require it
|
||||
if [[ -z "$ACSH_ACTIVE_API_KEY" && ${ACSH_PROVIDER^^} != "OLLAMA" && ${ACSH_PROVIDER^^} != "LMSTUDIO" ]]; then
|
||||
echo_error "ACSH_ACTIVE_API_KEY not set. Please set it with: export ${ACSH_PROVIDER^^}_API_KEY=<your-api-key>"
|
||||
return
|
||||
return 1
|
||||
fi
|
||||
api_key="${ACSH_ACTIVE_API_KEY}"
|
||||
payload=$(_build_payload "$user_input")
|
||||
@@ -297,9 +305,16 @@ openai_completion() {
|
||||
if [[ "${ACSH_PROVIDER^^}" == "OLLAMA" ]]; then
|
||||
\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" --data "$payload" -N > "$temp_file"
|
||||
else
|
||||
\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" -N > "$temp_file"
|
||||
if [[ -n "$api_key" ]]; then
|
||||
\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $api_key" \
|
||||
-d "$payload" -N > "$temp_file"
|
||||
else
|
||||
\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" -N > "$temp_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
status_code=$(tail -n1 "$temp_file")
|
||||
@@ -327,9 +342,16 @@ openai_completion() {
|
||||
if [[ "${ACSH_PROVIDER^^}" == "OLLAMA" ]]; then
|
||||
response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" --data "$payload")
|
||||
else
|
||||
response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload")
|
||||
if [[ -n "$api_key" ]]; then
|
||||
response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $api_key" \
|
||||
-d "$payload")
|
||||
else
|
||||
response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload")
|
||||
fi
|
||||
fi
|
||||
status_code=$(echo "$response" | tail -n1)
|
||||
response_body=$(echo "$response" | sed '$d')
|
||||
@@ -359,8 +381,8 @@ openai_completion() {
|
||||
500) echo_error "Internal Server Error: An unexpected error occurred on the API server." ;;
|
||||
*) echo_error "Unknown Error: Unexpected status code $status_code received. Response: $response_body" ;;
|
||||
esac
|
||||
return
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "${ACSH_PROVIDER^^}" == "OLLAMA" ]]; then
|
||||
content=$(echo "$response_body" | jq -r '.message.content')
|
||||
@@ -390,7 +412,7 @@ openai_completion() {
|
||||
|
||||
if [[ -z "$completions" ]]; then
|
||||
echo_error "Failed to parse completions from API response. Check $debug_log for details."
|
||||
return
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -n "$completions"
|
||||
@@ -443,13 +465,6 @@ _finishsh() {
|
||||
if [[ ${#COMPREPLY[@]} -eq 0 && $COMP_TYPE -eq 63 ]]; then
|
||||
local completions user_input user_input_hash
|
||||
acsh_load_config
|
||||
if [[ -z "$ACSH_ACTIVE_API_KEY" && ${ACSH_PROVIDER^^} != "OLLAMA" && ${ACSH_PROVIDER^^} != "LMSTUDIO" ]]; then
|
||||
local provider_key="${ACSH_PROVIDER}_API_KEY"
|
||||
provider_key=$(echo "$provider_key" | tr '[:lower:]' '[:upper:]')
|
||||
echo_error "${provider_key} is not set. Please set it using: export ${provider_key}=<your-api-key> or disable finish via: finish disable"
|
||||
echo
|
||||
return
|
||||
fi
|
||||
if [[ -n "${COMP_WORDS[*]}" ]]; then
|
||||
command="${COMP_WORDS[0]}"
|
||||
if [[ -n "$COMP_CWORD" && "$COMP_CWORD" -lt "${#COMP_WORDS[@]}" ]]; then
|
||||
@@ -529,7 +544,7 @@ show_help() {
|
||||
echo " clear Clear cache and log files"
|
||||
echo " --help Show this help message"
|
||||
echo
|
||||
echo "Submit issues at: https://git.appmodel.nl/Tour/finish/issues"
|
||||
echo "Submit issues at: https://git.appmodel.nl/tour/finish/issues"
|
||||
}
|
||||
|
||||
is_subshell() {
|
||||
@@ -707,7 +722,7 @@ acsh_load_config() {
|
||||
install_command() {
|
||||
local bashrc_file="$HOME/.bashrc" finish_setup="source finish enable" finish_cli_setup="complete -F _finishsh_cli finish"
|
||||
if ! command -v finish &>/dev/null; then
|
||||
echo_error "finish.sh not in PATH. Follow install instructions at https://git.appmodel.nl/Tour/finish"
|
||||
echo_error "finish.sh not in PATH. Follow install instructions at https://git.appmodel.nl/tour/finish"
|
||||
return
|
||||
fi
|
||||
if [[ ! -d "$HOME/.finish" ]]; then
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class finishSh < Formula
|
||||
desc "LLM-powered command-line finishtion"
|
||||
homepage "https://git.appmodel.nl/Tour/finish"
|
||||
url "https://git.appmodel.nl/Tour/finish/archive/v0.5.0.tar.gz"
|
||||
homepage "https://git.appmodel.nl/tour/finish"
|
||||
url "https://git.appmodel.nl/tour/finish/archive/v0.5.0.tar.gz"
|
||||
sha256 "" # Update with actual SHA256 of the release tarball
|
||||
license "BSD-2-Clause"
|
||||
version "0.5.0"
|
||||
@@ -36,7 +36,7 @@ class finishSh < Formula
|
||||
Ollama: https://ollama.ai
|
||||
|
||||
For more information, visit:
|
||||
https:/git.appmodel.nl/Tour/finish
|
||||
https:/git.appmodel.nl/tour/finish
|
||||
EOS
|
||||
end
|
||||
|
||||
|
||||
13
run_tests.sh
Normal file → Executable file
13
run_tests.sh
Normal file → Executable file
@@ -1,3 +1,12 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
bats tests/
|
||||
# Always run from the directory where this script lives
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# Execute the tests
|
||||
bash ./tests/test_finish.sh
|
||||
|
||||
# Also try the local Ollama end-to-end test (skips if Ollama not running)
|
||||
bash ./tests/test_finish_ollama.sh
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
setup() {
|
||||
# Install finish.sh and run testing against the main branch
|
||||
wget -qO- https://git.appmodel.nl/Tour/finish/raw/branch/main/docs/install.sh | bash -s -- main
|
||||
|
||||
# Source bashrc to make sure finish is available in the current session
|
||||
source ~/.bashrc
|
||||
|
||||
# Configure for local LM-Studio
|
||||
finish config set provider lmstudio
|
||||
finish config set endpoint http://plato.lan:1234/v1/chat/completions
|
||||
finish config set model darkidol-llama-3.1-8b-instruct-1.3-uncensored_gguf:2
|
||||
}
|
||||
|
||||
teardown() {
|
||||
# Remove finish.sh installation
|
||||
finish remove -y
|
||||
}
|
||||
|
||||
@test "which finish returns something" {
|
||||
run which finish
|
||||
[ "$status" -eq 0 ]
|
||||
[ -n "$output" ]
|
||||
}
|
||||
|
||||
@test "finish returns a string containing finish.sh (case insensitive)" {
|
||||
run finish
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ [Aa]utocomplete\.sh ]]
|
||||
}
|
||||
|
||||
@test "finish config should have lmstudio provider" {
|
||||
run finish config
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ lmstudio ]]
|
||||
}
|
||||
|
||||
@test "finish command 'ls # show largest files' should return something" {
|
||||
run finish command "ls # show largest files"
|
||||
[ "$status" -eq 0 ]
|
||||
[ -n "$output" ]
|
||||
}
|
||||
82
tests/test_finish.sh
Executable file
82
tests/test_finish.sh
Executable file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ----- tiny test framework -----
|
||||
pass() { printf "✔ %s\n" "$1"; }
|
||||
fail() { printf "✘ %s\n" "$1"; exit 1; }
|
||||
|
||||
assert_ok() {
|
||||
if [[ $1 -ne 0 ]]; then fail "$2"; fi
|
||||
}
|
||||
|
||||
assert_nonempty() {
|
||||
if [[ -z "$1" ]]; then fail "$2"; fi
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
if [[ ! "$1" =~ $2 ]]; then fail "$3"; fi
|
||||
}
|
||||
|
||||
# Ensure output does not contain any of the common error phrases.
|
||||
assert_no_common_errors() {
|
||||
local output="$1"
|
||||
local -a patterns=(
|
||||
"ACSH_ACTIVE_API_KEY not set"
|
||||
"Bad Request"
|
||||
"Unauthorized"
|
||||
"Too Many Requests"
|
||||
"Internal Server Error"
|
||||
"Unknown Error"
|
||||
"Failed to parse completions"
|
||||
"SyntaxError"
|
||||
"ERROR:"
|
||||
)
|
||||
for pat in "${patterns[@]}"; do
|
||||
if grep -qE "$pat" <<<"$output"; then
|
||||
printf "Test failed: output contains error pattern '%s'\nFull output follows:\n%s\n" "$pat" "$output"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
# --------------------------------
|
||||
|
||||
echo "=== SETUP ==="
|
||||
bash ./docs/install.sh main
|
||||
source ~/.bashrc
|
||||
|
||||
finish config set provider lmstudio
|
||||
finish config set endpoint http://plato.lan:1234/v1/chat/completions
|
||||
finish config set model darkidol-llama-3.1-8b-instruct-1.3-uncensored_gguf:2
|
||||
|
||||
# -------------------------------- TESTS --------------------------------
|
||||
|
||||
# 1) which finish should return something
|
||||
out=$(which finish 2>&1) ; code=$?
|
||||
assert_ok $code "which finish should exit 0"
|
||||
assert_nonempty "$out" "which finish returned empty output"
|
||||
pass "which finish returns path"
|
||||
|
||||
# 2) finish output should contain 'finish.sh'
|
||||
out=$(finish 2>&1) ; code=$?
|
||||
assert_ok $code "finish should exit 0"
|
||||
assert_contains "$out" "finish\.sh" "finish output does not contain finish.sh"
|
||||
pass "finish outputs reference to finish.sh"
|
||||
|
||||
# 3) config should contain lmstudio
|
||||
out=$(finish config 2>&1) ; code=$?
|
||||
assert_ok $code "finish config should exit 0"
|
||||
assert_contains "$out" "lmstudio" "finish config missing lmstudio provider"
|
||||
pass "finish config contains lmstudio"
|
||||
|
||||
# 4) finish command should run
|
||||
out=$(finish command "ls # show largest files" 2>&1) ; code=$?
|
||||
assert_ok $code "finish command did not exit 0"
|
||||
assert_nonempty "$out" "finish command returned empty output"
|
||||
assert_no_common_errors "$out"
|
||||
pass "finish command executed and returned output"
|
||||
|
||||
# ------------------------------- CLEANUP --------------------------------
|
||||
echo "=== CLEANUP ==="
|
||||
finish remove -y || true
|
||||
|
||||
echo "All tests passed."
|
||||
112
tests/test_finish_ollama.sh
Executable file
112
tests/test_finish_ollama.sh
Executable file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ----- tiny test framework -----
|
||||
pass() { printf "✔ %s\n" "$1"; }
|
||||
fail() { printf "✘ %s\n" "$1"; exit 1; }
|
||||
|
||||
assert_ok() {
|
||||
if [[ $1 -ne 0 ]]; then fail "$2"; fi
|
||||
}
|
||||
|
||||
assert_nonempty() {
|
||||
if [[ -z "$1" ]]; then fail "$2"; fi
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
if [[ ! "$1" =~ $2 ]]; then fail "$3"; fi
|
||||
}
|
||||
|
||||
# Ensure output does not contain any of the common error phrases.
|
||||
assert_no_common_errors() {
|
||||
local output="$1"
|
||||
local -a patterns=(
|
||||
"ACSH_ACTIVE_API_KEY not set"
|
||||
"Bad Request"
|
||||
"Unauthorized"
|
||||
"Too Many Requests"
|
||||
"Internal Server Error"
|
||||
"Unknown Error"
|
||||
"Failed to parse completions"
|
||||
"SyntaxError"
|
||||
"ERROR:"
|
||||
)
|
||||
for pat in "${patterns[@]}"; do
|
||||
if grep -qE "$pat" <<<"$output"; then
|
||||
printf "Test failed: output contains error pattern '%s'\nFull output follows:\n%s\n" "$pat" "$output"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
# --------------------------------
|
||||
|
||||
echo "=== OLLAMA TEST: SETUP ==="
|
||||
|
||||
# Always run from the repo root for predictable paths
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR/.."
|
||||
|
||||
# Install finish (adds to PATH and shell rc files)
|
||||
bash ./docs/install.sh main
|
||||
|
||||
# Load the updated shell rc so `finish` is available on PATH in this session
|
||||
if [[ -f ~/.bashrc ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source ~/.bashrc || true
|
||||
fi
|
||||
|
||||
# ---- Check prerequisites for local Ollama ----
|
||||
OLLAMA_URL=${OLLAMA_URL:-"http://localhost:11434"}
|
||||
|
||||
echo "Checking Ollama at $OLLAMA_URL ..."
|
||||
if ! curl -fsS --max-time 2 "$OLLAMA_URL/api/version" >/dev/null 2>&1; then
|
||||
echo "SKIP: Ollama is not reachable at $OLLAMA_URL. Start it with: 'ollama serve' and ensure a model is pulled (e.g., 'ollama pull llama3')."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Try to discover an installed model; prefer the first listed
|
||||
MODEL=$(curl -fsS "$OLLAMA_URL/api/tags" | jq -r '.models[0].name // empty' || echo "")
|
||||
if [[ -z "$MODEL" ]]; then
|
||||
echo "SKIP: No local Ollama models found. Pull one first, e.g.: 'ollama pull llama3:latest'"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Using Ollama model: $MODEL"
|
||||
|
||||
# -------------------------------- TESTS --------------------------------
|
||||
|
||||
# 1) configure finish to use local Ollama
|
||||
finish config set provider ollama
|
||||
finish config set endpoint "$OLLAMA_URL/api/chat"
|
||||
finish config set model "$MODEL"
|
||||
|
||||
# 2) which finish should return something
|
||||
out=$(which finish 2>&1) ; code=$?
|
||||
assert_ok $code "which finish should exit 0"
|
||||
assert_nonempty "$out" "which finish returned empty output"
|
||||
pass "which finish returns path"
|
||||
|
||||
# 3) finish output should contain 'finish.sh'
|
||||
out=$(finish 2>&1) ; code=$?
|
||||
assert_ok $code "finish should exit 0"
|
||||
assert_contains "$out" "finish\.sh" "finish output does not contain finish.sh"
|
||||
pass "finish outputs reference to finish.sh"
|
||||
|
||||
# 4) config should mention ollama
|
||||
out=$(finish config 2>&1) ; code=$?
|
||||
assert_ok $code "finish config should exit 0"
|
||||
assert_contains "$out" "ollama" "finish config missing ollama provider"
|
||||
pass "finish config contains ollama"
|
||||
|
||||
# 5) finish command should run and return output
|
||||
out=$(finish command "ls # show largest files" 2>&1) ; code=$?
|
||||
assert_ok $code "finish command did not exit 0"
|
||||
assert_nonempty "$out" "finish command returned empty output"
|
||||
assert_no_common_errors "$out"
|
||||
pass "finish command executed and returned output (ollama)"
|
||||
|
||||
# ------------------------------- CLEANUP --------------------------------
|
||||
echo "=== OLLAMA TEST: CLEANUP ==="
|
||||
finish remove -y || true
|
||||
|
||||
echo "Ollama test passed."
|
||||
Reference in New Issue
Block a user