diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 19:30:47 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 19:31:15 +0300 |
| commit | b1e34e861b5d732afe828d58aad2c638135061fd (patch) | |
| tree | 6ab65910221ff147b1fdc49299418d8af04d0a7b | |
| parent | c965a4ebddf98c368edd905324a4ecd79b2aae55 (diff) | |
| download | Project-Tick-b1e34e861b5d732afe828d58aad2c638135061fd.tar.gz Project-Tick-b1e34e861b5d732afe828d58aad2c638135061fd.zip | |
NOISSUE Add GitHub workflows for Project Tick project
- Create CodeQL analysis workflow for security checks on meshmc codebase.
- Add container build workflow for meshmc using Podman and Buildah.
- Implement scheduled flake update workflow for Nix dependencies.
- Introduce merge blocking PR automation to manage dependent PRs.
- Set up Nix build workflow for meshmc with multi-platform support.
- Add release workflow for publishing MeshMC artifacts on GitHub.
- Create CI workflow for tomlplusplus library with multi-compiler support.
- Implement CI workflow for uvim with various feature sets and architectures.
- Add .gitignore to exclude build artifacts and IDE files.
- Create .gitattributes files for various submodules to manage line endings and diff settings.
- Add post-receive hook for mirroring pushes to multiple forges.
- Include .gitignore files for images4docker and other submodules to manage temporary files.
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
45 files changed, 3357 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..2422cb5f67 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,47 @@ +# Project-Tick Monorepo +# ====================== + +# Global defaults +* text=auto eol=lf + +# Archives +*.7z binary +*.gz binary +*.tar binary +*.xz binary +*.zip binary + +# Images +*.bmp binary +*.gif binary +*.ico binary +*.jpg binary +*.jpeg binary +*.png binary +*.svg text +*.webp binary + +# Fonts +*.otf binary +*.ttf binary +*.woff binary +*.woff2 binary + +# Documents +*.pdf binary + +# Executables +*.exe binary +*.dll binary +*.so binary +*.dylib binary + +# Java +*.class binary +*.jar binary + +# Crypto +*.pem -crlf + +# Linguist overrides +archived/* linguist-vendored diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..3c147eb94b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,65 @@ +name: Bug Report +description: File a bug report +labels: [bug, needs-triage] +body: +- type: markdown + attributes: + value: | + If you need help with running Minecraft, please visit us [on our Discord](https://discord.gg/meshmc) before making a bug report. + + Before submitting a bug report, please make sure you have read this *entire* form, and that: + * You have read the [FAQ](https://github.com/Project-Tick/MeshMC/wiki/FAQ) and it has not answered your question + * Your bug is not caused by Minecraft or any mods you have installed. + * Your issue has not been reported before, [make sure to use the search function!](https://github.com/Project-Tick/MeshMC/issues) + + **Do not forget to give your issue a descriptive title.** "Bug in the instance screen" makes it hard to distinguish issues at a glance. +- type: dropdown + attributes: + label: Operating System + description: If you know this bug occurs on multiple operating systems, select all you have tested. + multiple: true + options: + - Windows + - macOS + - Linux + - Other +- type: textarea + attributes: + label: Version of MeshMC + description: The version of MeshMC used in the bug report. + placeholder: MeshMC 7.0.0 + validations: + required: true +- type: textarea + attributes: + label: Version of Qt + description: The version of Qt used in the bug report. You can find it in Help -> About MeshMC -> About Qt. + placeholder: Qt 6.3.0 + validations: + required: true +- type: textarea + attributes: + label: Description of bug + description: What did you expect to happen, what happened, and why is it incorrect? + placeholder: The cat button should show a cat, but it showed a dog instead! + validations: + required: true +- type: textarea + attributes: + label: Steps to reproduce + description: A bulleted list, or an exported instance if relevant. + placeholder: "* Press the cat button" + validations: + required: true +- type: textarea + attributes: + label: Suspected cause + description: If you know what could be causing this bug, describe it here. + validations: + required: false +- type: checkboxes + attributes: + label: This issue is unique + options: + - label: I have searched the issue tracker and did not find an issue describing my bug. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..37c7e6ebdc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: MeshMC Discord + url: https://discord.gg/meshmc + about: Please ask for support here before opening an issue. diff --git a/.github/ISSUE_TEMPLATE/rfc.yml b/.github/ISSUE_TEMPLATE/rfc.yml new file mode 100644 index 0000000000..d9f5b0a981 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rfc.yml @@ -0,0 +1,68 @@ +# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst +name: Request for Comment (RFC) +description: Propose a larger change and start a discussion. +labels: ["type: enhancement", "status: needs discussion", "status: needs triage"] +body: +- type: markdown + attributes: + value: | + ### Use this form to suggest a larger change for MeshMC. +- type: textarea + attributes: + label: Goal + description: Short description, 1-2 sentences. + placeholder: Remove the cat from the launcher. + validations: + required: true +- type: textarea + attributes: + label: Motivation + description: | + Introduce the topic. If this is a not-well-known section of MeshMC, a detailed explanation of the background is recommended. + Some example points of discussion: + - What specific problems are you facing right now that you're trying to address? + - Are there any previous discussions? Link to them and summarize them (don't force your readers to read them though!). + - Is there any precedent set by other software? If so, link to resources. + placeholder: I don't like cats. I think many users also don't like cats. + validations: + required: true +- type: textarea + attributes: + label: Specification + description: A concrete, thorough explanation of what is being planned. + placeholder: Remove the cat button and all references to the cat from the codebase. Including resource files. + validations: + required: true +- type: textarea + attributes: + label: Drawbacks + description: Carefully consider every possible objection and issue with your proposal. This section should be updated as feedback comes in from discussion. + placeholder: Some users might like cats. + validations: + required: true +- type: textarea + attributes: + label: Unresolved Questions + description: | + Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed? + Be careful here -- an RFC with a lot of remaining questions is likely to be stalled. + If your RFC is mostly unresolved questions and not too much substance, it may not be ready. + placeholder: Do a lot of users care about the cat? + validations: + required: true +- type: textarea + attributes: + label: Alternatives Considered + description: A list of alternatives, that have been considered and offer equal or similar features to the proposed change. + placeholder: Maybe the cat could be replaced with an axolotl? + validations: + required: true +- type: checkboxes + attributes: + label: This suggestion is unique + options: + - label: I have searched the issue tracker and did not find an issue describing my suggestion, especially not one that has been rejected. + required: true +- type: textarea + attributes: + label: You may use the editor below to elaborate further. diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml new file mode 100644 index 0000000000..53bd186531 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -0,0 +1,38 @@ +name: Suggestion +description: Make a suggestion +labels: [idea, needs-triage] +body: +- type: markdown + attributes: + value: | + ### Use this form to suggest a feature for MeshMC. +- type: input + attributes: + label: Role + description: In what way do you use MeshMC that needs this feature? + placeholder: I play modded Minecraft. + validations: + required: true +- type: input + attributes: + label: Suggestion + description: What do you want MeshMC to do? + placeholder: I want the cat button to meow. + validations: + required: true +- type: input + attributes: + label: Benefit + description: Why do you need MeshMC to do this? + placeholder: so that I can always hear a cat when I need to. + validations: + required: true +- type: checkboxes + attributes: + label: This suggestion is unique + options: + - label: I have searched the issue tracker and did not find an issue describing my suggestion, especially not one that has been rejected. + required: true +- type: textarea + attributes: + label: You may use the editor below to elaborate further. diff --git a/.github/actions/meshmc/package/linux/action.yml b/.github/actions/meshmc/package/linux/action.yml new file mode 100644 index 0000000000..457ccb27ed --- /dev/null +++ b/.github/actions/meshmc/package/linux/action.yml @@ -0,0 +1,153 @@ +name: Package for Linux +description: Create Linux packages for MeshMC + +inputs: + version: + description: Launcher version + required: true + build-type: + description: Type for the build + required: true + default: Debug + artifact-name: + description: Name of the uploaded artifact + required: true + default: Linux + qt-version: + description: Version of Qt to use + required: true + gpg-private-key: + description: Private key for AppImage signing + required: false + gpg-private-key-id: + description: ID for the gpg-private-key, to select the signing key + required: false + +runs: + using: composite + + steps: + - name: Cleanup Qt installation on Linux + shell: bash + run: | + rm -rf "$QT_PLUGIN_PATH"/printsupport + rm -rf "$QT_PLUGIN_PATH"/sqldrivers + rm -rf "$QT_PLUGIN_PATH"/help + rm -rf "$QT_PLUGIN_PATH"/designer + rm -rf "$QT_PLUGIN_PATH"/qmltooling + rm -rf "$QT_PLUGIN_PATH"/qmlls + rm -rf "$QT_PLUGIN_PATH"/qmllint + rm -rf "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so + + - name: Setup build variables + shell: bash + run: | + # Fixup architecture naming for AppImages + dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)" + case "$dpkg_arch" in + "amd64") + APPIMAGE_ARCH="x86_64" + ;; + "arm64") + APPIMAGE_ARCH="aarch64" + ;; + *) + echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY" + exit 1 + ;; + esac + echo "APPIMAGE_ARCH=$APPIMAGE_ARCH" >> "$GITHUB_ENV" + + # Used for the file paths of libraries + echo "DEB_HOST_MULTIARCH=$(dpkg-architecture -q DEB_HOST_MULTIARCH)" >> "$GITHUB_ENV" + + - name: Package AppImage + shell: bash + env: + VERSION: ${{ github.ref_type == 'tag' && github.ref_name || inputs.version }} + BUILD_DIR: build + INSTALL_APPIMAGE_DIR: install-appdir + + GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }} + run: | + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }} + + if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then + echo "$GPG_PRIVATE_KEY" > privkey.asc + gpg --import privkey.asc + gpg --export --armor ${{ inputs.gpg-private-key-id }} > pubkey.asc + else + echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY + fi + + sharun lib4bin \ + --hard-links \ + --with-hooks \ + --dst-dir "$INSTALL_APPIMAGE_DIR" \ + "$INSTALL_APPIMAGE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so + + cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/bin/ + # FIXME(@YongDo-Hyun): gamemode doesn't seem to be very portable with DBus. Find a way to make it work! + find "$INSTALL_APPIMAGE_DIR" -name '*gamemode*' -exec rm {} + + + #disable OpenGL and Vulkan launcher features until https://github.com/VHSgunzo/sharun/issues/35 + echo "LAUNCHER_DISABLE_GLVULKAN=1" > "$INSTALL_APPIMAGE_DIR"/.env + #makes the launcher use portals for file picking + echo "QT_QPA_PLATFORMTHEME=xdgdesktopportal" > "$INSTALL_APPIMAGE_DIR"/.env + ln -s org.projecttick.MeshMC.metainfo.xml "$INSTALL_APPIMAGE_DIR"/share/metainfo/org.projecttick.MeshMC.appdata.xml + ln -s share/applications/org.projecttick.MeshMC.desktop "$INSTALL_APPIMAGE_DIR" + ln -s share/icons/hicolor/256x256/apps/org.projecttick.MeshMC.png "$INSTALL_APPIMAGE_DIR" + mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun} + ls -la "$INSTALL_APPIMAGE_DIR" + + if [[ "${{ github.ref_type }}" == "tag" ]]; then + APPIMAGE_DEST="MeshMC-Linux-$APPIMAGE_ARCH.AppImage" + else + APPIMAGE_DEST="MeshMC-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage" + fi + + mkappimage \ + --updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|MeshMC-Linux-$APPIMAGE_ARCH.AppImage.zsync" \ + "$INSTALL_APPIMAGE_DIR" \ + "$APPIMAGE_DEST" + + - name: Package portable tarball + shell: bash + env: + BUILD_DIR: build + + INSTALL_PORTABLE_DIR: install-portable + run: | + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable + + sharun lib4bin \ + --with-hooks \ + --hard-links \ + --dst-dir "$INSTALL_PORTABLE_DIR" \ + "$INSTALL_PORTABLE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so + + # FIXME(@YongDo-Hyun): gamemode doesn't seem to be very portable with DBus. Find a way to make it work! + find "$INSTALL_PORTABLE_DIR" -name '*gamemode*' -exec rm {} + + + for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f -o -type l); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt + cd ${{ env.INSTALL_PORTABLE_DIR }} + tar -czf ../MeshMC-portable.tar.gz * + + - name: Upload binary tarball + uses: actions/upload-artifact@v7 + with: + name: MeshMC-${{ inputs.artifact-name }}-Qt6-Portable-${{ inputs.version }}-${{ inputs.build-type }} + path: MeshMC-portable.tar.gz + + - name: Upload AppImage + uses: actions/upload-artifact@v7 + with: + name: MeshMC-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage + path: MeshMC-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage + + - name: Upload AppImage Zsync + uses: actions/upload-artifact@v7 + with: + name: MeshMC-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync + path: MeshMC-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage.zsync diff --git a/.github/actions/meshmc/package/macos/action.yml b/.github/actions/meshmc/package/macos/action.yml new file mode 100644 index 0000000000..2a1c432a6d --- /dev/null +++ b/.github/actions/meshmc/package/macos/action.yml @@ -0,0 +1,146 @@ +name: Package for macOS +description: Create a macOS package for MeshMC + +inputs: + version: + description: Launcher version + required: true + build-type: + description: Type for the build + required: true + default: Debug + artifact-name: + description: Name of the uploaded artifact + required: true + default: macOS + apple-codesign-cert: + description: Certificate for signing macOS builds + required: false + apple-codesign-password: + description: Password for signing macOS builds + required: false + apple-codesign-id: + description: Certificate ID for signing macOS builds + required: false + apple-notarize-apple-id: + description: Apple ID used for notarizing macOS builds + required: false + apple-notarize-team-id: + description: Team ID used for notarizing macOS builds + required: false + apple-notarize-password: + description: Password used for notarizing macOS builds + required: false + sparkle-ed25519-key: + description: Private key for signing Sparkle updates + required: false + +runs: + using: composite + + steps: + - name: Fetch codesign certificate + shell: bash + run: | + echo '${{ inputs.apple-codesign-cert }}' | base64 --decode > codesign.p12 + if [ -n '${{ inputs.apple-codesign-id }}' ]; then + security create-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain + security import codesign.p12 -k build.keychain -P '${{ inputs.apple-codesign-password }}' -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ inputs.apple-codesign-password }}' build.keychain + else + echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY + fi + + - name: Package + shell: bash + env: + BUILD_DIR: build + INSTALL_DIR: install + run: | + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} + + cd ${{ env.INSTALL_DIR }} + chmod +x "MeshMC.app/Contents/MacOS/meshmc" + + if [ -n '${{ inputs.apple-codesign-id }}' ]; then + APPLE_CODESIGN_ID='${{ inputs.apple-codesign-id }}' + ENTITLEMENTS_FILE='../branding/App.entitlements' + else + APPLE_CODESIGN_ID='-' + ENTITLEMENTS_FILE='../branding/AdhocSignedApp.entitlements' + fi + + sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "$ENTITLEMENTS_FILE" --options runtime "MeshMC.app/Contents/MacOS/meshmc" + + - name: Notarize + shell: bash + env: + INSTALL_DIR: install + run: | + cd ${{ env.INSTALL_DIR }} + + if [ -n '${{ inputs.apple-notarize-password }}' ]; then + ditto -c -k --sequesterRsrc --keepParent "MeshMC.app" ../MeshMC.zip + xcrun notarytool submit ../MeshMC.zip \ + --wait --progress \ + --apple-id '${{ inputs.apple-notarize-apple-id }}' \ + --team-id '${{ inputs.apple-notarize-team-id }}' \ + --password '${{ inputs.apple-notarize-password }}' + + xcrun stapler staple "MeshMC.app" + else + echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY + fi + ditto -c -k --sequesterRsrc --keepParent "MeshMC.app" ../MeshMC.zip + + - name: Create DMG + shell: bash + env: + INSTALL_DIR: install + run: | + cd ${{ env.INSTALL_DIR }} + + mkdir -p src + cp -R "MeshMC.app" src/ + + ln -s /Applications src/ + + hdiutil create \ + -volname "MeshMC ${{ inputs.version }}" \ + -srcfolder src \ + -ov -format ULMO \ + "../MeshMC.dmg" + + - name: Make Sparkle signature + shell: bash + run: | + if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then + echo '${{ inputs.sparkle-ed25519-key }}' > ed25519-priv.pem + signature_zip=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/MeshMC.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n) + signature_dmg=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/MeshMC.dmg -inkey ed25519-priv.pem | openssl base64 | tr -d \\n) + rm ed25519-priv.pem + cat >> $GITHUB_STEP_SUMMARY << EOF + ### Artifact Information :information_source: + - :memo: Sparkle Signature (ed25519): \`$signature_zip\` (ZIP) + - :memo: Sparkle Signature (ed25519): \`$signature_dmg\` (DMG) + EOF + else + cat >> $GITHUB_STEP_SUMMARY << EOF + ### Artifact Information :information_source: + - :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork) + EOF + fi + + - name: Upload binary tarball + uses: actions/upload-artifact@v7 + with: + name: MeshMC-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }} + path: MeshMC.zip + + - name: Upload disk image + uses: actions/upload-artifact@v7 + with: + name: MeshMC-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}.dmg + path: MeshMC.dmg diff --git a/.github/actions/meshmc/package/windows/action.yml b/.github/actions/meshmc/package/windows/action.yml new file mode 100644 index 0000000000..33e3d42718 --- /dev/null +++ b/.github/actions/meshmc/package/windows/action.yml @@ -0,0 +1,142 @@ +name: Package for Windows +description: Create a Windows package for MeshMC + +inputs: + version: + description: Launcher version + required: true + build-type: + description: Type for the build + required: true + default: Debug + artifact-name: + description: Name of the uploaded artifact + required: true + msystem: + description: MSYS2 subsystem to use + required: false + windows-codesign-cert: + description: Certificate for signing Windows builds + required: false + windows-codesign-password: + description: Password for signing Windows builds + required: false + +runs: + using: composite + + steps: + - name: Package (MinGW) + if: ${{ inputs.msystem != '' }} + shell: msys2 {0} + env: + BUILD_DIR: build + INSTALL_DIR: install + run: | + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} + touch ${{ env.INSTALL_DIR }}/manifest.txt + for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt + + - name: Package (MSVC) + if: ${{ inputs.msystem == '' }} + shell: pwsh + env: + BUILD_DIR: build + INSTALL_DIR: install + run: | + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} + + cd ${{ github.workspace }} + + Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt + + - name: Fetch codesign certificate + shell: bash # yes, we are not using MSYS2 or PowerShell here + run: | + echo '${{ inputs.windows-codesign-cert }}' | base64 --decode > codesign.pfx + + - name: Sign executable + shell: pwsh + env: + INSTALL_DIR: install + run: | + if (Get-Content ./codesign.pfx){ + cd ${{ env.INSTALL_DIR }} + # We ship the exact same executable for portable and non-portable editions, so signing just once is fine + SignTool sign /fd sha256 /td sha256 /f ../codesign.pfx /p '${{ inputs.windows-codesign-password }}' /tr http://timestamp.digicert.com meshmc.exe + } else { + ":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY + } + + - name: Package (MinGW, portable) + if: ${{ inputs.msystem != '' }} + shell: msys2 {0} + env: + BUILD_DIR: build + INSTALL_DIR: install + INSTALL_PORTABLE_DIR: install-portable + run: | + cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable + for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt + + - name: Package (MSVC, portable) + if: ${{ inputs.msystem == '' }} + shell: pwsh + env: + BUILD_DIR: build + INSTALL_DIR: install + INSTALL_PORTABLE_DIR: install-portable + run: | + cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead + cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable + + Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt + + - name: Package (installer) + shell: pwsh + env: + BUILD_DIR: build + INSTALL_DIR: install + + NSCURL_VERSION: "v24.9.26.122" + NSCURL_SHA256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0" + run: | + New-Item -Name NSISPlugins -ItemType Directory + Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/"${{ env.NSCURL_VERSION }}"/NScurl.zip -OutFile NSISPlugins\NScurl.zip + $nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash + if ( $nscurl_hash -ne "${{ env.nscurl_sha256 }}") { + echo "::error:: NSCurl.zip sha256 mismatch" + exit 1 + } + Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl + + cd ${{ env.INSTALL_DIR }} + makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/win_install.nsi" + + - name: Sign installer + shell: pwsh + run: | + if (Get-Content ./codesign.pfx){ + SignTool sign /fd sha256 /td sha256 /f codesign.pfx /p '${{ inputs.windows-codesign-password }}' /tr http://timestamp.digicert.com MeshMC-Setup.exe + } else { + ":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY + } + + - name: Upload binary zip + uses: actions/upload-artifact@v5 + with: + name: MeshMC-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }} + path: install/** + + - name: Upload portable zip + uses: actions/upload-artifact@v5 + with: + name: MeshMC-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }} + path: install-portable/** + + - name: Upload installer + uses: actions/upload-artifact@v5 + with: + name: MeshMC-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }} + path: MeshMC-Setup.exe diff --git a/.github/actions/meshmc/setup-dependencies/action.yml b/.github/actions/meshmc/setup-dependencies/action.yml new file mode 100644 index 0000000000..9ab7781441 --- /dev/null +++ b/.github/actions/meshmc/setup-dependencies/action.yml @@ -0,0 +1,89 @@ +name: Setup Dependencies +description: Install and setup dependencies for building MeshMC + +inputs: + build-type: + description: Type for the build + required: true + default: Debug + artifact-name: + description: Name of the uploaded artifact + required: true + msystem: + description: MSYS2 subsystem to use + required: false + vcvars-arch: + description: Visual Studio architecture to use + required: false + qt-architecture: + description: Qt architecture + required: false + qt-version: + description: Version of Qt to use + required: true + github-token: + description: GitHub token for package feed authentication + required: false + default: ${{ github.token }} + +outputs: + build-type: + description: Type of build used + value: ${{ inputs.build-type }} + qt-version: + description: Version of Qt used + value: ${{ inputs.qt-version }} + +runs: + using: composite + + steps: + - name: Setup Linux dependencies + if: ${{ runner.os == 'Linux' }} + uses: ./.github/actions/meshmc/setup-dependencies/linux + with: + github-token: ${{ inputs.github-token }} + + - name: Setup macOS dependencies + if: ${{ runner.os == 'macOS' }} + uses: ./.github/actions/meshmc/setup-dependencies/macos + with: + build-type: ${{ inputs.build-type }} + github-token: ${{ inputs.github-token }} + + - name: Setup Windows dependencies + if: ${{ runner.os == 'Windows' }} + uses: ./.github/actions/meshmc/setup-dependencies/windows + with: + build-type: ${{ inputs.build-type }} + msystem: ${{ inputs.msystem }} + vcvars-arch: ${{ inputs.vcvars-arch }} + github-token: ${{ inputs.github-token }} + + # TODO(@YongDo-Hyun): Get this working on MSYS2! + - name: Setup ccache + if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }} + uses: hendrikmuhs/ccache-action@v1.2.22 + with: + variant: sccache + create-symlink: ${{ runner.os != 'Windows' }} + key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.artifact-name }}-sccache + + - name: Use ccache on debug builds + if: ${{ inputs.build-type == 'Debug' }} + shell: bash + env: + # Only use ccache on MSYS2 + CCACHE_VARIANT: ${{ (runner.os == 'Windows' && inputs.msystem != '') && 'ccache' || 'sccache' }} + run: | + echo "CMAKE_C_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV" + echo "CMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV" + + - name: Install Qt + if: ${{ inputs.msystem == '' }} + uses: jurplel/install-qt-action@v4 + with: + aqtversion: "==3.1.*" + version: ${{ inputs.qt-version }} + modules: qtimageformats qtnetworkauth qt5compat + cache: ${{ inputs.build-type == 'Debug' }} diff --git a/.github/actions/meshmc/setup-dependencies/linux/action.yml b/.github/actions/meshmc/setup-dependencies/linux/action.yml new file mode 100644 index 0000000000..46cb40e8a5 --- /dev/null +++ b/.github/actions/meshmc/setup-dependencies/linux/action.yml @@ -0,0 +1,59 @@ +name: Setup Linux dependencies +description: Install and setup dependencies for building MeshMC + +inputs: + github-token: + description: GitHub token for authentication + required: true + +runs: + using: composite + + steps: + - name: Install host dependencies + shell: bash + run: | + sudo apt-get -y update + sudo apt-get -y install \ + dpkg-dev \ + ninja-build extra-cmake-modules pkg-config scdoc \ + cmark gamemode-dev libarchive-dev libcmark-dev libqrencode-dev zlib1g-dev \ + libxcb-cursor-dev libtomlplusplus-dev libvulkan-dev + + - name: Setup AppImage tooling + shell: bash + env: + GH_TOKEN: ${{ inputs.github-token }} + run: | + # Determinate AppImage architecture to use + dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)" + case "$dpkg_arch" in + "amd64") + APPIMAGE_ARCH="x86_64" + ;; + "arm64") + APPIMAGE_ARCH="aarch64" + ;; + *) + echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY" + exit 1 + ;; + esac + + gh release download \ + --repo VHSgunzo/sharun \ + --pattern "sharun-$APPIMAGE_ARCH-aio" \ + --output ~/bin/sharun + + # FIXME!: revert this to probonopd/go-appimage once https://github.com/probonopd/go-appimage/pull/377 is merged! + gh release download continuous \ + --repo DioEgizio/go-appimage \ + --pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \ + --output ~/bin/mkappimage + + gh release download \ + --repo AppImageCommunity/AppImageUpdate \ + --pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \ + --output ~/bin/AppImageUpdate.AppImage + chmod +x ~/bin/* + echo "$HOME/bin" >> "$GITHUB_PATH" diff --git a/.github/actions/meshmc/setup-dependencies/macos/action.yml b/.github/actions/meshmc/setup-dependencies/macos/action.yml new file mode 100644 index 0000000000..3eb5b37fa6 --- /dev/null +++ b/.github/actions/meshmc/setup-dependencies/macos/action.yml @@ -0,0 +1,52 @@ +name: Setup macOS dependencies + +inputs: + build-type: + description: Type for the build + required: true + default: Debug + github-token: + description: GitHub token for package feed authentication + required: true + +runs: + using: composite + + steps: + - name: Install dependencies + shell: bash + run: | + brew update + brew install ninja extra-cmake-modules temurin@17 mono autoconf libarchive + + - name: Set JAVA_HOME + shell: bash + run: | + echo "JAVA_HOME=$(/usr/libexec/java_home -v 17)" >> "$GITHUB_ENV" + + - name: Setup vcpkg cache + if: ${{ inputs.build-type == 'Debug' }} + shell: bash + env: + USERNAME: ${{ github.repository_owner }} + GITHUB_TOKEN: ${{ inputs.github-token }} + FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + NUGET_RW: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + run: | + mono `vcpkg fetch nuget | tail -n 1` \ + sources add \ + -Source "$FEED_URL" \ + -StorePasswordInClearText \ + -Name GitHubPackages \ + -UserName "$USERNAME" \ + -Password "$GITHUB_TOKEN" + mono `vcpkg fetch nuget | tail -n 1` \ + setapikey "$GITHUB_TOKEN" \ + -Source "$FEED_URL" + MODE=$( [ "$NUGET_RW" = "true" ] && echo "readwrite" || echo "read" ) + echo "VCPKG_BINARY_SOURCES=clear;nuget,$FEED_URL,$MODE" >> "$GITHUB_ENV" + + - name: Setup vcpkg environment + shell: bash + run: | + echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV" diff --git a/.github/actions/meshmc/setup-dependencies/windows/action.yml b/.github/actions/meshmc/setup-dependencies/windows/action.yml new file mode 100644 index 0000000000..a06b38d389 --- /dev/null +++ b/.github/actions/meshmc/setup-dependencies/windows/action.yml @@ -0,0 +1,114 @@ +name: Setup Windows Dependencies +description: Install and setup dependencies for building MeshMC + +inputs: + build-type: + description: Type for the build + required: true + default: Debug + msystem: + description: MSYS2 subsystem to use + required: false + vcvars-arch: + description: Visual Studio architecture to use + required: true + default: amd64 + github-token: + description: GitHub token for package feed authentication + required: true + +runs: + using: composite + + steps: + # NOTE: Installed on MinGW as well for SignTool + - name: Enter VS Developer shell + if: ${{ runner.os == 'Windows' }} + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ inputs.vcvars-arch }} + vsversion: 2022 + + - name: Setup Java (MSVC) + uses: actions/setup-java@v5 + with: + # NOTE(@YongDo-Hyun): We should probably stay on Zulu. + # Temurin doesn't have Java 17 builds for WoA + distribution: zulu + java-version: 17 + + - name: Setup vcpkg cache (MSVC) + if: ${{ inputs.msystem == '' && inputs.build-type == 'Debug' }} + shell: pwsh + env: + USERNAME: ${{ github.repository_owner }} + GITHUB_TOKEN: ${{ inputs.github-token }} + FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + NUGET_RW: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + run: | + .$(vcpkg fetch nuget) ` + sources add ` + -Source "$env:FEED_URL" ` + -StorePasswordInClearText ` + -Name GitHubPackages ` + -UserName "$env:USERNAME" ` + -Password "$env:GITHUB_TOKEN" + .$(vcpkg fetch nuget) ` + setapikey "$env:GITHUB_TOKEN" ` + -Source "$env:FEED_URL" + $mode = if ($env:NUGET_RW -eq 'true') { 'readwrite' } else { 'read' } + "VCPKG_BINARY_SOURCES=clear;nuget,$env:FEED_URL,$mode" | Out-File -Append $env:GITHUB_ENV + + - name: Setup vcpkg environment (MSVC) + if: ${{ inputs.msystem == '' }} + shell: bash + run: | + echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV" + + - name: Setup MSYS2 (MinGW) + if: ${{ inputs.msystem != '' }} + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ inputs.msystem }} + update: true + install: >- + git + pacboy: >- + toolchain:p + ccache:p + cmake:p + extra-cmake-modules:p + ninja:p + qt6-base:p + qt6-svg:p + qt6-imageformats:p + qt6-networkauth:p + qt6-5compat:p + cmark:p + qrencode:p + tomlplusplus:p + libarchive:p + + - name: List pacman packages (MinGW) + if: ${{ inputs.msystem != '' }} + shell: msys2 {0} + run: | + pacman -Qe + + - name: Retrieve ccache cache (MinGW) + if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }} + uses: actions/cache@v5.0.4 + with: + path: '${{ github.workspace }}\.ccache' + key: ${{ runner.os }}-mingw-w64-ccache-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-mingw-w64-ccache + + - name: Setup ccache (MinGW) + if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }} + shell: msys2 {0} + run: | + ccache --set-config=cache_dir='${{ github.workspace }}\.ccache' + ccache --set-config=max_size='500M' + ccache --set-config=compression=true + ccache -p # Show config diff --git a/.github/actions/uvim/test_artifacts/action.yml b/.github/actions/uvim/test_artifacts/action.yml new file mode 100644 index 0000000000..79d1aa82f6 --- /dev/null +++ b/.github/actions/uvim/test_artifacts/action.yml @@ -0,0 +1,55 @@ +name: 'test_artifacts' +description: "Upload failed test artifacts" +runs: + using: "composite" + steps: + - name: Collect matrix properties for naming + uses: actions/github-script@v8 + id: matrix-props + env: + MATRIX_PROPS: ${{ toJSON(matrix) }} + with: + # An array-flattening-to-string JavaScript function. + script: | + const f = function (x) { return x.toString().length > 0; } + const g = function (x) { + return (Array.isArray(x)) + ? x.filter(f) + .map((function (h) { return function (y) { return h(y); }; })(g)) + .join('-') + : x; + } + return Object.values(JSON.parse(process.env.MATRIX_PROPS)) + .filter(f) + .map(g) + .join('-'); + # By default, the JSON-encoded return value of the function is + # set as the "result". + result-encoding: string + - name: Upload failed tests + uses: actions/upload-artifact@v7 + with: + # Name of the artifact to upload. + name: ${{ format('GH-{0}-{1}-{2}-{3}-{4}-failed-tests', + github.run_id, + github.run_attempt, + github.job, + strategy.job-index, + steps.matrix-props.outputs.result) }} + + # A file, directory or wildcard pattern that describes what + # to upload. + path: | + ${{ github.workspace }}/runtime/indent/testdir/*.fail + ${{ github.workspace }}/runtime/syntax/testdir/failed/* + ${{ github.workspace }}/src/testdir/failed/* + # The desired behavior if no files are found using the + # provided path. + if-no-files-found: ignore + + # Duration after which artifact will expire in days. 0 means + # using repository settings. + retention-days: 0 + + # If true, an artifact with a matching name will be deleted + overwrite: true diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000000..70acfdfd7e --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,3 @@ +query-filters: + - exclude: + id: cpp/fixme-comment diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 0000000000..60c37b9425 --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,2 @@ +allowRemediationCommits: + individual: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..bd2abdad87 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,9 @@ +<!-- +Hey there! Thanks for your contribution for MeshMC. + +Please make sure that your commits are signed off and please sign CLA first. +If you don't know how that works, check out our contribution guidelines: https://github.com/Project-Tick/MeshMC/blob/master/CONTRIBUTING.md#signing-your-work +If you already created your commits, you can run `git rebase --signoff develop` to retroactively sign-off all your commits and `git push --force` to override what you have pushed already. + +Note that signing and signing-off are two different things! +--> diff --git a/.github/workflows/cgit-ci.yml b/.github/workflows/cgit-ci.yml new file mode 100644 index 0000000000..9248d2bcef --- /dev/null +++ b/.github/workflows/cgit-ci.yml @@ -0,0 +1,60 @@ +name: "cgit: CI" + +on: + push: + paths: + - 'cgit/**' + - '.github/workflows/cgit-ci.yml' + pull_request: + paths: + - 'cgit/**' + - '.github/workflows/cgit-ci.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + + defaults: + run: + working-directory: cgit + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + submodules: true + + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + libssl-dev \ + zlib1g-dev \ + libcurl4-openssl-dev \ + asciidoc \ + xmlto + + - name: Install dependencies (macOS) + if: runner.os == 'macOS' + run: brew install openssl asciidoc xmlto + + - name: Build git + run: | + cd git + make -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu) prefix=/usr/local NO_GETTEXT=1 + + - name: Build cgit + run: make -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu) + + - name: Run tests + run: make test || true diff --git a/.github/workflows/cmark-ci.yml b/.github/workflows/cmark-ci.yml new file mode 100644 index 0000000000..45daf6082f --- /dev/null +++ b/.github/workflows/cmark-ci.yml @@ -0,0 +1,129 @@ +name: "cmark: CI" + +on: + push: + branches-ignore: + - 'dependabot/**' + paths: + - 'cmark/**' + - '.github/workflows/cmark-ci.yml' + pull_request: + paths: + - 'cmark/**' + - '.github/workflows/cmark-ci.yml' + workflow_dispatch: + +jobs: + linter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Install clang-tidy + run: sudo apt-get install -y clang-tidy + - name: lint with clang-tidy + working-directory: cmark + run: make lint + env: + CC: clang + CXX: clang++ + + posix: + strategy: + fail-fast: false + matrix: + os: [linux, macos] + cc: [clang, gcc] + build_type: [shared, static] + sanitizers: ['', ASan] + include: + - os: 'linux' + image: 'ubuntu-latest' + - os: 'macos' + image: 'macos-latest' + - cc: 'clang' + cxx: 'clang++' + - cc: 'gcc' + cxx: 'g++' + - build_type: 'shared' + cmake_shared: 'YES' + - build_type: 'static' + cmake_shared: 'NO' + - sanitizers: 'ASan' + san_cflags: '-fsanitize=address,undefined -fno-sanitize-recover=all' + - sanitizers: 'ASan' + os: 'linux' + cc: 'gcc' + build_type: 'shared' + test_env: 'LD_PRELOAD=$(gcc -print-file-name=libasan.so)' + - sanitizers: 'ASan' + os: 'linux' + cc: 'clang' + build_type: 'shared' + asan_cflags: '-shared-libasan' + test_env: 'LD_PRELOAD=$(clang -print-file-name=libclang_rt.asan-x86_64.so)' + - sanitizers: 'ASan' + build_type: 'shared' + asan_opts: 'detect_leaks=0' + - sanitizers: 'ASan' + cc: 'gcc' + build_type: 'static' + asan_cflags: '-static-libasan' + exclude: + - os: 'macos' + cc: 'gcc' + - os: 'macos' + sanitizers: 'ASan' + build_type: 'shared' + + runs-on: ${{ matrix.image }} + + env: + ASAN_OPTIONS: ${{ matrix.asan_opts }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + CFLAGS: '${{ matrix.san_cflags }} ${{ matrix.asan_cflags }}' + CXXFLAGS: '${{ matrix.san_cflags }} ${{ matrix.asan_cflags }}' + + steps: + - uses: actions/checkout@v6 + - name: Build and test + working-directory: cmark + run: | + cmake \ + -DBUILD_SHARED_LIBS=${{ matrix.cmake_shared }} \ + -DCMAKE_BUILD_TYPE=Debug \ + -S . -B build + cmake --build build + ${{ matrix.test_env }} ctest --test-dir build --output-on-failure + + windows: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + build_type: [shared, static] + include: + - build_type: 'shared' + cmake_shared: 'YES' + - build_type: 'static' + cmake_shared: 'NO' + steps: + - uses: actions/checkout@v6 + - uses: ilammy/msvc-dev-cmd@v1 + - name: Build and test + working-directory: cmark + run: | + cmake ^ + -DBUILD_SHARED_LIBS=${{ matrix.cmake_shared }} ^ + -DCMAKE_BUILD_TYPE=Debug ^ + -S . -B build + cmake --build build + ctest --test-dir build -C Debug --output-on-failure + shell: cmd + - name: Upload artifact + if: ${{ matrix.build_type == 'static' }} + uses: actions/upload-artifact@v7 + with: + name: cmark windows ${{ matrix.build_type }} + path: cmark/build/src/Debug/cmark.exe + if-no-files-found: error diff --git a/.github/workflows/cmark-fuzz.yml b/.github/workflows/cmark-fuzz.yml new file mode 100644 index 0000000000..fd999ca929 --- /dev/null +++ b/.github/workflows/cmark-fuzz.yml @@ -0,0 +1,30 @@ +name: "cmark: Fuzz" + +on: + pull_request: + paths: + - 'cmark/**' + - '.github/workflows/cmark-fuzz.yml' + +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Build Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'cmark' + dry-run: false + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'cmark' + fuzz-seconds: 600 + dry-run: false + - name: Upload Crash + uses: actions/upload-artifact@v7 + if: failure() + with: + name: artifacts + path: ./out/artifacts diff --git a/.github/workflows/corebinutils-ci.yml b/.github/workflows/corebinutils-ci.yml new file mode 100644 index 0000000000..34c9b3fcfd --- /dev/null +++ b/.github/workflows/corebinutils-ci.yml @@ -0,0 +1,69 @@ +name: "corebinutils: CI" + +on: + push: + paths: + - 'corebinutils/**' + - '.github/workflows/corebinutils-ci.yml' + pull_request: + paths: + - 'corebinutils/**' + - '.github/workflows/corebinutils-ci.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-linux: + runs-on: ubuntu-latest + + defaults: + run: + working-directory: corebinutils + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + bmake \ + libbsd-dev \ + libmd-dev + + - name: Configure + run: | + if [ -x ./configure ]; then + ./configure + fi + + - name: Build + run: | + if [ -f GNUmakefile ]; then + make -f GNUmakefile -j$(nproc) || true + else + make -j$(nproc) || true + fi + + build-freebsd: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Build on FreeBSD + uses: vmactions/freebsd-vm@v1 + with: + usesh: true + prepare: | + pkg install -y gmake + run: | + cd corebinutils + if [ -x ./configure ]; then + ./configure + fi + make -j$(sysctl -n hw.ncpu) || true diff --git a/.github/workflows/forgewrapper-build.yml b/.github/workflows/forgewrapper-build.yml new file mode 100644 index 0000000000..30010f6e1c --- /dev/null +++ b/.github/workflows/forgewrapper-build.yml @@ -0,0 +1,62 @@ +name: "ForgeWrapper: Build" + +on: + push: + branches: [master] + paths: + - 'forgewrapper/**' + - '.github/workflows/forgewrapper-build.yml' + pull_request: + branches: [master] + paths: + - 'forgewrapper/**' + - '.github/workflows/forgewrapper-build.yml' + +jobs: + build: + runs-on: ubuntu-latest + defaults: + run: + working-directory: forgewrapper + steps: + - uses: actions/checkout@v6 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "8" + architecture: x64 + - name: Build with Gradle + run: | + chmod +x ./gradlew + ./gradlew build -iS + - uses: actions/upload-artifact@v7 + with: + name: ForgeWrapper + path: forgewrapper/build/libs + + publish: + if: startsWith(github.ref, 'refs/tags/') + needs: build + runs-on: ubuntu-latest + defaults: + run: + working-directory: forgewrapper + steps: + - uses: actions/checkout@v6 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "8" + architecture: x64 + - name: Build with Gradle + env: + IS_PUBLICATION: true + run: | + chmod +x ./gradlew + ./gradlew publish -iS + - uses: actions/upload-artifact@v7 + with: + name: ForgeWrapper-Release + path: forgewrapper/build/libs diff --git a/.github/workflows/genqrcode-ci.yml b/.github/workflows/genqrcode-ci.yml new file mode 100644 index 0000000000..9931f66ec9 --- /dev/null +++ b/.github/workflows/genqrcode-ci.yml @@ -0,0 +1,71 @@ +name: "genqrcode: CI" + +on: + push: + paths: + - 'genqrcode/**' + - '.github/workflows/genqrcode-ci.yml' + pull_request: + paths: + - 'genqrcode/**' + - '.github/workflows/genqrcode-ci.yml' + +jobs: + cmake: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + env: + BUILD_TYPE: Release + defaults: + run: + working-directory: genqrcode + steps: + - uses: actions/checkout@v6 + - name: Install vcpkg deps (Windows) + if: matrix.os == 'windows-latest' + uses: lukka/run-vcpkg@v6 + with: + vcpkgArguments: getopt:x64-windows libiconv:x64-windows libpng:x64-windows + vcpkgDirectory: '${{ github.workspace }}/vcpkg' + vcpkgGitCommitId: '2a42024b53ebb512fb5dd63c523338bf26c8489c' + - name: Install deps (macOS) + if: matrix.os == 'macos-latest' + run: brew install pkg-config libpng + - name: Configure CMake + if: matrix.os != 'windows-latest' + run: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DWITH_TESTS=yes -DBUILD_SHARED_LIBS=on -S . -B build + - name: Configure CMake (Windows) + if: matrix.os == 'windows-latest' + run: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake -DWITH_TESTS=yes -S . -B build + - name: Build + run: cmake --build build --config $BUILD_TYPE -j 2 + - name: Test + run: ctest --test-dir build -C $BUILD_TYPE + + autotools: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + defaults: + run: + working-directory: genqrcode + steps: + - uses: actions/checkout@v6 + - name: Install deps (macOS) + if: matrix.os == 'macos-latest' + run: brew install automake autoconf pkg-config libpng + - name: Generate configure + run: ./autogen.sh + - name: Configure + run: ./configure --with-tests + - name: Build + run: make -j 2 + - name: Test + run: make check + - name: Distcheck + run: make -j 2 distcheck diff --git a/.github/workflows/images4docker-build.yml b/.github/workflows/images4docker-build.yml new file mode 100644 index 0000000000..4657d06d29 --- /dev/null +++ b/.github/workflows/images4docker-build.yml @@ -0,0 +1,85 @@ +name: "images4docker: Build" + +on: + push: + branches: ["trunk", "master"] + paths: + - "images4docker/dockerfiles/**" + - ".github/workflows/images4docker-build.yml" + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + prepare: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.make.outputs.matrix }} + count: ${{ steps.make.outputs.count }} + steps: + - uses: actions/checkout@v6 + - id: make + run: | + set -euo pipefail + + entries=() + for f in images4docker/dockerfiles/*.Dockerfile; do + name="$(basename "$f" .Dockerfile)" + entries+=("$name|$f") + done + + json='{"include":[' + first=true + for entry in "${entries[@]}"; do + IFS='|' read -r name dockerfile <<< "$entry" + $first || json+=',' + first=false + json+="{\"name\":\"$name\",\"dockerfile\":\"$dockerfile\"}" + done + json+=']}' + + echo "matrix=$json" >> "$GITHUB_OUTPUT" + echo "count=${#entries[@]}" >> "$GITHUB_OUTPUT" + + build: + needs: prepare + if: needs.prepare.outputs.count != '0' + runs-on: ubuntu-latest + strategy: + fail-fast: false + max-parallel: 6 + matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }} + steps: + - uses: actions/checkout@v6 + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Compute image tags + id: tagmeta + run: | + set -euo pipefail + short_sha="${GITHUB_SHA::12}" + ts="$(date -u +%Y%m%d-%H%M%S)" + echo "sha_tag=sha-${short_sha}" >> "$GITHUB_OUTPUT" + echo "immutable_tag=${ts}-r${GITHUB_RUN_ID}-a${GITHUB_RUN_ATTEMPT}-${short_sha}" >> "$GITHUB_OUTPUT" + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: images4docker + file: ${{ matrix.dockerfile }} + push: true + provenance: false + tags: | + ghcr.io/${{ github.repository_owner }}/images/${{ matrix.name }}:latest + ghcr.io/${{ github.repository_owner }}/images/${{ matrix.name }}:${{ steps.tagmeta.outputs.sha_tag }} + ghcr.io/${{ github.repository_owner }}/images/${{ matrix.name }}:${{ steps.tagmeta.outputs.immutable_tag }} diff --git a/.github/workflows/json4cpp-ci.yml b/.github/workflows/json4cpp-ci.yml new file mode 100644 index 0000000000..2646c1b5c9 --- /dev/null +++ b/.github/workflows/json4cpp-ci.yml @@ -0,0 +1,166 @@ +name: "json4cpp: CI" + +on: + push: + branches: + - develop + - master + - release/* + paths: + - 'json4cpp/**' + - '.github/workflows/json4cpp-ci.yml' + pull_request: + paths: + - 'json4cpp/**' + - '.github/workflows/json4cpp-ci.yml' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: json4cpp-${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + ci_test_gcc: + runs-on: ubuntu-latest + container: gcc:latest + steps: + - uses: actions/checkout@v6 + - name: Get latest CMake and ninja + uses: lukka/get-cmake@v4 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_gcc + + ci_static_analysis: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind] + steps: + - uses: actions/checkout@v6 + - name: Install Valgrind + run: sudo apt-get update ; sudo apt-get install -y valgrind + - name: Get latest CMake and ninja + uses: lukka/get-cmake@v4 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ${{ matrix.target }} + + ci_static_analysis_clang: + runs-on: ubuntu-latest + container: silkeh/clang:dev + strategy: + fail-fast: false + matrix: + target: [ci_test_clang, ci_clang_tidy, ci_test_clang_sanitizer, ci_clang_analyze, ci_single_binaries] + steps: + - name: Install dependencies + run: apt-get update ; apt-get install -y git clang-tools iwyu unzip + - uses: actions/checkout@v6 + - name: Get latest CMake and ninja + uses: lukka/get-cmake@v4 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ${{ matrix.target }} + + ci_test_compilers_gcc: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + compiler: ['7', '8', '9', '10', '11', '12', '13', '14', '15', 'latest'] + container: gcc:${{ matrix.compiler }} + steps: + - uses: actions/checkout@v6 + - name: Get latest CMake and ninja + uses: lukka/get-cmake@v4 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_compiler_default + + ci_test_compilers_clang: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + compiler: ['11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', 'latest'] + container: silkeh/clang:${{ matrix.compiler }} + steps: + - uses: actions/checkout@v6 + - name: Get latest CMake and ninja + uses: lukka/get-cmake@v4 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_compiler_default + + ci_test_coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake lcov ninja-build locales gcc-multilib g++-multilib + sudo locale-gen de_DE + sudo update-locale + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_coverage + - name: Upload coverage report + uses: actions/upload-artifact@v7 + with: + name: code-coverage-report + path: build/html + + macos: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-13, macos-14, macos-15] + steps: + - uses: actions/checkout@v6 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On + - name: Build + run: cmake --build build --target ci_test_clang + + windows: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [windows-2022, windows-2025] + steps: + - uses: actions/checkout@v6 + - name: Run CMake + run: cmake -S json4cpp -B build -DJSON_CI=On -G "Visual Studio 17 2022" + - name: Build + run: cmake --build build --config Release --target ci_test_msvc + + codeql: + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - uses: actions/checkout@v6 + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: cpp + - name: Build + run: | + cmake -S json4cpp -B build + cmake --build build + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/meshmc-backport.yml b/.github/workflows/meshmc-backport.yml new file mode 100644 index 0000000000..d468fd6986 --- /dev/null +++ b/.github/workflows/meshmc-backport.yml @@ -0,0 +1,28 @@ +name: "MeshMC: Backport" + +on: + pull_request_target: + types: [closed, labeled] + +permissions: {} + +jobs: + backport: + permissions: + contents: write + pull-requests: write + actions: write + + name: Backport Pull Request + if: github.repository_owner == 'Project-Tick' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Create backport PRs + uses: korthout/backport-action@v4.3.0 + with: + pull_description: |- + Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}. diff --git a/.github/workflows/meshmc-blocked-prs.yml b/.github/workflows/meshmc-blocked-prs.yml new file mode 100644 index 0000000000..0010801540 --- /dev/null +++ b/.github/workflows/meshmc-blocked-prs.yml @@ -0,0 +1,257 @@ +name: Blocked/Stacked Pull Requests Automation + +on: + pull_request_target: + types: + - opened + - reopened + - edited + - synchronize + workflow_dispatch: + inputs: + pr_id: + description: Local Pull Request number to work on + required: true + type: number + +permissions: {} + +jobs: + blocked_status: + name: Check Blocked Status + runs-on: ubuntu-slim + + steps: + - name: Generate token + id: generate-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ vars.PULL_REQUEST_APP_ID }} + private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }} + + - name: Setup From Dispatch Event + if: github.event_name == 'workflow_dispatch' + id: dispatch_event_setup + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + PR_NUMBER: ${{ inputs.pr_id }} + run: | + # setup env for the rest of the workflow + OWNER=$(dirname "${{ github.repository }}") + REPO=$(basename "${{ github.repository }}") + PR_JSON=$( + gh api \ + -H "Accept: application/vnd.github.raw+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$OWNER/$REPO/pulls/$PR_NUMBER" + ) + echo "PR_JSON=$PR_JSON" >> "$GITHUB_ENV" + + - name: Setup Environment + id: env_setup + env: + EVENT_PR_JSON: ${{ toJSON(github.event.pull_request) }} + run: | + # setup env for the rest of the workflow + PR_JSON=${PR_JSON:-"$EVENT_PR_JSON"} + { + echo "REPO=$(jq -r '.base.repo.name' <<< "$PR_JSON")" + echo "OWNER=$(jq -r '.base.repo.owner.login' <<< "$PR_JSON")" + echo "PR_NUMBER=$(jq -r '.number' <<< "$PR_JSON")" + echo "JOB_DATA=$(jq -c ' + { + "repo": .base.repo.name, + "owner": .base.repo.owner.login, + "repoUrl": .base.repo.html_url, + "prNumber": .number, + "prHeadSha": .head.sha, + "prHeadLabel": .head.label, + "prBody": (.body // ""), + "prLabels": (reduce .labels[].name as $l ([]; . + [$l])) + } + ' <<< "$PR_JSON")" + } >> "$GITHUB_ENV" + + + - name: Find Blocked/Stacked PRs in body + id: pr_ids + run: | + prs=$( + jq -c ' + .prBody as $body + | ( + $body | + reduce ( + . | scan("[Bb]locked (?:[Bb]y|[Oo]n):? #([0-9]+)") + | map({ + "type": "Blocked on", + "number": ( . | tonumber ) + }) + ) as $i ([]; . + [$i[]]) + ) as $bprs + | ( + $body | + reduce ( + . | scan("[Ss]tacked [Oo]n:? #([0-9]+)") + | map({ + "type": "Stacked on", + "number": ( . | tonumber ) + }) + ) as $i ([]; . + [$i[]]) + ) as $sprs + | ($bprs + $sprs) as $prs + | { + "blocking": $prs, + "numBlocking": ( $prs | length), + } + ' <<< "$JOB_DATA" + ) + echo "prs=$prs" >> "$GITHUB_OUTPUT" + + - name: Collect Blocked PR Data + id: blocking_data + if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + BLOCKING_PRS: ${{ steps.pr_ids.outputs.prs }} + run: | + blocked_pr_data=$( + while read -r pr_data ; do + gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$OWNER/$REPO/pulls/$(jq -r '.number' <<< "$pr_data")" \ + | jq -c --arg type "$(jq -r '.type' <<< "$pr_data")" \ + ' + . | { + "type": $type, + "number": .number, + "merged": .merged, + "state": (if .state == "open" then "Open" elif .merged then "Merged" else "Closed" end), + "labels": (reduce .labels[].name as $l ([]; . + [$l])), + "basePrUrl": .html_url, + "baseRepoName": .head.repo.name, + "baseRepoOwner": .head.repo.owner.login, + "baseRepoUrl": .head.repo.html_url, + "baseSha": .head.sha, + "baseRefName": .head.ref, + } + ' + done < <(jq -c '.blocking[]' <<< "$BLOCKING_PRS") | jq -c -s + ) + { + echo "data=$blocked_pr_data"; + echo "all_merged=$(jq -r 'all(.[] | (.type == "Stacked on" and .merged) or (.type == "Blocked on" and (.state != "Open")); .)' <<< "$blocked_pr_data")"; + echo "current_blocking=$(jq -c 'map( + select( + (.type == "Stacked on" and (.merged | not)) or + (.type == "Blocked on" and (.state == "Open")) + ) | .number + )' <<< "$blocked_pr_data" )"; + } >> "$GITHUB_OUTPUT" + + - name: Add 'blocked' Label if Missing + id: label_blocked + if: "(fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0) && !contains(fromJSON(env.JOB_DATA).prLabels, 'status: blocked') && !fromJSON(steps.blocking_data.outputs.all_merged)" + continue-on-error: true + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + gh -R ${{ github.repository }} issue edit --add-label 'status: blocked' "$PR_NUMBER" + + - name: Remove 'blocked' Label if All Dependencies Are Merged + id: unlabel_blocked + if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 && fromJSON(steps.blocking_data.outputs.all_merged) + continue-on-error: true + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + gh -R ${{ github.repository }} issue edit --remove-label 'status: blocked' "$PR_NUMBER" + + - name: Apply 'blocking' Label to Unmerged Dependencies + id: label_blocking + if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 + continue-on-error: true + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }} + run: | + while read -r pr ; do + gh -R ${{ github.repository }} issue edit --add-label 'status: blocking' "$pr" || true + done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES") + + - name: Apply Blocking PR Status Check + id: blocked_check + if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 + continue-on-error: true + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }} + run: | + pr_head_sha=$(jq -r '.prHeadSha' <<< "$JOB_DATA") + # create commit Status, overwrites previous identical context + while read -r pr_data ; do + DESC=$( + jq -r 'if .type == "Stacked on" then + "Stacked PR #" + (.number | tostring) + " is " + (if .merged then "" else "not yet " end) + "merged" + else + "Blocking PR #" + (.number | tostring) + " is " + (if .state == "Open" then "" else "not yet " end) + "merged or closed" + end ' <<< "$pr_data" + ) + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/${OWNER}/${REPO}/statuses/${pr_head_sha}" \ + -f "state=$(jq -r 'if (.type == "Stacked on" and .merged) or (.type == "Blocked on" and (.state != "Open")) then "success" else "failure" end' <<< "$pr_data")" \ + -f "target_url=$(jq -r '.basePrUrl' <<< "$pr_data" )" \ + -f "description=$DESC" \ + -f "context=ci/blocking-pr-check:$(jq '.number' <<< "$pr_data")" + done < <(jq -c '.[]' <<< "$BLOCKING_DATA") + + - name: Context Comment + id: generate-comment + if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 + continue-on-error: true + env: + BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }} + run: | + COMMENT_PATH="$(pwd)/temp_comment_file.txt" + echo '<h3>PR Dependencies :pushpin:</h3>' > "$COMMENT_PATH" + echo >> "$COMMENT_PATH" + pr_head_label=$(jq -r '.prHeadLabel' <<< "$JOB_DATA") + while read -r pr_data ; do + base_pr=$(jq -r '.number' <<< "$pr_data") + base_ref_name=$(jq -r '.baseRefName' <<< "$pr_data") + base_repo_owner=$(jq -r '.baseRepoOwner' <<< "$pr_data") + base_repo_name=$(jq -r '.baseRepoName' <<< "$pr_data") + compare_url="https://github.com/$base_repo_owner/$base_repo_name/compare/$base_ref_name...$pr_head_label" + status=$(jq -r ' + if .type == "Stacked on" then + if .merged then ":heavy_check_mark: Merged" else ":x: Not Merged (" + .state + ")" end + else + if .state != "Open" then ":white_check_mark: " + .state else ":x: Open" end + end + ' <<< "$pr_data") + type=$(jq -r '.type' <<< "$pr_data") + echo " - $type #$base_pr $status [(compare)]($compare_url)" >> "$COMMENT_PATH" + done < <(jq -c '.[]' <<< "$BLOCKING_DATA") + + { + echo 'body<<EOF'; + cat "${COMMENT_PATH}"; + echo 'EOF'; + } >> "$GITHUB_OUTPUT" + + - name: 💬 PR Comment + if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 + continue-on-error: true + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + COMMENT_BODY: ${{ steps.generate-comment.outputs.body }} + run: | + gh -R ${{ github.repository }} issue comment "$PR_NUMBER" \ + --body "$COMMENT_BODY" \ + --create-if-none \ + --edit-last + diff --git a/.github/workflows/meshmc-build.yml b/.github/workflows/meshmc-build.yml new file mode 100644 index 0000000000..d7b0a2335e --- /dev/null +++ b/.github/workflows/meshmc-build.yml @@ -0,0 +1,190 @@ +name: "MeshMC: Build" + +concurrency: + group: meshmc-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - 'master' + paths: + - 'meshmc/**' + - '.github/workflows/meshmc-build.yml' + - '.github/actions/meshmc/**' + merge_group: + types: [checks_requested] + pull_request: + paths: + - 'meshmc/**' + - '.github/workflows/meshmc-build.yml' + - '.github/actions/meshmc/**' + workflow_call: + inputs: + build-type: + description: Type of build (Debug or Release) + type: string + default: Debug + environment: + description: Deployment environment to run under + type: string + workflow_dispatch: + inputs: + build-type: + description: Type of build (Debug or Release) + type: string + default: Debug + +permissions: {} + +jobs: + build: + name: Build (${{ matrix.artifact-name }}) + + environment: ${{ inputs.environment || '' }} + + permissions: + contents: read + id-token: write + packages: write + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-24.04 + artifact-name: Linux + cmake-preset: linux + qt-version: 6.10.2 + + - os: ubuntu-24.04-arm + artifact-name: Linux-aarch64 + cmake-preset: linux + qt-version: 6.10.2 + + - os: windows-2022 + artifact-name: Windows-MinGW-w64 + cmake-preset: windows_mingw + msystem: CLANG64 + vcvars-arch: amd64_x86 + + - os: windows-11-arm + artifact-name: Windows-MinGW-arm64 + cmake-preset: windows_mingw + msystem: CLANGARM64 + vcvars-arch: arm64 + + - os: windows-2022 + artifact-name: Windows-MSVC + cmake-preset: windows_msvc + vcvars-arch: amd64 + qt-version: 6.10.2 + + - os: windows-11-arm + artifact-name: Windows-MSVC-arm64 + cmake-preset: windows_msvc + vcvars-arch: arm64 + qt-version: 6.10.2 + + - os: macos-26 + artifact-name: macOS + cmake-preset: macos_universal + macosx-deployment-target: 12.0 + qt-version: 6.9.3 + + runs-on: ${{ matrix.os }} + + defaults: + run: + shell: ${{ matrix.msystem != '' && 'msys2 {0}' || 'bash' }} + working-directory: meshmc + + env: + ARTIFACT_NAME: ${{ matrix.artifact-name }}-Qt6 + BUILD_PLATFORM: official + BUILD_TYPE: ${{ inputs.build-type || 'Debug' }} + CMAKE_PRESET: ${{ matrix.cmake-preset }} + MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx-deployment-target }} + + steps: + ## + # SETUP + ## + + - name: Checkout + uses: actions/checkout@v6 + with: + submodules: true + + - name: Setup dependencies + id: setup-dependencies + uses: ./.github/actions/meshmc/setup-dependencies + with: + build-type: ${{ env.BUILD_TYPE }} + artifact-name: ${{ matrix.artifact-name }} + msystem: ${{ matrix.msystem }} + vcvars-arch: ${{ matrix.vcvars-arch }} + qt-version: ${{ matrix.qt-version }} + + ## + # BUILD + ## + + - name: Configure project + run: | + cmake --preset "$CMAKE_PRESET" + + - name: Run build + run: | + cmake --build --preset "$CMAKE_PRESET" --config "$BUILD_TYPE" + + - name: Run tests + run: | + ctest --preset "$CMAKE_PRESET" --build-config "$BUILD_TYPE" + + ## + # PACKAGE + ## + + - name: Get short version + id: short-version + shell: bash + run: | + echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + + - name: Package (Linux) + if: ${{ runner.os == 'Linux' }} + uses: ./.github/actions/meshmc/package/linux + with: + version: ${{ steps.short-version.outputs.version }} + build-type: ${{ steps.setup-dependencies.outputs.build-type }} + artifact-name: ${{ matrix.artifact-name }} + qt-version: ${{ steps.setup-dependencies.outputs.qt-version }} + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-private-key-id: ${{ secrets.GPG_PRIVATE_KEY_ID }} + + - name: Package (macOS) + if: ${{ runner.os == 'macOS' }} + uses: ./.github/actions/meshmc/package/macos + with: + version: ${{ steps.short-version.outputs.version }} + build-type: ${{ steps.setup-dependencies.outputs.build-type }} + artifact-name: ${{ matrix.artifact-name }} + apple-codesign-cert: ${{ secrets.APPLE_CODESIGN_CERT }} + apple-codesign-password: ${{ secrets.APPLE_CODESIGN_PASSWORD }} + apple-codesign-id: ${{ secrets.APPLE_CODESIGN_ID }} + apple-notarize-apple-id: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }} + apple-notarize-team-id: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }} + apple-notarize-password: ${{ secrets.APPLE_NOTARIZE_PASSWORD }} + sparkle-ed25519-key: ${{ secrets.SPARKLE_ED25519_KEY }} + + - name: Package (Windows) + if: ${{ runner.os == 'Windows' }} + uses: ./.github/actions/meshmc/package/windows + with: + version: ${{ steps.short-version.outputs.version }} + build-type: ${{ env.BUILD_TYPE }} + artifact-name: ${{ matrix.artifact-name }} + windows-codesign-cert: ${{ secrets.WINDOWS_CODESIGN_CERT }} + windows-codesign-password: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }} + msystem: ${{ matrix.msystem }} diff --git a/.github/workflows/meshmc-codeql.yml b/.github/workflows/meshmc-codeql.yml new file mode 100644 index 0000000000..6dd764849a --- /dev/null +++ b/.github/workflows/meshmc-codeql.yml @@ -0,0 +1,59 @@ +name: "MeshMC: CodeQL" + +concurrency: + group: meshmc-codeql-${{ github.ref }} + cancel-in-progress: true + +on: + merge_group: + types: [checks_requested] + pull_request: + paths: + - 'meshmc/**' + - '.github/workflows/meshmc-codeql.yml' + workflow_dispatch: + +permissions: {} + +jobs: + CodeQL: + runs-on: ubuntu-latest + + permissions: + contents: read + security-events: write + + defaults: + run: + working-directory: meshmc + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + submodules: "true" + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + config-file: ./.github/codeql/codeql-config.yml + queries: security-and-quality + languages: cpp, java + + - name: Setup dependencies + uses: ./.github/actions/meshmc/setup-dependencies + with: + build-type: Debug + qt-version: 6.9.3 + + - name: Configure and Build + run: | + cmake --preset linux -DLauncher_USE_PCH=OFF + cmake --build --preset linux --config Debug + + - name: Run tests + run: | + ctest --preset linux --build-config Debug --extra-verbose --output-on-failure + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/meshmc-container.yml b/.github/workflows/meshmc-container.yml new file mode 100644 index 0000000000..3a41e15bcd --- /dev/null +++ b/.github/workflows/meshmc-container.yml @@ -0,0 +1,178 @@ +name: "MeshMC: Container" + +concurrency: + group: meshmc-container-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - 'master' + paths: + - 'meshmc/Containerfile' + - '.github/workflows/meshmc-container.yml' + merge_group: + types: [checks_requested] + pull_request: + paths: + - 'meshmc/Containerfile' + - '.github/workflows/meshmc-container.yml' + workflow_dispatch: + +permissions: {} + +env: + REGISTRY: ghcr.io + +jobs: + build: + name: Build (${{ matrix.arch }}) + + permissions: + contents: read + packages: write + + outputs: + image-name: ${{ steps.image-name.outputs.image-name }} + + strategy: + fail-fast: false + matrix: + include: + - arch: arm64 + os: ubuntu-24.04-arm + - arch: amd64 + os: ubuntu-24.04-arm + + runs-on: ${{ matrix.os }} + + steps: + - name: Set image name + id: image-name + run: | + echo "image-name=${REGISTRY}/${GITHUB_REPOSITORY_OWNER,,}/devcontainer" >> "$GITHUB_OUTPUT" + + - name: Install Podman + uses: redhat-actions/podman-install@main + if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }} + with: + github-token: ${{ github.token }} + + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Determine metadata for image + id: image-metadata + uses: docker/metadata-action@v6 + with: + images: | + ${{ steps.image-name.outputs.image-name }} + flavor: | + latest=false + tags: | + type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }} + type=sha + type=sha,format=long + type=ref,event=branch + type=ref,event=tag + + - name: Build image + id: build-image + uses: redhat-actions/buildah-build@v2 + with: + containerfiles: | + ./meshmc/Containerfile + tags: ${{ steps.image-metadata.outputs.tags }} + labels: ${{ steps.image-metadata.outputs.labels }} + + - name: Push image + id: push-image + if: ${{ github.event_name != 'pull_request' }} + uses: redhat-actions/push-to-registry@v2 + with: + tags: ${{ steps.build-image.outputs.tags }} + username: ${{ github.repository_owner }} + password: ${{ github.token }} + tls-verify: true + + - name: Export image digest + if: ${{ github.event_name != 'pull_request' }} + env: + DIGEST: ${{ steps.push-image.outputs.digest }} + run: | + mkdir -p "$RUNNER_TEMP"/digests + touch "$RUNNER_TEMP"/digests/"${DIGEST#sha256:}" + + - name: Upload digest artifact + if: ${{ github.event_name != 'pull_request' }} + uses: actions/upload-artifact@v7 + with: + name: digests-${{ matrix.arch }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + manifest: + name: Create manifest + needs: [build] + if: ${{ github.event_name != 'pull_request' }} + + permissions: + contents: read + packages: write + + runs-on: ubuntu-24.04 + + steps: + - name: Download digests + uses: actions/download-artifact@v8 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Install Podman + if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }} + uses: redhat-actions/podman-install@main + with: + github-token: ${{ github.token }} + + - name: Login to registry + uses: redhat-actions/podman-login@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ github.token }} + + - name: Determine metadata for manifest + id: manifest-metadata + uses: docker/metadata-action@v6 + with: + images: | + ${{ needs.build.outputs.image-name }} + flavor: | + latest=false + tags: | + type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }} + type=sha + type=sha,format=long + type=ref,event=branch + type=ref,event=tag + + - name: Create manifest list + working-directory: ${{ runner.temp }}/digests + env: + IMAGE_NAME: ${{ needs.build.outputs.image-name }} + run: | + while read -r tag; do + podman manifest create "$tag" \ + $(printf "$IMAGE_NAME@sha256:%s " *) + done <<< "$DOCKER_METADATA_OUTPUT_TAGS" + + - name: Push manifest + uses: redhat-actions/push-to-registry@v2 + with: + tags: ${{ steps.manifest-metadata.outputs.tags }} + username: ${{ github.repository_owner }} + password: ${{ github.token }} + tls-verify: true diff --git a/.github/workflows/meshmc-flake-update.yml b/.github/workflows/meshmc-flake-update.yml new file mode 100644 index 0000000000..c0be2756d4 --- /dev/null +++ b/.github/workflows/meshmc-flake-update.yml @@ -0,0 +1,39 @@ +name: "MeshMC: Update Flake" + +on: + schedule: + - cron: "0 0 * * 0" + workflow_dispatch: + +permissions: {} + +jobs: + update-flake: + if: github.repository_owner == 'Project-Tick' + + permissions: + contents: write + pull-requests: write + + runs-on: ubuntu-latest + + defaults: + run: + working-directory: meshmc + + steps: + - uses: actions/checkout@v6 + - uses: cachix/install-nix-action@v31 + + - uses: DeterminateSystems/update-flake-lock@v28 + with: + path-to-flake-dir: meshmc + commit-msg: "chore(nix): update lockfile" + pr-title: "chore(nix): update lockfile" + pr-labels: | + platform: Linux + area: packaging + complexity: low + priority: low + type: robot + changelog:omit diff --git a/.github/workflows/meshmc-merge-blocking-pr.yml b/.github/workflows/meshmc-merge-blocking-pr.yml new file mode 100644 index 0000000000..3542a470e0 --- /dev/null +++ b/.github/workflows/meshmc-merge-blocking-pr.yml @@ -0,0 +1,64 @@ +name: Merged Blocking Pull Request Automation + +on: + pull_request_target: + types: + - closed + workflow_dispatch: + inputs: + pr_id: + description: Local Pull Request number to work on + required: true + type: number + +permissions: {} + +jobs: + update-blocked-status: + name: Update Blocked Status + runs-on: ubuntu-slim + + # a pr that was a `blocking:<id>` label was merged. + # find the open pr's it was blocked by and trigger a refresh of their state + if: "${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'status: blocking') }}" + + steps: + - name: Generate token + id: generate-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ vars.PULL_REQUEST_APP_ID }} + private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }} + + - name: Gather Dependent PRs + id: gather_deps + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }} + run: | + blocked_prs=$( + gh -R ${{ github.repository }} pr list --label 'status: blocked' --json 'number,body' \ + | jq -c --argjson pr "$PR_NUMBER" ' + reduce ( .[] | select( + .body | + scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") | + map(tonumber) | + any(.[]; . == $pr) + )) as $i ([]; . + [$i]) + ' + ) + { + echo "deps=$blocked_prs" + echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")" + } >> "$GITHUB_OUTPUT" + + - name: Trigger Blocked PR Workflows for Dependants + if: fromJSON(steps.gather_deps.outputs.numdeps) > 0 + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + DEPS: ${{ steps.gather_deps.outputs.deps }} + run: | + while read -r pr ; do + gh -R ${{ github.repository }} workflow run 'blocked-prs.yml' -r "${{ github.ref_name }}" -f pr_id="$pr" + done < <(jq -c '.[].number' <<< "$DEPS") + diff --git a/.github/workflows/meshmc-nix.yml b/.github/workflows/meshmc-nix.yml new file mode 100644 index 0000000000..21af121a34 --- /dev/null +++ b/.github/workflows/meshmc-nix.yml @@ -0,0 +1,122 @@ +name: "MeshMC: Nix" + +concurrency: + group: meshmc-nix-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - "master" + - "release-*" + tags: + - "*" + paths: + - "meshmc/**.cpp" + - "meshmc/**.h" + - "meshmc/**.java" + - "meshmc/**.ui" + - "meshmc/**.md" + - "meshmc/**.nix" + - "meshmc/nix/**" + - "meshmc/flake.lock" + - "meshmc/buildconfig/**" + - "meshmc/cmake/**" + - "meshmc/launcher/**" + - "meshmc/libraries/**" + - "meshmc/branding/**" + - "meshmc/tests/**" + - "meshmc/CMakeLists.txt" + - ".github/workflows/meshmc-nix.yml" + pull_request: + paths: + - "meshmc/**.cpp" + - "meshmc/**.h" + - "meshmc/**.java" + - "meshmc/**.ui" + - "meshmc/**.md" + - "meshmc/**.nix" + - "meshmc/nix/**" + - "meshmc/flake.lock" + - "meshmc/buildconfig/**" + - "meshmc/cmake/**" + - "meshmc/launcher/**" + - "meshmc/libraries/**" + - "meshmc/branding/**" + - "meshmc/tests/**" + - "meshmc/CMakeLists.txt" + - ".github/workflows/meshmc-nix.yml" + workflow_dispatch: + +permissions: {} + +env: + DEBUG: ${{ github.ref_type != 'tag' }} + +jobs: + build: + name: Build (${{ matrix.system }}) + + permissions: + contents: read + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-22.04 + system: x86_64-linux + + - os: ubuntu-22.04-arm + system: aarch64-linux + + - os: macos-14 + system: aarch64-darwin + + runs-on: ${{ matrix.os }} + + defaults: + run: + working-directory: meshmc + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install Nix + uses: cachix/install-nix-action@v31 + + - name: Setup Nix Magic Cache + if: ${{ github.event_name == 'pull_request' }} + uses: DeterminateSystems/magic-nix-cache-action@v13 + with: + diagnostic-endpoint: "" + use-flakehub: false + + - name: Setup Cachix + if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + uses: cachix/cachix-action@v17 + with: + name: meshmc + authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + + - name: Run Flake checks + run: | + nix flake check --print-build-logs --show-trace + + - name: Build debug package + if: ${{ env.DEBUG == 'true' }} + run: | + nix build \ + --no-link --print-build-logs --print-out-paths \ + .#meshmc-debug >> "$GITHUB_STEP_SUMMARY" + + - name: Build release package + if: ${{ env.DEBUG == 'false' }} + env: + TAG: ${{ github.ref_name }} + SYSTEM: ${{ matrix.system }} + run: | + nix build --no-link --print-out-paths .#meshmc \ + | tee -a "$GITHUB_STEP_SUMMARY" \ + | xargs cachix pin meshmc "$TAG"-"$SYSTEM" diff --git a/.github/workflows/meshmc-publish.yml b/.github/workflows/meshmc-publish.yml new file mode 100644 index 0000000000..d0ce9948d7 --- /dev/null +++ b/.github/workflows/meshmc-publish.yml @@ -0,0 +1,25 @@ +name: "MeshMC: Publish" + +on: + release: + types: [released] + +permissions: {} + +jobs: + winget: + name: Winget + + permissions: + contents: read + + runs-on: ubuntu-latest + + steps: + - name: Publish on Winget + uses: vedantmgoyal2009/winget-releaser@v2 + with: + identifier: ProjectTick.MeshMC + version: ${{ github.event.release.tag_name }} + installers-regex: 'MeshMC-Windows-MSVC(:?-arm64|-Legacy)?-Setup-.+\.exe$' + token: ${{ secrets.WINGET_TOKEN }} diff --git a/.github/workflows/meshmc-release.yml b/.github/workflows/meshmc-release.yml new file mode 100644 index 0000000000..9a50e9ca73 --- /dev/null +++ b/.github/workflows/meshmc-release.yml @@ -0,0 +1,124 @@ +name: "MeshMC: Release" + +on: + push: + tags: + - "*" + +permissions: {} + +jobs: + build_release: + name: Build Release + uses: ./.github/workflows/meshmc-build.yml + permissions: + contents: read + id-token: write + packages: write + with: + build-type: Release + environment: Release + secrets: inherit + + create_release: + needs: build_release + permissions: + contents: write + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + submodules: "true" + path: "MeshMC-source" + - name: Download artifacts + uses: actions/download-artifact@v8 + - name: Grab and store version + run: | + tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$") + echo "VERSION=$tag_name" >> $GITHUB_ENV + - name: Package artifacts properly + run: | + mv ${{ github.workspace }}/MeshMC-source MeshMC-${{ env.VERSION }} + mv MeshMC-Linux-Qt6-Portable*/MeshMC-portable.tar.gz MeshMC-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz + mv MeshMC-Linux-aarch64-Qt6-Portable*/MeshMC-portable.tar.gz MeshMC-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz + mv MeshMC-*.AppImage/MeshMC-*-x86_64.AppImage MeshMC-Linux-x86_64.AppImage + mv MeshMC-*.AppImage.zsync/MeshMC-*-x86_64.AppImage.zsync MeshMC-Linux-x86_64.AppImage.zsync + mv MeshMC-*.AppImage/MeshMC-*-aarch64.AppImage MeshMC-Linux-aarch64.AppImage + mv MeshMC-*.AppImage.zsync/MeshMC-*-aarch64.AppImage.zsync MeshMC-Linux-aarch64.AppImage.zsync + mv MeshMC-macOS*/MeshMC.zip MeshMC-macOS-${{ env.VERSION }}.zip + mv MeshMC-macOS*/MeshMC.dmg MeshMC-macOS-${{ env.VERSION }}.dmg + + tar --exclude='.git' -czf MeshMC-${{ env.VERSION }}.tar.gz MeshMC-${{ env.VERSION }} + + for d in MeshMC-Windows-MSVC*; do + cd "${d}" || continue + LEGACY="$(echo -n ${d} | grep -o Legacy || true)" + ARM64="$(echo -n ${d} | grep -o arm64 || true)" + INST="$(echo -n ${d} | grep -o Setup || true)" + PORT="$(echo -n ${d} | grep -o Portable || true)" + NAME="MeshMC-Windows-MSVC" + test -z "${LEGACY}" || NAME="${NAME}-Legacy" + test -z "${ARM64}" || NAME="${NAME}-arm64" + test -z "${PORT}" || NAME="${NAME}-Portable" + test -z "${INST}" || mv MeshMC-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe + test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * + cd .. + done + + for d in MeshMC-Windows-MinGW-w64*; do + cd "${d}" || continue + INST="$(echo -n ${d} | grep -o Setup || true)" + PORT="$(echo -n ${d} | grep -o Portable || true)" + NAME="MeshMC-Windows-MinGW-w64" + test -z "${PORT}" || NAME="${NAME}-Portable" + test -z "${INST}" || mv MeshMC-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe + test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * + cd .. + done + + for d in MeshMC-Windows-MinGW-arm64*; do + cd "${d}" || continue + INST="$(echo -n ${d} | grep -o Setup || true)" + PORT="$(echo -n ${d} | grep -o Portable || true)" + NAME="MeshMC-Windows-MinGW-arm64" + test -z "${PORT}" || NAME="${NAME}-Portable" + test -z "${INST}" || mv MeshMC-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe + test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * + cd .. + done + + - name: Create release + id: create_release + uses: softprops/action-gh-release@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag_name: ${{ github.ref }} + name: MeshMC ${{ env.VERSION }} + draft: true + prerelease: false + fail_on_unmatched_files: true + files: | + MeshMC-Linux-x86_64.AppImage + MeshMC-Linux-x86_64.AppImage.zsync + MeshMC-Linux-aarch64.AppImage + MeshMC-Linux-aarch64.AppImage.zsync + MeshMC-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz + MeshMC-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz + MeshMC-Windows-MinGW-w64-${{ env.VERSION }}.zip + MeshMC-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip + MeshMC-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe + MeshMC-Windows-MinGW-arm64-${{ env.VERSION }}.zip + MeshMC-Windows-MinGW-arm64-Portable-${{ env.VERSION }}.zip + MeshMC-Windows-MinGW-arm64-Setup-${{ env.VERSION }}.exe + MeshMC-Windows-MSVC-arm64-${{ env.VERSION }}.zip + MeshMC-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip + MeshMC-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe + MeshMC-Windows-MSVC-${{ env.VERSION }}.zip + MeshMC-Windows-MSVC-Portable-${{ env.VERSION }}.zip + MeshMC-Windows-MSVC-Setup-${{ env.VERSION }}.exe + MeshMC-macOS-${{ env.VERSION }}.zip + MeshMC-macOS-${{ env.VERSION }}.dmg + MeshMC-${{ env.VERSION }}.tar.gz diff --git a/.github/workflows/tomlplusplus-ci.yml b/.github/workflows/tomlplusplus-ci.yml new file mode 100644 index 0000000000..974601fdf9 --- /dev/null +++ b/.github/workflows/tomlplusplus-ci.yml @@ -0,0 +1,146 @@ +name: "tomlplusplus: CI" + +on: + push: + paths: + - "tomlplusplus/**.h" + - "tomlplusplus/**.hpp" + - "tomlplusplus/**.cpp" + - "tomlplusplus/**.inl" + - "tomlplusplus/**.py" + - "tomlplusplus/**/meson.build" + - ".github/workflows/tomlplusplus-ci.yml" + pull_request: + paths: + - "tomlplusplus/**.h" + - "tomlplusplus/**.hpp" + - "tomlplusplus/**.cpp" + - "tomlplusplus/**.inl" + - "tomlplusplus/**.py" + - "tomlplusplus/**/meson.build" + - ".github/workflows/tomlplusplus-ci.yml" + workflow_dispatch: + +concurrency: + group: tomlplusplus-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + clang_version: "14" + gcc_version: "11" + +jobs: + linux: + strategy: + fail-fast: false + matrix: + compiler: + - "clang" + - "gcc" + linker: + - "lld" + type: + - "debug" + - "release" + + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: tomlplusplus + + steps: + - name: Install base dependencies + run: | + sudo apt -y update + sudo apt -y install --no-install-recommends git ninja-build libstdc++-${{ env.gcc_version }}-dev locales-all + + - uses: actions/checkout@v6 + + - name: Install python dependencies + run: | + pip3 install --user --no-cache-dir --upgrade meson + pip3 install --user --no-cache-dir --upgrade -r tools/requirements.txt + + - name: Check toml.hpp + run: | + cd tools + python3 ci_single_header_check.py + + - name: Install lld + if: ${{ startsWith(matrix.linker, 'lld') }} + run: | + sudo apt -y install --no-install-recommends lld-${{ env.clang_version }} + sudo update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-${{ env.clang_version }} 1000 + + - name: Install clang + if: ${{ startsWith(matrix.compiler, 'clang') }} + run: | + sudo apt -y install --no-install-recommends clang-${{ env.clang_version }} + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ env.clang_version }} 1000 + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ env.clang_version }} 1000 + + - name: Install gcc + if: ${{ startsWith(matrix.compiler, 'gcc') }} + run: | + sudo apt -y install --no-install-recommends gcc-${{ env.gcc_version }} g++-${{ env.gcc_version }} + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ env.gcc_version }} 1000 + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ env.gcc_version }} 1000 + + - name: Configure locales + run: | + sudo locale-gen 'en_US.utf8' 'ja_JP.utf8' 'de_DE.utf8' 'it_IT.utf8' 'tr_TR.utf8' 'fi_FI.utf8' 'fr_FR.utf8' 'zh_CN.utf8' + + - name: Configure Meson + run: | + CXX=c++ CXX_LD=${{ matrix.linker }} meson setup build --buildtype=${{ matrix.type }} -Ddevel=true -Db_lto=false + + - name: Build + run: meson compile -C build + + - name: Test + run: meson test -C build --verbose + + windows: + strategy: + fail-fast: false + matrix: + type: + - "debug" + - "release" + permissive: + - false + - true + arch: + - name: "x64" + runner: "windows-2022" + - name: "arm64" + runner: "windows-11-arm" + runs-on: ${{ matrix.arch.runner }} + + defaults: + run: + shell: cmd + working-directory: tomlplusplus + + steps: + - name: Install dependencies + run: | + python3 -m pip install -U pip + pip3 install meson ninja + + - uses: actions/checkout@v6 + + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch.name }} + + - name: Configure Meson + run: meson setup build --vsenv --buildtype=${{ matrix.type }} -Ddevel=true -Db_lto=false -Dpermissive=${{ matrix.permissive }} + + - name: Build + run: meson compile -C build + + - name: Test + run: meson test -C build --verbose diff --git a/.github/workflows/uvim-ci.yml b/.github/workflows/uvim-ci.yml new file mode 100644 index 0000000000..a94ac0c3c1 --- /dev/null +++ b/.github/workflows/uvim-ci.yml @@ -0,0 +1,180 @@ +name: "uvim: CI" + +on: + push: + branches: ['**'] + paths: + - 'uvim/**' + - '.github/workflows/uvim-ci.yml' + - '.github/actions/uvim/**' + pull_request: + paths: + - 'uvim/**' + - '.github/workflows/uvim-ci.yml' + - '.github/actions/uvim/**' + +concurrency: + group: uvim-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + linux: + runs-on: ${{ matrix.architecture == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + + env: + CC: ${{ matrix.compiler }} + GCC_VER: 14 + CLANG_VER: 21 + TEST: test + SRCDIR: ./src + LEAK_CFLAGS: -DEXITFREE + LOG_DIR: ${{ github.workspace }}/logs + TERM: xterm + DISPLAY: ':99' + DEBIAN_FRONTEND: noninteractive + + strategy: + fail-fast: false + matrix: + features: [tiny, normal, huge] + compiler: [clang, gcc] + extra: [[]] + architecture: [native] + include: + - features: tiny + compiler: clang + extra: [nogui] + - features: tiny + compiler: gcc + extra: [nogui] + - features: tiny + compiler: gcc + extra: [nogui] + architecture: arm64 + - features: huge + coverage: true + - features: huge + compiler: clang + interface: dynamic + python3: stable-abi + - features: huge + compiler: gcc + coverage: true + interface: dynamic + extra: [uchar, testgui] + - features: huge + compiler: gcc + coverage: true + extra: [unittests] + - features: huge + compiler: gcc + coverage: true + extra: [unittests] + architecture: arm64 + - features: normal + compiler: gcc + extra: [vimtags, proto, codestyle] + + defaults: + run: + working-directory: uvim + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get install -y \ + autoconf \ + clang \ + lcov \ + gettext \ + libcanberra-dev \ + libperl-dev \ + python3-dev \ + liblua5.4-dev \ + lua5.4 \ + ruby-dev \ + tcl-dev \ + libsodium-dev \ + libgtk-3-dev \ + desktop-file-utils \ + libtool-bin + + - name: Build + run: | + if [ "${{ matrix.features }}" = "tiny" ]; then + ./configure --with-features=tiny --disable-gui + elif [ "${{ matrix.features }}" = "normal" ]; then + ./configure --with-features=normal --disable-gui + else + ./configure --with-features=huge \ + --enable-perlinterp \ + --enable-pythoninterp \ + --enable-python3interp \ + --enable-rubyinterp \ + --enable-luainterp \ + --enable-tclinterp \ + --enable-gui=gtk3 + fi + make -j$(nproc) + + - name: Test + timeout-minutes: 25 + run: | + make $TEST + + - name: Upload test artifacts + if: failure() + uses: ./.github/actions/uvim/test_artifacts + + macos: + runs-on: ${{ matrix.runner }} + + env: + CC: clang + TEST: test + SRCDIR: ./src + LEAK_CFLAGS: -DEXITFREE + TERM: xterm + + strategy: + fail-fast: false + matrix: + features: [tiny, normal, huge] + runner: [macos-15] + + defaults: + run: + working-directory: uvim + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install dependencies + run: brew install lua + + - name: Build + run: | + if [ "${{ matrix.features }}" = "tiny" ]; then + ./configure --with-features=tiny --disable-gui + elif [ "${{ matrix.features }}" = "normal" ]; then + ./configure --with-features=normal --disable-gui + else + ./configure --with-features=huge \ + --enable-python3interp \ + --enable-rubyinterp \ + --enable-luainterp \ + --enable-tclinterp + fi + make -j$(sysctl -n hw.logicalcpu) + + - name: Test + timeout-minutes: 25 + run: | + make $TEST diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..3e203f8276 --- /dev/null +++ b/.gitignore @@ -0,0 +1,56 @@ +# Build artifacts +build/ +out/ +install/ +cmake-build-*/ + +# IDE and editor files +.idea/ +.vscode/ +*.swp +*.swo +*~ +.DS_Store +Thumbs.db +.directory +*.kdev4 +*.pro.user +CMakeLists.txt.user +CMakeLists.txt.user.* +.project +.settings +.ycm_extra_conf.* +compile_commands.json +tags +.clang-format-files +.cache/ +.ccls-cache/ +.clangd/ + +# OS files +.DS_Store +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Desktop.ini + +# Object files +*.o +*.obj +*.a +*.lib +*.lo +*.so +*.dylib +*.dll +*.exe + +# Debug +*.dSYM/ +*.su +*.idb +*.pdb + +# Dependency directories +node_modules/ diff --git a/cgit/.gitattributes b/cgit/.gitattributes new file mode 100644 index 0000000000..ef2baf058e --- /dev/null +++ b/cgit/.gitattributes @@ -0,0 +1,9 @@ +# cgit +* text=auto eol=lf +*.c text diff=c +*.h text diff=c +*.css text +*.js text +*.txt text +*.html text +*.png binary diff --git a/corebinutils/.gitattributes b/corebinutils/.gitattributes new file mode 100644 index 0000000000..66165bb849 --- /dev/null +++ b/corebinutils/.gitattributes @@ -0,0 +1,7 @@ +# corebinutils +* text=auto eol=lf +*.c text diff=c +*.h text diff=c +*.1 text +*.8 text +Makefile text diff --git a/forgewrapper/.gitattributes b/forgewrapper/.gitattributes new file mode 100644 index 0000000000..e40f609e71 --- /dev/null +++ b/forgewrapper/.gitattributes @@ -0,0 +1,8 @@ +# ForgeWrapper +* text=auto eol=lf +*.java text diff=java +*.gradle text +*.properties text +*.bat text eol=crlf +*.jar binary +gradlew text eol=lf diff --git a/genqrcode/.gitattributes b/genqrcode/.gitattributes new file mode 100644 index 0000000000..654d17dd59 --- /dev/null +++ b/genqrcode/.gitattributes @@ -0,0 +1,9 @@ +# genqrcode +* text=auto eol=lf +*.c text diff=c +*.h text diff=c +*.png binary +*.am text +*.ac text +*.in text +*.m4 text diff --git a/hooks/post-receive b/hooks/post-receive new file mode 100755 index 0000000000..dc328195c3 --- /dev/null +++ b/hooks/post-receive @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# ============================================================================== +# post-receive hook — Mirror push to multiple forges +# ============================================================================== +# +# Place this file in your bare repository: +# /path/to/project-tick.git/hooks/post-receive +# +# Make it executable: +# chmod +x hooks/post-receive +# +# Configuration: +# Set mirror remotes in the bare repo: +# +# git remote add github git@github.com:Project-Tick/Project-Tick.git +# git remote add gitlab git@gitlab.com:Project-Tick/Project-Tick.git +# git remote add codeberg git@codeberg.org:Project-Tick/Project-Tick.git +# git remote add sourceforge ssh://USERNAME@git.code.sf.net/p/project-tick/code +# +# Or use HTTPS with token auth: +# +# git remote add github https://x-access-token:TOKEN@github.com/Project-Tick/Project-Tick.git +# git remote add gitlab https://oauth2:TOKEN@gitlab.com/Project-Tick/Project-Tick.git +# git remote add codeberg https://TOKEN@codeberg.org/Project-Tick/Project-Tick.git +# +# Environment variables (optional): +# MIRROR_REMOTES — space-separated list of remote names to push to. +# Defaults to all configured mirror remotes. +# MIRROR_LOG — path to log file. Defaults to /var/log/git-mirror.log +# MIRROR_NOTIFY — email address for failure notifications (requires mail cmd) +# +# ============================================================================== + +set -euo pipefail + +# --------------------- +# Configuration +# --------------------- + +# Where to find mirror remotes. Override with MIRROR_REMOTES env var. +# Falls back to auto-detecting all remotes that aren't "origin". +MIRROR_REMOTES="${MIRROR_REMOTES:-}" +MIRROR_LOG="${MIRROR_LOG:-/var/log/git-mirror.log}" + +# Auto-detect remotes if not explicitly set +if [[ -z "$MIRROR_REMOTES" ]]; then + MIRROR_REMOTES=$(git remote | grep -v '^origin$' || true) +fi + +if [[ -z "$MIRROR_REMOTES" ]]; then + echo "[mirror] No mirror remotes configured. Skipping." >&2 + exit 0 +fi + +# --------------------- +# Logging +# --------------------- +log() { + local timestamp + timestamp="$(date -u '+%Y-%m-%d %H:%M:%S UTC')" + echo "[$timestamp] $*" | tee -a "$MIRROR_LOG" 2>/dev/null || echo "[$timestamp] $*" +} + +# --------------------- +# Main +# --------------------- + +log "=== Mirror push triggered ===" + +# Read the stdin from post-receive (old-sha new-sha refname) +REFS=() +while read -r oldrev newrev refname; do + REFS+=("$refname") + log " ref: $refname ($oldrev -> $newrev)" +done + +FAILED_REMOTES=() +SUCCEEDED_REMOTES=() + +for remote in $MIRROR_REMOTES; do + log "Pushing to remote: $remote" + + # Use --mirror for full mirror, or --all --tags for selective + # --mirror pushes ALL refs (branches, tags, notes, etc.) + # --force ensures deleted branches/tags are also synced + if git push --mirror --force "$remote" 2>&1 | tee -a "$MIRROR_LOG" 2>/dev/null; then + SUCCEEDED_REMOTES+=("$remote") + log " ✓ Successfully pushed to $remote" + else + FAILED_REMOTES+=("$remote") + log " ✗ FAILED to push to $remote" + fi +done + +log "--- Summary ---" +log " Succeeded: ${SUCCEEDED_REMOTES[*]:-none}" +log " Failed: ${FAILED_REMOTES[*]:-none}" + +# Send notification on failure if configured +if [[ ${#FAILED_REMOTES[@]} -gt 0 && -n "${MIRROR_NOTIFY:-}" ]]; then + if command -v mail &>/dev/null; then + { + echo "Mirror push failed for the following remotes:" + printf ' - %s\n' "${FAILED_REMOTES[@]}" + echo "" + echo "Repository: $(pwd)" + echo "Refs updated:" + printf ' %s\n' "${REFS[@]}" + echo "" + echo "Check log: $MIRROR_LOG" + } | mail -s "[git-mirror] Push failure in $(basename "$(pwd)")" "$MIRROR_NOTIFY" + fi +fi + +# Exit with error if any remote failed +if [[ ${#FAILED_REMOTES[@]} -gt 0 ]]; then + log "=== Finished with errors ===" + exit 1 +fi + +log "=== Finished successfully ===" +exit 0 diff --git a/images4docker/.gitattributes b/images4docker/.gitattributes new file mode 100644 index 0000000000..76a458a22f --- /dev/null +++ b/images4docker/.gitattributes @@ -0,0 +1,3 @@ +# images4docker +* text=auto eol=lf +*.Dockerfile text diff --git a/images4docker/.gitignore b/images4docker/.gitignore new file mode 100644 index 0000000000..a11336016d --- /dev/null +++ b/images4docker/.gitignore @@ -0,0 +1,4 @@ +# images4docker +*.log +*.tmp +.env diff --git a/json4cpp/.gitattributes b/json4cpp/.gitattributes new file mode 100644 index 0000000000..1eba5d990a --- /dev/null +++ b/json4cpp/.gitattributes @@ -0,0 +1,8 @@ +# json4cpp +* text=auto eol=lf +*.cpp text diff=cpp +*.h text diff=cpp +*.hpp text diff=cpp +*.json text +*.png binary +*.gif binary |
