name: Release on: push: tags: - 'v*' permissions: contents: write actions: write concurrency: group: release-${{ github.ref_name }} cancel-in-progress: true jobs: build-core: runs-on: ubuntu-latest strategy: matrix: arch: [amd64, arm64] defaults: run: working-directory: core steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version-file: ./core/go.mod - name: Format check run: | if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then echo "The following files are not formatted:" gofmt -s -l . exit 1 fi - name: Run tests run: go test -v ./... - name: Build dankinstall (${{ matrix.arch }}) env: GOOS: linux CGO_ENABLED: 0 GOARCH: ${{ matrix.arch }} run: | set -eux cd cmd/dankinstall go build -trimpath -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \ -o ../../dankinstall-${{ matrix.arch }} cd ../.. gzip -9 -k dankinstall-${{ matrix.arch }} sha256sum dankinstall-${{ matrix.arch }}.gz > dankinstall-${{ matrix.arch }}.gz.sha256 - name: Build dms (${{ matrix.arch }}) env: GOOS: linux CGO_ENABLED: 0 GOARCH: ${{ matrix.arch }} run: | set -eux cd cmd/dms go build -trimpath -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \ -o ../../dms-${{ matrix.arch }} cd ../.. gzip -9 -k dms-${{ matrix.arch }} sha256sum dms-${{ matrix.arch }}.gz > dms-${{ matrix.arch }}.gz.sha256 - name: Generate shell completions if: matrix.arch == 'amd64' run: | set -eux chmod +x dms-amd64 ./dms-amd64 completion bash > completion.bash ./dms-amd64 completion fish > completion.fish ./dms-amd64 completion zsh > completion.zsh - name: Build dms-distropkg (${{ matrix.arch }}) env: GOOS: linux CGO_ENABLED: 0 GOARCH: ${{ matrix.arch }} run: | set -eux cd cmd/dms go build -trimpath -tags distro_binary -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \ -o ../../dms-distropkg-${{ matrix.arch }} cd ../.. gzip -9 -k dms-distropkg-${{ matrix.arch }} sha256sum dms-distropkg-${{ matrix.arch }}.gz > dms-distropkg-${{ matrix.arch }}.gz.sha256 - name: Upload artifacts (${{ matrix.arch }}) if: matrix.arch == 'arm64' uses: actions/upload-artifact@v4 with: name: core-assets-${{ matrix.arch }} path: | core/dankinstall-${{ matrix.arch }}.gz core/dankinstall-${{ matrix.arch }}.gz.sha256 core/dms-${{ matrix.arch }}.gz core/dms-${{ matrix.arch }}.gz.sha256 core/dms-distropkg-${{ matrix.arch }}.gz core/dms-distropkg-${{ matrix.arch }}.gz.sha256 if-no-files-found: error - name: Upload artifacts with completions if: matrix.arch == 'amd64' uses: actions/upload-artifact@v4 with: name: core-assets-${{ matrix.arch }} path: | core/dankinstall-${{ matrix.arch }}.gz core/dankinstall-${{ matrix.arch }}.gz.sha256 core/dms-${{ matrix.arch }}.gz core/dms-${{ matrix.arch }}.gz.sha256 core/dms-distropkg-${{ matrix.arch }}.gz core/dms-distropkg-${{ matrix.arch }}.gz.sha256 core/completion.bash core/completion.fish core/completion.zsh if-no-files-found: error update-versions: runs-on: ubuntu-latest needs: build-core steps: - name: Create GitHub App token id: app_token uses: actions/create-github-app-token@v1 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} - name: Checkout uses: actions/checkout@v4 with: token: ${{ steps.app_token.outputs.token }} fetch-depth: 0 - name: Update VERSION env: GH_TOKEN: ${{ steps.app_token.outputs.token }} run: | set -euo pipefail git config user.name "dms-ci[bot]" git config user.email "dms-ci[bot]@users.noreply.github.com" version="${GITHUB_REF#refs/tags/}" echo "Updating to version: $version" echo "${version}" > quickshell/VERSION git add quickshell/VERSION if ! git diff --cached --quiet; then git commit -m "chore: bump version to $version" git pull --rebase origin master git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git HEAD:master fi git tag -f "${version}" git push -f https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git "${version}" release: runs-on: ubuntu-24.04 needs: [build-core, update-versions] env: TAG: ${{ github.ref_name }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Fetch updated tag after version bump run: | git fetch origin --force tag ${{ github.ref_name }} git checkout ${{ github.ref_name }} - name: Download core artifacts uses: actions/download-artifact@v4 with: pattern: core-assets-* merge-multiple: true path: ./_core_assets - name: Generate Changelog id: changelog run: | set -e PREVIOUS_TAG=$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || echo "") if [ -z "$PREVIOUS_TAG" ]; then CHANGELOG=$(git log --oneline --pretty=format:"%an|%s (%h)" | grep -v "^github-actions\[bot\]|" | sed 's/^[^|]*|/- /' | head -50) else CHANGELOG=$(git log --oneline --pretty=format:"%an|%s (%h)" "${PREVIOUS_TAG}..${TAG}" | grep -v "^github-actions\[bot\]|" | sed 's/^[^|]*|/- /') fi cat > RELEASE_BODY.md << 'EOF' ## Installation ```bash curl -fsSL https://install.danklinux.com | sh ``` ## Assets ### Complete Packages - **`dms-full-amd64.tar.gz`** - Complete package for x86_64 systems (CLI binaries + QML source + shell completions + installation guide) - **`dms-full-arm64.tar.gz`** - Complete package for ARM64 systems (CLI binaries + QML source + shell completions + installation guide) ### Individual Components - **`dms-cli-amd64.gz`** - DMS CLI binary for x86_64 systems - **`dms-cli-arm64.gz`** - DMS CLI binary for ARM64 systems - **`dms-distropkg-amd64.gz`** - DMS CLI binary built with distro_package tag for AMD64 systems - **`dms-distropkg-arm64.gz`** - DMS CLI binary built with distro_package tag for ARM64 systems - **`dankinstall-amd64.gz`** - Installer binary for x86_64 systems - **`dankinstall-arm64.gz`** - Installer binary for ARM64 systems - **`dms-qml.tar.gz`** - QML source code only ### Checksums - **`*.sha256`** - SHA256 checksums for verifying download integrity **Installation:** Extract the `dms-full-*.tar.gz` package for your architecture and follow the `INSTALL.md` instructions inside. --- EOF cat >> RELEASE_BODY.md << EOF ## What's Changed $CHANGELOG **Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${TAG} EOF echo "changelog<> $GITHUB_OUTPUT cat RELEASE_BODY.md >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Prepare release assets run: | set -euxo pipefail mkdir -p _release_assets # Copy core binaries and rename dms-*.gz to dms-cli-*.gz for file in _core_assets/dms-*.gz*; do if [ -f "$file" ]; then basename=$(basename "$file") if [[ "$basename" == dms-distropkg-* ]]; then cp "$file" "_release_assets/$basename" else newname=$(echo "$basename" | sed 's/^dms-/dms-cli-/') cp "$file" "_release_assets/$newname" fi fi done # Copy dankinstall binaries cp _core_assets/dankinstall-*.gz* _release_assets/ # Copy completions cp _core_assets/completion.* _release_assets/ 2>/dev/null || true # Create QML source package (exclude build artifacts and git files) # Copy root LICENSE and CONTRIBUTING.md to quickshell/ for packaging cp LICENSE CONTRIBUTING.md quickshell/ # Tar the CONTENTS of quickshell/, not the directory itself (cd quickshell && tar --exclude='.git' \ --exclude='.github' \ --exclude='*.tar.gz' \ -czf ../_release_assets/dms-qml.tar.gz .) # Generate checksum for QML package (cd _release_assets && sha256sum dms-qml.tar.gz > dms-qml.tar.gz.sha256) # Create full packages for each architecture for arch in amd64 arm64; do mkdir -p _temp_full/dms mkdir -p _temp_full/bin mkdir -p _temp_full/completions # Extract QML source tar -xzf _release_assets/dms-qml.tar.gz -C _temp_full/dms # Add CLI binaries if [ -f "_core_assets/dms-${arch}.gz" ]; then gunzip -c "_core_assets/dms-${arch}.gz" > _temp_full/bin/dms chmod +x _temp_full/bin/dms fi if [ -f "_core_assets/dms-distropkg-${arch}.gz" ]; then gunzip -c "_core_assets/dms-distropkg-${arch}.gz" > _temp_full/bin/dms-distropkg chmod +x _temp_full/bin/dms-distropkg fi # Add shell completions for completion in _core_assets/completion.*; do if [ -f "$completion" ]; then cp "$completion" _temp_full/completions/ fi done # Copy docs directory if [ -d "docs" ]; then cp -r docs _temp_full/ fi # Create installation guide cat > _temp_full/INSTALL.md << 'EOFINSTALL' # DankMaterialShell Installation ## Requirements - Wayland compositor (niri or Hyprland recommended) - Quickshell framework - Qt6 ## Installation Steps 1. **Install quickshell assets:** ```bash mkdir -p ~/.config/quickshell cp -r dms ~/.config/quickshell/ ``` 2. **Install the DMS CLI binaries:** ```bash sudo install -m 755 bin/dms /usr/local/bin/dms ``` 3. **Install shell completions (optional):** ```bash # Bash sudo install -m 644 completions/completion.bash /usr/share/bash-completion/completions/dms # Fish sudo install -m 644 completions/completion.fish /usr/share/fish/vendor_completions.d/dms.fish # Zsh sudo install -m 644 completions/completion.zsh /usr/share/zsh/site-functions/_dms ``` 4. **Start the shell:** ```bash dms run ``` ## Configuration - Settings are stored in `~/.config/DankMaterialShell/settings.json` - Plugins go in `~/.config/DankMaterialShell/plugins/` - See the documentation in the `dms/` directory for more details ## Troubleshooting - Run with verbose output: `DMS_LOG_LEVEL=debug dms run` - Ensure all dependencies are installed EOFINSTALL # Create the full package (cd _temp_full && tar -czf "../_release_assets/dms-full-${arch}.tar.gz" .) # Generate checksum (cd _release_assets && sha256sum "dms-full-${arch}.tar.gz" > "dms-full-${arch}.tar.gz.sha256") # Cleanup rm -rf _temp_full done - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ env.TAG }} name: Release ${{ env.TAG }} body: ${{ steps.changelog.outputs.changelog }} files: _release_assets/** draft: false prerelease: ${{ contains(env.TAG, '-') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} trigger-obs-update: runs-on: ubuntu-latest needs: release steps: - name: Checkout uses: actions/checkout@v4 - name: Install OSC run: | sudo apt-get update sudo apt-get install -y osc mkdir -p ~/.config/osc cat > ~/.config/osc/oscrc << EOF [general] apiurl = https://api.opensuse.org [https://api.opensuse.org] user = ${{ secrets.OBS_USERNAME }} pass = ${{ secrets.OBS_PASSWORD }} EOF chmod 600 ~/.config/osc/oscrc - name: Update OBS packages run: | VERSION="${{ github.ref_name }}" cd distro bash scripts/obs-upload.sh dms "Update to $VERSION" trigger-ppa-update: runs-on: ubuntu-latest needs: release steps: - name: Checkout uses: actions/checkout@v4 - name: Install build dependencies run: | sudo apt-get update sudo apt-get install -y \ debhelper \ devscripts \ dput \ lftp \ build-essential \ fakeroot \ dpkg-dev - name: Configure GPG env: GPG_KEY: ${{ secrets.GPG_PRIVATE_KEY }} run: | echo "$GPG_KEY" | gpg --import GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | grep sec | awk '{print $2}' | cut -d'/' -f2) echo "DEBSIGN_KEYID=$GPG_KEY_ID" >> $GITHUB_ENV - name: Upload to PPA run: | VERSION="${{ github.ref_name }}" cd distro/ubuntu/ppa bash create-and-upload.sh ../dms dms questing copr-build: runs-on: ubuntu-latest needs: release env: TAG: ${{ github.ref_name }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Determine version id: version run: | VERSION="${TAG#v}" echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Building DMS stable version: $VERSION" - name: Setup build environment run: | sudo apt-get update sudo apt-get install -y rpm wget curl jq gzip mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} - name: Download release assets run: | VERSION="${{ steps.version.outputs.version }}" cd ~/rpmbuild/SOURCES wget "https://github.com/AvengeMedia/DankMaterialShell/releases/download/v${VERSION}/dms-qml.tar.gz" || { echo "Failed to download dms-qml.tar.gz for v${VERSION}" exit 1 } - name: Generate stable spec file run: | VERSION="${{ steps.version.outputs.version }}" CHANGELOG_DATE="$(date '+%a %b %d %Y')" cat > ~/rpmbuild/SPECS/dms.spec <<'SPECEOF' # Spec for DMS stable releases - Generated by GitHub Actions %global debug_package %{nil} %global version VERSION_PLACEHOLDER %global pkg_summary DankMaterialShell - Material 3 inspired shell for Wayland compositors Name: dms Version: %{version} Release: 1%{?dist} Summary: %{pkg_summary} License: MIT URL: https://github.com/AvengeMedia/DankMaterialShell Source0: dms-qml.tar.gz BuildRequires: gzip BuildRequires: wget BuildRequires: systemd-rpm-macros Requires: (quickshell or quickshell-git) Requires: accountsservice Requires: dms-cli Requires: dgop Recommends: cava Recommends: cliphist Recommends: danksearch Recommends: hyprpicker Recommends: matugen Recommends: wl-clipboard Recommends: NetworkManager Recommends: qt6-qtmultimedia Suggests: qt6ct %description DankMaterialShell (DMS) is a modern Wayland desktop shell built with Quickshell and optimized for the niri and hyprland compositors. Features notifications, app launcher, wallpaper customization, and fully customizable with plugins. Includes auto-theming for GTK/Qt apps with matugen, 20+ customizable widgets, process monitoring, notification center, clipboard history, dock, control center, lock screen, and comprehensive plugin system. %package -n dms-cli Summary: DankMaterialShell CLI tool License: MIT URL: https://github.com/AvengeMedia/DankMaterialShell %description -n dms-cli Command-line interface for DankMaterialShell configuration and management. Provides native DBus bindings, NetworkManager integration, and system utilities. %package -n dgop Summary: Stateless CPU/GPU monitor for DankMaterialShell License: MIT URL: https://github.com/AvengeMedia/dgop Provides: dgop %description -n dgop DGOP is a stateless system monitoring tool that provides CPU, GPU, memory, and network statistics. Designed for integration with DankMaterialShell but can be used standalone. This package always includes the latest stable dgop release. %prep %setup -q -c -n dms-qml # Download architecture-specific binaries during build case "%{_arch}" in x86_64) ARCH_SUFFIX="amd64" ;; aarch64) ARCH_SUFFIX="arm64" ;; *) echo "Unsupported architecture: %{_arch}" exit 1 ;; esac wget -O %{_builddir}/dms-cli.gz "https://github.com/AvengeMedia/DankMaterialShell/releases/latest/download/dms-distropkg-${ARCH_SUFFIX}.gz" || { echo "Failed to download dms-cli for architecture %{_arch}" exit 1 } gunzip -c %{_builddir}/dms-cli.gz > %{_builddir}/dms-cli chmod +x %{_builddir}/dms-cli wget -O %{_builddir}/dgop.gz "https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-${ARCH_SUFFIX}.gz" || { echo "Failed to download dgop for architecture %{_arch}" exit 1 } gunzip -c %{_builddir}/dgop.gz > %{_builddir}/dgop chmod +x %{_builddir}/dgop %build %install install -Dm755 %{_builddir}/dms-cli %{buildroot}%{_bindir}/dms install -Dm755 %{_builddir}/dgop %{buildroot}%{_bindir}/dgop install -d %{buildroot}%{_datadir}/bash-completion/completions install -d %{buildroot}%{_datadir}/zsh/site-functions install -d %{buildroot}%{_datadir}/fish/vendor_completions.d %{_builddir}/dms-cli completion bash > %{buildroot}%{_datadir}/bash-completion/completions/dms || : %{_builddir}/dms-cli completion zsh > %{buildroot}%{_datadir}/zsh/site-functions/_dms || : %{_builddir}/dms-cli completion fish > %{buildroot}%{_datadir}/fish/vendor_completions.d/dms.fish || : install -Dm644 assets/systemd/dms.service %{buildroot}%{_userunitdir}/dms.service install -Dm644 assets/dms-open.desktop %{buildroot}%{_datadir}/applications/dms-open.desktop install -Dm644 assets/danklogo.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg install -dm755 %{buildroot}%{_datadir}/quickshell/dms cp -r %{_builddir}/dms-qml/* %{buildroot}%{_datadir}/quickshell/dms/ rm -rf %{buildroot}%{_datadir}/quickshell/dms/.git* rm -f %{buildroot}%{_datadir}/quickshell/dms/.gitignore rm -rf %{buildroot}%{_datadir}/quickshell/dms/.github rm -rf %{buildroot}%{_datadir}/quickshell/dms/distro echo "%{version}" > %{buildroot}%{_datadir}/quickshell/dms/VERSION %posttrans if [ -d "%{_sysconfdir}/xdg/quickshell/dms" ]; then rmdir "%{_sysconfdir}/xdg/quickshell/dms" 2>/dev/null || true rmdir "%{_sysconfdir}/xdg/quickshell" 2>/dev/null || true rmdir "%{_sysconfdir}/xdg" 2>/dev/null || true fi if [ "$1" -ge 2 ]; then pkill -USR1 -x dms >/dev/null 2>&1 || true fi %files %license LICENSE %doc README.md CONTRIBUTING.md %{_datadir}/quickshell/dms/ %{_userunitdir}/dms.service %{_datadir}/applications/dms-open.desktop %{_datadir}/icons/hicolor/scalable/apps/danklogo.svg %files -n dms-cli %{_bindir}/dms %{_datadir}/bash-completion/completions/dms %{_datadir}/zsh/site-functions/_dms %{_datadir}/fish/vendor_completions.d/dms.fish %files -n dgop %{_bindir}/dgop %changelog * CHANGELOG_DATE_PLACEHOLDER AvengeMedia - VERSION_PLACEHOLDER-1 - Stable release VERSION_PLACEHOLDER - Built from GitHub release - Includes latest dms-cli and dgop binaries SPECEOF sed -i "s/VERSION_PLACEHOLDER/${VERSION}/g" ~/rpmbuild/SPECS/dms.spec sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" ~/rpmbuild/SPECS/dms.spec - name: Build SRPM id: build run: | cd ~/rpmbuild/SPECS rpmbuild -bs dms.spec SRPM=$(ls ~/rpmbuild/SRPMS/*.src.rpm | tail -n 1) SRPM_NAME=$(basename "$SRPM") echo "srpm_path=$SRPM" >> $GITHUB_OUTPUT echo "srpm_name=$SRPM_NAME" >> $GITHUB_OUTPUT echo "SRPM built: $SRPM_NAME" - name: Upload SRPM artifact uses: actions/upload-artifact@v4 with: name: dms-stable-srpm-${{ steps.version.outputs.version }} path: ${{ steps.build.outputs.srpm_path }} retention-days: 90 - name: Install Copr CLI run: | sudo apt-get install -y python3-pip pip3 install copr-cli mkdir -p ~/.config cat > ~/.config/copr << EOF [copr-cli] login = ${{ secrets.COPR_LOGIN }} username = avengemedia token = ${{ secrets.COPR_TOKEN }} copr_url = https://copr.fedorainfracloud.org EOF chmod 600 ~/.config/copr - name: Upload to Copr run: | SRPM="${{ steps.build.outputs.srpm_path }}" VERSION="${{ steps.version.outputs.version }}" echo "Uploading SRPM to avengemedia/dms..." BUILD_OUTPUT=$(copr-cli build avengemedia/dms "$SRPM" --nowait 2>&1) echo "$BUILD_OUTPUT" BUILD_ID=$(echo "$BUILD_OUTPUT" | grep -oP 'Build was added to.*\K[0-9]+' || echo "unknown") if [ "$BUILD_ID" != "unknown" ]; then echo "Build submitted: https://copr.fedorainfracloud.org/coprs/avengemedia/dms/build/$BUILD_ID/" fi