summaryrefslogtreecommitdiff
path: root/meshmc/.github/workflows
diff options
context:
space:
mode:
Diffstat (limited to 'meshmc/.github/workflows')
-rw-r--r--meshmc/.github/workflows/backport.yml30
-rw-r--r--meshmc/.github/workflows/blocked-prs.yml257
-rw-r--r--meshmc/.github/workflows/build.yml185
-rw-r--r--meshmc/.github/workflows/codeql.yml52
-rw-r--r--meshmc/.github/workflows/container.yml177
-rw-r--r--meshmc/.github/workflows/merge-blocking-pr.yml64
-rw-r--r--meshmc/.github/workflows/nix.yml138
-rw-r--r--meshmc/.github/workflows/publish.yml25
-rw-r--r--meshmc/.github/workflows/release.yml124
-rw-r--r--meshmc/.github/workflows/update-flake.yml35
10 files changed, 1087 insertions, 0 deletions
diff --git a/meshmc/.github/workflows/backport.yml b/meshmc/.github/workflows/backport.yml
new file mode 100644
index 0000000000..0ca52b37cc
--- /dev/null
+++ b/meshmc/.github/workflows/backport.yml
@@ -0,0 +1,30 @@
+name: 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-slim
+ 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:
+ # Config README: https://github.com/korthout/backport-action#backport-action
+ pull_description: |-
+ Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}.
+
diff --git a/meshmc/.github/workflows/blocked-prs.yml b/meshmc/.github/workflows/blocked-prs.yml
new file mode 100644
index 0000000000..0010801540
--- /dev/null
+++ b/meshmc/.github/workflows/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/meshmc/.github/workflows/build.yml b/meshmc/.github/workflows/build.yml
new file mode 100644
index 0000000000..0ed6240b41
--- /dev/null
+++ b/meshmc/.github/workflows/build.yml
@@ -0,0 +1,185 @@
+name: Build
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+on:
+ push:
+ branches:
+ - 'master'
+ merge_group:
+ types: [checks_requested]
+ pull_request:
+ 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
+ # TODO(@YongDo-Hyun): This is the default in setup-dependencies/windows. Why isn't it working?!?!
+ 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' }}
+
+ 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/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/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/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/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/meshmc/.github/workflows/codeql.yml b/meshmc/.github/workflows/codeql.yml
new file mode 100644
index 0000000000..436ae07eef
--- /dev/null
+++ b/meshmc/.github/workflows/codeql.yml
@@ -0,0 +1,52 @@
+name: "CodeQL Code Scanning"
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+on:
+ merge_group:
+ types: [checks_requested]
+ pull_request:
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ CodeQL:
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ security-events: write
+
+ 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/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/meshmc/.github/workflows/container.yml b/meshmc/.github/workflows/container.yml
new file mode 100644
index 0000000000..762eff6c82
--- /dev/null
+++ b/meshmc/.github/workflows/container.yml
@@ -0,0 +1,177 @@
+name: Development Container
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+on:
+ push:
+ branches:
+ - 'master'
+ merge_group:
+ types: [checks_requested]
+ pull_request:
+ 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
+ # TODO(@YongDo-Hyun): Always use this when the action properly supports ARM
+ 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: |
+ ./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
+ # TODO(@YongDo-Hyun): Always use this when the action properly supports ARM
+ 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/meshmc/.github/workflows/merge-blocking-pr.yml b/meshmc/.github/workflows/merge-blocking-pr.yml
new file mode 100644
index 0000000000..3542a470e0
--- /dev/null
+++ b/meshmc/.github/workflows/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/meshmc/.github/workflows/nix.yml b/meshmc/.github/workflows/nix.yml
new file mode 100644
index 0000000000..a62d9c0aff
--- /dev/null
+++ b/meshmc/.github/workflows/nix.yml
@@ -0,0 +1,138 @@
+name: Nix
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+on:
+ push:
+ branches:
+ - "master"
+ - "release-*"
+ tags:
+ - "*"
+ paths:
+ # File types
+ - "**.cpp"
+ - "**.h"
+ - "**.java"
+ - "**.ui"
+ - "**.md"
+
+ # Build files
+ - "**.nix"
+ - "nix/**"
+ - "flake.lock"
+
+ # Directories
+ - "buildconfig/**"
+ - "cmake/**"
+ - "launcher/**"
+ - "libraries/**"
+ - "branding/**"
+ - "tests/**"
+
+ # Files
+ - "CMakeLists.txt"
+
+ # Workflows
+ - ".github/workflows/nix.yml"
+ pull_request:
+ paths:
+ # File types
+ - "**.cpp"
+ - "**.h"
+ - "**.java"
+ - "**.ui"
+ - "**.md"
+
+ # Build files
+ - "**.nix"
+ - "nix/**"
+ - "flake.lock"
+
+ # Directories
+ - "buildconfig/**"
+ - "cmake/**"
+ - "launcher/**"
+ - "libraries/**"
+ - "branding/**"
+ - "tests/**"
+
+ # Files
+ - "CMakeLists.txt"
+
+ # Workflows
+ - ".github/workflows/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 }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+
+ - name: Install Nix
+ uses: cachix/install-nix-action@v31
+
+ # For PRs
+ - name: Setup Nix Magic Cache
+ if: ${{ github.event_name == 'pull_request' }}
+ uses: DeterminateSystems/magic-nix-cache-action@v13
+ with:
+ diagnostic-endpoint: ""
+ use-flakehub: false
+
+ # For in-tree builds
+ - 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/meshmc/.github/workflows/publish.yml b/meshmc/.github/workflows/publish.yml
new file mode 100644
index 0000000000..9d2b3e06b9
--- /dev/null
+++ b/meshmc/.github/workflows/publish.yml
@@ -0,0 +1,25 @@
+name: Publish
+
+on:
+ release:
+ types: [ released ]
+
+permissions: {}
+
+jobs:
+ winget:
+ name: Winget
+
+ permissions:
+ contents: read
+
+ runs-on: ubuntu-slim
+
+ 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/meshmc/.github/workflows/release.yml b/meshmc/.github/workflows/release.yml
new file mode 100644
index 0000000000..8ce7409b2d
--- /dev/null
+++ b/meshmc/.github/workflows/release.yml
@@ -0,0 +1,124 @@
+name: Build Application and Make Release
+
+on:
+ push:
+ tags:
+ - "*"
+
+permissions: {}
+
+jobs:
+ build_release:
+ name: Build Release
+ uses: ./.github/workflows/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-slim
+ 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/meshmc/.github/workflows/update-flake.yml b/meshmc/.github/workflows/update-flake.yml
new file mode 100644
index 0000000000..9aa57ec2e4
--- /dev/null
+++ b/meshmc/.github/workflows/update-flake.yml
@@ -0,0 +1,35 @@
+name: Update Flake Lockfile
+
+on:
+ schedule:
+ # run weekly on sunday
+ - cron: "0 0 * * 0"
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ update-flake:
+ if: github.repository == 'Project-Tick/MeshMC'
+
+ permissions:
+ contents: write
+ pull-requests: write
+
+ runs-on: ubuntu-slim
+
+ steps:
+ - uses: actions/checkout@v6
+ - uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31
+
+ - uses: DeterminateSystems/update-flake-lock@v28
+ with:
+ 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