Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/actions/setup-odrcore/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: setup odrcore
description: >
Installs the toolchain and resolves odrcore and its dependencies with conan,
leaving the generated xcconfigs in conan-output and the runtime assets in
conan-assets. Every job that compiles the app needs the exact same ten steps,
so they live here instead of being copied into each workflow.

inputs:
xcode-version:
description: Xcode version to select on the runner
required: true
profile:
description: conan host profile under conan/profiles
required: true
configuration:
description: Xcode configuration to resolve the dependencies for
required: true
cache-flavor:
description: >
Cache namespace. The simulator and the device slice resolve a different
dependency set, so they must not overwrite each other's cache entry.
required: true
save-cache:
description: >
Whether this job may write the conan cache back. Jobs that only consume
what another job built restore without saving.
required: false
default: "true"

outputs:
conan-cache-key:
description: Cache key of the conan package cache, to restore it elsewhere
value: ${{ steps.conan-cache-key.outputs.key }}

runs:
using: composite
steps:
- name: checkout conan-odr-index
shell: bash
run: git submodule update --init --depth 1 conan-odr-index

# 3.12+ is required by the conan-odr-index helper scripts
- uses: actions/setup-python@v7
with:
python-version: "3.12"

- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ inputs.xcode-version }}

# conan itself is pinned by conan-odr-index so recipes and client stay in sync
- name: install conan
shell: bash
run: pip3 install -r conan-odr-index/requirements.txt

- name: conan profile
shell: bash
run: conan profile detect

- name: conan cache key
id: conan-cache-key
shell: bash
run: echo "key=conan2-${{ runner.os }}-xcode${{ inputs.xcode-version }}-${{ inputs.cache-flavor }}-index$(git rev-parse HEAD:conan-odr-index)-${{ hashFiles('conan/conanfile.py', 'conan/profiles/*') }}" >> "$GITHUB_OUTPUT"

# restore before exporting the recipes: the export must run on top of the
# restored cache so current recipes win over stale ones from the archive
- name: conan cache
if: inputs.save-cache == 'true'
uses: actions/cache@v6
with:
path: ~/.conan2/p
key: ${{ steps.conan-cache-key.outputs.key }}
restore-keys: |
conan2-${{ runner.os }}-xcode${{ inputs.xcode-version }}-${{ inputs.cache-flavor }}-

- name: restore conan cache
if: inputs.save-cache != 'true'
uses: actions/cache/restore@v6
with:
path: ~/.conan2/p
key: ${{ steps.conan-cache-key.outputs.key }}
restore-keys: |
conan2-${{ runner.os }}-xcode${{ inputs.xcode-version }}-${{ inputs.cache-flavor }}-

# recipes are exported from the submodule into the local cache, which is
# why no private remote has to be configured
- name: export conan-odr-index
shell: bash
run: python3 conan-odr-index/scripts/conan_export_all_packages.py

- name: conan install
shell: bash
run: >
conan install conan/
--output-folder=conan-output
--build=missing
--profile:host=conan/profiles/${{ inputs.profile }}
--deployer=conan/conandeployer.py
--deployer-folder=conan-assets
-o "configuration=${{ inputs.configuration }}"
97 changes: 97 additions & 0 deletions .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: build_test

on:
workflow_dispatch:
# branch pushes are covered by the pull_request trigger, so only main is built
# directly - otherwise every push to a branch with an open PR builds twice
push:
branches:
- main
paths-ignore:
- '**/*.md'
- 'fastlane/metadata/**'
pull_request:
paths-ignore:
- '**/*.md'
- 'fastlane/metadata/**'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read

env:
# the runner image only ships the iOS platform bundle for its default Xcode;
# older ones fail in ibtool with "iOS 26.0 Platform Not Installed"
xcode_version: "26.5"

jobs:
test:
runs-on: macos-26
steps:
- name: checkout
uses: actions/checkout@v7

- uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- uses: ./.github/actions/setup-odrcore
with:
xcode-version: ${{ env.xcode_version }}
profile: ios-simulator-arm64
configuration: Debug
cache-flavor: simulator

- name: run tests
run: bundle exec fastlane tests

# drop temporary download/source/build folders so only built packages get cached
- name: clean conan cache
run: conan cache clean "*"

- uses: actions/upload-artifact@v7
if: always()
with:
name: logs
path: |
/Users/runner/Library/Developer/Xcode/DerivedData/OpenDocumentReader-*/

# the test job only ever builds the simulator slice of one configuration, so
# release-only and device-only breakage used to surface at deploy time
build:
runs-on: macos-26
strategy:
fail-fast: false
matrix:
include:
- { scheme: "ODR Full", configuration: "Release" }
- { scheme: "ODR Lite", configuration: "Release Lite" }
steps:
- name: checkout
uses: actions/checkout@v7

- uses: ./.github/actions/setup-odrcore
with:
xcode-version: ${{ env.xcode_version }}
profile: ios
configuration: ${{ matrix.configuration }}
cache-flavor: device

# signing needs secrets this workflow does not have, so this only proves
# that the device slice compiles and links
- name: build
run: >
xcodebuild
-project OpenDocumentReader.xcodeproj
-scheme "${{ matrix.scheme }}"
-configuration "${{ matrix.configuration }}"
-sdk iphoneos
-destination 'generic/platform=iOS'
CODE_SIGNING_ALLOWED=NO
build

- name: clean conan cache
run: conan cache clean "*"
39 changes: 39 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: format

# swift-format comes with the Xcode toolchain, so this needs neither conan nor
# ruby and reports style breakage in a minute instead of after a full build.
# Unlike build_test this has no paths-ignore: every file the formatter touches
# gets checked.

on:
workflow_dispatch:
push:
branches:
- main
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read

env:
# the runner image only ships the iOS platform bundle for its default Xcode;
# older ones fail in ibtool with "iOS 26.0 Platform Not Installed"
xcode_version: "26.5"

jobs:
swift-format:
runs-on: macos-26
steps:
- name: checkout
uses: actions/checkout@v7

- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ env.xcode_version }}

- name: check formatting
run: scripts/format.sh --check
Loading