diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml deleted file mode 100644 index 6e62216a6..000000000 --- a/.github/workflows/clang-format.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Clang Format Check - -on: - push: - paths-ignore: ['**.md'] - branches-ignore: [master] - pull_request: - paths-ignore: ['**.md'] - branches-ignore: [master] - -jobs: - clang-format-check: - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Install clang format - run: | - sudo apt-get install -y clang-format-13 - - - name: 'Run clang-format' - run: | - ./CI/check-format.sh - ./CI/check-changes.sh diff --git a/.github/workflows/clean-caches.yml b/.github/workflows/clean-caches.yml deleted file mode 100644 index 9f67c643a..000000000 --- a/.github/workflows/clean-caches.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Cache Cleanup - -on: - schedule: - - cron: 0 0 * * * - workflow_dispatch: - -jobs: - purge: - name: Cache Cleanup - runs-on: ubuntu-latest - steps: - - name: Install Python & Modules - run: | - sudo apt install -y python3.11 - python3.11 -m pip install requests - - - name: Clean Caches - shell: python3.11 {0} - run: | - import re - from datetime import datetime - import requests - - s = requests.session() - s.headers['Authorization'] = 'Bearer ${{ secrets.GITHUB_TOKEN }}' - - r = s.get('https://api.github.com/repos/${{ github.repository }}/actions/caches', params=dict(per_page=100)) - r.raise_for_status() - caches = r.json()['actions_caches'] - - print(f'There are {len(caches)} total caches.') - - # find latest flatpak cache - flatpak_last_ts = None - flatpak_key = None - for cache in caches: - if not cache['ref'] == 'refs/heads/master' or not cache['key'].startswith('flatpak-builder'): - continue - ts = datetime.fromisoformat(cache['created_at']) - if not flatpak_last_ts or ts > flatpak_last_ts: - flatpak_key = cache['key'] - flatpak_last_ts = ts - - if flatpak_key: - print(f'Latest flatpak cache: {flatpak_key}') - - now = datetime.utcnow() - to_be_removed = [] - for cache in caches: - # add merge queue caches - if 'gh-readonly-queue' in cache['ref']: - to_be_removed.append(cache) - continue - - if flatpak_key and cache['key'].startswith('flatpak-builder'): - # add non-master flatpak caches that match latest key - if cache['key'] == flatpak_key and not cache['ref'] == 'refs/heads/master': - to_be_removed.append(cache) - continue - # add master flatpak caches that do not match the latest key - elif cache['key'] != flatpak_key and cache['ref'] == 'refs/heads/master': - to_be_removed.append(cache) - continue - - # add dated caches predating today - if (cache_date := re.search('[0-9]{4}\-[0-9]{2}\-[0-9]{2}', cache['key'])) is not None: - parsed_date = datetime.strptime(cache_date.group(), '%Y-%m-%d') - if (now - parsed_date).days > 0: - to_be_removed.append(cache) - - print(f'Removing {len(to_be_removed)} caches...') - for cache in to_be_removed: - print(f'Deleting cache "{cache["key"]}" with ID {cache["id"]}...', end=' ') - r = s.delete(f'https://api.github.com/repos/${{ github.repository }}/actions/caches/{cache["id"]}') - print(f'[{r.status_code}]') diff --git a/.github/workflows/compat-json.yml b/.github/workflows/compat-json.yml deleted file mode 100644 index be3d7ec4b..000000000 --- a/.github/workflows/compat-json.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Compatibility Data Validator - -on: - push: - paths: - - "plugins/win-capture/data/compatibility.json" - - "plugins/win-capture/data/package.json" - pull_request: - paths: - - "plugins/win-capture/data/compatibility.json" - - "plugins/win-capture/data/package.json" - -jobs: - schema: - name: Schema - runs-on: [ubuntu-22.04] - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install & Configure Python - run: | - sudo apt install python3-dev - python3 -m pip install jsonschema json_source_map - - - name: Validate Compatibility JSON Schema - run: | - JSON_FILES=( - plugins/win-capture/data/compatibility.json - plugins/win-capture/data/package.json - ) - python3 CI/check-jsonschema.py "${JSON_FILES[@]}" - - - name: Annotate Errors - if: failure() - uses: yuzutech/annotations-action@v0.4.0 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - title: "Compatibility JSON Errors" - input: "./validation_errors.json" diff --git a/.github/workflows/crowdin-sync-download.yml b/.github/workflows/crowdin-sync-download.yml deleted file mode 100644 index 05f45034f..000000000 --- a/.github/workflows/crowdin-sync-download.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: "Crowdin Sync: Import latest translations" -on: workflow_dispatch -jobs: - crowdin-sync-download: - name: Import latest translations - runs-on: ubuntu-latest - if: github.repository_owner == 'obsproject' - env: - CROWDIN_PAT: ${{ secrets.CROWDIN_SYNC_CROWDIN_PAT }} - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 0 - token: ${{ secrets.CROWDIN_SYNC_GITHUB_PAT }} - - uses: obsproject/obs-crowdin-sync/download@0.2.1 diff --git a/.github/workflows/crowdin-sync-upload.yml b/.github/workflows/crowdin-sync-upload.yml deleted file mode 100644 index 37edd6b8c..000000000 --- a/.github/workflows/crowdin-sync-upload.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "Crowdin Sync: Upload English strings" -on: - push: - branches: - - master - paths: - - "**/en-US.ini" -jobs: - crowdin-sync-upload: - name: Upload English strings - runs-on: ubuntu-latest - env: - CROWDIN_PAT: ${{ secrets.CROWDIN_SYNC_CROWDIN_PAT }} - GITHUB_EVENT_BEFORE: ${{ github.event.before }} - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - fetch-depth: 100 - - uses: obsproject/obs-crowdin-sync/upload@0.2.1 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 96cccc15f..000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,136 +0,0 @@ -name: Generate Documentation - -on: - push: - paths-ignore: - - "cmake/**" - branches: ['*'] - tags: ['*'] - pull_request: - paths: - - "docs/sphinx/**" - workflow_dispatch: - -jobs: - docs: - runs-on: ubuntu-latest - outputs: - commitHash: ${{ steps.setup.outputs.commitHash }} - commitBranch: ${{ steps.setup.outputs.commitBranch }} - fullCommitHash: ${{ steps.setup.outputs.fullCommitHash }} - env: - BUILD_CF_ARTIFACT: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Environment - id: setup - run: | - BRANCH=$(git describe --exact-match --tags 2> /dev/null || git branch --show-current) - # Remove patch version from tag - BRANCH=$(echo ${BRANCH} | sed -e 's/\.[0-9]*$//') - echo "commitBranch=${BRANCH}" >> $GITHUB_OUTPUT - echo "commitHash=$(git describe --exact-match --tags 2> /dev/null || git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - echo "fullCommitHash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - - - name: Bump Version Number - shell: bash - if: github.event_name != 'pull_request' - run: | - VERTEST="\#define\sLIBOBS_API_\w+_VER\s([0-9]{1,2})" - VER="" - MAJOR="" - while IFS= read -r l - do - if [[ $l =~ $VERTEST ]]; then - if [[ $VER = '' ]]; then MAJOR="${BASH_REMATCH[1]}"; else VER+="."; fi - VER+="${BASH_REMATCH[1]}" - fi - done < "libobs/obs-config.h" - - SVER="version = '([0-9\.]+)'" - RVER="version = '$VER'" - SREL="release = '([0-9\.]+)'" - RREL="release = '$VER'" - SCOPY="copyright = '([A-Za-z0-9, ]+)'" - RCOPY="copyright = '2017-$(date +"%Y"), Lain Bailey'" - sed -i -E -e "s/${SVER}/${RVER}/g" -e "s/${SREL}/${RREL}/g" -e "s/${SCOPY}/${RCOPY}/g" docs/sphinx/conf.py - - - uses: totaldebug/sphinx-publish-action@1.2.0 - with: - sphinx_src: 'docs/sphinx' - build_only: True - target_branch: 'master' - target_path: '../home/_build' - pre_build_commands: 'pip install -Iv sphinx==5.1.1' - - - name: Disable link extensions - shell: bash - if: ${{ env.BUILD_CF_ARTIFACT == 'true' }} - run: | - SOPT="html_link_suffix = None" - ROPT="html_link_suffix = ''" - sed -i -e "s/${SOPT}/${ROPT}/g" docs/sphinx/conf.py - - - uses: totaldebug/sphinx-publish-action@1.2.0 - if: ${{ env.BUILD_CF_ARTIFACT == 'true' }} - with: - sphinx_src: 'docs/sphinx' - build_only: True - target_branch: 'master' - target_path: '../home/_build_cf' - pre_build_commands: 'pip install -Iv sphinx==5.1.1' - - - uses: actions/upload-artifact@v3 - with: - name: 'OBS Studio Docs ${{ steps.setup.outputs.commitHash }}' - path: | - ${{ runner.temp }}/_github_home/_build - !${{ runner.temp }}/_github_home/_build/.doctrees - - - uses: actions/upload-artifact@v3 - if: ${{ env.BUILD_CF_ARTIFACT == 'true' }} - with: - name: 'CF Pages ${{ steps.setup.outputs.commitHash }}' - path: | - ${{ runner.temp }}/_github_home/_build_cf - !${{ runner.temp }}/_github_home/_build_cf/.doctrees - - deploy: - runs-on: ubuntu-latest - needs: docs - if: ${{ github.event_name == 'workflow_dispatch' || (github.repository_owner == 'obsproject' && startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request') }} - environment: - name: cf-pages-deploy - concurrency: - group: "cf-pages-deployment" - cancel-in-progress: true - steps: - - uses: actions/download-artifact@v3 - with: - name: 'CF Pages ${{ needs.docs.outputs.commitHash }}' - path: docs - - - name: Setup redirects - run: | - echo "/previous/27.2 https://obsproject.com/docs/27.2 302" >> docs/_redirects - echo "/previous/:major.:minor https://:major-:minor.${{ vars.CF_PAGES_PROJECT }}.pages.dev 302" >> docs/_redirects - - - name: Publish to live page - if: ${{ !contains(needs.docs.outputs.commitBranch, 'beta') && !contains(needs.docs.outputs.commitBranch, 'rc') }} - uses: cloudflare/wrangler-action@4c10c1822abba527d820b29e6333e7f5dac2cabd - with: - workingDirectory: docs - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish . --project-name=${{ vars.CF_PAGES_PROJECT }} --commit-hash='${{ needs.docs.outputs.fullCommitHash }}' - - - name: Publish to tag alias - if: ${{ startsWith(github.ref, 'refs/tags/') }} - uses: cloudflare/wrangler-action@4c10c1822abba527d820b29e6333e7f5dac2cabd - with: - workingDirectory: docs - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish . --project-name=${{ vars.CF_PAGES_PROJECT }} --commit-hash='${{ needs.docs.outputs.fullCommitHash }}' --branch='${{ needs.docs.outputs.commitBranch }}' diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml deleted file mode 100644 index 4a9835148..000000000 --- a/.github/workflows/flatpak.yml +++ /dev/null @@ -1,123 +0,0 @@ ---- - -name: Flatpak - -on: - release: - types: [published] - branches: [master, 'release/**'] - -env: - TWITCH_CLIENTID: ${{ secrets.TWITCH_CLIENT_ID }} - TWITCH_HASH: ${{ secrets.TWITCH_HASH }} - RESTREAM_CLIENTID: ${{ secrets.RESTREAM_CLIENTID }} - RESTREAM_HASH: ${{ secrets.RESTREAM_HASH }} - YOUTUBE_CLIENTID: ${{ secrets.YOUTUBE_CLIENTID }} - YOUTUBE_CLIENTID_HASH: ${{ secrets.YOUTUBE_CLIENTID_HASH }} - YOUTUBE_SECRET: ${{ secrets.YOUTUBE_SECRET }} - YOUTUBE_SECRET_HASH: ${{ secrets.YOUTUBE_SECRET_HASH }} - -jobs: - check_tag: - name: Check release tag - runs-on: [ubuntu-latest] - outputs: - valid_tag: ${{ steps.check_tag.outputs.valid_tag }} - matrix: ${{ steps.check_tag.outputs.matrix }} - steps: - - name: Check the tag - id: check_tag - run: | - shopt -s extglob - - case ${GITHUB_REF##*/} in - +([0-9]).+([0-9]).+([0-9]) ) - echo 'valid_tag=true' >> $GITHUB_OUTPUT - echo 'matrix=["beta", "stable"]' >> $GITHUB_OUTPUT - ;; - +([0-9]).+([0-9]).+([0-9])-@(beta|rc)*([0-9]) ) - echo 'valid_tag=true' >> $GITHUB_OUTPUT - echo 'matrix=["beta"]' >> $GITHUB_OUTPUT - ;; - * ) echo 'valid_tag=false' >> $GITHUB_OUTPUT ;; - esac - - publish: - name: Publish to Flathub - runs-on: [ubuntu-latest] - needs: check_tag - if: fromJSON(needs.check_tag.outputs.valid_tag) - env: - FLATPAK_BUILD_PATH: flatpak_app/files/share - container: - image: bilelmoussaoui/flatpak-github-actions:kde-6.4 - options: --privileged - strategy: - matrix: - branch: ${{ fromJSON(needs.check_tag.outputs.matrix) }} - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: 'Setup build environment' - id: setup - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CACHE_KEY: flatpak-builder-${{ hashFiles('build-aux/**/*.json') }} - run: | - dnf install -y -q gh - gh extension install actions/gh-actions-cache - - git config --global --add safe.directory $GITHUB_WORKSPACE - - KEY="$CACHE_KEY-x86_64" - CACHE_HIT=$(gh actions-cache list -B master --key $KEY | grep -q $KEY && echo 'true' || echo 'false') - - echo "git_hash=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - echo "cache_key=$CACHE_KEY" >> $GITHUB_OUTPUT - echo "cache_hit=$CACHE_HIT" >> $GITHUB_OUTPUT - - - name: Build Flatpak Manifest - uses: flatpak/flatpak-github-actions/flatpak-builder@v6.1 - with: - bundle: obs-studio-${{ steps.setup.outputs.git_hash }}.flatpak - manifest-path: build-aux/com.obsproject.Studio.json - cache: ${{ fromJSON(steps.setup.outputs.cache_hit) }} - cache-key: ${{ steps.setup.outputs.cache_key }} - mirror-screenshots-url: https://dl.flathub.org/repo/screenshots - branch: ${{ matrix.branch }} - - - name: Validate AppStream - shell: bash - working-directory: ${{ env.FLATPAK_BUILD_PATH }} - run: | - appstream-util validate appdata/com.obsproject.Studio.appdata.xml - - - name: Verify icon and metadata in app-info - shell: bash - working-directory: ${{ env.FLATPAK_BUILD_PATH }} - run: | - test -f app-info/icons/flatpak/128x128/com.obsproject.Studio.png || { echo "Missing 128x128 icon in app-info" ; exit 1; } - test -f app-info/xmls/com.obsproject.Studio.xml.gz || { echo "Missing com.obsproject.Studio.xml.gz in app-info" ; exit 1; } - - - name: Commit screenshots to the OSTree repository - run: | - ostree commit --repo=repo --canonical-permissions --branch=screenshots/x86_64 flatpak_app/screenshots - - - name: Publish to Flathub Beta - uses: flatpak/flatpak-github-actions/flat-manager@v6.1 - if: matrix.branch == 'beta' - with: - flat-manager-url: https://hub.flathub.org/ - repository: beta - token: ${{ secrets.FLATHUB_BETA_TOKEN }} - - - name: Publish to Flathub - uses: flatpak/flatpak-github-actions/flat-manager@v6.1 - if: matrix.branch == 'stable' - with: - flat-manager-url: https://hub.flathub.org/ - repository: stable - token: ${{ secrets.FLATHUB_TOKEN }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 9e9454194..000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,624 +0,0 @@ -name: 'BUILD' - -on: - push: - paths-ignore: ['**.md'] - branches: - - master - - 'release/**' - tags: ['*'] - pull_request: - paths-ignore: ['**.md'] - branches: [master] - merge_group: - branches: [master] - -env: - CACHE_REVISION: '006' - CEF_BUILD_VERSION_LINUX: '5060' - CEF_BUILD_VERSION_WIN: '5060' - QT_VERSION_MAC: '6.4.3' - QT_VERSION_WIN: '6.4.3' - DEPS_VERSION_WIN: '2023-06-22' - VLC_VERSION_WIN: '3.0.0-git' - TWITCH_CLIENTID: ${{ secrets.TWITCH_CLIENT_ID }} - TWITCH_HASH: ${{ secrets.TWITCH_HASH }} - RESTREAM_CLIENTID: ${{ secrets.RESTREAM_CLIENTID }} - RESTREAM_HASH: ${{ secrets.RESTREAM_HASH }} - YOUTUBE_CLIENTID: ${{ secrets.YOUTUBE_CLIENTID }} - YOUTUBE_CLIENTID_HASH: ${{ secrets.YOUTUBE_CLIENTID_HASH }} - YOUTUBE_SECRET: ${{ secrets.YOUTUBE_SECRET }} - YOUTUBE_SECRET_HASH: ${{ secrets.YOUTUBE_SECRET_HASH }} - GPU_PRIORITY_VAL: ${{ secrets.GPU_PRIORITY_VAL }} - -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - clang_check: - name: '01 - Code Format Check' - runs-on: [ubuntu-22.04] - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: 'Install clang-format' - run: sudo apt-get install -y clang-format-13 - - - name: 'Run clang-format' - run: | - ./CI/check-format.sh - ./CI/check-changes.sh - - - name: 'Install cmake-format' - run: sudo pip install cmakelang - - - name: 'Run cmake-format' - run: | - ./CI/check-cmake.sh - - - name: 'Run format-manifest.py' - run: | - python3 ./build-aux/format-manifest.py - ./CI/check-changes.sh - - config: - name: '01 - Configure Build Jobs' - runs-on: [ubuntu-22.04] - outputs: - create_artifacts: ${{ steps.config.outputs.create_artifacts }} - cache_date: ${{ steps.config.outputs.cache_date }} - steps: - - name: 'Configure Build Jobs' - id: config - run: | - if [[ "${{ github.event_name == 'pull_request' }}" == "true" ]]; then - if test -n "$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')"; then - echo 'create_artifacts=true' >> $GITHUB_OUTPUT - else - echo 'create_artifacts=false' >> $GITHUB_OUTPUT - fi - else - echo 'create_artifacts=true' >> $GITHUB_OUTPUT - fi - echo "cache_date=$(date +"%Y-%m-%d")" >> $GITHUB_OUTPUT - - macos_build: - name: '02 - macOS' - runs-on: [macos-13] - strategy: - matrix: - arch: ['x86_64', 'arm64'] - if: always() - needs: [config, clang_check] - env: - BLOCKED_FORMULAS: 'speexdsp curl php composer' - defaults: - run: - shell: bash - working-directory: 'obs-studio' - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - submodules: 'recursive' - path: 'obs-studio' - fetch-depth: 0 - - - name: 'Restore ccache from cache' - id: ccache-cache - uses: actions/cache@v3 - with: - path: ${{ github.workspace }}/.ccache - key: ${{ runner.os }}-ccache-${{ steps.github-check.outputs.generator }}-${{ matrix.arch }}-${{ github.event_name }}-${{ github.head_ref }} - restore-keys: | - ${{ runner.os }}-ccache-${{ steps.github-check.outputs.generator }}-${{ matrix.arch }}-push- - - - name: 'Setup build environment' - id: setup - run: | - REMOVE_FORMULAS="" - for FORMULA in ${{ env.BLOCKED_FORMULAS }}; do - if [ -d "/usr/local/opt/${FORMULA}" ]; then - REMOVE_FORMULAS="${REMOVE_FORMULAS}${FORMULA} " - fi - done - - if [ -n "${REMOVE_FORMULAS}" ]; then - brew uninstall ${REMOVE_FORMULAS} - fi - - echo "commitHash=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - - - name: 'Install dependencies' - run: CI/macos/01_install_dependencies.sh --architecture "${{ matrix.arch }}" - - - name: 'Install Apple Developer Certificate' - id: macos-codesign - env: - MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} - MACOS_SIGNING_CERT: ${{ secrets.MACOS_SIGNING_CERT }} - MACOS_SIGNING_CERT_PASSWORD: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} - MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} - MACOS_PROVISIONING_PROFILE: ${{ secrets.MACOS_SIGNING_PROVISIONING_PROFILE }} - run: | - if [[ "${MACOS_SIGNING_IDENTITY}" && "${MACOS_SIGNING_CERT}" ]]; then - CERTIFICATE_PATH="${RUNNER_TEMP}/build_certificate.p12" - KEYCHAIN_PATH="${RUNNER_TEMP}/app-signing.keychain-db" - - echo -n "${MACOS_SIGNING_CERT}" | base64 --decode --output="${CERTIFICATE_PATH}" - - : "${MACOS_KEYCHAIN_PASSWORD:="$(echo ${RANDOM} | sha1sum | head -c 32)"}" - - security create-keychain -p "${MACOS_KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}" - security set-keychain-settings -lut 21600 "${KEYCHAIN_PATH}" - security unlock-keychain -p "${MACOS_KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}" - - security import "${CERTIFICATE_PATH}" -P "${MACOS_SIGNING_CERT_PASSWORD}" -A \ - -t cert -f pkcs12 -k "${KEYCHAIN_PATH}" \ - -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/xcrun - - security set-key-partition-list -S 'apple-tool:,apple:' -k "${MACOS_KEYCHAIN_PASSWORD}" \ - "${KEYCHAIN_PATH}" &> /dev/null - security list-keychain -d user -s "${KEYCHAIN_PATH}" 'login-keychain' - - echo "CODESIGN_IDENT=${MACOS_SIGNING_IDENTITY}" >> $GITHUB_ENV - echo "MACOS_KEYCHAIN_PASSWORD=${MACOS_KEYCHAIN_PASSWORD}" >> $GITHUB_ENV - echo "haveCodesignIdent=true" >> $GITHUB_OUTPUT - else - echo "CODESIGN_IDENT=-" >> $GITHUB_ENV - echo "haveCodesignIdent=false" >> $GITHUB_OUTPUT - fi - - if [[ "${MACOS_PROVISIONING_PROFILE}" ]]; then - PROFILE_PATH="${RUNNER_TEMP}/build_profile.provisionprofile" - echo -n "${MACOS_PROVISIONING_PROFILE}" | base64 --decode --output="${PROFILE_PATH}" - - mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - security cms -D -i "${PROFILE_PATH}" -o "${RUNNER_TEMP}/build_profile.plist" - UUID="$(plutil -extract UUID raw "${RUNNER_TEMP}/build_profile.plist")" - TEAM_ID="$(plutil -extract TeamIdentifier.0 raw -expect string "${RUNNER_TEMP}/build_profile.plist")" - - cp "${PROFILE_PATH}" ~/Library/MobileDevice/Provisioning\ Profiles/${UUID}.provisionprofile - echo "provisionprofileUUID=${UUID}" >> $GITHUB_OUTPUT - echo "haveProvisioningProfile=true" >> $GITHUB_OUTPUT - echo "CODESIGN_TEAM=${TEAM_ID}" >> $GITHUB_ENV - else - echo "haveProvisioningProfile=false" >> $GITHUB_OUTPUT - fi - - if [[ "${MACOS_NOTARIZATION_USERNAME}" && "${MACOS_NOTARIZATION_PASSWORD}" ]]; then - echo "haveNotarizationUser=true" >> $GITHUB_OUTPUT - else - echo "haveNotarizationUser=false" >> $GITHUB_OUTPUT - fi - - - name: 'Build OBS' - env: - PROVISIONING_PROFILE: ${{ steps.macos-codesign.outputs.provisionprofileUUID }} - run: | - sudo xcode-select --switch /Applications/Xcode_14.3.1.app/Contents/Developer - if [[ '${{ steps.github-check.outputs.generator }}' == 'Xcode' ]]; then - SEEKING_TESTERS=1 CI/macos/02_build_obs.sh --codesign --architecture "${{ matrix.arch }}" - else - CI/macos/02_build_obs.sh --codesign --architecture "${{ matrix.arch }}" - fi - - - name: 'Create build artifact' - if: ${{ fromJSON(needs.config.outputs.create_artifacts) }} - run: | - : ${PACKAGE:=} - case "${GITHUB_EVENT_NAME}" in - push) if [[ ${GITHUB_REF_NAME} =~ [0-9]+.[0-9]+.[0-9]+(-(rc|beta).+)? ]]; then PACKAGE=1; fi ;; - pull_request) PACKAGE=1 ;; - esac - - if [[ "${PACKAGE}" ]]; then - sudo sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db \ - "INSERT OR REPLACE INTO access VALUES('kTCCServiceAppleEvents','/usr/local/opt/runner/provisioner/provisioner',1,2,3,1,NULL,NULL,0,'com.apple.finder',X'fade0c000000002c00000001000000060000000200000010636f6d2e6170706c652e66696e64657200000003',NULL,1592919552);" - sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db \ - "INSERT OR REPLACE INTO access VALUES('kTCCServiceAppleEvents','/usr/local/opt/runner/provisioner/provisioner',1,2,3,1,NULL,NULL,0,'com.apple.finder',X'fade0c000000002c00000001000000060000000200000010636f6d2e6170706c652e66696e64657200000003',NULL,1592919552);" - - CI/macos/03_package_obs.sh --codesign --architecture "${{ matrix.arch }}" - ARTIFACT_NAME=$(basename $(/usr/bin/find build_macos -type f -name "obs-studio-*.dmg" -depth 1 | head -1)) - echo "FILE_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV - fi - - - name: 'Upload build Artifact' - if: ${{ fromJSON(needs.config.outputs.create_artifacts) && env.FILE_NAME != '' }} - uses: actions/upload-artifact@v3 - with: - name: 'obs-studio-macos-${{ matrix.arch }}-${{ steps.setup.outputs.commitHash }}' - path: '${{ github.workspace }}/obs-studio/build_macos/${{ env.FILE_NAME }}' - - linux_build: - name: '02 - Linux' - runs-on: ${{ matrix.ubuntu }} - strategy: - matrix: - ubuntu: ['ubuntu-22.04'] - if: always() - needs: [config, clang_check] - defaults: - run: - shell: bash - working-directory: 'obs-studio' - env: - BUILD_FOR_DISTRIBUTION: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' }} - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - submodules: 'recursive' - path: 'obs-studio' - fetch-depth: 0 - - - name: 'Restore ccache from cache' - id: ccache-cache - uses: actions/cache@v3 - env: - CACHE_NAME: 'ccache-cache' - with: - path: ${{ github.workspace }}/.ccache - key: ${{ runner.os }}-ccache-${{ matrix.ubuntu }}-${{ github.event_name }}-${{ github.head_ref }} - restore-keys: | - ${{ runner.os }}-ccache-${{ matrix.ubuntu }}-push- - - - name: 'Restore Chromium Embedded Framework from cache' - id: cef-cache - uses: actions/cache@v3 - env: - CACHE_NAME: 'cef-cache' - with: - path: ${{ github.workspace }}/obs-build-dependencies/cef_binary_${{ env.CEF_BUILD_VERSION_LINUX }}_linux64 - key: ${{ runner.os }}-pr-${{ env.CACHE_NAME }}-${{ env.CEF_BUILD_VERSION_LINUX }}-${{ env.CACHE_REVISION }} - - - name: 'Setup build environment' - id: setup - run: | - echo "commitHash=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - - - name: 'Install dependencies' - env: - RESTORED_CEF: ${{ steps.cef-cache.outputs.cache-hit }} - run: CI/linux/01_install_dependencies.sh ${{ matrix.script_options }} - - - name: 'Build OBS' - run: CI/linux/02_build_obs.sh ${{ matrix.script_options }} - - - name: 'Run tests' - if: success() - run: cmake --build build -t test - - - name: 'Create build artifact' - if: ${{ success() && fromJSON(needs.config.outputs.create_artifacts) }} - run: | - CI/linux/03_package_obs.sh - ARTIFACT_NAME=$(basename $(/usr/bin/find build -maxdepth 1 -type f -name "obs-studio-*.deb" | sort -rn | head -1)) - echo "FILE_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV - echo "DEBUG_FILE_NAME=${ARTIFACT_NAME//.deb/-dbgsym.ddeb}" >> $GITHUB_ENV - - - name: 'Upload build Artifact' - if: ${{ success() && fromJSON(needs.config.outputs.create_artifacts) }} - uses: actions/upload-artifact@v3 - with: - name: 'obs-studio-${{ matrix.ubuntu }}-${{ steps.setup.outputs.commitHash }}' - path: '${{ github.workspace }}/obs-studio/build/${{ env.FILE_NAME }}' - - - name: 'Upload debug symbol Artifact' - if: ${{ success() && fromJSON(needs.config.outputs.create_artifacts) }} - uses: actions/upload-artifact@v3 - with: - name: 'obs-studio-${{ matrix.ubuntu }}-${{ steps.setup.outputs.commitHash }}-dbgsym' - path: '${{ github.workspace }}/obs-studio/build/${{ env.DEBUG_FILE_NAME }}' - - windows_build: - name: '02 - Windows' - runs-on: [windows-2022] - needs: [config, clang_check] - if: always() - env: - BUILD_FOR_DISTRIBUTION: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' }} - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - submodules: 'recursive' - fetch-depth: 0 - - - name: Setup Environment - id: setup - run: | - $CommitHash = git rev-parse --short=9 HEAD - "commitHash=${CommitHash}" >> $env:GITHUB_OUTPUT - - - name: 'Build OBS' - run: .github/scripts/Build-Windows.ps1 -Target x64 -Configuration RelWithDebInfo - - - name: 'Create build artifact' - if: ${{ success() && fromJSON(needs.config.outputs.create_artifacts) }} - run: | - .github/scripts/Package-Windows.ps1 -Target x64 -Configuration RelWithDebInfo - $ArtifactName = Get-ChildItem -filter "build_x64/obs-studio-*-windows-x64.zip" -File - Write-Output "FILE_NAME=${ArtifactName}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - - - name: 'Upload build artifact' - if: ${{ success() && fromJSON(needs.config.outputs.create_artifacts) }} - uses: actions/upload-artifact@v3 - with: - name: 'obs-studio-windows-x64-${{ steps.setup.outputs.commitHash }}' - path: '${{ env.FILE_NAME }}' - - linux_package: - name: '02 - Flatpak' - runs-on: [ubuntu-latest] - needs: [config, clang_check] - defaults: - run: - shell: bash - container: - image: bilelmoussaoui/flatpak-github-actions:kde-6.4 - options: --privileged - steps: - - - name: 'Checkout' - uses: actions/checkout@v3 - with: - submodules: 'recursive' - fetch-depth: 0 - - - name: 'Setup build environment' - id: setup - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CACHE_KEY: flatpak-builder-${{ hashFiles('build-aux/**/*.json') }} - run: | - dnf install -y -q gh - gh extension install actions/gh-actions-cache - - git config --global --add safe.directory $GITHUB_WORKSPACE - - KEY="$CACHE_KEY-x86_64" - CACHE_HIT=$(gh actions-cache list -B master --key $KEY | grep -q $KEY && echo 'true' || echo 'false') - - echo "git_hash=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - echo "cache_key=$CACHE_KEY" >> $GITHUB_OUTPUT - echo "cache_hit=$CACHE_HIT" >> $GITHUB_OUTPUT - - - name: Build Flatpak Manifest - uses: flatpak/flatpak-github-actions/flatpak-builder@v6.1 - with: - build-bundle: ${{ fromJSON(needs.config.outputs.create_artifacts) }} - bundle: obs-studio-flatpak-${{ steps.setup.outputs.git_hash }}.flatpak - manifest-path: build-aux/com.obsproject.Studio.json - cache: ${{ fromJSON(steps.setup.outputs.cache_hit) || (github.event_name == 'push' && github.ref == 'refs/heads/master') }} - restore-cache: ${{ fromJSON(steps.setup.outputs.cache_hit) }} - cache-key: ${{ steps.setup.outputs.cache_key }} - - macos_release: - name: '03 - macOS notarized image' - runs-on: [macos-13] - needs: [macos_build] - env: - BUILD_FOR_DISTRIBUTION: 'ON' - HAVE_SPARKLE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY != '' }} - outputs: - run_sparkle: ${{ steps.sparkle_check.outputs.run_sparkle }} - if: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' }} - strategy: - matrix: - arch: ['x86_64', 'arm64'] - defaults: - run: - shell: bash - steps: - - name: 'Install Apple Developer Certificate' - id: macos-codesign - env: - MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} - MACOS_SIGNING_CERT: ${{ secrets.MACOS_SIGNING_CERT }} - MACOS_SIGNING_CERT_PASSWORD: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} - MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} - MACOS_PROVISIONING_PROFILE: ${{ secrets.MACOS_SIGNING_PROVISIONING_PROFILE }} - MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }} - MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }} - run: | - if [[ "${MACOS_SIGNING_IDENTITY}" && "${MACOS_SIGNING_CERT}" ]]; then - CERTIFICATE_PATH="${RUNNER_TEMP}/build_certificate.p12" - KEYCHAIN_PATH="${RUNNER_TEMP}/app-signing.keychain-db" - - echo -n "${MACOS_SIGNING_CERT}" | base64 --decode --output="${CERTIFICATE_PATH}" - - : "${MACOS_KEYCHAIN_PASSWORD:="$(echo ${RANDOM} | sha1sum | head -c 32)"}" - - security create-keychain -p "${MACOS_KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}" - security set-keychain-settings -lut 21600 "${KEYCHAIN_PATH}" - security unlock-keychain -p "${MACOS_KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}" - - security import "${CERTIFICATE_PATH}" -P "${MACOS_SIGNING_CERT_PASSWORD}" -A \ - -t cert -f pkcs12 -k "${KEYCHAIN_PATH}" \ - -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/xcrun - - security set-key-partition-list -S 'apple-tool:,apple:' -k "${MACOS_KEYCHAIN_PASSWORD}" \ - "${KEYCHAIN_PATH}" &> /dev/null - security list-keychain -d user -s "${KEYCHAIN_PATH}" 'login-keychain' - - echo "CODESIGN_IDENT=${MACOS_SIGNING_IDENTITY}" >> $GITHUB_ENV - echo "MACOS_KEYCHAIN_PASSWORD=${MACOS_KEYCHAIN_PASSWORD}" >> $GITHUB_ENV - echo "haveCodesignIdent=true" >> $GITHUB_OUTPUT - else - echo "CODESIGN_IDENT=-" >> $GITHUB_ENV - echo "haveCodesignIdent=false" >> $GITHUB_OUTPUT - fi - - if [[ "${MACOS_PROVISIONING_PROFILE}" ]]; then - PROFILE_PATH="${RUNNER_TEMP}/build_profile.provisionprofile" - echo -n "${MACOS_PROVISIONING_PROFILE}" | base64 --decode --output="${PROFILE_PATH}" - - mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - security cms -D -i "${PROFILE_PATH}" -o "${RUNNER_TEMP}/build_profile.plist" - UUID="$(plutil -extract UUID raw "${RUNNER_TEMP}/build_profile.plist")" - TEAM_ID="$(plutil -extract TeamIdentifier.0 raw -expect string "${RUNNER_TEMP}/build_profile.plist")" - - cp "${PROFILE_PATH}" ~/Library/MobileDevice/Provisioning\ Profiles/${UUID}.provisionprofile - echo "provisionprofileUUID=${UUID}" >> $GITHUB_OUTPUT - echo "haveProvisioningProfile=true" >> $GITHUB_OUTPUT - echo "CODESIGN_TEAM=${TEAM_ID}" >> $GITHUB_ENV - else - echo "haveProvisioningProfile=false" >> $GITHUB_OUTPUT - fi - - if [[ "${MACOS_NOTARIZATION_USERNAME}" && "${MACOS_NOTARIZATION_PASSWORD}" ]]; then - echo "haveNotarizationUser=true" >> $GITHUB_OUTPUT - else - echo "haveNotarizationUser=false" >> $GITHUB_OUTPUT - fi - - - name: 'Checkout' - if: ${{ fromJSON(steps.macos-codesign.outputs.haveCodesignIdent) && fromJSON(steps.macos-codesign.outputs.haveNotarizationUser) }} - uses: actions/checkout@v3 - - - name: 'Setup build environment' - if: ${{ fromJSON(steps.macos-codesign.outputs.haveCodesignIdent) && fromJSON(steps.macos-codesign.outputs.haveNotarizationUser) }} - id: setup - run: | - echo "commitHash=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - - - name: 'Determine if Sparkle should run' - if: env.HAVE_CODESIGN_IDENTITY == 'true' - id: sparkle_check - run: | - echo 'run_sparkle=${{ env.HAVE_SPARKLE_KEY }}' >> $GITHUB_OUTPUT - - - name: 'Download artifact' - if: ${{ fromJSON(steps.macos-codesign.outputs.haveCodesignIdent) && fromJSON(steps.macos-codesign.outputs.haveNotarizationUser) }} - uses: actions/download-artifact@v3 - with: - name: 'obs-studio-macos-${{ matrix.arch }}-${{ steps.setup.outputs.commitHash }}' - - - name: 'Create disk image for distribution' - if: ${{ fromJSON(steps.macos-codesign.outputs.haveCodesignIdent) && fromJSON(steps.macos-codesign.outputs.haveNotarizationUser) }} - env: - CODESIGN_IDENT_USER: ${{ secrets.MACOS_NOTARIZATION_USERNAME }} - CODESIGN_IDENT_PASS: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }} - run: | - ARTIFACT_NAME=$(/usr/bin/find . -type f -name "obs-studio-*.dmg" -depth 1 | head -1) - CI/macos/03_package_obs.sh --notarize-image ${ARTIFACT_NAME} - - echo "FILE_NAME=$(basename ${ARTIFACT_NAME})" >> $GITHUB_ENV - - - name: 'Upload build Artifact' - if: ${{ fromJSON(steps.macos-codesign.outputs.haveCodesignIdent) && fromJSON(steps.macos-codesign.outputs.haveNotarizationUser) }} - uses: actions/upload-artifact@v3 - with: - name: 'obs-studio-macos-${{ matrix.arch }}-notarized' - path: '${{ github.workspace }}/${{ env.FILE_NAME }}' - - macos_sparkle: - name: '04 - macOS Sparkle Updates' - runs-on: [macos-13] - needs: [macos_release] - if: fromJSON(needs.macos_release.outputs.run_sparkle) - strategy: - matrix: - arch: ['x86_64', 'arm64'] - env: - SPARKLE_VERSION: '2.3.2' - SPARKLE_HASH: '2b3fe6918ca20a83729aad34f8f693a678b714a17d33b5f13ca2d25edfa7eed3' - defaults: - run: - shell: bash - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - path: 'repo' - ref: ${{ github.ref }} - - - name: 'Download artifact' - uses: actions/download-artifact@v3 - with: - name: 'obs-studio-macos-${{ matrix.arch }}-notarized' - path: 'artifacts' - - - name: 'Install Python requirements' - run: pip3 install requests xmltodict - - - name: 'Install Brew requirements' - run: brew install coreutils pandoc - - - name: 'Setup Sparkle' - run: | - curl -L "https://github.com/sparkle-project/Sparkle/releases/download/${{ env.SPARKLE_VERSION }}/Sparkle-${{ env.SPARKLE_VERSION }}.tar.xz" -o Sparkle.tar.xz - - if [[ '${{ env.SPARKLE_HASH }}' != "$(sha256sum Sparkle.tar.xz | cut -d " " -f 1)" ]]; then - echo "Sparkle download hash does not match!" - exit 1 - fi - - mkdir sparkle && cd sparkle - tar -xf ../Sparkle.tar.xz - - - name: 'Setup folder structure' - run: | - mkdir builds - mkdir -p output/appcasts/stable - mkdir -p output/sparkle_deltas/${{ matrix.arch }} - - - name: 'Determine branch and tag' - id: branch - run: | - pushd repo - - GIT_TAG="$(git describe --tags --abbrev=0)" - if [[ ${GIT_TAG} == *'beta'* || ${GIT_TAG} == *'rc'* ]]; then - echo "branch=beta" >> $GITHUB_OUTPUT - echo "deltas=1" >> $GITHUB_OUTPUT - else - echo "branch=stable" >> $GITHUB_OUTPUT - echo "deltas=1" >> $GITHUB_OUTPUT - fi - # Write tag description to file - git tag -l --format='%(contents)' ${GIT_TAG} >> ../notes.rst - - - name: 'Download existing Appcast and builds' - run: python3 repo/CI/macos/appcast_download.py --branch "${{ steps.branch.outputs.branch }}" --max-old-versions ${{ steps.branch.outputs.deltas }} - - - name: 'Prepare release notes' - run: | - # Insert underline at line 2 to turn first line into heading - sed -i '' '2i\'$'\n''###################################################' notes.rst - pandoc -f rst -t html notes.rst -o output/appcasts/notes_${{ steps.branch.outputs.branch }}.html - - - name: 'Setup Sparkle key' - run: echo -n "${{ secrets.SPARKLE_PRIVATE_KEY }}" >> eddsa_private.key - - - name: 'Generate Appcast' - run: | - mv artifacts/*.dmg builds/ - ./sparkle/bin/generate_appcast \ - --verbose \ - --ed-key-file ./eddsa_private.key \ - --download-url-prefix "https://cdn-fastly.obsproject.com/downloads/" \ - --full-release-notes-url "https://obsproject.com/osx_update/notes_${{ steps.branch.outputs.branch }}.html" \ - --maximum-versions 0 \ - --maximum-deltas ${{ steps.branch.outputs.deltas }} \ - --channel "${{ steps.branch.outputs.branch }}" builds/ - # Move deltas, if any - if compgen -G "builds/*.delta" > /dev/null; then - mv builds/*.delta output/sparkle_deltas/${{ matrix.arch }} - fi - # Move appcasts - mv builds/*.xml output/appcasts/ - - - name: 'Create 1.x Appcast' - run: python3 repo/CI/macos/appcast_convert.py - - - name: 'Upload Appcast and Deltas' - uses: actions/upload-artifact@v3 - with: - name: 'macos-sparkle-updates' - path: '${{ github.workspace }}/output' diff --git a/.github/workflows/qt-xml.yml b/.github/workflows/qt-xml.yml deleted file mode 100644 index 98798b823..000000000 --- a/.github/workflows/qt-xml.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: UI XML Validator - -on: - push: - paths-ignore: - - "cmake/**" - pull_request: - paths: - - "UI/forms/**" - -jobs: - qt-xml-validator: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Install xmllint - run: | - sudo apt-get -qq update - sudo apt-get install --no-install-recommends -y libxml2-utils - - - name: Register Annotations - uses: korelstar/xmllint-problem-matcher@v1 - - - name: Validate - run: | - xmllint --schema UI/forms/XML-Schema-Qt5.15.xsd --noout UI/forms/*.ui UI/forms/**/*.ui diff --git a/.github/workflows/services-json.yml b/.github/workflows/services-json.yml deleted file mode 100644 index 0c4891287..000000000 --- a/.github/workflows/services-json.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: Services Validator - -on: - push: - paths: - - "plugins/rtmp-services/data/services.json" - - "plugins/rtmp-services/data/package.json" - pull_request: - paths: - - "plugins/rtmp-services/data/services.json" - - "plugins/rtmp-services/data/package.json" - schedule: - - cron: 0 0 * * * - workflow_dispatch: - -jobs: - schema: - name: Schema - runs-on: [ubuntu-20.04] - if: ${{ github.repository_owner == 'obsproject' || github.event_name != 'schedule' }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install & Configure Python - run: | - sudo apt install python3.9-dev - python3.9 -m pip install jsonschema json_source_map - - - name: Validate Service JSON Schema - run: | - JSON_FILES=( - plugins/rtmp-services/data/services.json - plugins/rtmp-services/data/package.json - ) - python3.9 CI/check-jsonschema.py "${JSON_FILES[@]}" - - - name: Annotate Errors - if: failure() - uses: yuzutech/annotations-action@v0.4.0 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - title: "Service JSON Errors" - input: "./validation_errors.json" - - service_check: - name: Service Check - runs-on: macos-latest - needs: schema - if: ${{ github.repository_owner == 'obsproject' && github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Restore cache - uses: actions/cache@v3 - with: - path: ${{ github.workspace }}/other - # Workaround to create a new cache every time, since a cache key is immutable: - # https://github.com/actions/cache/blob/main/workarounds.md#update-a-cache - key: service-check-${{ github.run_id }} - restore-keys: service-check - - - name: Install & Configure Python - run: | - python3 -m pip install requests - - - name: Check Services - id: check - run: python3 -u CI/check-services.py - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WORKFLOW_RUN_ID: ${{ github.run_id }} - REPOSITORY: ${{ github.repository }} - - - uses: actions/upload-artifact@v3 - with: - name: timestamps - path: ${{ github.workspace }}/other/* - - - name: Create Pull Request - uses: peter-evans/create-pull-request@36a56dac0739df8d3d8ebb9e6e41026ba248ec27 - if: steps.check.outputs.make_pr == 'true' - with: - author: "Service Checker " - commit-message: "rtmp-services: Remove defunct servers/services" - title: "rtmp-services: Remove defunct servers/services" - branch: "automated/clean-services" - body: ${{ fromJSON(steps.check.outputs.pr_message) }} - delete-branch: true diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml deleted file mode 100644 index e03be2d17..000000000 --- a/.github/workflows/steam.yml +++ /dev/null @@ -1,266 +0,0 @@ -name: Steam Upload - -on: - release: - types: - - published - workflow_dispatch: - inputs: - tag: - description: 'Tag to fetch and upload (nightly if none)' - required: false - win_url_override: - description: 'Windows build to use (.zip only)' - required: false - mac_url_override: - description: 'Mac build to use (.dmg only)' - required: false - mac_arm_url_override: - description: 'Mac ARM build to use (.dmg only)' - required: false - -env: - WORKFLOW_ID: 583765 - GIT_NIGHTLY_BRANCH: master - STEAM_NIGHTLY_BRANCH: nightly - STEAM_STABLE_BRANCH: staging - STEAM_BETA_BRANCH: beta_staging - STEAM_PLAYTEST_BRANCH: staging - -jobs: - upload: - name: Steam upload - runs-on: macos-latest - if: github.repository_owner == 'obsproject' - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - path: source - - - name: Get build information - id: build-info - run: | - EVENT='${{ github.event_name }}' - if [[ ${EVENT} == 'release' || ( ${EVENT} == 'workflow_dispatch' && -n '${{ github.event.inputs.tag }}') ]]; then - if [[ ${EVENT} == "release" ]]; then - DESC='${{ github.event.release.tag_name }}' - if [[ '${{ github.event.release.prerelease }}' == 'true' ]]; then - BRANCH='${{ env.STEAM_BETA_BRANCH }}' - else - BRANCH='${{ env.STEAM_STABLE_BRANCH }}' - fi - ASSETS_URL='${{ github.event.release.assets_url }}' - else - RELEASE="$(curl -s '${{ github.api_url }}/repos/obsproject/obs-studio/releases/tags/${{ github.event.inputs.tag }}')" - - DESC="$(jq -r '.tag_name' <<< ${RELEASE})" - if [[ "$(jq -r '.prerelease' <<< ${RELEASE})" == 'true' ]]; then - BRANCH='${{ env.STEAM_BETA_BRANCH }}' - else - BRANCH='${{ env.STEAM_STABLE_BRANCH }}' - fi - ASSETS_URL="$(jq -r '.assets_url' <<< ${RELEASE})" - fi - - ASSETS="$(curl -s "${ASSETS_URL}")" - WIN_ASSET_URL="$(jq -r '.[] | select(.name|test(".*.zip")) .browser_download_url' <<< ${ASSETS})" - MAC_ASSET_URL="$(jq -r '.[] | select(.name|test(".*x86_64.*.dmg")) .browser_download_url' <<< ${ASSETS})" - MAC_ARM_ASSET_URL="$(jq -r '.[] | select(.name|test(".*arm64.*.dmg")) .browser_download_url' <<< ${ASSETS})" - TYPE='release' - else - BRANCH='${{ env.STEAM_NIGHTLY_BRANCH }}' - BUILDS="$(curl -s '${{ github.api_url }}/repos/obsproject/obs-studio/actions/workflows/${{ env.WORKFLOW_ID }}/runs?per_page=1&event=push&status=success&branch=${{ env.GIT_NIGHTLY_BRANCH }}')" - ARTIFACTS_URL="$(jq -r '.workflow_runs[].artifacts_url' <<< ${BUILDS})" - DESC="g$(jq -r '.workflow_runs[].head_sha' <<< "${BUILDS}" | cut -c1-9)" - - ARTIFACTS="$(curl -s ${ARTIFACTS_URL})" - WIN_ASSET_URL="$(jq -r '.artifacts[] | select(.name|test(".*windows-x64.*")) .archive_download_url' <<< ${ARTIFACTS})" - MAC_ASSET_URL="$(jq -r '.artifacts[] | select(.name|test(".*macos-x86_64.*")) .archive_download_url' <<< ${ARTIFACTS})" - MAC_ARM_ASSET_URL="$(jq -r '.artifacts[] | select(.name|test(".*macos-arm64.*")) .archive_download_url' <<< ${ARTIFACTS})" - TYPE='nightly' - fi - - # Apply overrides from workflow_dispatch - if [[ ${EVENT} == 'workflow_dispatch' ]]; then - if [[ -n '${{ github.event.inputs.win_url_override }}' ]]; then - WIN_ASSET_URL='${{ github.event.inputs.win_url_override }}' - fi - - if [[ -n '${{ github.event.inputs.mac_url_override }}' ]]; then - MAC_ASSET_URL='${{ github.event.inputs.mac_url_override }}' - fi - - if [[ -n '${{ github.event.inputs.mac_arm_url_override }}' ]]; then - MAC_ARM_ASSET_URL='${{ github.event.inputs.mac_arm_url_override }}' - fi - fi - - if [[ -z ${WIN_ASSET_URL} || -z ${MAC_ASSET_URL} || -z ${MAC_ARM_ASSET_URL} ]]; then - echo "Missing at least one asset URL!" - exit 1 - fi - - # set env variables for subsequent steps - echo "type=${TYPE}" >> $GITHUB_OUTPUT - echo "branch=${BRANCH}" >> $GITHUB_OUTPUT - echo "desc=${DESC}" >> $GITHUB_OUTPUT - echo "win_url=${WIN_ASSET_URL}" >> $GITHUB_OUTPUT - echo "mac_intel_url=${MAC_ASSET_URL}" >> $GITHUB_OUTPUT - echo "mac_arm_url=${MAC_ARM_ASSET_URL}" >> $GITHUB_OUTPUT - - - name: Restore build cache - id: cache - uses: actions/cache@v3 - with: - path: ${{ github.workspace }}/steam/build - key: ${{ steps.build-info.outputs.branch }}-${{ steps.build-info.outputs.desc }} - # Using "restore-keys" will restore the most recent cache for the branch, even if the exact cache doesn't exist. - # This doesn't set cache-hit to true so it won't skip the upload for nightlies. - restore-keys: ${{ steps.build-info.outputs.branch }} - - - name: Determine if Steam upload should run - # If the nightly build has already been uploaded and thus a cache exists skip this and the following steps. - # Steam does not prevent us from uploading duplicate builds so this would just pollute the dashboard. - # This is a bit of a hack and can fail to work if our cache has been evicted or we somehow have no commits for 7 days, - # but it's better than nothing! - id: should-run - run: | - if [[ '${{ steps.build-info.outputs.type }}' == 'release' || '${{ steps.cache.outputs.cache-hit }}' != 'true' ]]; then - echo "result=true" >> $GITHUB_OUTPUT - if [[ '${{ steps.build-info.outputs.branch }}' == '${{ env.STEAM_BETA_BRANCH }}' ]]; then - echo "result_playtest=true" >> $GITHUB_OUTPUT - else - echo "result_playtest=false" >> $GITHUB_OUTPUT - fi - else - echo "result=false" >> $GITHUB_OUTPUT - echo "result_playtest=false" >> $GITHUB_OUTPUT - fi - - - name: Download and prepare builds - if: steps.should-run.outputs.result == 'true' - run: | - echo "::group::Download Windows build" - if [[ '${{ steps.build-info.outputs.win_url }}' == *'api.github.com'* ]]; then - curl -L -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' '${{ steps.build-info.outputs.win_url }}' -o windows.zip - else - curl -L '${{ steps.build-info.outputs.win_url }}' -o windows.zip - fi - echo "::endgroup::" - - echo "::group::Download Mac builds" - if [[ '${{ steps.build-info.outputs.mac_intel_url }}' == *'api.github.com'* ]]; then - curl -L -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' '${{ steps.build-info.outputs.mac_intel_url }}' -o mac_x86.dmg.zip - else - curl -L '${{ steps.build-info.outputs.mac_intel_url }}' -o mac_x86.dmg - fi - - if [[ '${{ steps.build-info.outputs.mac_arm_url }}' == *'api.github.com'* ]]; then - curl -L -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' '${{ steps.build-info.outputs.mac_arm_url }}' -o mac_arm64.dmg.zip - else - curl -L '${{ steps.build-info.outputs.mac_arm_url }}' -o mac_arm64.dmg - fi - echo "::endgroup::" - - mkdir -p steam && cd steam - - echo "::group::Extract and prepare Win64" - mkdir steam-windows - ( - cd steam-windows - unzip ../../windows.zip - # CI builds can be double-zipped - if compgen -G "*.zip" > /dev/null; then - unzip *.zip - rm *.zip - fi - # copy install scripts and create sentinel file - cp -r ../../source/CI/steam/scripts_windows scripts - touch disable_updater - ) - echo "::endgroup::" - - echo "::group::Extract macOS (x86)" - mkdir -p steam-macos/x86 - # CI builds are zipped - if [[ -f ../mac_x86.dmg.zip ]]; then - unzip ../mac_x86.dmg.zip - else - mv ../mac_x86.dmg . - fi - - hdiutil attach -noverify -readonly -noautoopen -mountpoint /Volumes/x86 *.dmg - cp -R /Volumes/x86/OBS.app steam-macos/x86 - hdiutil unmount /Volumes/x86 - rm *.dmg - echo "::endgroup::" - - echo "::group::Extract and prepare macOS (arm64)" - mkdir -p steam-macos/arm64 - if [[ -f ../mac_arm64.dmg.zip ]]; then - unzip ../mac_arm64.dmg.zip - else - mv ../mac_arm64.dmg . - fi - - hdiutil attach -noverify -readonly -noautoopen -mountpoint /Volumes/arm64 *.dmg - cp -R /Volumes/arm64/OBS.app steam-macos/arm64 - hdiutil unmount /Volumes/arm64 - rm *.dmg - - cp ../source/CI/steam/scripts_macos/launch.sh steam-macos/launch.sh - echo "::endgroup::" - - - name: Setup steamcmd - if: steps.should-run.outputs.result == 'true' - uses: CyberAndrii/setup-steamcmd@b786e0da44db3d817e66fa3910a9560cb28c9323 - - - name: Generate Steam auth code - if: steps.should-run.outputs.result == 'true' - id: steam-totp - uses: CyberAndrii/steam-totp@c7f636bc64e77f1b901e0420b7890813141508ee - with: - shared_secret: ${{ secrets.STEAM_SHARED_SECRET }} - - - name: Upload to Steam - if: steps.should-run.outputs.result == 'true' - run: | - cd steam - echo "::group::Prepare Steam build script" - # The description in Steamworks for the build will be "github_-", e.g. "github_nightly-gaa73de952" - sed 's/@@DESC@@/${{ steps.build-info.outputs.branch }}-${{ steps.build-info.outputs.desc }}/;s/@@BRANCH@@/${{ steps.build-info.outputs.branch }}/' ../source/CI/steam/obs_build.vdf > build.vdf - echo "Generated file:" - cat build.vdf - echo "::endgroup::" - echo "::group::Upload to Steam" - steamcmd +login '${{ secrets.STEAM_USER }}' '${{ secrets.STEAM_PASSWORD }}' '${{ steps.steam-totp.outputs.code }}' +run_app_build "$(pwd)/build.vdf" +quit - echo "::endgroup::" - - - name: Generate Steam auth code (Playtest) - if: steps.should-run.outputs.result_playtest == 'true' - id: steam-totp-playtest - uses: CyberAndrii/steam-totp@c7f636bc64e77f1b901e0420b7890813141508ee - with: - shared_secret: ${{ secrets.STEAM_SHARED_SECRET }} - - - name: Upload to Steam (Playtest) - if: steps.should-run.outputs.result_playtest == 'true' - run: | - cd steam - echo "::group::Prepare Steam build script" - sed 's/@@DESC@@/${{ steps.build-info.outputs.branch }}-${{ steps.build-info.outputs.desc }}/;s/@@BRANCH@@/${{ env.STEAM_PLAYTEST_BRANCH }}/' ../source/CI/steam/obs_playtest_build.vdf > build_playtest.vdf - echo "Generated file:" - cat build_playtest.vdf - echo "::endgroup::" - echo "::group::Upload to Steam" - steamcmd +login '${{ secrets.STEAM_USER }}' '${{ secrets.STEAM_PASSWORD }}' '${{ steps.steam-totp-playtest.outputs.code }}' +run_app_build "$(pwd)/build_playtest.vdf" +quit - echo "::endgroup::" - - - name: Upload Steam build logs - if: steps.should-run.outputs.result == 'true' - uses: actions/upload-artifact@v3 - with: - name: steam-build-logs - path: ${{ github.workspace }}/steam/build/*.log diff --git a/CI/macos/appcast_convert.py b/CI/macos/appcast_convert.py deleted file mode 100644 index d47a55b08..000000000 --- a/CI/macos/appcast_convert.py +++ /dev/null @@ -1,96 +0,0 @@ -import os -from copy import deepcopy - -import xmltodict - - -DELTA_BASE_URL = "https://cdn-fastly.obsproject.com/downloads/sparkle_deltas" - - -def convert_appcast(filename): - print("Converting", filename) - in_path = os.path.join("output/appcasts", filename) - out_path = os.path.join("output/appcasts/stable", filename.replace("_v2", "")) - with open(in_path, "rb") as f: - xml_data = f.read() - if not xml_data: - return - - appcast = xmltodict.parse(xml_data, force_list=("item",)) - out_appcast = deepcopy(appcast) - - # Remove anything but stable channel items. - new_list = [] - for _item in appcast["rss"]["channel"]["item"]: - item = deepcopy(_item) - branch = item.pop("sparkle:channel", "stable") - if branch != "stable": - continue - # Remove delta information (incompatible with Sparkle 1.x) - item.pop("sparkle:deltas", None) - new_list.append(item) - - out_appcast["rss"]["channel"]["item"] = new_list - - with open(out_path, "wb") as f: - xmltodict.unparse(out_appcast, output=f, pretty=True) - - # Also create legacy appcast from x86 version. - if "x86" in filename: - out_path = os.path.join("output/appcasts/stable", "updates.xml") - with open(out_path, "wb") as f: - xmltodict.unparse(out_appcast, output=f, pretty=True) - - -def adjust_appcast(filename): - print("Adjusting", filename) - file_path = os.path.join("output/appcasts", filename) - with open(file_path, "rb") as f: - xml_data = f.read() - if not xml_data: - return - - arch = "arm64" if "arm64" in filename else "x86_64" - appcast = xmltodict.parse(xml_data, force_list=("item", "enclosure")) - - out_appcast = deepcopy(appcast) - out_appcast["rss"]["channel"]["title"] = "OBS Studio" - out_appcast["rss"]["channel"]["link"] = "https://obsproject.com/" - - new_list = [] - for _item in appcast["rss"]["channel"]["item"]: - item = deepcopy(_item) - # Fix changelog URL - # Sparkle doesn't allow us to specify the URL for a specific update, - # so we set the full release notes link instead and then rewrite the - # appcast. Yay. - if release_notes_link := item.pop("sparkle:fullReleaseNotesLink", None): - item["sparkle:releaseNotesLink"] = release_notes_link - - # If deltas exist, update their URLs to match server layout - # (generate_appcast doesn't allow this). - if deltas := item.get("sparkle:deltas", None): - for delta_item in deltas["enclosure"]: - delta_filename = delta_item["@url"].rpartition("/")[2] - delta_item["@url"] = f"{DELTA_BASE_URL}/{arch}/{delta_filename}" - - new_list.append(item) - - out_appcast["rss"]["channel"]["item"] = new_list - - with open(file_path, "wb") as f: - xmltodict.unparse(out_appcast, output=f, pretty=True) - - -if __name__ == "__main__": - for ac_file in os.listdir("output/appcasts"): - if ".xml" not in ac_file: - continue - if "v2" not in ac_file: - # generate_appcast may download legacy appcast files and update them as well. - # Those generated files are not backwards-compatible, so delete whatever v1 - # files it may have created and recreate them manually. - os.remove(os.path.join("output/appcasts", ac_file)) - continue - adjust_appcast(ac_file) - convert_appcast(ac_file) diff --git a/CI/macos/appcast_download.py b/CI/macos/appcast_download.py deleted file mode 100644 index 4bba55e56..000000000 --- a/CI/macos/appcast_download.py +++ /dev/null @@ -1,125 +0,0 @@ -import os -import sys -import plistlib -import glob -import subprocess -import argparse - -import requests -import xmltodict - - -def download_build(url): - print(f'Downloading build "{url}"...') - filename = url.rpartition("/")[2] - r = requests.get(url) - if r.status_code == 200: - with open(f"artifacts/{filename}", "wb") as f: - f.write(r.content) - else: - print(f"Build download failed, status code: {r.status_code}") - sys.exit(1) - - -def read_appcast(url): - print(f"Downloading feed {url} ...") - r = requests.get(url) - if r.status_code != 200: - print(f"Appcast download failed, status code: {r.status_code}") - sys.exit(1) - - filename = url.rpartition("/")[2] - with open(f"builds/{filename}", "wb") as f: - f.write(r.content) - - appcast = xmltodict.parse(r.content, force_list=("item",)) - - dl = 0 - for item in appcast["rss"]["channel"]["item"]: - channel = item.get("sparkle:channel", "stable") - if channel != target_branch: - continue - - if dl == max_old_vers: - break - download_build(item["enclosure"]["@url"]) - dl += 1 - - -def get_appcast_url(artifact_dir): - dmgs = glob.glob(artifact_dir + "/*.dmg") - if not dmgs: - raise ValueError("No artifacts!") - elif len(dmgs) > 1: - raise ValueError("Too many artifacts!") - - dmg = dmgs[0] - print(f"Mounting {dmg} ...") - out = subprocess.check_output( - [ - "hdiutil", - "attach", - "-readonly", - "-noverify", - "-noautoopen", - "-plist", - dmg, - ] - ) - d = plistlib.loads(out) - - mountpoint = "" - for item in d["system-entities"]: - if "mount-point" not in item: - continue - mountpoint = item["mount-point"] - break - - url = None - plist_files = glob.glob(mountpoint + "/*.app/Contents/Info.plist") - if plist_files: - plist_file = plist_files[0] - print(f"Reading plist {plist_file} ...") - plist = plistlib.load(open(plist_file, "rb")) - url = plist.get("SUFeedURL", None) - else: - print("No Plist file found!") - - print(f"Unmounting {mountpoint}") - subprocess.check_call(["hdiutil", "detach", mountpoint]) - return url - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "--artifacts-dir", - dest="artifacts", - action="store", - default="artifacts", - help="Folder containing artifact", - ) - parser.add_argument( - "--branch", - dest="branch", - action="store", - default="stable", - help="Channel/Branch", - ) - parser.add_argument( - "--max-old-versions", - dest="max_old_ver", - action="store", - type=int, - default=1, - help="Maximum old versions to download", - ) - args = parser.parse_args() - - target_branch = args.branch - max_old_vers = args.max_old_ver - url = get_appcast_url(args.artifacts) - if not url: - raise ValueError("Failed to get Sparkle URL from DMG!") - - read_appcast(url)