diff --git a/.github/workflows/appimage-build.yml b/.github/workflows/appimage-build.yml new file mode 100644 index 0000000..f7c5ab1 --- /dev/null +++ b/.github/workflows/appimage-build.yml @@ -0,0 +1,56 @@ +name: AppImage Build + +on: + workflow_dispatch: + # Ensure the build works on main + push: + branches: [main] + # Ensure the build works on each pull request + pull_request: + # Build and publish on release + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-22.04 + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + - uses: extractions/setup-just@v2 + + - name: Load dotenv + run: just ci-load-dotenv + + - name: Load dotenv + run: just bump-version + + # Install FUSE (https://github.com/AppImage/AppImageKit/wiki/FUSE) + - name: Install pkg2image dependencies + run: | + sudo add-apt-repository universe + sudo apt install libfuse2 + + # Install pkg2appimage and build the game (https://github.com/AppImageCommunity/pkg2appimage) + - name: Build AppImage + run: | + wget -c $(wget -q https://api.github.com/repos/AppImageCommunity/pkg2appimage/releases -O - | grep "pkg2appimage-.*-x86_64.AppImage" | grep browser_download_url | head -n 1 | cut -d '"' -f 4) + chmod +x ./pkg2appimage-*.AppImage + ./pkg2appimage-*.AppImage public/packaging/appimage/recipe.yml + + - name: Rename the AppImage + run: mv ./out/*.AppImage ${{ env.game_name }}-${{ env.game_version }}.AppImage + + - uses: actions/upload-artifact@v4 + with: + name: ${{ env.game_name }}-${{ env.game_version }}.AppImage + path: ./ + + # Publish, on each release + - name: Publish AppImage + if: startsWith(github.ref, 'refs/tags/') + run: | + gh release upload ${{ env.game_version }} ./${{ env.game_name }}-${{ env.game_version }}.AppImage + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/snapcraft-build.yaml b/.github/workflows/snapcraft-build.yaml new file mode 100644 index 0000000..f2433a5 --- /dev/null +++ b/.github/workflows/snapcraft-build.yaml @@ -0,0 +1,39 @@ +name: Snapcraft Build + +on: + workflow_dispatch: + # Ensure the build works on main + push: + branches: [main] + # Ensure the build works on each pull request + pull_request: + # Build and publish on release + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-22.04 + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + - uses: extractions/setup-just@v2 + + - name: Load dotenv + run: just bump-version + + - name: Build snap package + uses: snapcore/action-build@v1 + with: + path: public/packaging + id: snapcraft + + # Push, on each release, to the stable channel + - uses: snapcore/action-publish@v1 + if: startsWith(github.ref, 'refs/tags/') + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }} + with: + snap: ${{ steps.snapcraft.outputs.snap }} + release: stable diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c05084e..7c07ce9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,7 +49,8 @@ repos: LICENSE.md| LICENSES/| public/| - README.md + README.md| + RELEASING.md ) - id: format-shaders name: format shaders diff --git a/Justfile b/Justfile index 31510ca..d69a0e7 100644 --- a/Justfile +++ b/Justfile @@ -4,7 +4,6 @@ set dotenv-load := true - # === Aliases === [private] @@ -22,7 +21,7 @@ main_dir := home_dir / ".mkflower" cache_dir := main_dir / "cache" bin_dir := main_dir / "bin" -# Local directories +# Local directories for game exports build_dir := justfile_directory() / "build" dist_dir := justfile_directory() / "dist" @@ -30,18 +29,14 @@ dist_dir := justfile_directory() / "dist" godot_version := env_var('GODOT_VERSION') godot_platform := if arch() == "x86" { "linux.x86_32" -} else { - if arch() == "x86_64" { +} else if arch() == "x86_64" { "linux.x86_64" - } else { - if arch() == "arm" { - "linux.arm32" - } else { - if arch() == "aarch64" { - "linux.arm64" - } else { "" } - } - } +} else if arch() == "arm" { + "linux.arm32" +} else if arch() == "aarch64" { + "linux.arm64" +} else { + "" } godot_filename := "Godot_v" + godot_version + "_" + godot_platform godot_template := "Godot_v" + godot_version + "_export_templates.tpz" @@ -64,7 +59,13 @@ venv_dir := justfile_directory() / "venv" # Butler binary butler_bin := bin_dir / "butler" -butler_platform := if arch() == "x86" { "linux-386" } else { if arch() == "x86_64" { "linux-amd64" } else{ "" } } +butler_platform := if arch() == "x86" { + "linux-386" +} else if arch() == "x86_64" { + "linux-amd64" +} else { + "" +} # === Commands === @@ -80,9 +81,8 @@ butler_platform := if arch() == "x86" { "linux-386" } else { if arch() == "x86_6 # === Installer === # -# Recipes that check and/or install some binaries like Godot, Bulter ... -# This means the user doesn't have to worry about installation, -# and can be sure that the same code is running in CI and locally. +# Recipes for checking and/or installing binaries like Godot and Butler. +# Ensures consistent environments across CI and local development. # Download Godot [private] @@ -91,7 +91,7 @@ install-godot: makedirs unzip -o {{ cache_dir }}/{{ godot_filename }}.zip -d {{ cache_dir }} cp {{ cache_dir }}/{{ godot_filename }} {{ godot_bin }} -# Download Godot if not already done +# Check and download Godot if not already installed [private] @check-godot: [ ! -e {{ godot_bin }} ] && just install-godot || true @@ -104,7 +104,7 @@ install-templates: makedirs mkdir -p {{ godot_templates_dir }} cp {{ cache_dir }}/templates/* {{ godot_templates_dir }} -# Download Godot export templates if not already done +# Check and download Godot export templates if not already installed [private] @check-templates: [ ! -d {{ godot_templates_dir }} ] && just install-templates || true @@ -117,15 +117,16 @@ install-butler: makedirs mv {{ cache_dir }}/butler {{ butler_bin }} chmod +x {{ butler_bin }} -# Download Butler if not already done +# Check and download Butler if not already installed [private] @check-butler: [ ! -e {{ butler_bin }} ] && just install-butler || true # === Python === # -# Recipes that use python or python packages. -# This ensures that all python packages are installed in a virtual environment. +# Recipes for working with Python and Python packages. +# These recipes ensure that Python packages are installed within a virtual environment, +# providing a clean and isolated environment. export PIP_REQUIRE_VIRTUALENV := "true" @@ -146,8 +147,10 @@ credits: # === Godot === # -# Recipes around the Godot binary. -# This simplifies some recurring tasks, such as installing addons. +# Recipes for managing the Godot binary. +# These recipes simplify common tasks such as installing addons, importing game resources, +# and opening the Godot editor. + # Godot binary wrapper godot *ARGS: check-godot check-templates @@ -169,12 +172,18 @@ godot *ARGS: check-godot check-templates just godot --editor # === Butler === +# +# Recipes for managing the Butler binary. # Bulter wrapper butler *ARGS: check-butler {{ butler_bin }} {{ ARGS }} # === Export === +# +# Recipes for exporting the game to different platforms. +# Handles tasks such as updating version information, preparing directories, +# and exporting the game for Windows, MacOS, Linux, and the web. # Updates the game version for export @bump-version: @@ -220,8 +229,7 @@ export: export-windows export-mac export-linux # === Clean === # -# Recipes that clean up the project, deleting -# files and folders created by this Justfile. +# Recipes for cleaning up the project, removing files and folders created by this Justfile. # Remove game plugins clean-addons: @@ -241,8 +249,8 @@ clean: clean-addons clean-resources clean-export # === CI === # -# Recipes launched by CI steps. -# They can be run locally, but requires the setup of some environment variables. +# Recipes triggered by CI steps. +# Can be run locally but requires setup of environment variables. # Add some variables to Github env ci-load-dotenv: diff --git a/README.md b/README.md index 35c5cc1..2f55964 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,90 @@ A template to create new [Godot Engine](https://godotengine.org/) project. Eventually, you can remove any unused files, such as irrelevant github workflows for your project. Feel free to replace the License with one suited for your project. +## Installation + +### From a release + +Released binaries are available on Itch.io and +on the Github repository, in the release section. + +Download the zip archive, accordingly to your OS, and unzip it. + +- **Windows**: Double click on `Greeter.exe`. +- **MacOS**: Double click on `Greeter.app`. +- **Linux**: In a terminal, run `./Greeter.x86_64`. + +### From Snap + +With the [Snap command line](https://manpages.ubuntu.com/manpages/focal/en/man8/snap.8.html), run: +``` +snap install godot-template +``` + +To run the game: +``` +godot-template.greeter +``` + +### From an AppImage + +The AppImage is available on the Github + repository, in the release section. + +More details on how to run an AppImage, on the + [official documentation](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage). + +### From source + +> [!IMPORTANT] +> For this installation, you need to have +> the Godot Editor installed. + +Clone the source locally: +``` +git clone https://github.com/MechanicalFlower/godot-template.git +``` + +You need to install addons first: +``` +godot --headless --script plug.gd install +``` + +And simply run the game as any Godot project: +``` +godot +``` + +## Development + +The project use: +- [`just`](https://just.systems/man/en/) as command runner, +- [`pre-commit`](https://pre-commit.com/) to run formatters, this requires [Python 3](https://docs.python.org/3/). + +> [!IMPORTANT] +> Actually, `just` recipes only support Linux. + +To check all available recipes, run: +``` +just +``` + +To run formatters: +``` +just fmt +``` + +To install, and run the game: +``` +just install-addons +just godot +``` + +> [!TIP] +> In `just` recipes, the Godot Editor is installed +> automatically. This ensure that you +> use the right version of the engine. + ## Contributing ![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg) @@ -41,3 +125,7 @@ Feel free to replace the License with one suited for your project. We welcome community contributions to this project. Please read our [Contributor Guide](CONTRIBUTING.md) for more information on how to get started. + +## Releasing + +Please read our [Release Guide](RELEASING.md) for more information on how we manage our releases. diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..9b50d5f --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,37 @@ +# Releasing + +This document outlines the release policy for games within our organization. + +## Versioning + +We adhere to [Semantic Versioning](https://semver.org/) for our releases, following the `MAJOR.MINOR.PATCH` format. + +## Branching + +Our projects maintain the following active branches: +* **main**: This branch represents the next release and is where all merges take place. + +## Continuous Delivery + +We use [Github Actions](https://docs.github.com/en/actions) to automate the release process. When a new version is released, the CI pipeline automatically triggers a publication on the **GitHub** and **itch.io** platforms. + +## Steps to release + +1. Update the version in the code base + - Update the `.env` file + 1. Change the `GAME_VERSION` variable to the new version + 2. Run the `bump-version` recipe + - Update the `CHANGELOG.md` file + 1. Replace the `Unreleased` title with the new version + 2. Add a link for the new version at the bottom of the changelog + 3. Create a new `Unreleased` section +2. Merge the change into the `main` branch + 1. Create a branch `release-` from the `main` branch + 2. Commit the changes with `"chore: bump version to for release"` as message + 3. Push the branch to the remote repository + 4. Create a pull request targeting the `main` branch + 5. Review the changes in the pull request and ensure they meet the release criteria + 6. Merge the pull request into the `main` branch +3. Tag the `main` branch + 1. Tag the `main` branch with the release version + 2. Push the tags to the remote repository diff --git a/public/.gitignore b/public/.gitignore index e4fdbdb..b2bab8b 100644 --- a/public/.gitignore +++ b/public/.gitignore @@ -1 +1,2 @@ *.import +*.snap diff --git a/public/packaging/appimage/recipe.yml b/public/packaging/appimage/recipe.yml new file mode 100644 index 0000000..6922f08 --- /dev/null +++ b/public/packaging/appimage/recipe.yml @@ -0,0 +1,46 @@ +app: Greeter + +ingredients: + dist: trusty + sources: + - deb http://us.archive.ubuntu.com/ubuntu/ trusty main universe + packages: + - libx11-6 + - libxinerama1 + - libxcursor1 + - libxrandr2 + - libfreetype6 + - libpng12-0 + - libasound2 + - libpulse0 + - libgl1-mesa-glx + - zlib1g + - libgcc1 + - libc6 + script: + # Download released builds + - wget -c "https://github.com/MechanicalFlower/Greeter/releases/download/0.1.0/Greeter-linux-v0.1.0.zip" + - unzip *.zip + # Download the icon and the .desktop file + - wget -c "https://raw.githubusercontent.com/MechanicalFlower/Greeter/0.1.0/public/packaging/org.mechanicalflower.Greeter.desktop" + - wget -c "https://raw.githubusercontent.com/MechanicalFlower/Greeter/0.1.0/assets/icon.png" + +script: + - sed -i.bak -e "s,Version=.*$,,g" ../org.mechanicalflower.Greeter.desktop + # Replace the icon path in the desktop file + - sed -i.bak -e "s,Icon=org.mechanicalflower.Greeter$,Icon=/usr/share/icons/hicolor/apps/Greeter.png,g" ../org.mechanicalflower.Greeter.desktop + # Replace the exec command in the desktop file + - sed -i.bak -e "s,Exec=Greeter-wrapper$,Exec=bin/Greeter.x86_64 --main-pack bin/Greeter.pck --rendering-driver opengl3,g" ../org.mechanicalflower.Greeter.desktop + # Copy the desktop file + - mkdir -p usr/share/applications/ + - cp ../org.mechanicalflower.Greeter.desktop . + - cp ../org.mechanicalflower.Greeter.desktop usr/share/applications/org.mechanicalflower.Greeter.desktop + # Copy the icon + - mkdir -p usr/share/icons/hicolor/apps/ + - cp ../icon.png usr/share/icons/hicolor/apps/Greeter.png + # Copy game files + - mkdir -p usr/bin/ + - cp ../Greeter.x86_64 usr/bin/Greeter.x86_64 + - cp ../Greeter.pck usr/bin/Greeter.pck + # Ensure the game is an executable + - chmod +x usr/bin/Greeter.x86_64 diff --git a/public/packaging/org.mechanicalflower.Greeter.desktop b/public/packaging/org.mechanicalflower.Greeter.desktop new file mode 100644 index 0000000..ce1d4d8 --- /dev/null +++ b/public/packaging/org.mechanicalflower.Greeter.desktop @@ -0,0 +1,11 @@ + +[Desktop Entry] +Type=Application + +Name=Greeter +Comment==Godot template. +Categories=Game; + +Icon=org.mechanicalflower.Greeter +Exec=greeter-wrapper +Terminal=false diff --git a/public/packaging/snap/snapcraft.yaml b/public/packaging/snap/snapcraft.yaml new file mode 100644 index 0000000..39b77b7 --- /dev/null +++ b/public/packaging/snap/snapcraft.yaml @@ -0,0 +1,51 @@ + +--- +name: godot-template +base: core20 +version: '0.1.0' +summary: A greeter race minigame +description: | + A greeter race minigame, made with Godot Engine. +grade: stable +confinement: strict +license: MIT +architectures: [amd64] + +apps: + greeter: + command: Greeter.x86_64 --main-pack $SNAP/Greeter.pck --rendering-driver opengl3 + extensions: [gnome-3-38] + plugs: + - pulseaudio + - opengl + - x11 + desktop: org.mechanicalflower.Greeter.desktop + environment: + LD_LIBRARY_PATH: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio:$SNAP" + +parts: + greeter-source: + source: https://github.com/MechanicalFlower/Greeter/archive/refs/tags/0.1.0.tar.gz + override-build: | + snapcraftctl build + + # Icon paths in the desktop file will be rewritten to use ${SNAP}/ if specified as desktop file in snapcraft.yaml + sed -i.bak -e "s|Icon=org.mechanicalflower.Greeter$|Icon=gui/icon.png|g" ${SNAPCRAFT_PART_SRC}/public/packaging/org.mechanicalflower.Greeter.desktop + + cp ${SNAPCRAFT_PART_SRC}/public/packaging/org.mechanicalflower.Greeter.desktop ${SNAPCRAFT_PART_INSTALL}/org.mechanicalflower.Greeter.desktop + plugin: nil + override-prime: | + snapcraftctl prime + + mkdir -p ${SNAPCRAFT_PRIME}/gui + cp ${SNAPCRAFT_PART_SRC}/assets/icon.png ${SNAPCRAFT_PRIME}/gui/icon.png + greeter-dist: + source: https://github.com/MechanicalFlower/Greeter/releases/download/0.1.0/Greeter-linux-v0.1.0.zip + override-build: | + snapcraftctl build + + cp ${SNAPCRAFT_PART_SRC}/Greeter.x86_64 ${SNAPCRAFT_PART_INSTALL}/Greeter.x86_64 + cp ${SNAPCRAFT_PART_SRC}/Greeter.pck ${SNAPCRAFT_PART_INSTALL}/Greeter.pck + + chmod +x ${SNAPCRAFT_PART_INSTALL}/Greeter.x86_64 + plugin: nil