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/ # Copy root assets directory to quickshell for systemd service and desktop file cp -r assets 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 = %{version}-%{release} Requires: dgop Recommends: cava Recommends: cliphist Recommends: danksearch 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. %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 %build %install install -Dm755 %{_builddir}/dms-cli %{buildroot}%{_bindir}/dms 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 # Signal running DMS instances to reload pkill -USR1 -x dms >/dev/null 2>&1 || : %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 %changelog * CHANGELOG_DATE_PLACEHOLDER AvengeMedia - VERSION_PLACEHOLDER-1 - Stable release VERSION_PLACEHOLDER - Built from GitHub release 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