Skip to content

CI: Some matrix jobs have been combined to reduce the number of workers. #297

CI: Some matrix jobs have been combined to reduce the number of workers.

CI: Some matrix jobs have been combined to reduce the number of workers. #297

Workflow file for this run

name: 🚀 Deploy content to Github Pages
on:
push:
branches-ignore: gh-pages
# Must not overlap with conditions in `gdextension_build.yml`
paths:
[
docs/**,
images/**,
dd3d_web_build/**,
examples_dd3d/**,
Doxyfile,
src/**,
.github/**,
"!.github/**/util_*",
"patches/**",
lib_utils.py,
SConstruct,
]
workflow_call:
workflow_dispatch:
inputs:
production_build:
description: Production build
default: true
type: boolean
# docs/ for documentation
# demo/ for demo project
# dev/ for development version
# dev/BRANCH/docs and dev/BRANCH/demo for dev docs/ and demo/
# Permissions to update the PAGES_BRANCH branch
permissions:
contents: write
pages: write
id-token: write
actions: write
# Stop the same workflow actions
concurrency:
group: ${{github.workflow}}-${{github.event.pull_request.number || github.ref}}
cancel-in-progress: true
env:
PAGES_BRANCH: gh-pages
DEV_DEPLOY: ${{!format('{0}', inputs.production_build) && 'true' || format('{0}', !inputs.production_build)}} # Default true
GH_TOKEN: ${{github.token}}
jobs:
data_preparation:
name: ⛏ Data preparation
runs-on: ubuntu-latest
outputs:
head_sha: ${{steps.get_sha.outputs.head_sha}}
lib_version: ${{steps.get_lib_version.outputs.version}}
deploy_version: ${{steps.get_lib_version.outputs.deploy_version}}
domain: ${{steps.get_domain.outputs.domain}}
steps:
- name: Is development version
shell: bash
run: |
echo "Is a development build: \`${{env.DEV_DEPLOY}}\`" >> $GITHUB_STEP_SUMMARY
- name: Get HEAD
shell: bash
id: get_sha
run: |
sha=$(gh api \
-H "Accept: application/vnd.github.sha" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{github.repository}}/commits/${{env.PAGES_BRANCH}})
if [ $? -ne 0 ]; then
echo "Curl failed with error: $?"
exit $?
fi
echo "head_sha=$sha" >> $GITHUB_OUTPUT
echo "\`$sha\` will be used as a restore point." >> $GITHUB_STEP_SUMMARY
- name: Checkout version.h
uses: actions/checkout@v4
with:
path: current
sparse-checkout: |
src/version.h
- name: Get library version
id: get_lib_version
shell: bash
env:
REF: ${{github.ref_name}}
run: |
# Get DD3D version
source_file="current/src/version.h"
major=$(grep -oP '(?<=#define DD3D_MAJOR )\d+' "$source_file")
minor=$(grep -oP '(?<=#define DD3D_MINOR )\d+' "$source_file")
patch=$(grep -oP '(?<=#define DD3D_PATCH )\d+' "$source_file")
version_string="$major.$minor.$patch"
echo "version=$version_string" >> $GITHUB_OUTPUT
echo "Library Version found in file \`version.h\`: \`$version_string\`" >> $GITHUB_STEP_SUMMARY
fixed_ref_name=$(echo "$REF" | tr -c [:alnum:]+[:cntrl:] [_*])
deploy_version=""
if [ "${{env.DEV_DEPLOY}}" == "true" ]; then
deploy_version=$fixed_ref_name
echo "deploy_version=$deploy_version" >> $GITHUB_OUTPUT
else
deploy_version=$version_string
echo "deploy_version=$deploy_version" >> $GITHUB_OUTPUT
fi
echo "Deploy version: \`$deploy_version\`" >> $GITHUB_STEP_SUMMARY
- name: Checkout CNAME
uses: actions/checkout@v4
continue-on-error: true
id: checkout_cname
with:
ref: ${{env.PAGES_BRANCH}}
path: pages
sparse-checkout: |
CNAME
- name: Get CNAME or domain
id: get_domain
run: |
if [ "${{steps.checkout_cname.conclusion}}" == "success" ]; then
cname=$(cat pages/CNAME)
echo "domain=$cname" >> $GITHUB_OUTPUT
echo "Found CNAME record: \`$cname\`" >> $GITHUB_STEP_SUMMARY
else
domain="${{github.repository_owner}}.github.io/${{github.event.repository.name}}"
echo "domain=$domain" >> $GITHUB_OUTPUT
echo "CNAME not found, presumably domain of gh-pages: \`$domain\`" >> $GITHUB_STEP_SUMMARY
fi
web-gdextension:
name: 🕸 Build a Web library
needs: data_preparation
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
include:
- platform: web
target: template_release
arch: wasm32
artifact: web.demo_build
additional: lto=yes force_enabled_dd3d=yes threads=yes
- platform: linux
target: editor
arch: x86_64
artifact: linux.demo_build
additional: lto=yes
env:
EM_VERSION: 3.1.63
# Faster build, but bigger library size (726KB vs 680KB)
FORCE_DISABLE_UNITY: no
SCONS_CACHE: ${{github.workspace}}/.scons-cache/
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Download Emscripten
if: ${{matrix.platform == 'web'}}
uses: mymindstorm/setup-emsdk@v14
# Continue if failed to cache
# https://github.com/mymindstorm/setup-emsdk/issues/20
continue-on-error: true
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: obj/emsdk_cache
- name: Compile GDExtension
uses: ./.github/actions/compile_gdextension
with:
platform: ${{matrix.platform}}
target: ${{matrix.target}}
arch: ${{matrix.arch}}
artifact: ${{matrix.artifact}}
additional: ${{matrix.additional}}
additional_enabled_dd3d: false
output_libs_path: bin
use_cache: true
generate_docs:
name: 📚 Generate Docs
needs: data_preparation
runs-on: ubuntu-20.04
env:
DOXYGEN_VERSION: 1.10.0
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Restore doxygen directory
uses: actions/cache/restore@v4
id: restore_doxygen
with:
path: obj/doxygen-${{env.DOXYGEN_VERSION}}
key: doxygen-${{env.DOXYGEN_VERSION}}
- name: Install Doxygen
if: ${{!steps.restore_doxygen.outputs.cache-hit}}
shell: bash
run: |
mkdir obj
cd obj
wget -nv https://www.doxygen.nl/files/doxygen-${{env.DOXYGEN_VERSION}}.linux.bin.tar.gz
tar -xf doxygen-${{env.DOXYGEN_VERSION}}.linux.bin.tar.gz
- name: Save doxygen directory
if: ${{!steps.restore_doxygen.outputs.cache-hit}}
uses: actions/cache/save@v4
with:
path: obj/doxygen-${{env.DOXYGEN_VERSION}}
key: doxygen-${{env.DOXYGEN_VERSION}}
- name: Run Doxygen
shell: bash
run: |
( cat Doxyfile ; echo "PROJECT_NUMBER=${{needs.data_preparation.outputs.lib_version}}" ) | ./obj/doxygen-${{env.DOXYGEN_VERSION}}/bin/doxygen -
- name: Get destination_dir
id: get_ref
shell: bash
env:
content_dir: docs
# dev folder name must be synced with :fix_ref_names
run: |
new_ref_name=""
if [ "${{env.DEV_DEPLOY}}" == "true" ]; then
new_ref_name="dev/${{needs.data_preparation.outputs.deploy_version}}/$content_dir"
echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT
else
new_ref_name="$content_dir/${{needs.data_preparation.outputs.deploy_version}}"
echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT
fi
echo "Target URL: https://${{needs.data_preparation.outputs.domain}}/$new_ref_name" >> $GITHUB_STEP_SUMMARY
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{secrets.GITHUB_TOKEN}}
publish_dir: obj/doxygen/html
destination_dir: ${{steps.get_ref.outputs.new_ref_name}}
publish_branch: ${{env.PAGES_BRANCH}}
allow_empty_commit: true
keep_files: true
commit_message: Updated documentation
user_name: "github-actions-deploy[bot]"
user_email: "github-actions-deploy[bot]@users.noreply.github.com"
export_demo_project:
name: 🌐📦 Export Demo Project
runs-on: ubuntu-20.04
needs: [data_preparation, generate_docs, web-gdextension]
env:
GODOT_VERSION: 4.2.1-stable
PROJECT_PATH: dd3d_web_build
BUILD_FOLDER: demo_build
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Godot
uses: ./.github/actions/setup_godot
id: setup_godot
with:
tag: ${{env.GODOT_VERSION}}
file_suffix: "stable_linux.x86_64.zip"
download_export_templates: true
is_mono: false
- name: Delete old libs folder
shell: bash
run: |
rm -rf addons/debug_draw_3d/libs
- name: Download Binaries
uses: actions/download-artifact@v4
with:
path: addons/debug_draw_3d/libs
pattern: "*.demo_build"
merge-multiple: true
- name: Prepare Web Build
run: |
find addons/debug_draw_3d/libs -mindepth 1
cp -r addons ${{env.PROJECT_PATH}}/addons
cp -r examples_dd3d ${{env.PROJECT_PATH}}/examples_dd3d
- name: Import Assets
run: ${{steps.setup_godot.outputs.godot}} -v -e --headless --path ${{env.PROJECT_PATH}} --quit || true
- name: Web Build
shell: bash --noprofile --norc -o pipefail {0}
run: |
max_attempts=3
current_attempt=1
last_exit_code=0
until [ $current_attempt -gt $max_attempts ]; do
rm -rf ${{env.BUILD_FOLDER}}
mkdir ${{env.BUILD_FOLDER}}
cp ${{env.PROJECT_PATH}}/coi-serviceworker.min.js ${{env.BUILD_FOLDER}}/coi-serviceworker.min.js
${{steps.setup_godot.outputs.godot}} -v --headless --path ${{env.PROJECT_PATH}} --export-release web $(pwd)/${{env.BUILD_FOLDER}}/index.html
last_exit_code=$?
if [ $last_exit_code -eq 0 ]; then
echo "Successful export! Attempt: $current_attempt"
exit 0
else
echo "Failed to export. Attempt: $current_attempt. Exit code: $last_exit_code"
current_attempt=$((current_attempt + 1))
fi
done
echo "The maximum number of attempts has been reached. Last error code: $?"
exit $last_exit_code
- name: Fix Permissions
run: |
chmod -c -R +rX "${{env.BUILD_FOLDER}}" | while read line; do
echo "::warning title=Invalid file permissions automatically fixed::$line"
done
- name: Get destination_dir
id: get_ref
shell: bash
env:
content_dir: demo
# dev folder name must be synced with :fix_ref_names
run: |
new_ref_name=""
if [ "${{env.DEV_DEPLOY}}" == "true" ]; then
new_ref_name="dev/${{needs.data_preparation.outputs.deploy_version}}/$content_dir"
echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT
else
new_ref_name="$content_dir/${{needs.data_preparation.outputs.deploy_version}}"
echo "new_ref_name=$new_ref_name" >> $GITHUB_OUTPUT
fi
echo "Target URL: https://${{needs.data_preparation.outputs.domain}}/$new_ref_name" >> $GITHUB_STEP_SUMMARY
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{secrets.GITHUB_TOKEN}}
publish_dir: ${{env.BUILD_FOLDER}}
destination_dir: ${{steps.get_ref.outputs.new_ref_name}}
publish_branch: ${{env.PAGES_BRANCH}}
allow_empty_commit: true
keep_files: true
commit_message: Updated demo build
user_name: "github-actions-deploy[bot]"
user_email: "github-actions-deploy[bot]@users.noreply.github.com"
finalization:
name: 🏁 Finalization
needs: [data_preparation, export_demo_project]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{env.PAGES_BRANCH}}
# MUST BE A SUFFICIENT VALUE TO BE ABLE TO RESET TO THE INITIAL COMMIT
fetch-depth: 4
- name: Clean unused folders
if: env.DEV_DEPLOY == 'false'
continue-on-error: true
# default bash without -e (fail-fast)
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference
shell: bash --noprofile --norc -o pipefail {0}
run: |
# Get branches
response=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{github.repository}}/branches)
# Can't compare existing folders with no branches
if [ $? -ne 0 ]; then
echo "Error: Could not load the list of branches. Exiting."
exit 1
fi
git_branches=$(echo "$response" | jq -r '.[].name')
# Fix ref names
# :fix_ref_names
for ((i=0; i<${#git_branches[@]}; i++)); do
git_branches[$i]=$(echo "${git_branches[$i]}" | tr -c [:alnum:]+[:cntrl:] [_*])
done
echo "Found branches:"
echo "${git_branches[@]}"
cd dev
# 'cd' must run successfully to avoid accidentally deleting anything unnecessary
if [ $? -ne 0 ]; then
echo "Error: Could not change folder to 'dev'. Exiting."
exit 1
fi
# Get directories
folders=$(find . -mindepth 1 -maxdepth 1 -type d)
echo "Existing folders:"
echo ${folders[@]}
for folder in $folders; do
folder_name=$(basename "$folder")
# Check if the branch exists
if ! echo "$git_branches" | grep -q "^$folder_name$"; then
echo "Removing the folder: $folder_name"
rm -r "$folder_name"
fi
done
- name: Add a dev index.html
shell: bash --noprofile --norc -o pipefail {0}
run: |
html_template='
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Development versions</title>
<style>
html {
background: #21232b;
color: #ebf0f1;
}
a {
color: #f59031;
text-decoration-line: none;
font-weight: 600;
}
a:hover,
a:focus {
text-decoration-line: underline;
}
</style>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
</head>
<body>
<h1>Links to versions in development</h1>
<ul id="links-list"></ul>
<script>
document.addEventListener("DOMContentLoaded", function () {
fetch("/dev_versions.json")
.then(response => response.json())
.then(data => {
var linksList = document.getElementById("links-list");
data.forEach(function (url) {
["demo", "docs"].forEach(function (suffix) {
var listItem = document.createElement("li");
var link = document.createElement("a");
link.href = url + "/" + suffix;
link.textContent = url + "/" + suffix;
listItem.appendChild(link);
linksList.appendChild(listItem);
})
linksList.appendChild(document.createElement("br"));
});
})
.catch(error => {
console.error("Error loading JSON file:", error);
var linksList = document.getElementById("links-list");
var listItem = document.createElement("li");
listItem.textContent = "Error loading a file with available versions";
linksList.appendChild(listItem);
});
});
</script>
</body>
</html>
'
cd dev
# 'cd' must run successfully
if [ $? -ne 0 ]; then
echo "The 'dev' folder does not exist."
exit 1
fi
echo "$html_template" > index.html
echo "Updated navigation in 'dev' folder"
- name: Generate a list of available versions
shell: bash --noprofile --norc -o pipefail {0}
run: |
generate_json() {
# Go to
pushd "$1" > /dev/null
if [ $? -ne 0 ]; then
echo "Error: Could not change folder to '$1'. Exiting."
return 1
fi
# Find all folders, sort, remove './'
folders=$(find . -mindepth 1 -maxdepth 1 -type d | sort -r | sed 's|^\./||')
if [ -z "$folders" ]; then
json="[]"
else
# Folders to JSON array
json=$(echo "$folders" | jq -R -s 'split("\n")[:-1]')
fi
# Go back to the root
popd > /dev/null
echo "$json" > $2
echo "Saved folder list for '$1' to '$2'."
}
if [ "${{env.DEV_DEPLOY}}" = "false" ]; then
# Only on release
generate_json "docs" "docs_versions.json"
generate_json "demo" "demo_versions.json"
fi
generate_json "dev" "dev_versions.json"
- name: Generate redirects
if: env.DEV_DEPLOY == 'false'
shell: bash --noprofile --norc -o pipefail {0}
run: |
# Redirect template
html_template='
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Redirecting to REDIRECT_TO_FOLDER/</title>
<noscript>
<meta http-equiv="refresh" content="1; url=REDIRECT_TO_FOLDER/" />
</noscript>
<script>
window.location.replace("REDIRECT_TO_FOLDER/" + window.location.hash);
</script>
<style>
html {
background: #21232b;
color: #ebf0f1;
}
a {
color: #f59031;
font-weight: 600;
}
</style>
</head>
<body>
Redirecting to <a href="REDIRECT_TO_FOLDER/">REDIRECT_TO_FOLDER/</a>...
</body>
</html>
'
generate_redirect() {
# Go to
pushd "$1" > /dev/null
if [ $? -ne 0 ]; then
echo "Error: Could not change folder to '$1'. Exiting."
return 1
fi
# Find all the folders, sort, remove './' and get only the first one, most likely the newest version
first_folder=$(find . -mindepth 1 -maxdepth 1 -type d | sort -r | sed 's|^\./||' | head -n 1)
if [ -n "$first_folder" ]; then
echo "${html_template//REDIRECT_TO_FOLDER/$first_folder}" > index.html
echo "Created a redirect from '$1' to '$first_folder'"
else
echo "The '$1' folder is empty. Exiting."
fi
# Go back to the root
popd > /dev/null
}
generate_redirect "docs"
generate_redirect "demo"
# Root to docs/ redirect
echo "${html_template//REDIRECT_TO_FOLDER/docs}" > index.html
echo "Added redirection to docs/"
- name: Commit changes
shell: bash
run: |
git config --global user.name 'github-actions-auto-updater[bot]'
git config --global user.email 'github-actions-auto-updater[bot]@users.noreply.github.com'
git diff
git add -A
git commit --allow-empty -am "Folder structure updated"
- name: Squash and push
shell: bash
run: |
git reset --soft ${{needs.data_preparation.outputs.head_sha}}
msg=$'Pages have been updated (${{env.DEV_DEPLOY == 'true' && 'Dev' || 'Release'}}, deploy version: ${{needs.data_preparation.outputs.deploy_version}}): ${{github.sha}}\n'
git commit --allow-empty -am "${msg}$(git log --format=%B --reverse HEAD..HEAD@{1})"
git push -f
echo "## Changed files:" >> $GITHUB_STEP_SUMMARY
codeblock_tmp=$'```\nSTATS\n```'
echo "${codeblock_tmp//STATS/$(git diff --stat HEAD~)}" >> $GITHUB_STEP_SUMMARY
deploy:
name: 🌐 Deploy
needs: [finalization]
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{steps.deployment.outputs.page_url}}
steps:
- name: Remove `github-pages` if the action was restarted
uses: geekyeggo/delete-artifact@v4
with:
token: ${{secrets.GITHUB_TOKEN}}
name: github-pages
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{env.PAGES_BRANCH}}
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload entire repository
path: "."
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
restore_on_fail:
name: 🔄 Restore gh-pages
needs:
[
data_preparation,
generate_docs,
export_demo_project,
finalization,
deploy,
]
if: failure() || cancelled()
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{env.PAGES_BRANCH}}
# MUST BE A SUFFICIENT VALUE TO BE ABLE TO RESET TO THE INITIAL COMMIT
fetch-depth: 4
- name: Reset and push
shell: bash
continue-on-error: true
run: |
if [ -n "${{needs.data_preparation.outputs.head_sha}}" ]; then
git reset --hard ${{needs.data_preparation.outputs.head_sha}}
git push -f
echo "The branch has been reset to \`${{needs.data_preparation.outputs.head_sha}}\`" >> $GITHUB_STEP_SUMMARY
fi