Merge pull request #1175 from past-due/github_actions_1

Add GitHub Actions CI
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
new file mode 100644
index 0000000..c3fadd1
--- /dev/null
+++ b/.github/workflows/CI.yml
@@ -0,0 +1,92 @@
+name: CI
+
+# Controls when the action will run. 
+on:
+  # Triggers the workflow on push or pull request events
+  push:
+  pull_request:
+  # Allows you to run this workflow manually from the Actions tab
+  workflow_dispatch:
+
+env:
+  # See: https://github.com/actions/virtual-environments/tree/main/images/macos
+  XCODE_DEV_PATH: /Applications/Xcode_12.2.app/Contents/Developer
+
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+  build:
+    strategy:
+      matrix:
+        include:
+          - platform: "macos"
+          - platform: "maccat"
+          - platform: "ios"
+          - platform: "tvos"
+      fail-fast: false
+
+    name: 'MoltenVK (${{ matrix.platform }})'
+    
+    # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources
+    runs-on: macos-latest
+
+    steps:
+      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
+      - uses: actions/checkout@v2
+
+      - name: Select Xcode version
+        run: sudo xcode-select -switch "${XCODE_DEV_PATH}"
+
+      - name: Prep
+        id: prep
+        run: |
+          echo "Get Xcode version info"
+          XCODE_VERSION="$(xcodebuild -version)"
+          echo "${XCODE_VERSION}"
+          XCODE_VERSION="$(echo "${XCODE_VERSION}" | tr '\t\r\n ' '_')"
+          echo "${XCODE_VERSION}"
+          echo "::set-output name=XCODE_VERSION::${XCODE_VERSION}"
+
+      - name: Cache Dependencies
+        id: cache-dependencies
+        if: success() && !(github.event_name == 'push' && contains(github.ref, 'refs/tags/')) # never cache dependencies for pushed tags
+        uses: actions/cache@v2
+        with:
+          path: |
+            External/build
+            !External/build/Intermediates
+          key: ${{ runner.os }}-${{ steps.prep.outputs.XCODE_VERSION }}-${{ matrix.platform }}-${{ hashFiles('fetchDependencies','ExternalRevisions/**','ExternalDependencies.xcodeproj/**','Scripts/**') }}
+
+      - name: Fetch Dependencies (Use Built Cache)
+        if: steps.cache-dependencies.outputs.cache-hit == 'true'
+        run: |
+          ./fetchDependencies -v --none
+
+      - name: Fetch Dependencies
+        if: steps.cache-dependencies.outputs.cache-hit != 'true'
+        run: |
+          ./fetchDependencies -v --${{ matrix.platform }}
+
+      - name: Output Dependency Build Logs on Failure
+        if: failure()
+        run: cat "dependenciesbuild.log"
+
+      - name: Build MoltenVK
+        run: |
+          make ${{ matrix.platform }}
+
+      - name: Output MoltenVK Build Logs on Failure
+        if: failure()
+        run: |
+          if [ -f "xcodebuild.log" ]; then
+            cat "xcodebuild.log"
+          fi
+
+      - name: Tar Artifacts
+        # See: https://github.com/actions/upload-artifact#maintaining-file-permissions-and-case-sensitive-files
+        run: tar -cvf "${{ matrix.platform }}.tar" Package/Release/
+
+      - name: Upload Artifacts
+        uses: actions/upload-artifact@v2
+        with:
+          name: ${{ matrix.platform }}
+          path: "${{ matrix.platform }}.tar"
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 81a3a5d..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-language: objective-c 
-
-# macOS and Xcode Version
-os: osx
-osx_image: xcode12.2
-
-# Build with verbose logging to avoid Travis timing out.
-script:
-  - ./fetchDependencies -v --no-parallel-build --macos
-  - xcodebuild build -project MoltenVKPackaging.xcodeproj -scheme "MoltenVK Package (macOS only)"
-  - xcodebuild build -workspace Demos/Demos.xcworkspace -scheme "Cube-macOS"
-
diff --git a/Makefile b/Makefile
index e96a870..2faf9f9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,19 @@
 XC_PROJ := MoltenVKPackaging.xcodeproj
 XC_SCHEME := MoltenVK Package
 
+XCODEBUILD := set -o pipefail && $(shell command -v xcodebuild)
+# Used to determine if xcpretty is available
+XCPRETTY_PATH := $(shell command -v xcpretty 2> /dev/null)
+
+OUTPUT_FMT_CMD =
+ifdef XCPRETTY_PATH
+	# Pipe output to xcpretty, while preserving full log as xcodebuild.log
+	OUTPUT_FMT_CMD = | tee "xcodebuild.log" | xcpretty -c
+else
+	# Use xcodebuild -quiet parameter
+	OUTPUT_FMT_CMD = -quiet
+endif
+
 # Specify individually (not as dependencies) so the sub-targets don't run in parallel
 .PHONY: all
 all:
@@ -22,55 +35,55 @@
 
 .PHONY: macos
 macos:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (macOS only)"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (macOS only)" $(OUTPUT_FMT_CMD)
 
 .PHONY: macos-debug
 macos-debug:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (macOS only)" -configuration "Debug"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (macOS only)" -configuration "Debug" $(OUTPUT_FMT_CMD)
 
 .PHONY: ios
 ios:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" $(OUTPUT_FMT_CMD)
 
 .PHONY: ios-debug
 ios-debug:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -configuration "Debug"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -configuration "Debug" $(OUTPUT_FMT_CMD)
 
 .PHONY: iossim
 iossim:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=iOS Simulator"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=iOS Simulator" $(OUTPUT_FMT_CMD)
 
 .PHONY: iossim-debug
 iossim-debug:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=iOS Simulator" -configuration "Debug"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=iOS Simulator" -configuration "Debug" $(OUTPUT_FMT_CMD)
 
 .PHONY: maccat
 maccat:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=macOS,variant=Mac Catalyst"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=macOS,variant=Mac Catalyst" $(OUTPUT_FMT_CMD)
 
 .PHONY: maccat-debug
 maccat-debug:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=macOS,variant=Mac Catalyst" -configuration "Debug"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (iOS only)" -destination "generic/platform=macOS,variant=Mac Catalyst" -configuration "Debug" $(OUTPUT_FMT_CMD)
 
 .PHONY: tvos
 tvos:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" $(OUTPUT_FMT_CMD)
 
 .PHONY: tvos-debug
 tvos-debug:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -configuration "Debug"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -configuration "Debug" $(OUTPUT_FMT_CMD)
 
 .PHONY: tvossim
 tvossim:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -destination "generic/platform=tvOS Simulator"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -destination "generic/platform=tvOS Simulator" $(OUTPUT_FMT_CMD)
 
 .PHONY: tvossim-debug
 tvossim-debug:
-	xcodebuild build -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -destination "generic/platform=tvOS Simulator" -configuration "Debug"
+	$(XCODEBUILD) build -project "$(XC_PROJ)" -scheme "$(XC_SCHEME) (tvOS only)" -destination "generic/platform=tvOS Simulator" -configuration "Debug" $(OUTPUT_FMT_CMD)
 
 .PHONY: clean
 clean:
-	xcodebuild clean -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME)"
+	$(XCODEBUILD) clean -quiet -project "$(XC_PROJ)" -scheme "$(XC_SCHEME)"
 	rm -rf Package
 
 # Usually requires 'sudo make install'
diff --git a/fetchDependencies b/fetchDependencies
index 4f55904..bba7456 100755
--- a/fetchDependencies
+++ b/fetchDependencies
@@ -395,6 +395,14 @@
 echo ========== Started building dependency libraries at `date +"%r"` ==========
 echo Please be patient on first build
 
+function execute_xcodebuild_command () {
+	if [ -n "${XCPRETTY}" ]; then
+		set -o pipefail && xcodebuild "$@" | tee -a "dependenciesbuild.log" | ${XCPRETTY}
+	else
+		xcodebuild "$@"
+	fi
+}
+
 # Build an Xcode scheme for an OS and platform
 # 1 - OS
 # 2 - Platform
@@ -414,7 +422,7 @@
 
 	echo Building external libraries for platform ${XC_PLTFM} and destination ${XC_DEST}
 
-	xcodebuild 													\
+	execute_xcodebuild_command 									\
 		-project "${XC_PROJ}"									\
 		-scheme "${XC_SCHEME}"									\
 		-destination "generic/platform=${XC_DEST}"				\
@@ -444,6 +452,19 @@
 XC_PROJ="${EXT_DEPS}.xcodeproj"
 XC_DD_PATH="${EXT_DIR}/build"
 
+# Determine if xcpretty is present
+XCPRETTY_PATH=$(command -v xcpretty 2> /dev/null || true) # ignore failures
+
+# If xcpretty is present, use it to format xcodebuild output
+XCPRETTY=""
+if [ -n "$XCPRETTY_PATH" ]; then
+	XCPRETTY="xcpretty -c"
+fi
+if [ "$XC_USE_BCKGND" != "" ]; then
+	# For now, avoid using xcpretty if parallel background tasks are being used
+	XCPRETTY=""
+fi
+
 # Structure build tasks by platform so they can be built in parallel per platform.
 # Content for each platform must be built in series to avoid
 if [ "$XC_USE_BCKGND" != "" ]; then