name: CI
on:
push:
branches: [ master ] tags: [ 'v*' ] pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
rust: stable
target: x86_64-unknown-linux-gnu
artifact_name: mal-cli
asset_name: mal-cli-linux-x86_64
- os: macos-latest
rust: stable
target: x86_64-apple-darwin
artifact_name: mal-cli
asset_name: mal-cli-macos-x86_64
- os: windows-latest
rust: stable
target: x86_64-pc-windows-msvc
artifact_name: mal-cli.exe
asset_name: mal-cli-windows-x86_64.exe
runs-on: ${{ matrix.os }}
if: startsWith(github.ref, 'refs/tags/v') continue-on-error: ${{ matrix.rust == 'nightly' }}
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
components: clippy
targets: ${{ matrix.target }}
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-${{ matrix.rust }}-
${{ runner.os }}-cargo-
- name: Build Debug
run: |
rustc --version
make build
- name: Run clippy
run: |
cargo clean
make clippy
- name: Build Release
shell: bash
run: |
make build-release
if [[ "$RUNNER_OS" == "Windows" ]]; then
echo "Detected Windows"
./target/release/mal.exe --version || echo "mal.exe not found"
ls -l target/release/ || true
cp target/release/mal.exe target/release/${{ matrix.artifact_name }}
else
echo "Detected Linux/macOS"
./target/release/mal --version || echo "mal not found"
ls -l target/release/ || true
cp target/release/mal target/release/${{ matrix.artifact_name }}
fi
- name: Upload binary artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset_name }}
path: target/release/${{ matrix.artifact_name }}
build-linux-musl:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: x86_64-unknown-linux-musl
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-musl-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-musl-cargo-
- name: Setup MUSL
run: |
sudo apt-get update -qq
sudo apt-get install -qq musl-tools
- name: Build Debug
run: |
make build-linux-musl-debug
./target/x86_64-unknown-linux-musl/debug/mal --version
- name: Build Release
run: |
make build-linux-musl-release
./target/x86_64-unknown-linux-musl/release/mal --version
- name: Upload MUSL binary artifacts
uses: actions/upload-artifact@v4
with:
name: mal-cli-linux-musl-static
path: target/x86_64-unknown-linux-musl/release/mal
rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
if: ${{ !startsWith(github.ref, 'refs/tags/v') }} steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt -- --check
security-audit:
name: Security audit
runs-on: ubuntu-latest
if: ${{ !startsWith(github.ref, 'refs/tags/v') }} steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-audit-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Run security audit
run: make audit
release:
name: Create GitHub Release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs: [build, build-linux-musl]
steps:
- uses: actions/checkout@v4
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release-assets
VERSION="${{ steps.version.outputs.VERSION }}"
ls -R ./artifacts/
# Copy and rename artifacts for release with version
cp artifacts/mal-cli-linux-x86_64/mal-cli release-assets/mal-cli-v${VERSION}-linux-x86_64
cp artifacts/mal-cli-linux-musl-static/mal release-assets/mal-cli-v${VERSION}-linux-musl-x86_64
cp artifacts/mal-cli-macos-x86_64/mal-cli release-assets/mal-cli-v${VERSION}-macos-x86_64
cp artifacts/mal-cli-windows-x86_64.exe/mal-cli.exe release-assets/mal-cli-v${VERSION}-windows-x86_64.exe
# Make binaries executable
chmod +x release-assets/mal-cli-v${VERSION}-*
# Create checksums
cd release-assets
sha256sum * > checksums.txt
cd ..
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: |
release-assets/*
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
aur-release:
name: Release to AUR
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs: [release]
steps:
- uses: actions/checkout@v4
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Generate PKGBUILD
run: |
# Download source tarball to calculate sha256
curl -L -o source.tar.gz "https://github.com/${GITHUB_REPOSITORY}/archive/refs/tags/v${{ steps.version.outputs.VERSION }}.tar.gz"
SHA256=$(sha256sum source.tar.gz | cut -d' ' -f1)
cat > PKGBUILD << EOF
# Maintainer: L4z3x <moussaousselmal1970@gmail.com>
pkgname=mal-cli
pkgver=${{ steps.version.outputs.VERSION }}
pkgrel=1
pkgdesc="A powerful CLI tool for MyAnimeList"
arch=('x86_64')
url="https://github.com/${GITHUB_REPOSITORY}"
license=('MIT')
depends=('gcc-libs')
makedepends=('rust' 'cargo')
source=("\${pkgname}-\${pkgver}.tar.gz::https://github.com/${GITHUB_REPOSITORY}/archive/refs/tags/v\${pkgver}.tar.gz")
sha256sums=('${SHA256}')
options=('!lto')
build() {
cd "\${srcdir}/mal-cli-\${pkgver}"
cargo build --release --locked
}
package() {
cd "\${srcdir}/mal-cli-\${pkgver}"
install -Dm755 "target/release/mal" "\${pkgdir}/usr/bin/mal"
}
EOF
# Generate .SRCINFO manually (simpler than installing makepkg)
cat > .SRCINFO << EOF
pkgbase = mal-cli
pkgdesc = A powerful CLI tool for MyAnimeList
pkgver = ${{ steps.version.outputs.VERSION }}
pkgrel = 1
url = https://github.com/${GITHUB_REPOSITORY}
arch = x86_64
license = MIT
makedepends = rust
makedepends = cargo
depends = gcc-libs
source = mal-cli-${{ steps.version.outputs.VERSION }}.tar.gz::https://github.com/${GITHUB_REPOSITORY}/archive/refs/tags/v${{ steps.version.outputs.VERSION }}.tar.gz
sha256sums = ${SHA256}
pkgname = mal-cli
EOF
- name: Publish to AUR
uses: KSXGitHub/github-actions-deploy-aur@v4.1.1
with:
pkgname: mal-cli
pkgbuild: ./PKGBUILD
commit_username: ${{ secrets.AUR_USERNAME }}
commit_email: ${{ secrets.AUR_EMAIL }}
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: "Update to version ${{ steps.version.outputs.VERSION }}"
ssh_keyscan_types: rsa,ecdsa,ed25519
allow_empty_commits: false
debian-release:
name: Create Debian Package
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs: [release]
steps:
- uses: actions/checkout@v4
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Install packaging tools
run: |
sudo apt-get update
sudo apt-get install -y devscripts build-essential lintian fakeroot
- name: Download Linux binary
uses: actions/download-artifact@v4
with:
name: mal-cli-linux-x86_64
path: ./artifacts
- name: Create Debian package structure
run: |
PKG_NAME="mal-cli"
VERSION="${{ steps.version.outputs.VERSION }}"
PKG_DIR="${PKG_NAME}_${VERSION}"
# Create package directory structure
mkdir -p ${PKG_DIR}/DEBIAN
mkdir -p ${PKG_DIR}/usr/bin
mkdir -p ${PKG_DIR}/usr/share/doc/${PKG_NAME}
# Copy binary and make executable
cp ./artifacts/mal-cli ${PKG_DIR}/usr/bin/mal
chmod +x ${PKG_DIR}/usr/bin/mal
# Create control file
cat > ${PKG_DIR}/DEBIAN/control << EOF
Package: mal-cli
Version: ${VERSION}
Section: utils
Priority: optional
Architecture: amd64
Depends: libc6 (>= 2.17), libgcc-s1 (>= 3.0)
Maintainer: L4z3x <moussaousselmal1970@gmail.com>
Description: A powerful CLI tool for MyAnimeList
mal-cli is a command-line interface tool that provides functionality
for interacting with MyAnimeList. It allows users to manage their
anime lists and perform various operations from the terminal.
.
This package provides the 'mal' command for MyAnimeList operations.
Homepage: https://github.com/${GITHUB_REPOSITORY}
EOF
# Create copyright file
cat > ${PKG_DIR}/usr/share/doc/${PKG_NAME}/copyright << EOF
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: mal-cli
Upstream-Contact: L4z3x <moussaousselmal1970@gmail.com>
Source: https://github.com/${GITHUB_REPOSITORY}
Files: *
Copyright: $(date +%Y) L4z3x
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
EOF
# Create changelog
cat > ${PKG_DIR}/usr/share/doc/${PKG_NAME}/changelog.Debian << EOF
mal-cli (${VERSION}-1) unstable; urgency=medium
* New upstream release ${VERSION}
* Updated dependencies and build system
-- L4z3x <moussaousselmal1970@gmail.com> $(date -R)
EOF
# Compress changelog
gzip -9 ${PKG_DIR}/usr/share/doc/${PKG_NAME}/changelog.Debian
# Create postinst script (optional, for any post-installation tasks)
cat > ${PKG_DIR}/DEBIAN/postinst << EOF
#!/bin/bash
set -e
# Ensure binary is executable
chmod +x /usr/bin/mal
exit 0
EOF
chmod 755 ${PKG_DIR}/DEBIAN/postinst
# Create prerm script (optional, for cleanup before removal)
cat > ${PKG_DIR}/DEBIAN/prerm << EOF
#!/bin/bash
set -e
# Nothing to do before removal
exit 0
EOF
chmod 755 ${PKG_DIR}/DEBIAN/prerm
- name: Build Debian package
run: |
PKG_NAME="mal-cli"
VERSION="${{ steps.version.outputs.VERSION }}"
PKG_DIR="${PKG_NAME}_${VERSION}"
# Set package permissions correctly
find ${PKG_DIR} -type d -exec chmod 755 {} \;
find ${PKG_DIR}/usr -type f -exec chmod 644 {} \;
chmod +x ${PKG_DIR}/usr/bin/mal
chmod 755 ${PKG_DIR}/DEBIAN/postinst
chmod 755 ${PKG_DIR}/DEBIAN/prerm
# Build the package
dpkg-deb --build ${PKG_DIR}
# Rename to standard naming convention
mv ${PKG_DIR}.deb mal-cli_${VERSION}-1_amd64.deb
# Verify the package
dpkg-deb --info mal-cli_${VERSION}-1_amd64.deb
dpkg-deb --contents mal-cli_${VERSION}-1_amd64.deb
# Optional: Run lintian to check for issues (warnings are ok)
lintian mal-cli_${VERSION}-1_amd64.deb || true
- name: Test Debian package
run: |
VERSION="${{ steps.version.outputs.VERSION }}"
# Test installation (dry-run)
sudo dpkg --dry-run -i mal-cli_${VERSION}-1_amd64.deb
# Actually install and test
sudo dpkg -i mal-cli_${VERSION}-1_amd64.deb || true
sudo apt-get install -f -y # Fix any dependency issues
# Test that the command works
mal --version || echo "Note: mal command may require specific setup"
# Remove the package
sudo dpkg -r mal-cli || true
- name: Upload Debian package to GitHub Release
uses: softprops/action-gh-release@v2
with:
files: mal-cli_${{ steps.version.outputs.VERSION }}-1_amd64.deb
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-crate:
name: Publish to crates.io
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') needs: [build]
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- uses: katyo/publish-crates@v2
with:
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}