[
  {
    "path": ".github/CODEOWNERS",
    "content": "# https://help.github.com/en/articles/about-code-owners\n# These owners will be the default owners for everything in\n# the repo. Unless a later match takes precedence, they\n# will be requested for review when someone opens a PR.\n*       @wetransfer/ios-collect\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Mark stale issues and pull requests\n\non:\n  schedule:\n  - cron: \"0 0 * * *\"\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/stale@98ed4cb500039dbcccf4bd9bedada4d0187f2757 # v3\n      with:\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n        stale-issue-label: 'Stale'\n        stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity. Remove the Stale label or comment or this will be closed in 10 days.'\n        stale-pr-label: 'Stale'\n        stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity. Remove the Stale label or comment or this will be closed in 10 days.'\n        exempt-issue-labels: 'enhancement'\n        days-before-stale: 30\n        days-before-close: 10\n"
  },
  {
    "path": ".gitignore",
    "content": "junit-results.xml\n.build\nnode_modules\nbuild\n*.xcodeproj\nFastlane/report.xml\nFastlane/README.md\n.spm-build\n\n### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n"
  },
  {
    "path": "Bitrise/Scripts/configure_environment_for_pr.sh",
    "content": "app=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" &>/dev/null && pwd)\"\nsource $app/setup_environment.sh\n\nPR_LABELS=$(\n  curl \\\n    -s \\\n    -u ${GITBUDDY_ACCESS_TOKEN} \\\n    -H \"${HEADER}\" \\\n    ${ISSUE_URL} \\\n    | jq -r '.labels[] | .name'\n)\n\necho \"PR labels are: ${PR_LABELS}\"\n\nif [[ \"$PR_LABELS\" == *\"ci-testing\"* ]]; then\n  echo \"This PR is configured for testing CI.\"\n  envman add --key CI_TESTING --value \"true\"\nelse\n  echo \"This PR is not configured for testing CI and runs as normal.\"\n  envman add --key CI_TESTING --value \"false\"\nfi\n\nif [[ \"$PR_LABELS\" == *\"create-simulator-build\"* ]]; then\n  echo \"This PR is going to deliver a Simulator Build inside the Danger message.\"\n  envman add --key CREATE_SIMULATOR_BUILD --value \"true\"\nelse\n  echo \"This PR is not going to deliver a Simulator Build inside the Danger message.\"\n  envman add --key CREATE_SIMULATOR_BUILD --value \"false\"\nfi\n\nCHANGED_FILES=$(\n  curl -s -u ${GITBUDDY_ACCESS_TOKEN} -H \"${HEADER}\" ${PULL_FILES_URL} | jq -r '.[].filename'\n)\n\nif echo \"$CHANGED_FILES\" | grep -q \"\\.swift$\"; then\n  echo \"The PR contains '.swift' files, let's test and run Danger\"\n  envman add --key SKIP_TESTS --value \"false\"\nelse\n  echo \"The PR does not contain '.swift' files, let's skip tests and Danger\"\n  envman add --key SKIP_TESTS --value \"true\"\nfi"
  },
  {
    "path": "Bitrise/Scripts/pr_assignments.sh",
    "content": "app=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" &>/dev/null && pwd)\"\nsource $app/setup_environment.sh\n\nPR_ASSIGNESS=$(\n  curl \\\n    -s \\\n    -u ${GITBUDDY_ACCESS_TOKEN} \\\n    -H ${HEADER} \\\n    ${ISSUE_URL} \\\n    | jq -r '.assignees[] | .login'\n)\n\nif [ -z ${PR_ASSIGNESS} ]; then\n  echo \"PR assignees is empty. Continuing...\"\nelse\n  echo \"PR assignees is not empty: ${PR_ASSIGNESS}. Nothing to do here...\"\n  exit 0\nfi\n\nPR_AUTHOR=$(\n  curl \\\n    -s \\\n    -u ${GITBUDDY_ACCESS_TOKEN} \\\n    -H ${HEADER} \\\n    ${ISSUE_URL} \\\n    | jq -r .user.login\n)\n\ncurl \\\n  -s \\\n  -u ${GITBUDDY_ACCESS_TOKEN} \\\n  -X POST \\\n  -H ${HEADER} \\\n  ${ISSUE_URL}/assignees \\\n  -d '{\"assignees\":[\"'${PR_AUTHOR}'\"]}' \\\n  &> /dev/null"
  },
  {
    "path": "Bitrise/Scripts/setup_environment.sh",
    "content": "# We can have both HTTPS and SSH urls.\n# HTTPS: https://github.com/WeTransfer/WeTransfer-iOS-CI.git\n# SSH: git@github.com:WeTransfer/Mule.git\n#\n# Given the difference in URLs, the shared component is the last one (e.g. Mule.git).\n# It's first needed to reverse the URL, split it by `.` and get the second part of it (the -f2 in `cut`),\n# enabling to equate the URL split:\n#   - URL: https://github.com/WeTransfer/WeTransfer-iOS-CI.git\n#   - Reversed: tig.IC-SOi-refsnarTeW/refsnarTeW/moc.buhtig//:sptth\n#   - Sectioned: [1: tig].[2: IC-SOi-refsnarTeW/refsnarTeW/moc].[3: buhtig//:sptth]\n# The previous split is the input to the next one, this time by `/`, and then the first element is used (the -f1 in `cut`).\n#   - Input: IC-SOi-refsnarTeW/refsnarTeW/moc\n#   - Sectioned: [1: IC-SOi-refsnarTeW]/[2: refsnarTeW]/[3: moc]\n# And lastly, we revert the result one more time, as the result will be reversed otherwise.\nREPOSITORY_NAME=$(echo ${GIT_REPOSITORY_URL} | rev | cut -d '.' -f2 | cut -d '/' -f1 | rev)\nISSUE_URL=\"https://api.github.com/repos/${BITRISEIO_GIT_REPOSITORY_OWNER}/${REPOSITORY_NAME}/issues/${BITRISE_PULL_REQUEST}\"\nHEADER=\"Accept: application/vnd.github.v3+json\"\nPULL_FILES_URL=\"https://api.github.com/repos/${BITRISEIO_GIT_REPOSITORY_OWNER}/${REPOSITORY_NAME}/pulls/${BITRISE_PULL_REQUEST}/files\""
  },
  {
    "path": "Bitrise/tag_releasing_bitrise.yml",
    "content": "---\nformat_version: '8'\ndefault_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git\nproject_type: ios\ntrigger_map:\n- tag: \"*\"\n  workflow: wetransfer_tag_releasing\nworkflows:\n  wetransfer_tag_releasing:\n    steps:\n    - cache-pull: {}\n    - script:\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            set -ex\n\n            if [ ! -d \"Submodules/WeTransfer-iOS-CI\" ] ; then\n              # file does not exist - simply exit with success\n              exit 0\n            fi\n\n            # Get the latest master branch for WeTransfer-iOS-CI if the submodule exists\n            git submodule update --remote --no-fetch Submodules/WeTransfer-iOS-CI\n        title: Update WeTransfer-iOS-CI submodule\n    - bitrise-step-install-bundler: {}\n    - script:\n        inputs:\n        - content: |-\n            envman add --key BREW_MINT --value \"$(brew --cellar)/mint\"\n            envman add --key BREW_OPT_MINT --value \"/usr/local/opt/mint\"\n\n            brew install mint\n            brew link mint\n            mint install WeTransfer/GitBuddy\n        title: Brew install\n    - script:\n        title: Set up signed commits\n        inputs:\n        - content: |-\n            #!/bin/bash\n            echo -e $GPG_KEY | gpg --import\n            \n            # Let'em know who is pushing commits to our branches!\n            git config --global user.name \"wetransferplatform\"\n            git config --global user.email \"platform+github@wetransfer.com\"\n            git config --global user.signinkey \"$WETRANSFERPLATFORM_SIGNIN_KEY\"\n            git config --global commit.gpgSign true\n            git config --global tag.gpgSign true      \n    - script:\n        title: Run Fastlane\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            gem install cocoapods\n\n            # Use the environment FASTLANE_TAG_RELEASE_LANE if available. Otherwise, fallback to \"release_from_tag\"\n            lane=${FASTLANE_TAG_RELEASE_LANE:=release_from_tag}\n            bundle exec fastlane $lane\n    - script:\n        title: Clean up after failure\n        is_always_run: true\n        run_if: .IsBuildFailed\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n\n            bundle exec fastlane clean_up_release_from_tag\n    - cache-push:\n        run_if: true\n        inputs:\n        - is_debug_mode: 'true'\n        - cache_paths: |\n            $BITRISE_CACHE_DIR\n            $BREW_MINT\n            $BREW_OPT_MINT\n            .build\napp:\n  envs:\n  - opts:\n      is_expand: true\n      is_required: true\n    GPG_KEY: $WETRANSFERPLATFORM_GPG_KEY"
  },
  {
    "path": "Bitrise/testing_bitrise.yml",
    "content": "---\nformat_version: '8'\ndefault_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git\nproject_type: ios\ntrigger_map:\n- pull_request_source_branch: \"*\"\n  workflow: wetransfer_pr_testing\nworkflows:\n  pr_testing:\n    steps:\n    - script:\n        title: Assign PR author and configure CI Testing mode\n        inputs:\n        - content: |-\n            #!/bin/bash\n\n            if [ ! -d \"Submodules/WeTransfer-iOS-CI\" ] ; then\n                echo 'Running inside the submodule itself'\n\n                # Assign a PR owner if not existing.\n                ./Bitrise/Scripts/pr_assignments.sh\n\n                # Configure CI_TESTING environment variable.\n                ./Bitrise/Scripts/configure_environment_for_pr.sh\n            else\n                echo 'Running from another package using a submodule'\n\n                # Assign a PR owner if not existing.\n                ./Submodules/WeTransfer-iOS-CI/Bitrise/Scripts/pr_assignments.sh\n\n                # Configure CI_TESTING environment variable.\n                ./Submodules/WeTransfer-iOS-CI/Bitrise/Scripts/configure_environment_for_pr.sh\n            fi\n    - script:\n        run_if: '{{enveq \"CI_TESTING\" \"false\"}}'\n        title: Skip running for Draft PRs\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            if [ \"$GITHUB_PR_IS_DRAFT\" = true ] ; then\n                echo 'Cancelling CI run since the PR is in draft'\n                exit 1\n            fi\n    - restore-cache@1:          \n        run_if: '{{enveq \"SKIP_TESTS\" \"false\" | and .IsCI }}'\n        inputs:          \n        - key: spm-cache-{{ checksum \"Package.resolved\" \"*.xcodeproj/**/Package.resolved\" \"WeTransferPRLinter/Package.resolved\" }}\n    - script:\n        run_if: '{{enveq \"CI_TESTING\" \"false\" | and .IsCI }}'\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            set -ex\n\n            if [ ! -d \"Submodules/WeTransfer-iOS-CI\" ] ; then\n              echo 'file does not exist - simply exit with success'\n              exit 0\n            fi\n\n            # Update WeTransfer-iOS-CI if the submodule exists\n            # (pulls the submodule at the commit pointed by the parent repo!)\n            git submodule update Submodules/WeTransfer-iOS-CI\n        title: Update WeTransfer-iOS-CI submodule\n    - script:\n        run_if: .IsCI\n        title: Force SSH\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            # As we work with submodules, make sure we use SSH for this config so we can push our PR later on.\n            # See for more info: https://discuss.bitrise.io/t/git-force-to-use-ssh-url-instead-of-https-for-github-com/4384\n            # git config --global url.\"git@github.com:\".insteadOf \"https://github.com/\"\n            for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts\n    - script:\n        run_if: '{{enveq \"SKIP_TESTS\" \"false\"}}'\n        no_output_timeout: 600 # 10 minutes\n        title: Run Fastlane\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            # Use the environment FASTLANE_LANE if available. Otherwise, fallback to \"test\"\n            lane=${FASTLANE_LANE:=test}\n            bundle exec fastlane $lane\n    - deploy-to-bitrise-io@2:\n        run_if: '{{enveq \"CREATE_SIMULATOR_BUILD\" \"true\"}}'\n        title: Deploy Simulator Build to Bitrise\n        is_skippable: true\n        inputs:\n        - notify_user_groups: none\n        - is_enable_public_page: 'false'\n        - is_compress: 'true'\n        - debug_mode: 'true'\n        - deploy_path: build/derived_data/Build/Products/Debug-iphonesimulator/${XCODE_TARGET}.app/  \n    - deploy-to-bitrise-io@2:\n        run_if: '{{enveq \"SKIP_TESTS\" \"false\"}}'\n        is_skippable: true\n        inputs:\n        - notify_user_groups: none\n        - is_enable_public_page: 'false'\n        - is_compress: 'true'\n        - debug_mode: 'true'\n        - deploy_path: build/reports/\n    - deploy-to-bitrise-io@2:\n        run_if: '{{enveq \"SKIP_TESTS\" \"false\"}}'\n        title: Deploy pipeline test reports\n        inputs:\n        - pipeline_intermediate_files: |-\n            build/reports/:BITRISE_TEST_REPORTS_${FASTLANE_LANE:=DEFAULT}\n    - save-cache@1:\n        is_always_run: true\n        inputs:\n        - key: spm-cache-{{ checksum \"Package.resolved\" \"*.xcodeproj/**/Package.resolved\" \"WeTransferPRLinter/Package.resolved\" }}\n        - paths: .spm-build\n        - is_key_unique: 'true'\n\n  wetransfer_pr_testing:\n    before_run:\n    - pr_testing\n    after_run:\n    - workflow_danger\n    \n  workflow_danger:\n    steps:\n    - script:\n        title: Set up Danger Caching\n        is_always_run: true\n        inputs:\n        - content: |-\n            if [ \"$BITRISEIO_GIT_REPOSITORY_SLUG\" == \"WeTransfer-iOS-CI\" ]; then\n                envman add --key DANGER_CHECKSUM_PATH --value \"Package.resolved\"\n                envman add --key DANGER_BUILD_DIRECTORY --value \".build\"\n            else\n                envman add --key DANGER_CHECKSUM_PATH --value \"Submodules/WeTransfer-iOS-CI/Package.resolved\"\n                envman add --key DANGER_BUILD_DIRECTORY --value \"Submodules/WeTransfer-iOS-CI/.build\"\n            fi\n    - restore-cache@1:\n        is_always_run: true      \n        inputs:          \n        - key: danger-build-cache-{{ checksum \"$DANGER_CHECKSUM_PATH\" }}\n    - script:\n        title: Run Danger\n        is_always_run: true\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            # debug log\n            set -x\n\n            # By changing directory into WeTransfer-iOS-CI, we can run Danger from there.\n            # Caching is still done per repository which is why we add the build and cache paths.\n            # --cwd makes sure to run Danger in the current repository directory\n            # The Dangerfile.swift from within the WeTransfer-iOS-CI repo is used.\n            #\n            # This all allows us to not define Danger dependencies in every repo. It also optimises reusing the SPM cache on CI systems.\n\n            if [ \"$BITRISEIO_GIT_REPOSITORY_SLUG\" == \"WeTransfer-iOS-CI\" ]; then\n                chmod +x danger-swift\n                ./danger-swift ci\n            else\n                cd Submodules/WeTransfer-iOS-CI\n                ./danger-swift ci --cwd ../../\n            fi\n    - save-cache@1:\n        is_always_run: true\n        inputs:\n        - key: danger-build-cache-{{ checksum \"$DANGER_CHECKSUM_PATH\" }}\n        - paths: \"$DANGER_BUILD_DIRECTORY\"\n        - is_key_unique: 'true'\n"
  },
  {
    "path": "BuildTools/.swiftformat",
    "content": "--indent 4\n--patternlet inline\n--disable unusedArguments,hoistAwait,hoistTry,conditionalAssignment,wrapMultilineStatementBraces,braces,redundantreturn \n--header strip\n--commas inline\n--selfrequired waitFor,expectation\n--swiftversion 5.9\n--exclude ../../ios-libs-monorepo"
  },
  {
    "path": "BuildTools/.swiftlint.yml",
    "content": "disabled_rules: # Rule identifiers to exclude from running\n  - identifier_name\n  - force_unwrapping\n  - force_cast\n  - force_try\n  - orphaned_doc_comment\n  - opening_brace\n  - switch_case_alignment\n  - trailing_comma\n  - todo\n  - nesting\n  - explicit_init\nopt_in_rules:\n  - block_based_kvo\n  - class_delegate_protocol\n  - contains_over_first_not_nil\n  - convenience_type\n  - empty_count\n  - empty_string\n  - fallthrough\n  - fatal_error_message\n  - first_where\n  - identical_operands\n  - joined_default_parameter\n  - object_literal\n  - operator_usage_whitespace\n  - overridden_super_call\n  - private_outlet\n  - prohibited_super_call\n  - redundant_nil_coalescing\n  - switch_case_on_newline\n  - toggle_bool\n  - type_contents_order\n  - multiline_function_chains\n  - accessibility_trait_for_button\n  - accessibility_label_for_image\n  - shorthand_optional_binding\n  - contains_over_filter_count\n  - contains_over_filter_is_empty\n  - contains_over_range_nil_comparison\n  - discouraged_assert\n  - empty_xctest_method\n  - flatmap_over_map_reduce\n  - last_where\n  - let_var_whitespace\n  - reduce_into\n  - redundant_type_annotation\n  - self_binding\n  - sorted_first_last\n  - sorted_imports\n  - unneeded_parentheses_in_closure_argument\n  - untyped_error_in_catch\n  - xct_specific_matcher\n  - private_swiftui_state\n  - unneeded_override\n\nanalyzer_rules:\n  - capture_variable\n  - unused_import\n\nexplicit_init:\n  severity: warning\n  include_bare_init: true\nsyntactic_sugar: error\nunused_closure_parameter: error\nunused_optional_binding:\n  severity: error\nline_length:\n  warning: 140\n  error: 160\nfile_length:\n  warning: 660\n  error: 1320\nfunction_body_length:\n  warning: 150\n  error: 200\ntype_body_length:\n  warning: 400\n  error: 500\ntype_name:\n  max_length: # warning and error\n    warning: 50\n    error: 60\nobject_literal:\n  color_literal: false\ntype_contents_order:\n  order:\n    - case\n    - subtype\n    - associated_type\n    - type_alias\n    - ib_outlet\n    - ib_inspectable\n    - type_property\n    - [deinitializer, initializer, instance_property]\n    - view_life_cycle_method\n    - [subscript, other_method, ib_action]\n    - type_method\n\ncustom_rules:\n  overridden_only_calls_super:\n    included: \".*.swift\"\n    regex: 'override func [^\\n]*\\{\\n(\\s*super\\.[^\\n]*\\n(\\s*\\/\\/[^\\n]*\\n)*|(\\s*\\/\\/[^\\n]*\\n)+)\\s*\\}'\n    message: \"Overridden methods which only call super can be removed\"\n\n  final_class:\n    included: \".*.swift\"\n    regex: \"^class|^private class|^public class|^internal class\"\n    message: \"Consider using final for this class, or use a struct\"\n\n  unowned_self:\n    included: \".*.swift\"\n    regex: \"unowned self\"\n    message: \"It is safer to use weak instead of unowned\"\n\nexcluded:\n  # We add ../../../ to work with the way Danger is expanding paths based on the config file.\n  - ${SRCROOT}/Carthage\n  - ${SRCROOT}/.build\n  - ${SRCROOT}/.spm-build\n  - ${SRCROOT}/Playgrounds\n  - ${SRCROOT}/Submodules\n  - ${SRCROOT}/SourcePackages\n  - ${SRCROOT}/*/SourcePackages\n  - ${SRCROOT}/*/*/SourcePackages\n  - ${SRCROOT}/*/*/*/SourcePackages\n  - ${SRCROOT}/Vendor\n  - ${SRCROOT}/Pods\n  - ${SRCROOT}/bundle\n  - ${SRCROOT}/scripts/genstrings.swift\n  - ${SRCROOT}/danger/DangerTests.swift\n  - ${SRCROOT}/*UITests\n  - ${SRCROOT}/.rbenv\n  - ${SRCROOT}/*/*/*/*/main.swift # App Store Connect SDK structure\n  - ${SRCROOT}/*/*/*/*/PackageJSON.swift\n"
  },
  {
    "path": "BuildTools/Mintfile",
    "content": "nicklockwood/SwiftFormat@0.52.4\nrealm/SwiftLint@0.53.0"
  },
  {
    "path": "BuildTools/swiftformat.sh",
    "content": "#!/bin/bash\n\nif [ -z \"$CI\" ]; then\n    export PATH=\"$PATH:/opt/homebrew/bin:/usr/local/bin\"\n\n    BASEDIR=$(dirname \"$0\")\n    MINT_FILE_PATH=$BASEDIR/Mintfile\n    SWIFT_FORMAT=SwiftFormat\n    SWIFT_FORMAT_VERSION=$(grep -F $SWIFT_FORMAT $MINT_FILE_PATH)\n\n    if ! xcrun --sdk macosx mint which -s $SWIFT_FORMAT_VERSION > /dev/null; then\n        xcrun --sdk macosx mint bootstrap -m $MINT_FILE_PATH\n    fi\n\n    xcrun --sdk macosx mint run -m $MINT_FILE_PATH $SWIFT_FORMAT --config \"$BASEDIR/.swiftformat\" .\nfi\n"
  },
  {
    "path": "BuildTools/swiftlint.sh",
    "content": "#!/bin/bash\n\nif [ -z \"$CI\" ]; then\n    export PATH=\"$PATH:/opt/homebrew/bin:/usr/local/bin\"\n\n    set -e\n\n    BASEDIR=$(dirname \"$0\") # Sets the folder to WeTransfer-iOS-CI/BuildTools/\n    MINT_FILE_PATH=$BASEDIR/Mintfile\n    SWIFT_LINT=SwiftLint\n    SWIFT_LINT_VERSION=$(grep -F $SWIFT_LINT $MINT_FILE_PATH)\n\n    if ! xcrun --sdk macosx mint which -s $SWIFT_LINT_VERSION > /dev/null; then\n      xcrun --sdk macosx mint bootstrap -m $MINT_FILE_PATH\n    fi\n\n    execution_directory=\"$(pwd)\"\n    count=0\n    export SRCROOT=\"$(pwd)\"\n\n    printf \"\\nExecuting SwiftLint from ${execution_directory}\\n\"\n\n    # Unstaged files\n    while read filename; do\n        export SCRIPT_INPUT_FILE_$count=\"${filename}\"\n        echo \"Found '${filename}'\"\n        count=$((count + 1))\n    done < <(git diff --relative --name-only $SRCROOT | grep \".swift$\")\n\n    # Staged files\n    while read filename; do\n        export SCRIPT_INPUT_FILE_$count=\"${filename}\"\n        echo \"Found '${filename}'\"\n        count=$((count + 1))\n    done < <(git diff --relative --diff-filter=d --cached --name-only $SRCROOT | grep \".swift$\")\n\n    # Committed files\n    while read filename; do\n        export SCRIPT_INPUT_FILE_$count=\"${filename}\"\n        echo \"Found '${filename}'\"\n        count=$((count + 1))\n    done < <(git diff develop... --relative --diff-filter=d --name-only $SRCROOT | grep \".swift$\")\n\n    export SCRIPT_INPUT_FILE_COUNT=$count\n\n    if (( $count > 0 )); then\n        echo \"Found ${count} lintable files! Linting...\"\n        xcrun --sdk macosx mint run -m $MINT_FILE_PATH $SWIFT_LINT lint --use-script-input-files --config \"$BASEDIR/.swiftlint.yml\" --force-exclude || true;\n    else\n        echo \"No files to lint, the number of files found is $count\"\n        exit 0\n    fi\nfi\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mobile@wetransfer.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "Changelog.md",
    "content": "### 3.2.0\n- Disable weak delegate rule in test target ([#64](https://github.com/WeTransfer/WeTransfer-iOS-CI/pull/64)) via @kairadiagne\n- Merge release 3.1.0 into master ([#62](https://github.com/WeTransfer/WeTransfer-iOS-CI/pull/62)) via @WeTransferBot\n\n### 3.1.0\n- Only update the CI submodule remotely ([#57](https://github.com/WeTransfer/WeTransfer-iOS-CI/pull/57)) via @AvdLee\n- Merge release 3.0.0 into master ([#56](https://github.com/WeTransfer/WeTransfer-iOS-CI/pull/56))\n\n### 3.0.0\n\n- Tag Releasing: automated open-source releases ([#55](https://github.com/WeTransfer/WeTransfer-iOS-CI/pull/55)) via @AvdLee\n- Use the new build system for Scan ([#53](https://github.com/WeTransfer/WeTransfer-iOS-CI/pull/53)) via @AvdLee\n\n### 1.0\n- First public release! 🎉\n- Added SwiftLint for source code and test code\n- Added a shared Dangerfile\n- Added a runscript to use with CI tools\n- Added a fastlane lane to quickly integrate in other projects\n"
  },
  {
    "path": "DangerFakeSources/DangerFakeSource.swift",
    "content": "/// Is used for the Package.swift in implementing projects to have a fake Swift source file.\n/// E.g:\n/// .target(name: \"DangerDependencies\", dependencies: [\"Danger\", \"WeTransferPRLinter\"], path: \"Submodules/WeTransfer-iOS-CI/Danger-Swift\", sources: [\"DangerFakeSource.swift\"]),\n"
  },
  {
    "path": "Dangerfile.swift",
    "content": "import Danger\nimport WeTransferPRLinter\n\nWeTransferPRLinter.lint(swiftLintConfigsFolderPath: \"BuildTools\")\n"
  },
  {
    "path": "Fastlane/Fastfile",
    "content": "# rubocop:disable Layout/LineLength\n\nimport \"#{File.dirname(__FILE__)}/shared_lanes.rb\"\nimport \"#{File.dirname(__FILE__)}/testing_lanes.rb\"\n\ndesc 'Tests the WeTransferPRLinter Swift Package'\nlane :test_pr_linter do\n  test_package(\n        package_name: 'WeTransferPRLinter',\n        package_path: 'WeTransferPRLinter/',\n        disable_automatic_package_resolution: false,\n        disable_concurrent_testing: false,\n        destination: 'platform=macOS')\nend"
  },
  {
    "path": "Fastlane/deployment_lanes.rb",
    "content": "# rubocop:disable Layout/LineLength\n\nrequire 'spaceship'\nrequire 'uri'\nrequire 'json'\n\ndesc 'Creates a new release candidate'\ndesc ''\ndesc '- Creates a new TestFlight build including the unreleased changelog'\ndesc '- Creates a Github Draft Release including the unreleased changelog'\ndesc ''\ndesc '#### Options'\ndesc 'It is recommended to manage these options through a .env file.'\ndesc ' * **`app_identifier`**: The bundle identifier of the main app. (`APP_IDENTIFIER`)'\ndesc ' * **`app_identifiers`**: A comma separated string containing all bundle identifiers, e.g. app + extensions. (APP_IDENTIFIERS)'\ndesc ' * **`xcodeproj`**: The path to the Xcode project file. (`XCODEPROJ`)'\ndesc ' * **`target`**: The target to build. (`XCODE_TARGET`)'\ndesc \" * **`scheme`**: The project's scheme. (`XCODE_SCHEME`)\"\ndesc ' * **`xcconfig`**: A (optional) xcconfig file to use to build the app. (`BETA_XCCONFIG`)'\ndesc ' * **`team_id`**: The ID of your App Store Connect team. (`FASTLANE_ITC_TEAM_ID`)'\ndesc ' * **`contact_email`**: The contact email for beta review. (`BETA_CONTACT_EMAIL`)'\ndesc ' * **`contact_first_name`**: The first name of the contact for beta review. (`BETA_CONTACT_FIRST_NAME`)'\ndesc ' * **`contact_last_name`**: The last name of the contact for beta review. (`BETA_CONTACT_LAST_NAME`)'\ndesc ' * **`contact_phone`**: The phone number of the contact for beta review. (`BETA_CONTACT_PHONE`)'\ndesc ' * **`demo_account_name`**: The name of the demo account for beta review. (`BETA_DEMO_ACCOUNT_NAME`)'\ndesc ' * **`demo_account_password`**: The passwords for the demo account for beta review. (`BETA_DEMO_ACCOUNT_PASSWORD`)'\ndesc ' * **`groups`**: A list of TestFlight groups that should get access to the beta build. (`TESTFLIGHT_GROUPS_BETA`)'\nlane :beta do |options|\n  xcodeproj = options[:xcodeproj] || ENV['XCODEPROJ']\n  target = options[:target] || ENV['XCODE_TARGET']\n  scheme = options[:scheme] || ENV['XCODE_SCHEME']\n\n  if is_changed_since_last_tag == false\n    tag_name = last_git_tag\n    cancel_message = 'A new Beta build has been cancelled as there are no changes since the last available tag.'\n    UI.important cancel_message\n    slack_message(cancel_message, type: :info, tag_name: tag_name, default_payloads: [])\n    next\n  end\n\n  if is_running_on_CI(options)\n    clear_derived_data\n  end\n\n  build_number = update_build_number(xcodeproj: xcodeproj, target: target)\n  tag_name = create_tag_name(xcodeproj: xcodeproj, target: target)\n\n  UI.message \"Proceeding to build app version: #{tag_name}\"\n\n  if is_running_on_CI(options)\n    certs(app_identifier: options[:app_identifiers] || ENV['APP_IDENTIFIERS'])\n    prepare_for_ci\n  end\n\n  # Set timeout to prevent xcodebuild -list -project to take to much retries.\n  ENV['FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT'] = '120'\n  ENV['FASTLANE_XCODE_LIST_TIMEOUT'] = '120'\n\n  gym(\n    scheme: scheme,\n    configuration: 'Release',\n    xcconfig: options[:xcconfig] || ENV['BETA_XCCONFIG'],\n    cloned_source_packages_path: 'SourcePackages'\n  )\n\n  # Refresh key as it's only valid for 20 minutes and gym can take a long time.\n  authenticate(use_app_manager_role: true)\n\n  # Get the name of the current git branch.\n  branch_name = options[:branch] || ENV['BITRISE_GIT_BRANCH']\n  if branch_name.nil? || branch_name.empty?\n    branch_name = git_branch\n  end\n\n  # Create a new GitHub release\n  last_non_candidate_tag = latest_github_release_tag\n  release_title = \"#{tag_name} - Beta\"\n  release_output = sh(\"mint run --silent gitbuddy release -l #{last_non_candidate_tag} -b #{branch_name} --skip-comments --json --use-github-release-notes --use-pre-release --target-commitish #{branch_name} --tag-name #{tag_name} --release-title '#{release_title}'\")\n  release_json = JSON.parse(release_output)\n\n  release_url = release_json['url']\n  changelog = release_json['changelog']\n  stripped_changelog = strip_changelog(input: changelog)\n  truncated_changelog = truncate(stripped_changelog, 3900) # 4000 characters is the maximum allowed by Apple\n\n  UI.message \"Created release with URL: #{release_url}\"\n\n  begin\n    testflight(\n      beta_app_review_info: {\n        contact_email: options[:contact_email] || ENV['BETA_CONTACT_EMAIL'],\n        contact_first_name: options[:contact_first_name] || ENV['BETA_CONTACT_FIRST_NAME'],\n        contact_last_name: options[:contact_last_name] || ENV['BETA_CONTACT_LAST_NAME'],\n        contact_phone: options[:contact_phone] || ENV['BETA_CONTACT_PHONE'],\n        demo_account_name: options[:demo_account_name] || ENV['BETA_DEMO_ACCOUNT_NAME'],\n        demo_account_password: options[:demo_account_password] || ENV['BETA_DEMO_ACCOUNT_PASSWORD']\n      },\n      groups: options[:groups] || ENV['TESTFLIGHT_GROUPS_BETA'],\n      changelog: truncated_changelog,\n      team_id: options[:team_id] || ENV['FASTLANE_ITC_TEAM_ID']\n    )\n  rescue StandardError => e\n    raise e unless e.message.include?('Another build is in review')\n\n    UI.important \"TestFlight delivery failed because a build is already in review, but continuing anyway!\"\n  end\n\n  success_message = 'A new Beta has been published.'\n  UI.success \"#{success_message} (#{tag_name})\"\n  slack_message(success_message, type: :release_build, tag_name: tag_name, release_url: release_url)\nend\n\ndesc 'Creates a new App Store Release'\ndesc ''\ndesc '- Fetches the latest Github Release'\ndesc '- Merges the related tag into main'\ndesc '- Updates the changelog, creates a PR to develop for this as well'\ndesc '- Uses the changelog and creates a new Github App Store Release'\ndesc '- Submits the build to App Store Connect and TestFlight'\ndesc ''\ndesc '#### Options'\ndesc 'It is recommended to manage these options through a .env file. '\ndesc ' * **`app_identifier`**: The bundle identifier of the main app. (`APP_IDENTIFIER`)'\ndesc ' * **`app_identifiers`**: A comma separated string containing all bundle identifiers, e.g. app + extensions. (APP_IDENTIFIERS)'\ndesc ' * **`xcodeproj`**: The path to the Xcode project file. (`XCODEPROJ`)'\ndesc ' * **`target`**: The target to build. (`XCODE_TARGET`)'\ndesc \" * **`scheme`**: The project's scheme. (`XCODE_SCHEME`)\"\ndesc ' * **`xcconfig`**: The xcconfig file to use to build the app, optional. (`RELEASE_XCCONFIG`)'\ndesc ' * **`team_id`**: The ID of your App Store Connect team. (`FASTLANE_ITC_TEAM_ID`)'\ndesc ' * **`contact_email`**: The contact email for beta review. (`BETA_CONTACT_EMAIL`)'\ndesc ' * **`contact_first_name`**: The first name of the contact for beta review. (`BETA_CONTACT_FIRST_NAME`)'\ndesc ' * **`contact_last_name`**: The last name of the contact for beta review. (`BETA_CONTACT_LAST_NAME`)'\ndesc ' * **`contact_phone`**: The phone number of the contact for beta review. (`BETA_CONTACT_PHONE`)'\ndesc ' * **`demo_account_name`**: The name of the demo account for beta review. (`BETA_DEMO_ACCOUNT_NAME`)'\ndesc ' * **`demo_account_password`**: The passwords for the demo account for beta review. (`BETA_DEMO_ACCOUNT_PASSWORD`)'\ndesc ' * **`groups`**: A list of TestFlight groups that should get access to the beta build. (`TESTFLIGHT_GROUPS_RELEASE`)'\ndesc ' * **`hotfix`**: Whether the build is a hotfix release.'\ndesc ''\nlane :release do |options|\n  # Get the latest released tag, merge it into main and push it to remote.\n  xcodeproj = options[:xcodeproj] || ENV['XCODEPROJ']\n  target = options[:target] || ENV['XCODE_TARGET']\n  scheme = options[:scheme] || ENV['XCODE_SCHEME']\n\n  version_number = get_version_number(xcodeproj: xcodeproj, target: target)\n  latest_release_tag = latest_github_release\n  is_hotfix = options[:hotfix] || false\n\n  begin\n    unless is_hotfix\n      ensure_release_is_needed(\n        version_number: version_number,\n        tag_name: latest_release_tag,\n        app_identifier: options[:app_identifier] || ENV['APP_IDENTIFIER']\n      )\n    end\n\n    sh \"git fetch --tags origin #{ENV['BITRISE_GIT_BRANCH']} --no-recurse-submodules\"\n\n    branch_name = is_hotfix ? \"hotfix/#{latest_release_tag}\" : \"release/#{latest_release_tag}\"\n\n    unless is_hotfix\n      sh \"git checkout #{latest_release_tag} -b #{branch_name}\"\n    else\n      sh \"git branch #{branch_name} origin/main\"\n      sh \"git checkout #{branch_name}\"\n    end\n\n    # Update any new submodules\n    sh 'git submodule sync && git submodule update --init --recursive && git submodule update --remote --no-fetch ../Submodules/WeTransfer-iOS-CI'\n\n    update_build_number(xcodeproj: xcodeproj, target: target)\n    last_non_candidate_tag = latest_github_release_tag\n\n    # Create a new Github Release, which also merges the Changelog.md\n    tag_name = create_tag_name(xcodeproj: xcodeproj, target: target)\n    release_title = is_hotfix ? \"#{tag_name} - Release (hotfix)\" : \"#{tag_name} - Release\"\n\n    # Push the changes to our release branch so we can create a tag from it\n    sh 'git commit -a -m \"Created a new release\"'\n    sh \"git push origin #{branch_name}\"\n\n    release_latest_tag = is_hotfix ? latest_release_tag : last_non_candidate_tag\n    release_base_branch = is_hotfix ? 'main' : 'develop'\n    target_commitish = branch_name\n    release_output = sh(\"mint run --silent gitbuddy release --skip-comments --use-github-release-notes -l #{release_latest_tag} -b #{release_base_branch} -c '../Changelog.md' --changelogToTag #{latest_release_tag} --target-commitish #{target_commitish} --tag-name #{tag_name} --release-title '#{release_title}' --json\")\n    release_json = JSON.parse(release_output)\n\n    release_url = release_json['url']\n    changelog = release_json['changelog']\n    stripped_changelog = strip_changelog(input: changelog)\n\n    UI.message \"Created release with URL: #{release_url}\"\n\n    # Push the updated changelog.\n    sh 'git commit -a -m \"Created a new release\"'\n    sh \"git push origin #{branch_name}\"\n\n    repo = git_repository_name\n\n    # Create a pull request for main to include the updated Changelog.md\n    create_pull_request(\n      api_token: ENV['DANGER_GITHUB_API_TOKEN'],\n      repo: repo,\n      title: \"Merge release #{tag_name} into main\",\n      head: branch_name,\n      base: 'main', # The branch to merge the changes into.\n      body: \"Containing all the changes for our latest release: [#{tag_name}](#{release_url}).\"\n    )\n\n    # Create a pull request for develop to include the updated Changelog.md\n    create_pull_request(\n      api_token: ENV['DANGER_GITHUB_API_TOKEN'],\n      repo: repo,\n      title: \"Update Changelog in develop for latest release: #{tag_name}\",\n      head: branch_name,\n      base: 'develop', # The branch to merge the changes into.\n      body: \"The changelog has been updated containing the changes from our latest release: [#{tag_name}](#{release_url}).\"\n    )\n\n    # Create and submit the actual build.\n    clear_derived_data\n\n    if is_running_on_CI(options)\n      certs(app_identifier: options[:app_identifiers] || ENV['APP_IDENTIFIERS'])\n      prepare_for_ci\n    end\n\n    # Set timeout to prevent xcodebuild -list -project to take to much retries.\n    ENV['FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT'] = '120'\n    ENV['FASTLANE_XCODE_LIST_TIMEOUT'] = '120'\n    ENV['FASTLANE_XCODEBUILD_SETTINGS_RETRIES'] = '6'\n\n    gym(\n      scheme: scheme,\n      configuration: 'Release',\n      xcconfig: options[:xcconfig] || ENV['RELEASE_XCCONFIG'],\n      cloned_source_packages_path: 'SourcePackages'\n    )\n\n    # Refresh key as it's only valid for 20 minutes and TestFlight can take a long time.\n    authenticate(use_app_manager_role: true)\n\n    stripped_changelog.prepend(\"This build has been submitted to the App Store.\\n\\n\")\n    truncated_changelog = truncate(stripped_changelog, 3900) # 4000 characters is the maximum allowed by Apple\n\n    testflight_groups = options[:groups] || ENV['TESTFLIGHT_GROUPS_RELEASE']\n\n    UI.message \"Creating a TestFlight build which will be available to these groups: #{testflight_groups}\"\n\n    testflight(\n      beta_app_review_info: {\n        contact_email: options[:contact_email] || ENV['BETA_CONTACT_EMAIL'],\n        contact_first_name: options[:contact_first_name] || ENV['BETA_CONTACT_FIRST_NAME'],\n        contact_last_name: options[:contact_last_name] || ENV['BETA_CONTACT_LAST_NAME'],\n        contact_phone: options[:contact_phone] || ENV['BETA_CONTACT_PHONE'],\n        demo_account_name: options[:demo_account_name] || ENV['BETA_DEMO_ACCOUNT_NAME'],\n        demo_account_password: options[:demo_account_password] || ENV['BETA_DEMO_ACCOUNT_PASSWORD']\n      },\n      skip_waiting_for_build_processing: false,\n      skip_submission: false, # Ensure distributing the release build to TestFlight groups.\n      groups: testflight_groups,\n      changelog: truncated_changelog,\n      team_id: options[:team_id] || ENV['FASTLANE_ITC_TEAM_ID'],\n      verbose: true\n    )\n\n    # Refresh key as it's only valid for 20 minutes and TestFlight can take a long time.\n    authenticate(use_app_manager_role: true)\n\n    # Use the latest TestFlight build and submit it for review.\n    deliver(\n      build_number: get_build_number(xcodeproj: xcodeproj).to_s,\n      submit_for_review: true,\n      team_id: options[:team_id] || ENV['FASTLANE_ITC_TEAM_ID'],\n      force: true, # Skip HTMl report verification\n      skip_binary_upload: true, # Not needed as we use the TestFlight build.\n      phased_release: true,\n      automatic_release: false,\n      precheck_include_in_app_purchases: false,\n\n      # Screenshots should be manually updated using `fastlane deliver_screenshots`.\n      # Updating screenshots during the release phase risks unexpected issues and could delay our\n      # release train. Therefore, we want to update screenshots explicitly to capture issues early on.\n      skip_screenshots: true, \n      submission_information: {\n        add_id_info_uses_idfa: false\n      }\n    )\n\n    # Delete 10 pre-releases found before the release we just created.\n    # This is temporarily set to 10 to test out. We can eventually increase this number slowly\n    # so we will eventually clean up all pre-releases.\n    sh \"mint run gitbuddy tagDeletion -l 10 --prerelease-only --verbose\"\n\n    # Currently doesn't work because as you can't download dsyms with an API key\n    # upload_dsyms\n\n    release_type = is_hotfix ? 'Release (hotfix)' : 'Release'\n    success_message = \"A new #{release_type} has been submitted to the App Store.\"\n    UI.success \"#{success_message} (#{tag_name})\"\n    slack_message(success_message, type: :submitted, tag_name: tag_name, release_url: release_url)\n\n  rescue StandardError => exception\n    UI.error exception\n    handle_error(:release, exception)\n  end\nend\n\ndesc 'Creates a hotfix using the release lane. Should always be called on the main branch.'\nlane :hotfix do\n  release(hotfix: true)\nend\n\ndesc 'Create a build for running tests on browser stack'\nlane :appium_build do |options|\n  scheme = options[:scheme] || ENV['XCODE_SCHEME']\n  clear_derived_data\n  # Set timeout to prevent xcodebuild -list -project to take to much retries.\n  ENV['FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT'] = '120'\n  ENV['FASTLANE_XCODE_LIST_TIMEOUT'] = '120'\n\n  install_certificates(options)\n\n  gym(\n    scheme: scheme,\n    configuration: 'Debug',\n    export_method: 'development',\n    xcconfig: options[:xcconfig] || ENV['BETA_XCCONFIG'],\n    cloned_source_packages_path: '.build'\n  )\n\n  UI.message \"IPA saved at #{ENV['IPA_OUTPUT_PATH']}\"\nend\n\ndesc 'install the certificates onto Bitrise so this can build for firebase test lab'\nlane :install_certificates do |options|\n  certs(app_identifier: options[:app_identifiers] || ENV['APP_IDENTIFIERS'], type: 'development') if is_running_on_CI(options)\nend\n\ndesc 'Generates a JWT token used for JWT authorization with the App Store Connect API.'\ndesc 'The JWT token is added to the shared lane context so that it is automatically loaded into actions that require it.'\ndesc ''\ndesc '#### Options'\ndesc ' * **`use_app_manager_role`**: Whether it should use the token with the App Manager Role or Developer Role. This is needed when you want to upload build metadata in addition to a build to TestFlight'\ndesc ''\ndesc 'This lane makes use of the following environment variables:'\ndesc ' - `JWT_ISSUER_ID`: The identifier of the issuer of the JWT token'\ndesc ' - `APP_MANAGER_KEY_ID`: The id of the JWT token used to authenticate with an App manager role'\ndesc ' - `DEVELOPER_KEY_ID`: The id of the JWT token used to authenticate with a developer role'\ndesc ' - `APP_MANAGER_KEY_PATH`: The path to the file containing the private key'\ndesc ' - `DEVELOPER_KEY_PATH`: The path to the file containing the private key'\ndesc ''\nlane :authenticate do |options|\n  use_app_manager_role = options[:use_app_manager_role] || false\n  key_id = use_app_manager_role ? ENV['APP_MANAGER_KEY_ID'] : ENV['DEVELOPER_KEY_ID']\n  key_filepath = use_app_manager_role ? ENV['APP_MANAGER_KEY_PATH'] : ENV['DEVELOPER_KEY_PATH']\n  issuer_id = ENV['JWT_ISSUER_ID']\n\n  UI.important \"Authenticating using #{use_app_manager_role ? 'App Manager Role' : 'Developer Role'}\"\n\n  app_store_connect_api_key(\n    key_id: key_id,\n    issuer_id: issuer_id,\n    key_filepath: key_filepath,\n    duration: 1200, # 90 minutes, matching Bitrise timeout limit.\n    in_house: false # optional but may be required if using match/sigh\n  )\nend\n\ndesc 'Returns true if there are new changes since the last available tag'\nprivate_lane :is_changed_since_last_tag do\n  sh \"git fetch --tags origin #{ENV['BITRISE_GIT_BRANCH']} --no-recurse-submodules\"\n  last_tag = last_git_tag\n  changes = sh \"git --no-pager diff --name-status #{last_tag} HEAD\"\n  UI.message \"Is local HEAD changed since last tag #{last_tag}: #{!changes.empty?}\"\n  is_changed = !changes.empty?\nend\n\ndesc 'Updates the build number of the project based on the commit count'\ndesc ''\ndesc '#### Options'\ndesc ' * **`xcodeproj`**: the path to the Xcode project to read the version number from'\ndesc ' * **`target`**: The target within the project to read the version number from'\ndesc ''\nprivate_lane :update_build_number do |options|\n  # Get the path to the Xcode project and the target to read the version number from.\n  xcodeproj = options[:xcodeproj]\n  target = options[:target]\n\n  # Compute a new build number based on the commit count.\n  build = sh 'git rev-list --all --count'\n  new_build_number = 200 + Integer(build)\n\n  # Fetch the build number of the most recent test flight build, to make sure\n  # that the new build number will be higher.\n  version_number = get_version_number(xcodeproj: xcodeproj, target: target)\n  latest_app_store_build_number = latest_testflight_build_number\n  test_flight_build_number = latest_testflight_build_number(version: version_number)\n\n  if new_build_number <= latest_app_store_build_number\n    UI.message 'git build number is smaller than the build number of the latest release'\n    UI.message \"Using the latest release build number #{latest_app_store_build_number} + 1\"\n    new_build_number = latest_app_store_build_number + 1\n  end\n\n  if new_build_number <= test_flight_build_number\n    UI.message 'git build number is smaller than test flight build number'\n    UI.message \"Using the TestFlight build number #{test_flight_build_number} + 1\"\n    new_build_number = test_flight_build_number + 1\n  end\n\n  increment_build_number(build_number: new_build_number)\nend\n\ndesc 'Syncs production certificates on CI'\ndesc ''\ndesc '#### Options'\ndesc ' * **`app_identifier`**: a list of all app identifiers for which to sync the certs'\ndesc ''\nlane :certs do |options|\n  # Create Keychain to store certificates in\n  create_keychain(\n    name: ENV['MATCH_KEYCHAIN_NAME'],\n    password: ENV['MATCH_KEYCHAIN_PASSWORD'],\n    default_keychain: true,\n    unlock: true,\n    timeout: 3600,\n    add_to_search_list: true\n  )\n  # Sync certificates\n  match(\n    keychain_name: (ENV['MATCH_KEYCHAIN_NAME']).to_s,\n    keychain_password: (ENV['MATCH_KEYCHAIN_PASSWORD']).to_s,\n    app_identifier: options[:app_identifier],\n    force: true,\n    type: options[:type] || 'appstore',\n    platform: options.fetch(:platform, 'ios'),\n    readonly: options.fetch(:readonly, false)\n  )\nend\n\ndesc \"Fetch the version number that's currently in prepare for submission mode in App Store Connect.\"\ndesc ''\ndesc '#### Options'\ndesc ' * **`app_identifier`**: The bundle identifier of the app for which to fetch the preparing version number'\ndesc ''\nprivate_lane :current_preparing_app_version do |options|\n  UI.message 'fetching highest version on App Store Connect...'\n\n  api_key = Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]\n  token = Spaceship::ConnectAPI::Token.create(**api_key)\n  Spaceship::ConnectAPI.token = token\n\n  app = Spaceship::ConnectAPI::App.find(options[:app_identifier])\n\n  if app.nil?\n    UI.message 'App not found'\n    next\n  end\n\n  if app.get_edit_app_store_version.nil?\n    UI.message 'No preparing version number found'\n    next\n  end\n\n  UI.message \"Latest preparing version is #{app.get_edit_app_store_version.version_string}\"\n\n  app.get_edit_app_store_version.version_string\nend\n\ndesc 'Ensures that a new release is allowed to happen'\ndesc ''\ndesc '#### Options'\ndesc ' * **`app_identifier`**: The bundle identifier of the app for which to fetch the preparing version number'\ndesc ' * **`version_number`**: The version number of the project'\ndesc ' * **`tag_name`**: The name of the latest release on GitHub'\ndesc ''\nprivate_lane :ensure_release_is_needed do |options|\n  preparing_app_version = current_preparing_app_version(app_identifier: options[:app_identifier])\n\n  if preparing_app_version.nil?\n    message = 'Weekly release cancelled as App Store Connect does not contain a preparing app version'\n    UI.important message\n    slack(\n      message: message,\n      success: false,\n      default_payloads: %i[git_branch last_git_commit_message]\n    )\n\n    raise message\n  end\n\n  local_project_version_number = Gem::Version.new(options[:version_number])\n  tag_version_number = Gem::Version.new(options[:tag_name].split('b')[0])\n\n  app_store_preparing_version = Gem::Version.new(preparing_app_version)\n\n  project_version_is_newer = tag_version_number < local_project_version_number\n  preparing_version_is_newer = tag_version_number < app_store_preparing_version\n\n  # Cancel when did not manage to create a stable release on GitHub or when the App Store Connect preparing version doesn't match the project version.\n  if project_version_is_newer || preparing_version_is_newer\n    UI.important \"Release cancelled. Tag version: #{tag_version_number}, project version: #{local_project_version_number}, app store preparing version: #{app_store_preparing_version}\"\n\n    slack(\n      message: 'Weekly released cancelled as no new green light build is available.',\n      success: false,\n      default_payloads: %i[git_branch last_git_commit_message],\n      payload: {\n        'Latest available release tag' => tag_version_number\n      }\n    )\n\n    raise 'Weekly released cancelled as no new green light build is available.'\n  end\nend\n\ndesc 'Get latest release from Github that is not a beta'\nprivate_lane :latest_github_release_tag do\n  origin_name = git_repository_name.split('/')\n  organisation = origin_name[0]\n  repository = origin_name[1]\n\n  # We set the page size to the max of 100 releases per page so that as a quick way\n  # of avoiding pagination. This gives us more than enough release candidates for weekly or\n  # a bi-weekly build train. This lane will fail when there were more then 99 pre-releases published since the\n  # latest release. Because then the results won't return the lates non candidate release and thus we don't know the tag.\n  result = github_api(\n    server_url: 'https://api.github.com',\n    api_token: ENV['DANGER_GITHUB_API_TOKEN'],\n    http_method: 'GET',\n    path: \"/repos/#{organisation}/#{repository}/releases?per_page=100\"\n  )\n  latest_release = result[:json].find { |release| !release['name'].downcase.include? 'beta' }\n  UI.message \"Found latest release version: #{latest_release['tag_name']}\"\n  latest_release['tag_name']\nend\n\ndesc 'Strips URLs and unuseful decoration for reading changelogs outside of GitHub'\ndesc 'Used for example for the App Store changelog'\ndesc '#### Options'\ndesc ' * **`input`**: The text from which to strip the URLs and decoration'\ndesc ''\nprivate_lane :strip_changelog do |options|\n  output = options[:input]\n    # Add an extra enter before headers\n    .gsub('### ', \"\\n### \")\n    # Remove all trailing URLs including the \" in \" prefix.\n    .gsub(/ in https?:\\/\\/[\\S]+/, '')\n\n  # Remove the last line containing \"Full Changelog...\" since it's not useful outside of GitHub, and the first line containing <!--- Release notes...\n  lines = output.strip.split(\"\\n\").drop(1)\n  lines.pop\n\n  # Join together again, chop (aka trim) linebreaks and whitespaces, and return as the result.\n  lines.join(\"\\n\").chop\nend\n\ndesc 'Generates a new tag name using the projects build and version number'\ndesc ''\ndesc '#### Options'\ndesc ' * **`xcodeproj**: The name of the Xcode project to use to get the build and version number'\ndesc ' * **`target`**: The Xcode target to use to get the build and version number'\ndesc ''\nprivate_lane :create_tag_name do |options|\n  version_number = get_version_number(xcodeproj: options[:xcodeproj], target: options[:target])\n  build_number = get_build_number(xcodeproj: options[:xcodeproj])\n  tag_name = version_number + 'b' + build_number\nend\n"
  },
  {
    "path": "Fastlane/provisioning_lanes.rb",
    "content": "desc 'Installs the required certificates on your machine using fastlane match'\nlane :install_match_dependencies do\n  authenticate\n\n  match_configuration(\n    type: 'development',\n    readonly: true,\n    platform: 'ios'\n  )\n\n  match_configuration(\n    type: 'appstore',\n    readonly: true,\n    platform: 'ios'\n  )\n\n  if ENV.include?(\"MACOS_APP_IDENTIFIERS\")\n    UI.message 'Installing macOS Match Dependencies'\n\n    match_configuration(\n      type: 'development',\n      readonly: true,\n      platform: 'macos',\n      app_identifier: ENV[\"MACOS_APP_IDENTIFIERS\"]\n    )\n\n    match_configuration(\n      type: 'appstore',\n      readonly: true,\n      platform: 'macos',\n      app_identifier: ENV[\"MACOS_APP_IDENTIFIERS\"],\n      additional_cert_types: [\"mac_installer_distribution\"]\n    )\n  end\nend\n\ndesc 'Update the development certificates and profiles using fastlane match'\nlane :update_match_development_dependencies do\n  match_configuration(\n    type: 'development',\n    readonly: false,\n    platform: 'ios'\n  )\n\n  if ENV.include?(\"MACOS_APP_IDENTIFIERS\")\n    UI.message 'Updating macOS Match Development Dependencies'\n    match_configuration(\n      type: 'development',\n      readonly: false,\n      platform: 'macos',\n      app_identifier: ENV[\"MACOS_APP_IDENTIFIERS\"]\n    )\n  end\nend\n\ndesc 'Update the appstore certificates and profiles using fastlane match'\nlane :update_match_appstore_dependencies do\n  match_configuration(\n    type: 'appstore',\n    readonly: false,\n    platform: 'ios'\n  )\n\n  if ENV.include?(\"MACOS_APP_IDENTIFIERS\")\n    UI.message 'Updating macOS Match AppStore Dependencies'\n    match_configuration(\n      type: 'appstore',\n      readonly: false,\n      platform: 'macos',\n      app_identifier: ENV[\"MACOS_APP_IDENTIFIERS\"],\n      additional_cert_types: [\"mac_installer_distribution\"]\n    )\n  end\nend\n\ndesc 'A convenience method for using fastlane match'\nprivate_lane :match_configuration do |options|\n  api_key = authenticate\n\n  sync_code_signing(\n    type: options[:type],\n    api_key: api_key,\n    readonly: options[:readonly],\n    platform: options[:platform],\n    app_identifier: options.fetch(:app_identifier, ENV[\"APP_IDENTIFIERS\"]),\n    additional_cert_types: options.fetch(:additional_cert_types, [])\n  )\nend\n\ndesc 'Adds a Macos device to your developer account.'\nlane :add_macos_device do\n  add_device(platform: 'mac')\nend\n\ndesc 'Adds a new device to your developer account.'\nlane :add_device do |options|\n  device_name = prompt(text: 'Enter the device name: ')\n  device_udid = prompt(text: 'Enter the device UDID: ')\n\n  device_hash = {}\n  device_hash[device_name] = device_udid\n\n  authenticate\n\n  register_devices(\n    devices: device_hash,\n    team_id: ENV['FASTLANE_TEAM_ID'],\n    platform: options.fetch(:platform, 'ios')\n  )\n\n  sign\nend\n\ndesc 'Download and refresh profiles for local development'\nprivate_lane :sign do\n  app_identifiers = ENV['APP_IDENTIFIERS']\n  match(type: 'development', force: true, app_identifier: app_identifiers)\n  match(type: 'adhoc', force: true, app_identifier: app_identifiers)\n  match(type: 'appstore', force: true, app_identifier: app_identifiers)\nend\n"
  },
  {
    "path": "Fastlane/shared_lanes.rb",
    "content": "desc 'Executes a bash script that prepares for a CI run.'\ndesc ''\ndesc '#### Options'\ndesc ' * **`script`**: The path to the bash script that prepares for a CI run. (`PREPARE_CI_SCRIPT`)'\ndesc ''\nlane :prepare_for_ci do |options|\n  script = options[:script] || ENV['PREPARE_CI_SCRIPT']\n\n  if script.nil?\n    puts 'Did not find a script to prepare for a CI run.'\n    next\n  end\n\n  sh(script)\nend\n\ndesc 'Returns the repository name. E.g: WeTransfer/Mocker'\nlane :git_repository_name do\n  sh(\"git remote show origin -n | grep h.URL | sed 's/.*://;s/.git$//'\").strip\nend\n\ndesc 'Get latest release from Github. Draft releases and prereleases are not returned by this endpoint. See: https://developer.github.com/v3/repos/releases/#get-the-latest-release'\nlane :latest_github_release do\n  origin_name = git_repository_name.split('/')\n  organisation = origin_name[0]\n  repository = origin_name[1]\n\n  result = github_api(\n    server_url: 'https://api.github.com',\n    api_token: ENV['DANGER_GITHUB_API_TOKEN'],\n    http_method: 'GET',\n    path: \"/repos/#{organisation}/#{repository}/releases/latest\"\n  )\n\n  puts \"Latest Github release is #{result[:json]['tag_name']}\"\n  result[:json]['tag_name']\nend\n\ndesc 'Runs danger locally for the given PR ID.'\nlane :run_danger_locally do\n  pr_id = prompt(text: 'Enter the pull request identifier: ', ci_input: \"3\")\n\n  origin_name = git_repository_name.split('/')\n  organisation = origin_name[0]\n  repository = origin_name[1]\n\n  ENV[\"BITRISE_IO\"] = \"random-value-does-not-matter\"\n  ENV[\"BITRISEIO_GIT_REPOSITORY_OWNER\"] = organisation\n  ENV[\"BITRISEIO_GIT_REPOSITORY_SLUG\"] = repository\n  ENV[\"BITRISE_PULL_REQUEST\"] = pr_id\n\n  # By changing directory into WeTransfer-iOS-CI, we can run Danger from there.\n  # Caching is still done per repository which is why we add the build and cache paths.\n  # --cwd makes sure to run Danger in the current repository directory\n  # The Dangerfile.swift from within the WeTransfer-iOS-CI repo is used.\n  #\n  # This all allows us to not define Danger dependencies in every repo. It also optimises reusing the SPM cache on CI systems.\n  sh(\"cd #{ENV['PWD']}/Submodules/WeTransfer-iOS-CI && danger-swift ci --cache-path ../../.build --build-path ../../.build --cwd ../../ --verbose\")\n\n  # Reset so that Fastlane don't thinks we're a CI anymore.\n  ENV[\"BITRISE_IO\"] = nil\nend\n\n## Helper\n\n# Checks if the current environment is CI.\ndef is_running_on_CI(options = nil)\n  (options != nil ? options[:ci] : false) || ENV['CI'] == 'true'\nend\n\n# Truncates a given string to a certain length and adds a truncation mark in the\n# end if the string is long enough.\ndef truncate(string, max)\n  return if string.empty?\n\n  truncation_mark = '...'\n  if string.length > max\n    max > truncation_mark.length ? \"#{string[0...max-truncation_mark.length]}#{truncation_mark}\" : \"#{string[0...max]}\"\n  else\n    string\n  end\nend\n\n# Posts a message about the status of a build to Slack.\n# It is required to create an incoming Webhook for Slack and set this as an environment variable `SLACK_URL`.\n#\n# ==== Options\n# * type - adds an emoji to easier identify the messages context ([:error, :info, :release_build, :submitted]).\n# * tag_name - adds the tag name at the end of the given slack message.\n# * success - was this build successful? (true/false) Default is true.\n# * default_payloads - Specifies default payloads to include. Pass an empty array to suppress all the default payloads ([:git_branch]).\n# * additional_payloads - Additional payloads to be added to the slack message. A hash is expected.\n# * release_url - URL to be added as payload.\ndef slack_message(message, options = {})\n  return if message.empty?\n\n  supported_types = {\n    error: \":x: \",\n    info: \":information_source: \",\n    release_build: \":tada: \",\n    submitted: \":rocket: \"\n  }\n\n  slack_message_tag = \" (#{options[:tag_name]})\" if options[:tag_name] && !options[:tag_name].empty?\n  slack_message = \"#{supported_types[options[:type]]}#{message}#{slack_message_tag}\"\n  slack_success = !!options[:success] == options[:success] ? options[:success] : true\n  default_payloads = options[:default_payloads] ? options[:default_payloads] : [:git_branch]\n  slack_payload = {}\n  slack_payload['Release URL'] = options[:release_url] if options[:release_url] && !options[:release_url].empty?\n  slack_payload.merge!(options[:additional_payloads]) if options[:additional_payloads]\n\n  slack(\n    message: slack_message,\n    success: slack_success,\n    default_payloads: default_payloads,\n    payload: slack_payload\n  )\nend\n\nlane :clean_up_release_from_tag do |options|\n  latest_tag = ENV['BITRISE_GIT_TAG']\n\n  latest_release_branch = \"release/#{latest_tag}\"\n  if `git ls-remote --heads origin #{latest_release_branch}`.empty?\n    UI.message \"Branch #{latest_release_branch} doesn't exist. Nothing to delete.\"\n  else\n    sh \"git push origin --delete #{latest_release_branch}\"\n  end\n\n  if `git ls-remote --tags origin #{latest_tag}`.empty?\n    UI.message \"Tag #{latest_tag} doesn't exist. Nothing to delete.\"\n  else\n    sh \"git push origin --delete #{latest_tag}\"\n  end\nend\n\n# Shared method for handling errors that are being raised during fastlane deployment.\n# Errors being raised on the test lane (PR tests) will be ignore, because they could lead to too much spam on the slack channel.\ndef handle_error(lane, exception)\n  return if lane.to_s.start_with?(\"test\") # Do not report errors on lanes that start with \"test\" (ex. :test, :test_package, :test_sdk).\n  return unless is_running_on_CI # Do not report errors on other environments than CI.\n\n  # Makes sure we clean up the tag and the release branch if release_from_tag failed, to allow future releases\n  clean_up_release_from_tag if lane == :release_from_tag\n\n  slack_message(\n    \"Something went wrong with the deployment on lane: #{lane}.\",\n    type: :error,\n    success: false,\n    additional_payloads: {\n      \"Bitrise build\" => ENV['BITRISE_BUILD_URL'],\n      \"Error Info\" => exception.to_s\n    }\n  )\nend\n"
  },
  {
    "path": "Fastlane/testing_lanes.rb",
    "content": "# rubocop:disable Layout/LineLength\n\nrequire 'uri'\n\ndesc 'Runs tests for a specific package'\ndesc ''\ndesc '#### Options'\ndesc ' * **`package_name`**: The name of the package to test'\ndesc ' * **`package_path`**: The path to the package'\ndesc ''\nlane :test_package do |options|\n  UI.abort_with_message! \"Package path is missing\" unless options[:package_path]\n  UI.abort_with_message! \"Package name is missing\" unless options[:package_name]\n  test_project(options)\nend\n\ndesc 'Runs tests for an external project'\ndesc ''\ndesc '#### Options'\ndesc \" * **`scheme`**: The project's scheme\"\ndesc ' * **`project_path`**: The path to the project'\ndesc ' * **`project_name`**: The name of the project'\ndesc ' * **`parallel_testing`**: Enables parallel testing'\ndesc ' * **`xcargs`**: An optional extra set of arguments to pass to Fastlane Scan'\ndesc ' * **`destination`**: ..'\nlane :test_project do |options|\n  # Set timeout to prevent xcodebuild -list -project to take to much retries.\n  ENV['FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT'] = '30'\n  ENV['FASTLANE_XCODE_LIST_TIMEOUT'] = '30'\n\n  begin\n    if options[:destination].nil?\n      device = options[:device] || 'iPhone 16 (18.0)'\n    end\n\n    if options[:package_path].nil?\n      project_path = \"#{options[:project_path]}#{options[:project_name]}.xcodeproj\"\n    end\n\n    scheme = options[:scheme] || options[:package_name]\n    source_packages_dir = \"#{ENV['PWD']}/.spm-build\"\n    \n    # Setup Datadog CI Insights\n    # configure_datadog_ci_test_tracing(\n    #   service_name: scheme\n    # )\n\n    # Remove any leftover reports before running so local runs won't fail due to an existing file.\n    sh(\"rm -rf #{ENV['PWD']}/build/reports/#{scheme}.xcresult\")\n\n    code_coverage_enabled = true\n\n    if options.fetch(:build_for_testing, false)\n      # The flag -enableCodeCoverage is only supported when testing.\n      code_coverage_enabled = nil\n    end\n\n    scan(\n      step_name: options[:step_name] || \"Scan - #{scheme}\",\n      scheme: scheme,\n      testplan: options[:testplan],\n      project: project_path,\n      device: device,\n      destination: options[:destination],\n      code_coverage: code_coverage_enabled,\n      disable_concurrent_testing: true, # As of 27th October 2021, this seems to not be working anymore. We need `parallel-testing-enabled NO` instead.\n      fail_build: true,\n      skip_slack: true,\n      output_types: '',\n      # xcodebuild_formatter: '', # Add this to get verbose logging by disabling xcbeautify.\n      suppress_xcode_output: false,\n      buildlog_path: ENV['BITRISE_DEPLOY_DIR'], # By configuring `BITRISE_DEPLOY_DIR` we make sure our build log is deployed and available in Bitrise.\n      prelaunch_simulator: false,\n      parallel_testing: options.fetch(:parallel_testing, false),\n      xcargs: \"-clonedSourcePackagesDirPath #{source_packages_dir} -retry-tests-on-failure -test-iterations 3 #{options.fetch(:xcargs, nil)}\",\n      include_simulator_logs: false, # Needed for this: https://github.com/fastlane/fastlane/issues/8909\n      result_bundle: true,\n      output_directory: \"#{ENV['PWD']}/build/reports/\",\n      derived_data_path: \"#{ENV['PWD']}/build/derived_data\", # Set buildlog and derived data path to fix permission issues on Bitrise.\n      package_path: options[:package_path], # Optional path to the SPM package to test.\n      build_for_testing: options.fetch(:build_for_testing, nil),\n      test_without_building: options.fetch(:test_without_building, nil),\n      disable_package_automatic_updates: true, # Makes xcodebuild -showBuildSettings more reliable too.\n      skip_package_dependencies_resolution: options.fetch(:disable_automatic_package_resolution, false)\n    )\n  rescue StandardError => e\n    if options.fetch(:raise_exception_on_failure, false)\n      raise e\n    else\n      UI.important(\"Tests failed for #{e}\")\n    end\n  end\nend\n\ndesc 'Configures environment variables to enable Datadog CI Tests Tracing'\ndesc ''\ndesc 'To enable Datadog CI Tests Tracing for your project:'\ndesc ' 1. Add the DD_API_KEY env variable as a secret to Bitrise'\ndesc ' 2. Link the DatadogSDKTesting package following instructions here: https://docs.datadoghq.com/continuous_integration/setup_tests/swift/'\nlane :configure_datadog_ci_test_tracing do |options|\n  if ENV.include?(\"DD_API_KEY\")\n    ENV[\"TEST_RUNNER_DD_TEST_RUNNER\"] = '1' \n    ENV[\"TEST_RUNNER_DD_ENV\"] = 'ci' \n    ENV[\"TEST_RUNNER_DD_SITE\"] = 'datadoghq.eu'\n    ENV[\"TEST_RUNNER_DD_SERVICE\"] = options[:service_name]\n    ENV[\"TEST_RUNNER_DD_API_KEY\"] = ENV['DD_API_KEY']\n    ENV[\"TEST_RUNNER_SRCROOT\"] = ENV['PWD']\n    ENV[\"TEST_RUNNER_DD_TRACE_DEBUG\"] = '1'\n    ENV[\"TEST_RUNNER_DD_GIT_REPOSITORY_URL\"] = ENV['GIT_REPOSITORY_URL']\n    ENV[\"TEST_RUNNER_DD_GIT_BRANCH\"] = ENV['BITRISE_GIT_BRANCH']\n    ENV[\"TEST_RUNNER_DD_GIT_COMMIT_SHA\"] = ENV['BITRISE_GIT_COMMIT']\n    ENV[\"TEST_RUNNER_DD_GIT_COMMIT_MESSAGE\"] = ENV['BITRISE_GIT_MESSAGE']\n    ENV[\"TEST_RUNNER_DD_GIT_COMMIT_AUTHOR_NAME\"] = ENV['GIT_CLONE_COMMIT_AUTHOR_NAME']\n    puts \"Configured Datadog CI tracing.\"\n  else \n    puts \"Datadog CI tracing not configured since DD_API_KEY is missing.\"\n  end\nend\n\ndesc 'Create a release from a tag triggered CI run'\nlane :release_from_tag do\n  # Get the latest tag, which is the new release that triggered this lane.\n  sh('git fetch --tags origin master --no-recurse-submodules -q')\n\n  latest_tag = ENV['BITRISE_GIT_TAG']\n\n  # Create a release branch\n  sh \"git branch release/#{latest_tag} origin/master\"\n  sh \"git checkout release/#{latest_tag}\"\n  sh \"git merge -X theirs #{latest_tag}\"\n\n  release_output = sh('mint run --silent gitbuddy release -c \"../Changelog.md\"')\n  release_url = URI.extract(release_output).find { |url| url.include? 'releases/tag' }\n  puts \"Created release with URL: #{release_url}\"\n\n  # Run only if there's a podspec to update\n  if Dir['../*.podspec'].any?\n    # Update the podspec. It finds the .podspec automatically in the current folder.\n    version_bump_podspec(version_number: latest_tag)\n\n    begin\n      # Push the podspec to trunk\n      pod_push\n    rescue StandardError => e\n      UI.important(\"Pod push failed: #{e}\")\n    end\n  end\n\n  # Push the changes to the branch\n  sh('git commit -a -m \"Created a new release\"')\n  sh(\"git push origin release/#{latest_tag}\")\n\n  # Create a pull request for master to include the updated Changelog.md and podspec\n  create_pull_request(\n    api_token: ENV['DANGER_GITHUB_API_TOKEN'],\n    repo: git_repository_name,\n    title: \"Merge release #{latest_tag} into master\",\n    base: 'master', # The branch to merge the changes into.\n    body: \"Containing all the changes for our [**#{latest_tag} Release**](#{release_url}).\"\n  )\nend\n\ndesc 'Unhide dev dependencies for danger'\nlane :unhide_spm_package_dev_dependencies do\n  text = File.read('../Package.swift')\n  new_contents = text.gsub('// dev ', '')\n\n  # To write changes to the file, use:\n  File.open('../Package.swift', 'w') { |file| file.puts new_contents }\nend\n\ndesc 'Get all changed files in the current PR'\ndesc 'Requires that the enviroment contains a Danger GitHub API token `DANGER_GITHUB_API_TOKEN`'\ndesc ''\ndesc '#### Options'\ndesc ' * **`pr_id`**: The identifier of the PR that contains the changes.'\ndesc ''\nlane :changed_files_in_pr do |options|\n  origin_name = git_repository_name.split('/')\n  organisation = origin_name[0]\n  repository = origin_name[1]\n\n  if options[:pr_id].nil?\n    raise 'Missing PR ID input'\n  elsif ENV['DANGER_GITHUB_API_TOKEN'].nil?\n    raise \"Missing 'DANGER_GITHUB_API_TOKEN' environment variable\"\n  end\n\n  puts \"Fetching changed files for PR #{options[:pr_id]} using token ...#{ENV['DANGER_GITHUB_API_TOKEN'].chars.last(5).join}\"\n\n  result = github_api(\n    server_url: 'https://api.github.com',\n    api_token: ENV['DANGER_GITHUB_API_TOKEN'],\n    http_method: 'GET',\n    path: \"/repos/#{organisation}/#{repository}/pulls/#{options[:pr_id]}\"\n  )\n\n  baseRef = result[:json]['base']['ref']\n\n  # As CI fetches only the minimum we need to fetch the remote to make diffing work correctly.\n  sh 'git config remote.origin.fetch \"+refs/heads/*:refs/remotes/origin/*\"'\n  sh 'git fetch --no-recurse-submodules --no-tags'\n  sh \"git diff --name-only HEAD origin/#{baseRef}\"\nend\n\ndesc 'Check whether any of the changes happened in the given path'\ndesc ''\ndesc '#### Options'\ndesc ' * **`path`**: The path in which to check for changed files'\ndesc ''\nlane :pr_changes_contains_path do |options|\n  changes_contains_path = options[:changed_files].include?(options[:path])\n\n  if changes_contains_path\n    puts \"Changes found for path #{options[:path]}\"\n  elsif puts \"No changes found for path #{options[:path]}\"\n  end\n\n  changes_contains_path\nend\n\n# This block will get executed when an error occurs, in any of the blocks (before_all, the lane itself or after_all).\nerror do |lane, exception|\n  handle_error(lane, exception)\nend\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngem 'dotenv'\n"
  },
  {
    "path": "Package.resolved",
    "content": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"Files\",\n        \"repositoryURL\": \"https://github.com/JohnSundell/Files\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"d273b5b7025d386feef79ef6bad7de762e106eaf\",\n          \"version\": \"4.2.0\"\n        }\n      },\n      {\n        \"package\": \"Logger\",\n        \"repositoryURL\": \"https://github.com/shibapm/Logger\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"53c3ecca5abe8cf46697e33901ee774236d94cce\",\n          \"version\": \"0.2.3\"\n        }\n      },\n      {\n        \"package\": \"OctoKit\",\n        \"repositoryURL\": \"https://github.com/nerdishbynature/octokit.swift\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"44192458beb89180c3a3a1245d904aacac8be0ae\",\n          \"version\": \"0.13.0\"\n        }\n      },\n      {\n        \"package\": \"RequestKit\",\n        \"repositoryURL\": \"https://github.com/nerdishbynature/RequestKit.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"e4d905fed938807e36d87f28375f88b7c1c26840\",\n          \"version\": \"3.3.0\"\n        }\n      },\n      {\n        \"package\": \"danger-swift\",\n        \"repositoryURL\": \"https://github.com/danger/swift\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"e43a19617fc905ef303b1af2f0449b99fc6ea0f2\",\n          \"version\": \"3.20.2\"\n        }\n      },\n      {\n        \"package\": \"SwiftFormat\",\n        \"repositoryURL\": \"https://github.com/nicklockwood/SwiftFormat\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"ab6844edb79a7b88dc6320e6cee0a0db7674dac3\",\n          \"version\": \"0.54.5\"\n        }\n      },\n      {\n        \"package\": \"Version\",\n        \"repositoryURL\": \"https://github.com/mxcl/Version\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"303a0f916772545e1e8667d3104f83be708a723c\",\n          \"version\": \"2.1.0\"\n        }\n      },\n      {\n        \"package\": \"XCResultKit\",\n        \"repositoryURL\": \"https://github.com/davidahouse/XCResultKit.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"4d13c245f374d9af67fb9260cd14a4d58f6c6c82\",\n          \"version\": \"1.2.1\"\n        }\n      }\n    ]\n  },\n  \"version\": 1\n}\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.5\n// The above package version relates to the version Danger/Swift is using on their Git repo package file.\nimport PackageDescription\n\nlet package = Package(\n    name: \"WeTransfer-iOS-CI\",\n    platforms: [\n        .macOS(.v10_15)\n    ],\n    products: [\n        .library(name: \"DangerDeps\", type: .dynamic, targets: [\"DangerDependencies\"])\n    ],\n    dependencies: [\n        .package(name: \"danger-swift\", url: \"https://github.com/danger/swift\", from: \"3.20.2\"),\n        .package(path: \"WeTransferPRLinter\")\n    ],\n    targets: [\n        .target(name: \"DangerDependencies\", dependencies: [\n            .product(name: \"Danger\", package: \"danger-swift\"),\n            .product(name: \"WeTransferPRLinter\", package: \"WeTransferPRLinter\")\n        ], path: \"DangerFakeSources\", sources: [\"DangerFakeSource.swift\"])\n    ]\n)\n"
  },
  {
    "path": "README.md",
    "content": "# WeTransfer-iOS-CI\n![Build Status](https://app.bitrise.io/app/9829cbc3cc6501a3.svg?token=hCyPPIJ1MV2h0xyX1Ux4kA)\n\nContaining shared CI logic to quickly set up your repository with:\n\n- Tests running for each pull request\n- Danger reports for each pull request\n\n# Why should I use it?\nWhat's in it for me? Well, quite a lot! With low effort to add it to your project.\n\n- Integrate [SwiftLint](https://github.com/realm/SwiftLint) to lint source code and tests\n- Integrate [Fastlane](https://github.com/fastlane/fastlane) to run tests for PRs\n- Integrate [Danger](http://danger.systems/) to automatically improve PR reviews\n- Easily add automated releases based on tag-triggers\n\n## Danger features\nFollowing is a list of features which are posted in a comment on PRs based on the submitted files.\n\n  - Warn for big PRs, containing more than 500 lines of code\n  - Warn for missing PR description\n  - Warn for missing updated tests\n  - Show code coverage of PR related files\n  - Show any failed tests\n  - Show all `warnings` and `errors` in the project\n  - Show slowest tests\n\nAll this is written in Swift and fully tested 🚀\n\n### Custom linting\nThese warnings are posted inline inside the PR, helping you to solve them easily.\n\n  - Check for `final class` usage\n  - `override` methods without adding logic\n  -  Suggest `weak` over `unowned`\n  -  Suggest `// MARK:` usage for large files\n\n![](Assets/danger_comment.png)\n_This is an example comment. Note that `WeTransferBot` will be replaced by your own bot. More info can be found here: [Getting started with Danger](http://danger.systems/guides/getting_started.html)._\n\n### Adjusting slowests tests\nThe following environment variables can be used to adjust the slowest tests outcomes:\n- Use `SLOW_TESTS_DURATION_THRESHOLD` to configure a minimum duration threshold before a slow test shows up. Defaults to `2`.\n- Use `SLOW_TESTS_LIMIT` to configure the limit of slow tests to be shown. Defaults to `3`.\n\n# How to integrate?\n\n### 1: Add submodule\nAdd this repository as a submodule with the correct path `Submodules/WeTransfer-iOS-CI`:\n\n```\n[submodule \"Submodules/WeTransfer-iOS-CI\"]\n\tpath = Submodules/WeTransfer-iOS-CI\n\turl = https://github.com/WeTransfer/WeTransfer-iOS-CI.git\n```\n\n### 2: Create a fastlane file\n\nCreate a fastlane file which executes testing with code coverage enabled. Import the Fastfile from this repo and trigger the `test` lane.\n\n```ruby\nimport \"./../Submodules/WeTransfer-iOS-CI/Fastlane/Fastfile\"\nimport \"./../Submodules/WeTransfer-iOS-CI/Fastlane/shared_lanes.rb\"\n\ndesc \"Run the tests and prepare for Danger\"\nlane :test do |options|\n  test_project(\n    project_path: \"YOUR_PROJECT_PATH/\",\n    project_name: \"YOUR_PROJECT_NAME\",\n    scheme: \"YOUR_PROJECT_SCHEME\")\nend\n\n```\n\n### 3: Integrate SwiftLint in your project\nAdd a run script and use the common used [SwiftLint](https://github.com/WeTransfer/WeTransfer-iOS-CI/blob/master/BuildTools/swiftlint.sh) script:\n\n```shell\n./Submodules/WeTransfer-iOS-CI/BuildTools/swiftlint.sh\n```\n\n### 4: Make use of the shared Bitrise.yml workflows\nThe shared Bitrise.yml files make it really easy to integrate CI into open-source projects. It's been optimized using [this](https://blog.bitrise.io/tune-your-bitrise-workflows-using-cache-in-steps) blog post for caching and triggers like:\n\n- Manage gems & brews\n- Cache pulling\n- Run fastlane for testing\n- Run Danger from this repo\n- Cache pushing\n\n#### How to use this in your Bitrise configuration?\nFor Danger, you need to set the `DANGER_GITHUB_API_TOKEN` in your Bitrise secrets.\n\nMake sure your Bitrise.yml looks like this:\n\n```yml\ntrigger_map:\n- pull_request_source_branch: \"*\"\n  workflow: wetransfer_pr_testing\nworkflows:\n  wetransfer_pr_testing:\n    steps:\n    - activate-ssh-key:\n        run_if: '{{getenv \"SSH_RSA_PRIVATE_KEY\" | ne \"\"}}'\n    - git-clone: {}\n    - script:\n        title: Continue from WeTransfer-iOS-CI repo\n        inputs:\n        - content: |-\n            #!/bin/bash\n            set -ex\n            bitrise run --config ./Bitrise/testing_bitrise.yml \"${BITRISE_TRIGGERED_WORKFLOW_ID}\"\n```\n\n_Note: Don't change `wetransfer_pr_testing` as this needs to match the Bitrise.yml file workflow._\n\n### 5: Add automated releases based on tags\nBy making use of the Bitrise tag triggered builds we can automate the releases of open-source projects. The automation currently performs the following steps:\n\n- Automatically fetch the changelog using the [ChangelogProducer](https://github.com/WeTransfer/ChangelogProducer)\n- Create a GitHub release containing the changelog\n- Update and push the podspec\n- Update the `Changelog.md` with the new changes\n- Create a release branch and open a PR for those changes\n\n#### How to use this in your Bitrise configuration?\nAs open-source projects are making use of HTTPS by default we need to force Bitrise to use SSH instead. Therefore, we need to add the SSH key manually to the secret environment variables with the key `SSH_RSA_PRIVATE_KEY`. You can can read more about this here: [How can I generate an SSH key pair?](https://devcenter.bitrise.io/faq/how-to-generate-ssh-keypair/).\n\nWe also need to create a environment secret for CocoaPods trunk pushes with the key `COCOAPODS_TRUNK_TOKEN`. How to do that is explained here: [Automated CocoaPod releases with CI](https://fuller.li/posts/automated-cocoapods-releases-with-ci/).\n\nAfter all, you're secrets should look as follows:\n\n![](Assets/bitrise_env_vars.png)\n\nAfter that, we need to add a new trigger for tags:\n\n```yaml\ntrigger_map:\n- pull_request_source_branch: \"*\"\n  workflow: wetransfer_pr_testing\n- tag: \"*\"\n  workflow: wetransfer_tag_releasing\n```\n\nAnd we need to add the new workflow:\n\n```yaml\nwetransfer_tag_releasing:\nsteps:\n- activate-ssh-key:\n    run_if: '{{getenv \"SSH_RSA_PRIVATE_KEY\" | ne \"\"}}'\n- script:\n    title: Force SSH\n    inputs:\n    - content: |-\n        #!/usr/bin/env bash\n        # As we work with submodules, make sure we use SSH for this config so we can push our PR later on.\n        # See for more info: https://discuss.bitrise.io/t/git-force-to-use-ssh-url-instead-of-https-for-github-com/4384\n        git config --global url.\"git@github.com:\".insteadOf \"https://github.com/\"\n- git-clone: {}\n- script:\n    title: Continue from WeTransfer-iOS-CI repo\n    inputs:\n    - content: |-\n        #!/bin/bash\n        set -ex\n        bitrise run --config ./Submodules/WeTransfer-iOS-CI/Bitrise/tag_releasing_bitrise.yml \"${BITRISE_TRIGGERED_WORKFLOW_ID}\"\n```\n\nAfter that, you can simply create a new tag and the whole release process will be triggered! 🚀\n\n### 6: App deployment lanes\nIf you are building an app instead of a framework you can make use of the deployment lanes.\n\nThe `beta` lane takes care of:\n- Generating a changelog based on the GH issues that were solved and PR's that were merged in since the last beta build.\n- Create a draft release in GitHub.\n- Create a new AppStore release candidate and upload it to TestFlight.\n\nThe `release` does the following:\n- Fetch the lates green (approved) release from GitHub.\n- Create a new release branch in GitHub.\n- Create a PR that merges the release branch into the main branch.\n- Create a PR that merges the release branch into develop in order to make sure that develop contains the updated changelog and incremented build number.\n- Create a release build, upload it to TestFlight and submit for review.\n\nThese two lanes allow for the following workflow:\n1. Use the `beta` lane to upload an AppStore Release Candidate to TestFlight.\n2. Once the build went trough QA and has been approved for release mark it as green.\n3. Submit a new build to the App Store using the `release` lane.\n\n#### Marking a build as release ready\n- Find the draft release matching the tested TestFlight build number at `http://github.com/{organization}/{repo}/releases`.\n- Edit the draft and press the green button `Publish release`.\n\n#### How to use this in your project?\n\nImport the `deployment_lanes.rb` from this repo into the Fastfile. If you haven't done so already in step 2 also import the `shared_lanes` file.\n\n```ruby\nimport \"./../Submodules/WeTransfer-iOS-CI/Fastlane/deployment_lanes.rb\"\n```\n\nThen you need to make sure to authenticate with App Store Connect before running the deployment lanes. This can be done by adding a `before_all` block, like so:\n\n```ruby\nbefore_all do |lane, options|\n  authenticate\nend\n```\n\nThen there is two ways you can start using the deployment lanes. The first one is to create a new lane in the Fastfile from which you call one of the deployment lanes specifying values for all the options. The other option is to use environment variables, for example by using a .env file. In that case the lanes can be called directly without passing any options. An example of a .env file can be found [here](sample_fastlane_env).\n\n### 7: Provisioning lanes\n\nThe provisioning lanes help you with provisioning related task such as code signing and device management. To use them all you need to do is import `provisioning_lanes.rb` from this repo into the Fastfile.\n\n## Running Bitrise locally\nMake sure to have your `Bitrise.yml` locally inside your repo and then just run `bitrise run <workflow_local>` after adding the following local testing workflow:\n\n```yaml\n  <workflow_name>_local:\n    steps:\n    - script:\n        title: Setup environment variables\n        inputs:\n        - content: |-\n            #!/bin/bash\n            # Change these for your current local session.\n            export BITRISE_IO=\"fake_bitrise\"\n            export BITRISEIO_GIT_REPOSITORY_OWNER=\"WeTransfer\"                                                                                       \n            export BITRISEIO_GIT_REPOSITORY_SLUG=\"WeTransfer-iOS-SDK\"                                                                                \n            export BITRISE_PULL_REQUEST=452                                                                                                          \n\n            bitrise run <workflow_name>\n```\n\nDoing so allows you to run Bitrise workflows locally which will even update the Danger messages in GitHub itself. It kind of mimics [this](https://github.com/danger/danger-js/blob/fe5f080b4a267012dd80a9d589faee3bd278dc18/source/ci_source/providers/Bitrise.ts) Bitrise representation using env variables.\n\n\n## Bitrise Key-Based caching\nKey-based caching uses checksums. To test out a checksum locally, use `find . -print | grep -i */Package.resolved`. For example, that could result in:\n\n```yaml\n- key: spm-cache-{{ checksum \"Package.resolved\" \"*.xcodeproj/**/Package.resolved\" \"WeTransferPRLinter/Package.resolved\" }}\n```\n\n### Decompress caches\nIf you want to decompress a `tzst` cache file after downloading it from Bitrise, you can use the following command:\n\n```bash\n% tar -xvf /path/to/cache-20221110-112409.tzst \n```\n\n## Danger Binary Updating\n- See https://github.com/danger/swift/issues/476\n- Fork https://github.com/danger/swift\n- Update Danger's Package.swift to Swift 5.9 and switch `isDevelop` to `false`\n- Run `swift build --configuration release --arch arm64 --arch x86_64`\n- Copy the file from `.build/apple/Products/Release/danger-swift` to the root of the repository\n\n## License\nWeTransfer-iOS-CI is available under the MIT license. See the LICENSE file for more info.\n"
  },
  {
    "path": "WeTransferPRLinter/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\nxcuserdata/"
  },
  {
    "path": "WeTransferPRLinter/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "WeTransferPRLinter/Package.resolved",
    "content": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"Files\",\n        \"repositoryURL\": \"https://github.com/JohnSundell/Files\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"d273b5b7025d386feef79ef6bad7de762e106eaf\",\n          \"version\": \"4.2.0\"\n        }\n      },\n      {\n        \"package\": \"Logger\",\n        \"repositoryURL\": \"https://github.com/shibapm/Logger\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"53c3ecca5abe8cf46697e33901ee774236d94cce\",\n          \"version\": \"0.2.3\"\n        }\n      },\n      {\n        \"package\": \"OctoKit\",\n        \"repositoryURL\": \"https://github.com/nerdishbynature/octokit.swift\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"44192458beb89180c3a3a1245d904aacac8be0ae\",\n          \"version\": \"0.13.0\"\n        }\n      },\n      {\n        \"package\": \"RequestKit\",\n        \"repositoryURL\": \"https://github.com/nerdishbynature/RequestKit.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"e4d905fed938807e36d87f28375f88b7c1c26840\",\n          \"version\": \"3.3.0\"\n        }\n      },\n      {\n        \"package\": \"danger-swift\",\n        \"repositoryURL\": \"https://github.com/danger/swift.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"e43a19617fc905ef303b1af2f0449b99fc6ea0f2\",\n          \"version\": \"3.20.2\"\n        }\n      },\n      {\n        \"package\": \"SwiftFormat\",\n        \"repositoryURL\": \"https://github.com/nicklockwood/SwiftFormat\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"2d5a2b6bde636c1feae2c852ab9a50f221e98c66\",\n          \"version\": \"0.55.3\"\n        }\n      },\n      {\n        \"package\": \"Version\",\n        \"repositoryURL\": \"https://github.com/mxcl/Version\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"303a0f916772545e1e8667d3104f83be708a723c\",\n          \"version\": \"2.1.0\"\n        }\n      },\n      {\n        \"package\": \"XCResultKit\",\n        \"repositoryURL\": \"https://github.com/davidahouse/XCResultKit.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"4d13c245f374d9af67fb9260cd14a4d58f6c6c82\",\n          \"version\": \"1.2.1\"\n        }\n      }\n    ]\n  },\n  \"version\": 1\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Package.swift",
    "content": "// swift-tools-version:5.3\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"WeTransferPRLinter\",\n    platforms: [\n        .macOS(.v10_15)\n    ],\n    products: [\n        .library(\n            name: \"WeTransferPRLinter\",\n            targets: [\"WeTransferPRLinter\"]\n        )\n    ],\n    dependencies: [\n        .package(name: \"danger-swift\", url: \"https://github.com/danger/swift\", from: \"3.20.2\"),\n        .package(name: \"Files\", url: \"https://github.com/JohnSundell/Files\", from: \"4.1.1\"),\n        .package(name: \"XCResultKit\", url: \"https://github.com/davidahouse/XCResultKit.git\", from: \"1.2.1\")\n    ],\n    targets: [\n        .target(\n            name: \"WeTransferPRLinter\",\n            dependencies: [\n                .product(name: \"Danger\", package: \"danger-swift\"),\n                \"Files\",\n                \"XCResultKit\"\n            ]\n        ),\n        .testTarget(\n            name: \"WeTransferPRLinterTests\",\n            dependencies: [\n                \"WeTransferPRLinter\",\n                .product(name: \"DangerFixtures\", package: \"danger-swift\")\n            ],\n            resources: [\n                .copy(\"Resources/\")\n            ]\n        )\n    ]\n)\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/SwiftLintExecutor.swift",
    "content": "import Danger\nimport Foundation\n\n/// Defines a type that's capable of executing SwiftLint.\npublic protocol SwiftLintExecuting {\n    static func lint(files: [Danger.File], configFile: String)\n}\n\n/// A simple facade for testing purposes that directly calls SwiftLint.\npublic enum SwiftLintExecutor: SwiftLintExecuting {\n    public static func lint(files: [Danger.File], configFile: String) {\n        SwiftLint.lint(\n            .files(files),\n            inline: false,\n            configFile: configFile,\n            quiet: true\n        )\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/WeTransferPRLinter.swift",
    "content": "import Danger\nimport Files\nimport Foundation\n\n// danger:disable unowned_self\n\npublic enum WeTransferPRLinter {\n    public static func lint(\n        using danger: DangerDSL = Danger(),\n        swiftLintExecutor: SwiftLintExecuting.Type = SwiftLintExecutor.self,\n        xcResultSummaryReporter: XCResultSummaryReporter.Type = XCResultSummaryReporter.self,\n        reportsPath: String = \"build/reports\",\n        swiftLintConfigsFolderPath: String? = nil,\n        fileManager: FileManager = .default,\n        environmentVariables: [String: String] = ProcessInfo.processInfo.environment\n    ) {\n        let skippedTests = environmentVariables[\"SKIP_TESTS\"]?.lowercased() == \"true\"\n\n        measure(taskName: \"XCResults Summary\", skipIf: skippedTests, danger: danger) {\n            reportXCResultsSummary(\n                using: danger,\n                summaryReporter: xcResultSummaryReporter,\n                reportsPath: reportsPath,\n                fileManager: fileManager,\n                environmentVariables: environmentVariables\n            )\n        }\n\n        measure(taskName: \"PR Description Validation\", danger: danger) {\n            validatePRDescription(using: danger)\n        }\n\n        measure(taskName: \"Validating Work in Progress\", danger: danger) {\n            validateWorkInProgress(using: danger)\n        }\n\n        measure(taskName: \"Bitrise URL showing\", danger: danger) {\n            showBitriseBuildURL(using: danger, environmentVariables: environmentVariables)\n        }\n\n        measure(taskName: \"Simulator Download URL showing\", danger: danger) {\n            showSimulatorBuildDownloadURL(using: danger, environmentVariables: environmentVariables)\n        }\n\n        measure(taskName: \"SwiftLint\", skipIf: skippedTests, danger: danger) {\n            swiftLint(using: danger, executor: swiftLintExecutor, configsFolderPath: swiftLintConfigsFolderPath, fileManager: fileManager, environmentVariables: environmentVariables)\n        }\n    }\n\n    private static func measure(\n        taskName: String,\n        skipIf shouldSkip: Bool = false,\n        danger: DangerDSL,\n        task: () -> Void\n    ) {\n        guard !shouldSkip else {\n            danger.message(\"Skipped running \\(taskName) as `shouldSkip` returned true.\")\n            return\n        }\n\n        let startDate = Date()\n        task()\n        let differenceInSeconds = Int(Date().timeIntervalSince(startDate))\n        print(\"Finished executing \\(taskName) in \\(differenceInSeconds) seconds\")\n    }\n\n    static func reportXCResultsSummary(\n        using danger: DangerDSL,\n        summaryReporter: XCResultSummaryReporting.Type,\n        reportsPath: String,\n        fileManager: FileManager,\n        environmentVariables: [String: String]\n    ) {\n        defer { print(\"\\n\") }\n\n        var xcResultFiles = xcResultFiles(for: environmentVariables)\n        if let reportsFolder = try? Folder(path: reportsPath) {\n            xcResultFiles.append(contentsOf: reportsFolder.subfolders.filter { $0.extension == \"xcresult\" })\n        }\n\n        guard !xcResultFiles.isEmpty else {\n            return print(\"Skipping XCResult summaries since no xcresult files were found.\")\n        }\n\n        print(\"Found XCResult Summary Reports:\\n- \\(xcResultFiles.map(\\.name).joined(separator: \"\\n- \"))\")\n\n        let pathsToFilter: [String] = [\n            \"Submodules/\",\n            \"SourcePackages/\",\n            \".build/\",\n            \".spm-build/\"\n        ]\n        let shouldReportWarnings = environmentVariables[\"REPORT_WARNINGS\"]?.lowercased() == \"true\"\n\n        summaryReporter.reportXCResultSummary(for: xcResultFiles, using: danger, shouldReportWarnings: shouldReportWarnings, fileManager: fileManager) { result in\n            guard let file = result.file else {\n                return true\n            }\n\n            /// Filter specific paths to make sure we don't display results from\n            /// vendor packages, SPM packages, etc.\n            for pathToFilter in pathsToFilter {\n                guard file.contains(pathToFilter) else {\n                    continue\n                }\n                print(\"Filtered out \\(file) for filtered path \\(pathToFilter)\")\n                return false\n            }\n\n            return true\n        }\n        print(\"Finished reporting XCResult summaries.\")\n    }\n\n    static func xcResultFiles(for environmentVariables: [String: String]) -> [Folder] {\n        environmentVariables.compactMap { key, value -> [Folder]? in\n            guard key.starts(with: \"BITRISE_TEST_REPORTS_\") else { return nil }\n            guard let folder = try? Folder(path: value) else { return nil }\n            return folder.subfolders.filter { $0.extension == \"xcresult\" }\n        }.flatMap { $0 }\n    }\n\n    /// Mainly to encourage writing up some reasoning about the PR, rather than just leaving a title.\n    static func validatePRDescription(using danger: DangerDSL) {\n        guard let description = danger.github.pullRequest.body, !description.isEmpty else {\n            danger.warn(\"Please provide a summary in the Pull Request description\")\n            return\n        }\n    }\n\n    /// Warn for PRs that are still work in progress.\n    static func validateWorkInProgress(using danger: DangerDSL) {\n        let hasWIPLabel = danger.github.issue.labels.contains(where: { $0.name.contains(\"WIP\") })\n        let hasWIPTitle = danger.github.pullRequest.title.contains(\"WIP\")\n\n        guard hasWIPLabel || hasWIPTitle else {\n            return\n        }\n        danger.warn(\"PR is classed as Work in Progress\")\n    }\n\n    /// Show the Bitrise build URL for easier access.\n    static func showBitriseBuildURL(using danger: DangerDSL, environmentVariables: [String: String] = ProcessInfo.processInfo.environment) {\n        guard let bitriseURL = environmentVariables[\"BITRISE_BUILD_URL\"] else {\n            print(\"Bitrise URL not found\")\n            return\n        }\n        danger.message(\"View more details on <a href=\\\"\\(bitriseURL)\\\" target=\\\"_blank\\\">Bitrise</a>\")\n    }\n\n    /// Show the simulator build download URL.\n    static func showSimulatorBuildDownloadURL(\n        using danger: DangerDSL,\n        environmentVariables: [String: String] = ProcessInfo.processInfo.environment\n    ) {\n        // Example value in BITRISE_PERMANENT_DOWNLOAD_URL_MAP:\n        // \"Transfer.app.zip=>https://...\"\n        guard let map = environmentVariables[\"BITRISE_PERMANENT_DOWNLOAD_URL_MAP\"]?.components(separatedBy: \",\"),\n              let targetName = environmentVariables[\"XCODE_TARGET\"],\n              let simulatorBuildDownloadURL = map.first(where: { $0.hasPrefix(\"\\(targetName).app.zip\") }),\n              let url = simulatorBuildDownloadURL.components(separatedBy: \"=>\").last\n        else {\n            print(\"Simulator build download URL not found\")\n            return\n        }\n        danger.message(\"Download <a href=\\\"\\(url)\\\" target=\\\"_blank\\\">Simulator Build</a>\")\n    }\n\n    /// Triggers SwiftLint.\n    static func swiftLint(\n        using danger: DangerDSL,\n        executor: SwiftLintExecuting.Type = SwiftLintExecutor.self,\n        configsFolderPath: String? = nil,\n        fileManager: FileManager,\n        environmentVariables: [String: String] = [:]\n    ) {\n        defer { print(\"\\n\") }\n\n        guard environmentVariables[\"DISABLE_DANGER_SWIFTLINT\"] != \"true\" else {\n            return print(\"Skip SwiftLint linting since `disable_danger_swiftlint` environment variable was set.\")\n        }\n\n        let configsFolderPath: String = {\n            if let configsFolderPath, fileManager.fileExists(atPath: configsFolderPath, isDirectory: nil) {\n                return configsFolderPath\n            } else {\n                return \"\\(fileManager.currentDirectoryPath)/Submodules/WeTransfer-iOS-CI/BuildTools\"\n            }\n        }()\n        print(\"Starting SwiftLint with configs folder path: \\(configsFolderPath)...\")\n        let srcRoot = ProcessInfo.processInfo.environment[\"SRCROOT\"]\n        print(\"SRC Root for SwiftLint exclusions is \\(srcRoot ?? \"-\")\")\n\n        let files = danger.git.createdFiles + danger.git.modifiedFiles\n        let swiftFiles = files.filter { $0.fileType == .swift }\n\n        if !swiftFiles.isEmpty {\n            print(\"Linting files:\\n- \\(swiftFiles.joined(separator: \"\\n- \"))\")\n            executor.lint(files: swiftFiles, configFile: \"\\(configsFolderPath)/.swiftlint.yml\")\n        } else {\n            print(\"No files found to lint\")\n        }\n    }\n}\n\nextension String {\n    /// Whether the current String contains a class definition.\n    var isClassDefinition: Bool {\n        for nonClassElement in [\"func\", \"//\", \"protocol\", \"\\\"\"] {\n            guard !contains(nonClassElement) else { return false }\n        }\n        return contains(\"class\")\n    }\n\n    /// Whether the class defined in the current line should be marked as final, if the current line contains a class.\n    var shouldBeFinalClass: Bool {\n        guard isClassDefinition else { return false }\n        return !contains(\"final\") && !contains(\"open\")\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/Extensions/Danger+XCResultItemReporting.swift",
    "content": "import Danger\nimport Foundation\n\nextension DangerDSL {\n    /// Reports the given result item based on the available metadata like file and line number.\n    /// - Parameter resultItem: The result item to report to Danger.\n    func report(_ resultItem: XCResultItem) {\n        if let _ = resultItem.file, let _ = resultItem.line {\n            switch resultItem.category {\n            case .message:\n                message(resultItem.message)\n            case .error:\n                fail(resultItem.message)\n            case .warning:\n                warn(resultItem.message)\n            }\n        } else {\n            switch resultItem.category {\n            case .message:\n                message(resultItem.message)\n            case .error:\n                fail(resultItem.message)\n            case .warning:\n                warn(resultItem.message)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/Extensions/DocumentLocation+FileInfo.swift",
    "content": "import Foundation\nimport XCResultKit\n\nstruct FileMetadata {\n    let filename: String\n    let line: Int\n}\n\nextension DocumentLocation {\n    // swiftlint:disable:next line_length\n    /// Returns `FileMetadata` for URLs like: `▿ file:///Users/josh/Projects/fastlane/test-ios/TestTests/TestTests.swift#CharacterRangeLen=0&EndingLineNumber=36&StartingLineNumber=36`\n    /// by extracting the query parameters from it.\n    /// - Parameter fileManager: The file manager to use for fetching the current execution directory.\n    /// - Returns: The `FileMetadata` if it could be found.\n    func fileMetadata(fileManager: FileManager = .default) -> FileMetadata? {\n        guard let url = URL(string: url) else { return nil }\n\n        // Replace # with ? so we can make use of the query parameters.\n        let components = URLComponents(string: self.url.replacingOccurrences(of: \"#\", with: \"?\"))\n        guard\n            let lineString = components?.queryItems?.first(where: { $0.name == \"StartingLineNumber\" })?.value,\n            let line = Int(lineString)\n        else {\n            return nil\n        }\n\n        let currentPath = fileManager.currentDirectoryPath.last == \"/\"\n            ? fileManager.currentDirectoryPath\n            : fileManager.currentDirectoryPath + \"/\"\n        let path = url.path.deletingPrefix(currentPath)\n\n        return FileMetadata(filename: path, line: line)\n    }\n}\n\nprivate extension String {\n    func deletingPrefix(_ prefix: String) -> String {\n        guard hasPrefix(prefix) else { return String(self) }\n        return String(dropFirst(prefix.count))\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/Extensions/ErrorExtensions.swift",
    "content": "import Files\nimport Foundation\n\nextension LocationError {\n    var isMissingError: Bool {\n        switch reason {\n        case .missing:\n            return true\n        default:\n            return false\n        }\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/ResultItems/IssueSummaries.swift",
    "content": "import Foundation\nimport XCResultKit\n\n/// Summaries of errors, warnings, and test failures. Examples:\n///\n/// **ContentCreatorTests.testUnsupportedErrorItemProviderWithoutSupportedFileRepresentation():**\n/// failed - Creating invalid content should give an error.\n///\n/// CoreExtensions/Sources/CoreExtensions/OptionalExtensions.swift#L15 - Initialization of variable 'property' was never used; consider\n/// replacing with assignment to '_' or removing it\nextension ResultIssueSummaries {\n    func createResults(context: ResultGenerationContext, testPlanRunSummaries: ActionTestPlanRunSummaries) -> [XCResultItem] {\n        var results: [XCResultItem] = []\n        results.append(contentsOf: testFailureSummaries.createResults(\n            context: context,\n            testPlanRunSummaries: testPlanRunSummaries\n        ))\n        results.append(contentsOf: errorSummaries.createResults(category: .error, context: context))\n        results.append(contentsOf: warningSummaries.createResults(category: .warning, context: context))\n        return results\n    }\n}\n\nextension [TestFailureIssueSummary] {\n    /// Test Failure Summaries contain all failed tests, even if they succeeded after retry.\n    /// We can use this method to filter out retried tests and don't report them as failure,\n    /// but instead show them as a warning.\n    func createResults(context: ResultGenerationContext, testPlanRunSummaries: ActionTestPlanRunSummaries) -> [XCResultItem] {\n        let failedTestIdentifiers = testPlanRunSummaries.failedTestIdentifiers\n        let retriedTestIdentifiers = testPlanRunSummaries.retriedTestIdentifiers\n\n        let failedAndRetryResults = compactMap { testFailureIssueSummary -> [XCResultItem]? in\n            let identifier = testFailureIssueSummary.testCaseName.replacingOccurrences(of: \".\", with: \"/\")\n            if retriedTestIdentifiers.contains(identifier) {\n                return testFailureIssueSummary.createTestRetriedResult(context: context, testPlanRunSummaries: testPlanRunSummaries)\n            } else if failedTestIdentifiers.contains(identifier) {\n                return testFailureIssueSummary.createTestFailureResult(context: context, testPlanRunSummaries: testPlanRunSummaries)\n            }\n\n            return nil\n        }\n        .flatMap { $0 }\n        let skippedResults: [XCResultItem] = testPlanRunSummaries.skippedTests.compactMap { actionTestMetadata -> [XCResultItem]? in\n            guard let summaryRef = actionTestMetadata.summaryRef else {\n                return nil\n            }\n            guard let actionTestSummary = context.resultFile.getActionTestSummary(id: summaryRef.id) else {\n                return nil\n            }\n            return actionTestSummary.createResults(context: context)\n        }\n        .flatMap { $0 }\n\n        return failedAndRetryResults + skippedResults\n    }\n}\n\nextension ActionTestSummary: XCResultItemsConvertible {\n    func createResults(context: ResultGenerationContext) -> [XCResultItem] {\n        guard let title = activitySummaries.first?.title else {\n            return []\n        }\n        let message = \"**\\(identifier ?? \"<unknown>\"):**<br/>\\(title)\"\n        return [XCResultItem(message: message, category: .warning)]\n    }\n}\n\nextension TestFailureIssueSummary {\n    func createTestFailureResult(context: ResultGenerationContext, testPlanRunSummaries: ActionTestPlanRunSummaries) -> [XCResultItem] {\n        let message = \"**\\(testCaseName):**<br/>\\(message)\"\n        let fileMetadata = documentLocationInCreatingWorkspace?.fileMetadata(fileManager: context.fileManager)\n        return [XCResultItem(message: message, file: fileMetadata?.filename, line: fileMetadata?.line, category: .error)]\n    }\n\n    func createTestRetriedResult(context: ResultGenerationContext, testPlanRunSummaries: ActionTestPlanRunSummaries) -> [XCResultItem] {\n        let message = \"**\\(testCaseName) succeeded after retry:**<br/>\\(message)\"\n        let fileMetadata = documentLocationInCreatingWorkspace?.fileMetadata(fileManager: context.fileManager)\n        return [XCResultItem(message: message, file: fileMetadata?.filename, line: fileMetadata?.line, category: .warning)]\n    }\n}\n\nextension IssueSummary {\n    func createResults(category: XCResultItem.Category, context: ResultGenerationContext) -> [XCResultItem] {\n        let fileMetadata = documentLocationInCreatingWorkspace?.fileMetadata(fileManager: context.fileManager)\n        return [XCResultItem(message: message, file: fileMetadata?.filename, line: fileMetadata?.line, category: category)]\n    }\n}\n\nextension [IssueSummary] {\n    func createResults(category: XCResultItem.Category, context: ResultGenerationContext) -> [XCResultItem] {\n        flatMap { $0.createResults(category: category, context: context) }\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/ResultItems/TestSummaries.swift",
    "content": "import Foundation\nimport XCResultKit\n\n/// Creates test summary messages like:\n/// `StormTests: Executed 66 tests, with 0 failures in 9.181 seconds`\nextension ActionRecord: XCResultItemsConvertible {\n    func testPlanRunSummaries(resultFile: XCResultFile) -> ActionTestPlanRunSummaries? {\n        guard\n            let testsReferenceID = actionResult.testsRef?.id,\n            let testPlanRunSummaries = resultFile.getTestPlanRunSummaries(id: testsReferenceID)\n        else {\n            return nil\n        }\n        return testPlanRunSummaries\n    }\n\n    func createResults(context: ResultGenerationContext) -> [XCResultItem] {\n        guard let testPlanRunSummaries = testPlanRunSummaries(resultFile: context.resultFile) else {\n            return []\n        }\n\n        let issueResultItems = actionResult.issues.createResults(context: context, testPlanRunSummaries: testPlanRunSummaries)\n\n        let testPlanResultItems = testPlanRunSummaries.summaries.flatMap { testPlanRunSummary in\n            testPlanRunSummary.testableSummaries.flatMap { actionTestableSummary in\n                actionTestableSummary.createResults(context: context)\n            }\n        }\n\n        var slowestTestsItems: [XCResultItem] = []\n        if #available(macOS 12.0, *) {\n            slowestTestsItems = testPlanRunSummaries.createResultForSlowestTests()\n        }\n        return issueResultItems + testPlanResultItems + slowestTestsItems\n    }\n}\n\nextension ActionTestPlanRunSummaries {\n    /// - Returns: A set of identifiers for tests that failed, even after retrying.\n    var failedTestIdentifiers: Set<String> {\n        Set<String>(summaries.flatMap { $0.testableSummaries.flatMap(\\.failedTestIdentifiers) })\n    }\n\n    /// - Returns: A set of identifiers for the tests that were retried.\n    var retriedTestIdentifiers: Set<String> {\n        Set<String>(summaries.flatMap { $0.testableSummaries.flatMap(\\.retriedTestIdentifiers) })\n    }\n\n    /// - Returns: Metadata for all tests that were skipped.\n    var skippedTests: [ActionTestMetadata] {\n        summaries.flatMap { $0.testableSummaries.flatMap(\\.skippedTests) }\n    }\n\n    var allTests: [ActionTestMetadata] {\n        summaries.flatMap { $0.testableSummaries.flatMap(\\.allTests) }\n    }\n\n    @available(macOS 12.0, *)\n    func createResultForSlowestTests() -> [XCResultItem] {\n        let allTests = allTests\n        guard !allTests.isEmpty else { return [] }\n\n        var durationThreshold: Double = 2\n        var slowTestsLimit = 3\n\n        if let envDurationThreshold = ProcessInfo.processInfo.environment[\"SLOW_TESTS_DURATION_THRESHOLD\"] {\n            durationThreshold = Double(envDurationThreshold) ?? durationThreshold\n        }\n\n        if let envSlowTestsLimit = ProcessInfo.processInfo.environment[\"SLOW_TESTS_LIMIT\"] {\n            slowTestsLimit = Int(envSlowTestsLimit) ?? slowTestsLimit\n        }\n\n        let slowestTests = allTests\n            .sorted(using: KeyPathComparator(\\.duration, order: .reverse))\n            .filter { test in\n                guard let duration = test.duration else { return false }\n                /// Tests under our `durationThreshold` second are acceptable.\n                return duration > durationThreshold\n            }\n            .prefix(slowTestsLimit)\n\n        return slowestTests.compactMap { testMetadata in\n            guard let duration = testMetadata.duration else { return nil }\n            let durationString = String(format: \"%.3fs\", duration)\n            return XCResultItem(message: \"Slowest test: \\(testMetadata.identifier ?? \"<unknown>\") (\\(durationString))\", category: .message)\n        }\n    }\n}\n\nextension ActionTestableSummary: XCResultItemsConvertible {\n    var failedTestIdentifiers: Set<String> {\n        tests.failedTestIdentifiers\n    }\n\n    var retriedTestIdentifiers: Set<String> {\n        tests.retriedTestIdentifiers\n    }\n\n    var skippedTests: [ActionTestMetadata] {\n        tests.skippedTests\n    }\n\n    var allTests: [ActionTestMetadata] {\n        tests.allTests\n    }\n\n    var totalNumberOfTests: Int {\n        tests.totalNumberOfTests\n    }\n\n    var totalDuration: String {\n        let totalDuration: Double = tests.reduce(0) { totalDuration, testSummaryGroup in\n            var totalDuration = totalDuration\n            totalDuration += testSummaryGroup.duration\n            return totalDuration\n        }\n        return String(format: \"%.3f\", totalDuration)\n    }\n\n    var totalNumberOfFailingTests: Int {\n        failedTestIdentifiers.count\n    }\n\n    func createResults(context: ResultGenerationContext) -> [XCResultItem] {\n        guard let targetName else { return [] }\n        let message = \"\\(targetName): Executed \\(totalNumberOfTests) tests (\\(totalNumberOfFailingTests) failed,\"\n            + \" \\(retriedTestIdentifiers.count) retried, \\(skippedTests.count) skipped) in \\(totalDuration) seconds\"\n        return [XCResultItem(message: message, category: .message)]\n    }\n}\n\nextension [ActionTestSummaryGroup] {\n    var totalNumberOfTests: Int {\n        reduce(0) { totalCount, testSummaryGroup in\n            var totalCount = totalCount\n            totalCount += testSummaryGroup.totalNumberOfTests\n            return totalCount\n        }\n    }\n\n    var failedTestIdentifiers: Set<String> {\n        reduce([]) { identifiers, testSummaryGroup in\n            identifiers.union(testSummaryGroup.failedTestIdentifiers)\n        }\n    }\n\n    var retriedTestIdentifiers: Set<String> {\n        reduce([]) { identifiers, testSummaryGroup in\n            identifiers.union(testSummaryGroup.retriedTestIdentifiers)\n        }\n    }\n\n    var skippedTests: [ActionTestMetadata] {\n        reduce([]) { skippedTests, testSummaryGroup in\n            skippedTests + testSummaryGroup.skippedTests\n        }\n    }\n\n    var allTests: [ActionTestMetadata] {\n        reduce([]) { skippedTests, testSummaryGroup in\n            skippedTests + testSummaryGroup.allTests\n        }\n    }\n}\n\nextension ActionTestSummaryGroup {\n    var totalNumberOfTests: Int {\n        subtests.count + subtestGroups.totalNumberOfTests\n    }\n\n    var failedTestIdentifiers: Set<String> {\n        subtests.failedTestIdentifiers.union(subtestGroups.failedTestIdentifiers)\n    }\n\n    var retriedTestIdentifiers: Set<String> {\n        subtests.retriedTestIdentifiers.union(subtestGroups.retriedTestIdentifiers)\n    }\n\n    var skippedTests: [ActionTestMetadata] {\n        subtests.skipped + subtestGroups.skippedTests\n    }\n\n    var allTests: [ActionTestMetadata] {\n        subtests + subtestGroups.allTests\n    }\n}\n\nextension [ActionTestMetadata] {\n    private var successIdentifiers: Set<String> {\n        Set<String>(filter { $0.testStatus == \"Success\" }.compactMap(\\.identifier))\n    }\n\n    private var failedIdentifiers: Set<String> {\n        Set<String>(filter { $0.testStatus == \"Failure\" }.compactMap(\\.identifier))\n    }\n\n    var skipped: [ActionTestMetadata] {\n        filter { $0.testStatus == \"Skipped\" }\n    }\n\n    var failedTestIdentifiers: Set<String> {\n        /// Substract success identifiers to filter out retried tests.\n        failedIdentifiers.subtracting(successIdentifiers)\n    }\n\n    var retriedTestIdentifiers: Set<String> {\n        /// Tests that succeeded eventually intersect with failed tests.\n        successIdentifiers.intersection(failedIdentifiers)\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/XCResultCoverageFactory.swift",
    "content": "import Danger\nimport Foundation\nimport XCResultKit\n\nstruct XCResultCoverageReporter {\n    let resultFiles: [XCResultFile]\n    let danger: DangerDSL\n\n    func report(minimumCoverage: Double) {\n        var markdown = \"## Code Coverage Report\\n\"\n        markdown += \"\"\"\n        | Name | Coverage ||\n        | --- | --- | --- |\\n\n        \"\"\"\n\n        resultFiles.forEach { resultFile in\n            guard let coverage = resultFile.getCodeCoverage() else {\n                print(\"Could not get code coverage report \\(resultFile.url.lastPathComponent)\")\n                return\n            }\n\n            guard let invocationRecord = resultFile.getInvocationRecord() else {\n                return\n            }\n\n            let testSummaries = invocationRecord.actions.map { $0.testPlanRunSummaries(resultFile: resultFile) }\n            let testTargetNames = testSummaries.compactMap {\n                $0?.summaries.flatMap { $0.testableSummaries.compactMap(\\.targetName) }\n            }\n            .flatMap { $0 }\n\n            markdown += coverage.targets\n                .compactMap { target in\n                    guard testTargetNames.contains(target.coverageTargetName) else { return nil }\n                    return \"\\(target.name) | \\(target.coverageDescription)% | \\(target.lineCoverage > minimumCoverage ? \"✅\" : \"⚠️\")\\n\"\n                }\n                .joined()\n        }\n\n        danger.markdown(markdown)\n    }\n}\n\nextension CodeCoverageTarget {\n    /// Converts e.g. `0.7142857142857143` into `71.43`.\n    var coverageDescription: String {\n        String(format: \"%.2f\", lineCoverage * 100)\n    }\n\n    /// Changes e.g. `PRLinterApp.framework` to `PRLinterApp`.\n    var coverageTargetName: String {\n        URL(fileURLWithPath: name).deletingPathExtension().lastPathComponent\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/XCResultItem.swift",
    "content": "import Foundation\n\n/// Defines a result item that can be used to report into `Danger`.\npublic struct XCResultItem: Equatable, Hashable {\n    public enum Category {\n        case warning, error, message\n    }\n\n    public let message: String\n    public var file: String?\n    public var line: Int?\n    public let category: Category\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/XCResultItemConvertible.swift",
    "content": "import Foundation\nimport XCResultKit\n\n/// Defines a type that can be converted into `XCResultItem` instances.\nprotocol XCResultItemsConvertible {\n    func createResults(context: ResultGenerationContext) -> [XCResultItem]\n}\n\nextension Array: XCResultItemsConvertible where Element: XCResultItemsConvertible {\n    func createResults(context: ResultGenerationContext) -> [XCResultItem] {\n        flatMap { $0.createResults(context: context) }\n    }\n}\n\n/// Combine all available summaries and return them as a collection of results.\nextension ActionsInvocationRecord: XCResultItemsConvertible {\n    func createResults(context: ResultGenerationContext) -> [XCResultItem] {\n        /// Test summaries, warnings, errors, and failures.\n        let actionsResults = actions.createResults(context: context)\n        let warnings = issues.warningSummaries.createResults(category: .warning, context: context)\n        let errors = issues.errorSummaries.createResults(category: .error, context: context)\n        return actionsResults + warnings + errors\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/XCResultItemsFactory.swift",
    "content": "import Foundation\nimport XCResultKit\n\n/// A filter that can be used to hide specific results based on certain conditions.\npublic typealias ResultsFilter = (XCResultItem) -> Bool\n\n/// The context of generation which can be used to fetch information from for generating `XCResultItem` instances.\nstruct ResultGenerationContext {\n    let resultFile: XCResultFile\n    let fileManager: FileManager\n}\n\n/// Generates `XCResultItem` instances from the input `XCResultFile`.\nstruct XCResultItemsFactory {\n    let resultFile: XCResultFile\n    let resultsFilter: ResultsFilter?\n    var fileManager: FileManager = .default\n\n    func make() -> [XCResultItem] {\n        guard let invocationRecord = resultFile.getInvocationRecord() else {\n            return [XCResultItem(message: \"Could not get invocation record for \\(resultFile.url.lastPathComponent)\", category: .warning)]\n        }\n\n        let context = ResultGenerationContext(resultFile: resultFile, fileManager: fileManager)\n        var results = invocationRecord.createResults(context: context)\n        if let resultsFilter {\n            results = results.filter(resultsFilter)\n        }\n        return results\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Sources/WeTransferPRLinter/XCResultReporting/XCResultSummaryReporter.swift",
    "content": "import Danger\nimport Files\nimport Foundation\nimport XCResultKit\n\npublic typealias XCResultSummaryContaining = Folder\n\npublic protocol XCResultSummaryReporting {\n    static func reportXCResultSummary(\n        for files: [XCResultSummaryContaining],\n        using danger: DangerDSL,\n        shouldReportWarnings: Bool,\n        fileManager: FileManager,\n        resultsFilter: ResultsFilter?\n    )\n}\n\n/// Fetches `XCResultItem` instances and reports them into the given `DangerDSL`.\npublic enum XCResultSummaryReporter: XCResultSummaryReporting {\n    public static func reportXCResultSummary(\n        for files: [XCResultSummaryContaining],\n        using danger: DangerDSL,\n        shouldReportWarnings: Bool = false,\n        fileManager: FileManager = .default,\n        resultsFilter: ResultsFilter? = nil\n    ) {\n        let resultFiles = files.map { file in\n            XCResultFile(url: file.url)\n        }\n\n        let results = resultFiles.flatMap { resultFile -> [XCResultItem] in\n            print(\"Generating XCResult Summary report for \\(resultFile.url.lastPathComponent)\")\n            return XCResultItemsFactory(resultFile: resultFile, resultsFilter: resultsFilter, fileManager: fileManager).make()\n        }\n\n        let resultsToReport = {\n            if !shouldReportWarnings {\n                let (filteredResults, warningsCount) = results.reduce(into: ([], 0)) { result, item in\n                    item.category == .warning ? result.1 += 1 : result.0.append(item)\n                }\n                danger.report(.init(message: \"Project has \\(warningsCount) warnings\", category: .warning))\n                return filteredResults\n            } else {\n                return results\n            }\n        }()\n        resultsToReport.forEach(danger.report)\n\n        XCResultCoverageReporter(resultFiles: resultFiles, danger: danger).report(minimumCoverage: 0.8)\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~4E1_sR6fvIXaaTJigDgQ0l5kPvU7nEUbW0cyDJsN4oBw-MVGmoFI5P2675iEqgReHQmAWu94Z5XB0McnaOBUrQ==",
    "content": "[{\"name\":\"tmp\",\"type\":2}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~9vmIfhpgp3BVAWA7Oa0s5hizb2_fngYykKv9mR6NtK-9SSJbUM3m1iLu_j_qfVGmljJbA7tAz5PMpCEXW8jdpQ==",
    "content": "[{\"name\":\"remote-container\",\"type\":2}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~KWE2MOYZMODDTXU7J7xsMpwGZlSIGUtzxsMHzDEBIpzgpu0vUDoeSbW_PMavMln34cyjL6qaQ9Ds3OJl-IVRXw==",
    "content": "[{\"name\":\"remote-container\",\"type\":2}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~KpISh1vhIt2qfkv7ekxejO20MXYPTewAi5IggCFQ-JmvCmtIZgiH0xwqGDSoyTWQfUDJs6DCNAUxdQfuURRVAQ==",
    "content": "[{\"name\":\"TestThisDude-9FB8AFAA-7589-481B-903A-8FEA28D324AE\",\"type\":2},{\"name\":\"scheduling.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~QHvOgVVGxLaHgTBSgEsgmIUZY4-CSTW2q93BXQnhzbgvLNb_ol7FpVWFOoXc4UpMbpciTos04fFg6t0YRxuy6A==",
    "content": "[{\"name\":\"tmp\",\"type\":2}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~cS83JaeJ1xiN8lScWDodIxc9Q2SXpMB_XbAJ-BhA4pELMiLo3zI9JtOS6X8HOJ7xIZcEijoBEFOBKMwSDaBz3A==",
    "content": "[{\"name\":\"testmanagerd.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~heRI-dvvI9lcl_zQd4EXNqZJqTnLnTHiXq7ytqG_3WgMpzSKOGsPNam4QJEiEkK4FB7enUPBR8o2Dyo1p7vnNA==",
    "content": "[{\"name\":\"57EB1AB0-1579-4AD5-9453-E4F594F6371C\",\"type\":2}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~k8dUikOBxVULPXyD9ucqYbJS6lxlT3EPFk2AX5e_rvTwSsvMuILlrTmX238xU6idtxUw1j159j282BVaVXTWmg==",
    "content": "[{\"name\":\"TestUITests-324FDA7F-DAF5-4C28-8B5B-D80E388E42B9\",\"type\":2},{\"name\":\"scheduling.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~xg6b7aqSDgRPP96aSoKJWVMWphwlcIqADeRq6HQP_mrSqDCGyInBy2iliwpOimZO7X08C0lxWwpsLEgjK6nUIw==",
    "content": "[{\"name\":\"76D2BFB5-B797-4696-8AAF-9733A37AC6FE\",\"type\":2}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~ymVqV5ehQ17GywIEd6vETOaubylqExxpyLMkYyOVEKwJuvq1EqqfdGDiHkxMrXa5yJ-uf0F6kfLrU2EQloBPtQ==",
    "content": "[{\"name\":\"TestUITests-57EB1AB0-1579-4AD5-9453-E4F594F6371C.xctestconfiguration\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Data/data.0~yxxUaY0PV9YF4qd_coDCwb32HgkOmza4A5_9lePfaOok9_QmHfqX62GEegU23bpJ1vSR2F0yi3t7cEMUVFqJbQ==",
    "content": "[{\"name\":\"TestThisDude-76D2BFB5-B797-4696-8AAF-9733A37AC6FE.xctestconfiguration\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/Trainer_example_result.xcresult/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>dateCreated</key>\n\t<date>2019-09-04T05:43:18Z</date>\n\t<key>externalLocations</key>\n\t<array/>\n\t<key>rootId</key>\n\t<dict>\n\t\t<key>hash</key>\n\t\t<string>0~ONz3zz9Pw_nPCwJ5jRCSIXJ00j2SVJKG1oMFAGgFnDzG6cKlJJR1m8rKrcnaF5Fd_ClaQXfnmGBPDEgtjwvrPQ==</string>\n\t</dict>\n\t<key>storage</key>\n\t<dict>\n\t\t<key>backend</key>\n\t\t<string>fileBacked2</string>\n\t\t<key>compression</key>\n\t\t<string>standard</string>\n\t</dict>\n\t<key>version</key>\n\t<dict>\n\t\t<key>major</key>\n\t\t<integer>3</integer>\n\t\t<key>minor</key>\n\t\t<integer>20</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/coverage_fail_flaky_skip_example.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw==",
    "content": "[]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/coverage_fail_flaky_skip_example.xcresult/Data/data.0~FA2Aa792LjpVqLXJftt19H40IEY2LreIlqIb_rRNPRwRtG9Je44pKGV7jUv7_FP4BpBljrF2f6zvKdjwNqxwKg==",
    "content": "[{\"name\":\"PRLinterAppTests-D09637DF-3BC0-401A-B861-AFC5AB6A17A3\",\"type\":2},{\"name\":\"scheduling.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/coverage_fail_flaky_skip_example.xcresult/Data/data.0~VXBp0VvOYuVdcrFm2whfw8N2Gd8Qim_XL5_-GLjfekOxvFy6vhaZ2tLc_Ay0OlJYnHbLy3YfhbzssTTmizzecA==",
    "content": "[{\"name\":\"testmanagerd.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/coverage_fail_flaky_skip_example.xcresult/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>dateCreated</key>\n\t<date>2021-11-17T12:13:28Z</date>\n\t<key>externalLocations</key>\n\t<array/>\n\t<key>rootId</key>\n\t<dict>\n\t\t<key>hash</key>\n\t\t<string>0~ZIaTRwToD26Wu4lCRnSbKHj4tbBXVO-1pXFd3UDdy394agT-ZVlTJGEgw8708fiDkS6Qyp4DBWVF-df1rcJGgg==</string>\n\t</dict>\n\t<key>storage</key>\n\t<dict>\n\t\t<key>backend</key>\n\t\t<string>fileBacked2</string>\n\t\t<key>compression</key>\n\t\t<string>standard</string>\n\t</dict>\n\t<key>version</key>\n\t<dict>\n\t\t<key>major</key>\n\t\t<integer>3</integer>\n\t\t<key>minor</key>\n\t\t<integer>34</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/transfer_warnings_example.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw==",
    "content": "[]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/transfer_warnings_example.xcresult/Data/data.0~ICRz45qvGM70TTBvkh724ADixLBcfCARQ-lAvJnL1D_QuFqsKt2YRE1V1KMNcKqcJrS98e5RKoaHof4k5iaFhw==",
    "content": "[{\"name\":\"testmanagerd.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/transfer_warnings_example.xcresult/Data/data.0~KZqwDujPf5Qq6q1ay3FjJfA5lOr5hot-M-q3CboHO8f4TM7Yr5V0JDm-bR9SvsztOX78GbrH4dYTkt0zhzsaLA==",
    "content": "[{\"name\":\"TransferTests-7E17CEF6-AE03-48C9-B9C1-BC8B4D4F7F06\",\"type\":2},{\"name\":\"scheduling.log\",\"type\":1}]"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/Resources/transfer_warnings_example.xcresult/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>dateCreated</key>\n\t<date>2022-04-15T06:28:32Z</date>\n\t<key>externalLocations</key>\n\t<array/>\n\t<key>rootId</key>\n\t<dict>\n\t\t<key>hash</key>\n\t\t<string>0~tt6XA7W-qHwv0wit-kXOZ-oG4il4fPuBcVI4ubJvmStg_t9tCY-M3t-sgMBPDURsQCHUUuQ_PvqPQ5KjkFnDeA==</string>\n\t</dict>\n\t<key>storage</key>\n\t<dict>\n\t\t<key>backend</key>\n\t\t<string>fileBacked2</string>\n\t\t<key>compression</key>\n\t\t<string>standard</string>\n\t</dict>\n\t<key>version</key>\n\t<dict>\n\t\t<key>major</key>\n\t\t<integer>3</integer>\n\t\t<key>minor</key>\n\t\t<integer>37</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/TestHelpers/DangerTestExtensions.swift",
    "content": "@testable import Danger\n@testable import DangerFixtures\nimport Foundation\n\n/// Adds an option for overriding settings for testing.\nextension DangerDSL {\n    /// Available overrides. To add a new one, open the `TestDSLGitHubJSON` and add a key for replacement.\n    enum TestOverride: String {\n        case prDescription = \"PR_DESCRIPTION_CONTENT\"\n        case prTitle = \"PR_TITLE\"\n        case prLabel = \"PR_LABEL\"\n    }\n\n    typealias DangerTestSettings = [TestOverride: String]\n\n    init(testSettings: DangerTestSettings) {\n        var JSONString = TestDSLGitHubJSON\n\n        testSettings.forEach { testSetting in\n            JSONString = JSONString.replacingOccurrences(of: testSetting.key.rawValue, with: testSetting.value)\n        }\n\n        self = parseDangerDSL(with: JSONString)\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/TestHelpers/Mocks.swift",
    "content": "@testable import Danger\nimport Foundation\n@testable import WeTransferPRLinter\n\nstruct MockedSwiftLintExecutor: SwiftLintExecuting {\n    static var lintedFiles: [String: [File]] = [:]\n\n    static func lint(files: [File], configFile: String) {\n        lintedFiles[configFile] = files\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/TestHelpers/TestGithubDSL.swift",
    "content": "// swiftlint:disable line_length file_length\n\n/// Used by `DangerTestExtensions.swift` for testing purposes. Some properties in here will be overriden for tests.\npublic let TestDSLGitHubJSON = \"\"\"\n\n{\n  \"danger\": {\n      \"git\": {\n        \"modified_files\": [\n          \".travis.yml\",\n          \"Kiosk.xcodeproj/project.pbxproj\",\n          \"Kiosk/App/Logger.swift\",\n          \"Kiosk/App/Networking/NetworkLogger.swift\",\n          \"Kiosk/App/Networking/Networking.swift\",\n          \"Kiosk/App/Networking/XAppToken.swift\",\n          \"Kiosk/Auction Listings/ListingsViewModel.swift\",\n          \"Kiosk/HelperFunctions.swift\",\n          \"Kiosk/Images.xcassets/AppIcon.appiconset/Contents.json\",\n          \"KioskTests/Bid Fulfillment/ConfirmYourBidArtsyLoginViewControllerTests.swift\",\n          \"KioskTests/Bid Fulfillment/ConfirmYourBidEnterYourEmailViewControllerTests.swift\",\n          \"KioskTests/Bid Fulfillment/LoadingViewControllerTests.swift\",\n          \"KioskTests/Bid Fulfillment/RegistrationEmailViewControllerTests.swift\",\n          \"KioskTests/Bid Fulfillment/RegistrationPasswordViewModelTests.swift\",\n          \"KioskTests/Bid Fulfillment/SwipeCreditCardViewControllerTests.swift\",\n          \"KioskTests/ListingsViewControllerTests.swift\",\n          \"KioskTests/Models/SaleArtworkTests.swift\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__alphabetical@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__grid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__highest_bid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__least_bids@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__lowest_bid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_artworks_not_for_sale__a_listings_controller__most_bids@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__alphabetical@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__grid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__highest_bid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__least_bids@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__lowest_bid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__with_lot_numbers__a_listings_controller__most_bids@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__alphabetical@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__grid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__highest_bid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__least_bids@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__lowest_bid@2x.png\",\n          \"KioskTests/ReferenceImages/ListingsViewControllerTests/when_displaying_stubbed_contents__without_lot_numbers__a_listings_controller__most_bids@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/default__placing_a_bid@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_error_due_to_outbid@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_succeeded_but_not_resolved@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_success_highest@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/ending__placing_bid_success_not_highest@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/ending__registering_user_not_resolved@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/ending__registering_user_success@2x.png\",\n          \"KioskTests/ReferenceImages/LoadingViewControllerTests/errors__correctly_placing_a_bid@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationEmailViewControllerTests/looks_right_by_default@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationEmailViewControllerTests/looks_right_with_existing_email@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationMobileViewControllerTests/looks_right_by_default@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationMobileViewControllerTests/looks_right_with_existing_mobile@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationPasswordViewControllerTests/looks_right_with_a_valid_password@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationPasswordViewControllerTests/looks_right_with_an_invalid_password@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationPostalZipViewControllerTests/looks_right_by_default@2x.png\",\n          \"KioskTests/ReferenceImages/RegistrationPostalZipViewControllerTests/looks_right_with_existing_postal_code@2x.png\",\n          \"KioskTests/ReferenceImages/YourBiddingDetailsViewControllerTests/displays_bidder_number_and_PIN@2x.png\",\n          \"KioskTests/XAppTokenSpec.swift\",\n          \"Podfile\",\n          \"Podfile.lock\"\n        ],\n        \"created_files\": [\".ruby-version\"],\n        \"deleted_files\": [],\n        \"commits\": [\n          {\n            \"sha\": \"93ae30cf2aee4241c442fb3242543490998cffdb\",\n            \"parents\": [\"68c8db83776c1942145f530159a3fffddb812577\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-07-26T19:54:16Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-07-26T19:55:00Z\"\n            },\n            \"message\": \"[Xcode] Updates for compatibility with Xcode 7.3.1.\",\n            \"tree\": {\n              \"sha\": \"fb6bc3fda2456c5ff0a4e8f307f24ee73f281fc1\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/fb6bc3fda2456c5ff0a4e8f307f24ee73f281fc1\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/93ae30cf2aee4241c442fb3242543490998cffdb\"\n          },\n          {\n            \"sha\": \"4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n            \"parents\": [\"93ae30cf2aee4241c442fb3242543490998cffdb\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-07-26T19:55:53Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-07-26T19:55:53Z\"\n            },\n            \"message\": \"[CI] Updates Travis to Xcode 7.3.\",\n            \"tree\": {\n              \"sha\": \"01f7e53a061a1df01e7d6d3a6fb4d2ce9ee0e39a\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/01f7e53a061a1df01e7d6d3a6fb4d2ce9ee0e39a\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\"\n          },\n          {\n            \"sha\": \"d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n            \"parents\": [\"4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-07-26T21:17:40Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-07-26T21:17:40Z\"\n            },\n            \"message\": \"[Deps] Updates dependencies for Swift 2.2.\",\n            \"tree\": {\n              \"sha\": \"a30d9d8be16847c33eb50483a653f27475f197a4\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/a30d9d8be16847c33eb50483a653f27475f197a4\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\"\n          },\n          {\n            \"sha\": \"c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n            \"parents\": [\"d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-15T20:41:00Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-15T20:41:00Z\"\n            },\n            \"message\": \"[Tests] Cleans up snapshot tests for Xcode 7.3.1.\",\n            \"tree\": {\n              \"sha\": \"74f18cfa9f377497c46295e5bc254556a9eb159f\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/74f18cfa9f377497c46295e5bc254556a9eb159f\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\"\n          },\n          {\n            \"sha\": \"263d74a15e856f563f18864c459167c46c92cf48\",\n            \"parents\": [\"c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-15T20:42:13Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-15T20:42:13Z\"\n            },\n            \"message\": \"[Tests] Fixes typo, thanks @Gerst20051.\",\n            \"tree\": {\n              \"sha\": \"505840c1fd602e9ce7e44fda47488229aa1284b2\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/505840c1fd602e9ce7e44fda47488229aa1284b2\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/263d74a15e856f563f18864c459167c46c92cf48\"\n          },\n          {\n            \"sha\": \"b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n            \"parents\": [\"263d74a15e856f563f18864c459167c46c92cf48\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-15T20:54:06Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-15T20:54:06Z\"\n            },\n            \"message\": \"[Podfile] Adds comment for specific pod commit.\",\n            \"tree\": {\n              \"sha\": \"4589f4905bd0e23710a257ed6560983cbda91838\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/4589f4905bd0e23710a257ed6560983cbda91838\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\"\n          },\n          {\n            \"sha\": \"31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n            \"parents\": [\"b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-16T23:23:51Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-16T23:23:51Z\"\n            },\n            \"message\": \"[CI] Fix for intermittent CI failures.\",\n            \"tree\": {\n              \"sha\": \"e31f2c677fd09e21e2a056853a9f722c8f6a6c69\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/e31f2c677fd09e21e2a056853a9f722c8f6a6c69\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/31b4eccb1bba8510485d468a0b73221eead2b0f0\"\n          },\n          {\n            \"sha\": \"db2af03f247bec4d12a3e743b4464a70501fac77\",\n            \"parents\": [\"31b4eccb1bba8510485d468a0b73221eead2b0f0\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T13:34:47Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T13:34:47Z\"\n            },\n            \"message\": \"[Ruby] Adds version-specifier.\",\n            \"tree\": {\n              \"sha\": \"9226b26bd2cc9f6e50076badff8229bec8ff818b\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/9226b26bd2cc9f6e50076badff8229bec8ff818b\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/db2af03f247bec4d12a3e743b4464a70501fac77\"\n          },\n          {\n            \"sha\": \"57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n            \"parents\": [\"db2af03f247bec4d12a3e743b4464a70501fac77\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T13:42:29Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T13:42:29Z\"\n            },\n            \"message\": \"[CI] Split up failing test + switch to syncrhonous testing.\",\n            \"tree\": {\n              \"sha\": \"64bc098d18f98b3363e7a02fefba816140e17b8f\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/64bc098d18f98b3363e7a02fefba816140e17b8f\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/57b041fbbbebd075f7fe186fb754cf7cce85519c\"\n          },\n          {\n            \"sha\": \"851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n            \"parents\": [\"57b041fbbbebd075f7fe186fb754cf7cce85519c\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T13:48:43Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T13:58:30Z\"\n            },\n            \"message\": \"[CI] Fixes pre-launching simulator UUID.\",\n            \"tree\": {\n              \"sha\": \"9cbec8e2436334ac71c0254ff34595d24cf1c134\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/9cbec8e2436334ac71c0254ff34595d24cf1c134\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/851e911b4e8697a0f8e3b84c19df6cec30aead2a\"\n          },\n          {\n            \"sha\": \"9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n            \"parents\": [\"851e911b4e8697a0f8e3b84c19df6cec30aead2a\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:10:05Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:10:05Z\"\n            },\n            \"message\": \"[CI] Fixes intermittently failing test comparing dates.\",\n            \"tree\": {\n              \"sha\": \"2ab689baa382cc918289529955121d17672db7a4\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/2ab689baa382cc918289529955121d17672db7a4\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\"\n          },\n          {\n            \"sha\": \"1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n            \"parents\": [\"9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:41:27Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:41:27Z\"\n            },\n            \"message\": \"[Deps] Updates dependencies to latest Swift 2.x versions.\",\n            \"tree\": {\n              \"sha\": \"0ef37421cfa8cbd2d729e58de786b77f6219d3ad\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/0ef37421cfa8cbd2d729e58de786b77f6219d3ad\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/1aa0360bc7a95d7878160ae91eea62324ac3252f\"\n          },\n          {\n            \"sha\": \"fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n            \"parents\": [\"1aa0360bc7a95d7878160ae91eea62324ac3252f\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:41:31Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:41:31Z\"\n            },\n            \"message\": \"[CI] Fixes more intermittent tests.\",\n            \"tree\": {\n              \"sha\": \"00271b152921db4988396350eca46ed6b19f6649\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/00271b152921db4988396350eca46ed6b19f6649\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\"\n          },\n          {\n            \"sha\": \"c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n            \"parents\": [\"fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:55:34Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T14:55:34Z\"\n            },\n            \"message\": \"[CI] Removed duplicate simulator launch.\",\n            \"tree\": {\n              \"sha\": \"965807f296e1a3fb30134508062825cf30806786\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/965807f296e1a3fb30134508062825cf30806786\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/c6eb849f100cbaa261680ee0d3dc819b91aa8af1\"\n          },\n          {\n            \"sha\": \"d769f276e066d79169a8bfa5795c8a4853f942f3\",\n            \"parents\": [\"c6eb849f100cbaa261680ee0d3dc819b91aa8af1\"],\n            \"author\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T15:14:19Z\"\n            },\n            \"committer\": {\n              \"name\": \"Ash Furrow\",\n              \"email\": \"ash@ashfurrow.com\",\n              \"date\": \"2016-08-17T15:20:42Z\"\n            },\n            \"message\": \"[Feedback] Adds clarifying comments as per feedback in #609.\",\n            \"tree\": {\n              \"sha\": \"9004fe3df2b4d7d3285460095c37d9f62b4be26a\",\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/9004fe3df2b4d7d3285460095c37d9f62b4be26a\"\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/d769f276e066d79169a8bfa5795c8a4853f942f3\"\n          }\n        ]\n      },\n      \"github\": {\n        \"issue\": {\n          \"url\": \"https://api.github.com/repos/artsy/eidolon/issues/609\",\n          \"repository_url\": \"https://api.github.com/repos/artsy/eidolon\",\n          \"labels_url\": \"https://api.github.com/repos/artsy/eidolon/issues/609/labels{/name}\",\n          \"comments_url\": \"https://api.github.com/repos/artsy/eidolon/issues/609/comments\",\n          \"events_url\": \"https://api.github.com/repos/artsy/eidolon/issues/609/events\",\n          \"html_url\": \"https://github.com/artsy/eidolon/pull/609\",\n          \"id\": 167696965,\n          \"number\": 609,\n          \"title\": \"PR_TITLE\",\n          \"user\": {\n            \"login\": \"ashfurrow\",\n            \"id\": 498212,\n            \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n            \"gravatar_id\": \"\",\n            \"url\": \"https://api.github.com/users/ashfurrow\",\n            \"html_url\": \"https://github.com/ashfurrow\",\n            \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n            \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n            \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n            \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n            \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n            \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n            \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n            \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n            \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n            \"type\": \"User\",\n            \"site_admin\": false\n          },\n          \"labels\": [\n            {\n              \"id\": 983870497,\n              \"node_id\": \"MDU6TGFiZWw5ODM4NzA0OTc=\",\n              \"url\": \"https://api.github.com/repos/WeTransfer/Coyote/labels/PR_LABEL\",\n              \"name\": \"PR_LABEL\",\n              \"color\": \"ededed\",\n              \"default\": false,\n              \"description\": null\n            }\n          ],\n          \"state\": \"closed\",\n          \"locked\": false,\n          \"assignee\": {\n            \"login\": \"orta\",\n            \"id\": 49038,\n            \"avatar_url\": \"https://avatars2.githubusercontent.com/u/49038?v=4\",\n            \"gravatar_id\": \"\",\n            \"url\": \"https://api.github.com/users/orta\",\n            \"html_url\": \"https://github.com/orta\",\n            \"followers_url\": \"https://api.github.com/users/orta/followers\",\n            \"following_url\": \"https://api.github.com/users/orta/following{/other_user}\",\n            \"gists_url\": \"https://api.github.com/users/orta/gists{/gist_id}\",\n            \"starred_url\": \"https://api.github.com/users/orta/starred{/owner}{/repo}\",\n            \"subscriptions_url\": \"https://api.github.com/users/orta/subscriptions\",\n            \"organizations_url\": \"https://api.github.com/users/orta/orgs\",\n            \"repos_url\": \"https://api.github.com/users/orta/repos\",\n            \"events_url\": \"https://api.github.com/users/orta/events{/privacy}\",\n            \"received_events_url\": \"https://api.github.com/users/orta/received_events\",\n            \"type\": \"User\",\n            \"site_admin\": false\n          },\n          \"assignees\": [\n            {\n              \"login\": \"orta\",\n              \"id\": 49038,\n              \"avatar_url\": \"https://avatars2.githubusercontent.com/u/49038?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/orta\",\n              \"html_url\": \"https://github.com/orta\",\n              \"followers_url\": \"https://api.github.com/users/orta/followers\",\n              \"following_url\": \"https://api.github.com/users/orta/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/orta/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/orta/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/orta/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/orta/orgs\",\n              \"repos_url\": \"https://api.github.com/users/orta/repos\",\n              \"events_url\": \"https://api.github.com/users/orta/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/orta/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            }\n          ],\n          \"milestone\": {\n                \"url\": \"https://api.github.com/repos/octocat/Hello-World/milestones/1\",\n                \"html_url\": \"https://github.com/octocat/Hello-World/milestones/v1.0\",\n                \"labels_url\": \"https://api.github.com/repos/octocat/Hello-World/milestones/1/labels\",\n                \"id\": 1002604,\n                \"number\": 1,\n                \"state\": \"open\",\n                \"title\": \"v1.0\",\n                \"description\": \"Tracking milestone for version 1.0\",\n                \"creator\": {\n                    \"login\": \"octocat\",\n                    \"id\": 1,\n                    \"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\",\n                    \"gravatar_id\": \"\",\n                    \"url\": \"https://api.github.com/users/octocat\",\n                    \"html_url\": \"https://github.com/octocat\",\n                    \"followers_url\": \"https://api.github.com/users/octocat/followers\",\n                    \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\",\n                    \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\",\n                    \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\",\n                    \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\",\n                    \"organizations_url\": \"https://api.github.com/users/octocat/orgs\",\n                    \"repos_url\": \"https://api.github.com/users/octocat/repos\",\n                    \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\",\n                    \"received_events_url\": \"https://api.github.com/users/octocat/received_events\",\n                    \"type\": \"User\",\n                    \"site_admin\": false\n                },\n                \"open_issues\": 4,\n                \"closed_issues\": 8,\n                \"created_at\": \"2011-04-10T20:09:31Z\",\n                \"updated_at\": \"2014-03-03T18:58:10Z\",\n                \"closed_at\": \"2013-02-12T13:22:01Z\",\n                \"due_on\": \"2012-10-09T23:39:01Z\"\n            },\n          \"comments\": 8,\n          \"created_at\": \"2016-07-26T19:57:30Z\",\n          \"updated_at\": \"2016-08-17T15:26:14Z\",\n          \"closed_at\": \"2016-08-17T15:26:14Z\",\n          \"author_association\": \"MEMBER\",\n          \"pull_request\": {\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/pulls/609\",\n            \"html_url\": \"https://github.com/artsy/eidolon/pull/609\",\n            \"diff_url\": \"https://github.com/artsy/eidolon/pull/609.diff\",\n            \"patch_url\": \"https://github.com/artsy/eidolon/pull/609.patch\"\n          },\n          \"body\": \"PR_DESCRIPTION_CONTENT\",\n          \"closed_by\": {\n            \"login\": \"ashfurrow\",\n            \"id\": 498212,\n            \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n            \"gravatar_id\": \"\",\n            \"url\": \"https://api.github.com/users/ashfurrow\",\n            \"html_url\": \"https://github.com/ashfurrow\",\n            \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n            \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n            \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n            \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n            \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n            \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n            \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n            \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n            \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n            \"type\": \"User\",\n            \"site_admin\": false\n          }\n        },\n        \"pr\": {\n          \"url\": \"https://api.github.com/repos/artsy/eidolon/pulls/609\",\n          \"id\": 78914852,\n          \"html_url\": \"https://github.com/artsy/eidolon/pull/609\",\n          \"diff_url\": \"https://github.com/artsy/eidolon/pull/609.diff\",\n          \"patch_url\": \"https://github.com/artsy/eidolon/pull/609.patch\",\n          \"issue_url\": \"https://api.github.com/repos/artsy/eidolon/issues/609\",\n          \"number\": 609,\n          \"state\": \"closed\",\n          \"locked\": false,\n          \"title\": \"PR_TITLE\",\n          \"user\": {\n            \"login\": \"ashfurrow\",\n            \"id\": 498212,\n            \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n            \"gravatar_id\": \"\",\n            \"url\": \"https://api.github.com/users/ashfurrow\",\n            \"html_url\": \"https://github.com/ashfurrow\",\n            \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n            \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n            \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n            \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n            \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n            \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n            \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n            \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n            \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n            \"type\": \"User\",\n            \"site_admin\": false\n          },\n          \"body\": \"PR_DESCRIPTION_CONTENT\",\n          \"created_at\": \"2016-07-26T19:57:30Z\",\n          \"updated_at\": \"2016-08-17T15:26:15Z\",\n          \"closed_at\": \"2016-08-17T15:26:14Z\",\n          \"merged_at\": \"2016-08-17T15:26:14Z\",\n          \"merge_commit_sha\": \"e80bc6c78cd2f3524577e1401d7a460feba7a26c\",\n          \"assignee\": {\n            \"login\": \"orta\",\n            \"id\": 49038,\n            \"avatar_url\": \"https://avatars2.githubusercontent.com/u/49038?v=4\",\n            \"gravatar_id\": \"\",\n            \"url\": \"https://api.github.com/users/orta\",\n            \"html_url\": \"https://github.com/orta\",\n            \"followers_url\": \"https://api.github.com/users/orta/followers\",\n            \"following_url\": \"https://api.github.com/users/orta/following{/other_user}\",\n            \"gists_url\": \"https://api.github.com/users/orta/gists{/gist_id}\",\n            \"starred_url\": \"https://api.github.com/users/orta/starred{/owner}{/repo}\",\n            \"subscriptions_url\": \"https://api.github.com/users/orta/subscriptions\",\n            \"organizations_url\": \"https://api.github.com/users/orta/orgs\",\n            \"repos_url\": \"https://api.github.com/users/orta/repos\",\n            \"events_url\": \"https://api.github.com/users/orta/events{/privacy}\",\n            \"received_events_url\": \"https://api.github.com/users/orta/received_events\",\n            \"type\": \"User\",\n            \"site_admin\": false\n          },\n          \"assignees\": [\n            {\n              \"login\": \"orta\",\n              \"id\": 49038,\n              \"avatar_url\": \"https://avatars2.githubusercontent.com/u/49038?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/orta\",\n              \"html_url\": \"https://github.com/orta\",\n              \"followers_url\": \"https://api.github.com/users/orta/followers\",\n              \"following_url\": \"https://api.github.com/users/orta/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/orta/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/orta/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/orta/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/orta/orgs\",\n              \"repos_url\": \"https://api.github.com/users/orta/repos\",\n              \"events_url\": \"https://api.github.com/users/orta/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/orta/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            }\n          ],\n          \"requested_reviewers\": [],\n          \"milestone\": null,\n          \"commits_url\": \"https://api.github.com/repos/artsy/eidolon/pulls/609/commits\",\n          \"review_comments_url\": \"https://api.github.com/repos/artsy/eidolon/pulls/609/comments\",\n          \"review_comment_url\": \"https://api.github.com/repos/artsy/eidolon/pulls/comments{/number}\",\n          \"comments_url\": \"https://api.github.com/repos/artsy/eidolon/issues/609/comments\",\n          \"statuses_url\":\n            \"https://api.github.com/repos/artsy/eidolon/statuses/d769f276e066d79169a8bfa5795c8a4853f942f3\",\n          \"head\": {\n            \"label\": \"artsy:xcode-update\",\n            \"ref\": \"xcode-update\",\n            \"sha\": \"d769f276e066d79169a8bfa5795c8a4853f942f3\",\n            \"user\": {\n              \"login\": \"artsy\",\n              \"id\": 546231,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/546231?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/artsy\",\n              \"html_url\": \"https://github.com/artsy\",\n              \"followers_url\": \"https://api.github.com/users/artsy/followers\",\n              \"following_url\": \"https://api.github.com/users/artsy/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/artsy/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/artsy/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/artsy/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/artsy/orgs\",\n              \"repos_url\": \"https://api.github.com/users/artsy/repos\",\n              \"events_url\": \"https://api.github.com/users/artsy/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/artsy/received_events\",\n              \"type\": \"Organization\",\n              \"site_admin\": false\n            },\n            \"repo\": {\n              \"id\": 22613546,\n              \"name\": \"eidolon\",\n              \"full_name\": \"artsy/eidolon\",\n              \"owner\": {\n                \"login\": \"artsy\",\n                \"id\": 546231,\n                \"avatar_url\": \"https://avatars3.githubusercontent.com/u/546231?v=4\",\n                \"gravatar_id\": \"\",\n                \"url\": \"https://api.github.com/users/artsy\",\n                \"html_url\": \"https://github.com/artsy\",\n                \"followers_url\": \"https://api.github.com/users/artsy/followers\",\n                \"following_url\": \"https://api.github.com/users/artsy/following{/other_user}\",\n                \"gists_url\": \"https://api.github.com/users/artsy/gists{/gist_id}\",\n                \"starred_url\": \"https://api.github.com/users/artsy/starred{/owner}{/repo}\",\n                \"subscriptions_url\": \"https://api.github.com/users/artsy/subscriptions\",\n                \"organizations_url\": \"https://api.github.com/users/artsy/orgs\",\n                \"repos_url\": \"https://api.github.com/users/artsy/repos\",\n                \"events_url\": \"https://api.github.com/users/artsy/events{/privacy}\",\n                \"received_events_url\": \"https://api.github.com/users/artsy/received_events\",\n                \"type\": \"Organization\",\n                \"site_admin\": false\n              },\n              \"private\": false,\n              \"html_url\": \"https://github.com/artsy/eidolon\",\n              \"description\": \"The Artsy Auction Kiosk App\",\n              \"fork\": false,\n              \"url\": \"https://api.github.com/repos/artsy/eidolon\",\n              \"forks_url\": \"https://api.github.com/repos/artsy/eidolon/forks\",\n              \"keys_url\": \"https://api.github.com/repos/artsy/eidolon/keys{/key_id}\",\n              \"collaborators_url\": \"https://api.github.com/repos/artsy/eidolon/collaborators{/collaborator}\",\n              \"teams_url\": \"https://api.github.com/repos/artsy/eidolon/teams\",\n              \"hooks_url\": \"https://api.github.com/repos/artsy/eidolon/hooks\",\n              \"issue_events_url\": \"https://api.github.com/repos/artsy/eidolon/issues/events{/number}\",\n              \"events_url\": \"https://api.github.com/repos/artsy/eidolon/events\",\n              \"assignees_url\": \"https://api.github.com/repos/artsy/eidolon/assignees{/user}\",\n              \"branches_url\": \"https://api.github.com/repos/artsy/eidolon/branches{/branch}\",\n              \"tags_url\": \"https://api.github.com/repos/artsy/eidolon/tags\",\n              \"blobs_url\": \"https://api.github.com/repos/artsy/eidolon/git/blobs{/sha}\",\n              \"git_tags_url\": \"https://api.github.com/repos/artsy/eidolon/git/tags{/sha}\",\n              \"git_refs_url\": \"https://api.github.com/repos/artsy/eidolon/git/refs{/sha}\",\n              \"trees_url\": \"https://api.github.com/repos/artsy/eidolon/git/trees{/sha}\",\n              \"statuses_url\": \"https://api.github.com/repos/artsy/eidolon/statuses/{sha}\",\n              \"languages_url\": \"https://api.github.com/repos/artsy/eidolon/languages\",\n              \"stargazers_url\": \"https://api.github.com/repos/artsy/eidolon/stargazers\",\n              \"contributors_url\": \"https://api.github.com/repos/artsy/eidolon/contributors\",\n              \"subscribers_url\": \"https://api.github.com/repos/artsy/eidolon/subscribers\",\n              \"subscription_url\": \"https://api.github.com/repos/artsy/eidolon/subscription\",\n              \"commits_url\": \"https://api.github.com/repos/artsy/eidolon/commits{/sha}\",\n              \"git_commits_url\": \"https://api.github.com/repos/artsy/eidolon/git/commits{/sha}\",\n              \"comments_url\": \"https://api.github.com/repos/artsy/eidolon/comments{/number}\",\n              \"issue_comment_url\": \"https://api.github.com/repos/artsy/eidolon/issues/comments{/number}\",\n              \"contents_url\": \"https://api.github.com/repos/artsy/eidolon/contents/{+path}\",\n              \"compare_url\": \"https://api.github.com/repos/artsy/eidolon/compare/{base}...{head}\",\n              \"merges_url\": \"https://api.github.com/repos/artsy/eidolon/merges\",\n              \"archive_url\": \"https://api.github.com/repos/artsy/eidolon/{archive_format}{/ref}\",\n              \"downloads_url\": \"https://api.github.com/repos/artsy/eidolon/downloads\",\n              \"issues_url\": \"https://api.github.com/repos/artsy/eidolon/issues{/number}\",\n              \"pulls_url\": \"https://api.github.com/repos/artsy/eidolon/pulls{/number}\",\n              \"milestones_url\": \"https://api.github.com/repos/artsy/eidolon/milestones{/number}\",\n              \"notifications_url\": \"https://api.github.com/repos/artsy/eidolon/notifications{?since,all,participating}\",\n              \"labels_url\": \"https://api.github.com/repos/artsy/eidolon/labels{/name}\",\n              \"releases_url\": \"https://api.github.com/repos/artsy/eidolon/releases{/id}\",\n              \"deployments_url\": \"https://api.github.com/repos/artsy/eidolon/deployments\",\n              \"created_at\": \"2014-08-04T17:38:26Z\",\n              \"updated_at\": \"2017-10-24T08:59:48Z\",\n              \"pushed_at\": \"2017-09-22T21:03:37Z\",\n              \"git_url\": \"git://github.com/artsy/eidolon.git\",\n              \"ssh_url\": \"git@github.com:artsy/eidolon.git\",\n              \"clone_url\": \"https://github.com/artsy/eidolon.git\",\n              \"svn_url\": \"https://github.com/artsy/eidolon\",\n              \"homepage\": \"http://artsy.github.io/blog/2014/11/13/eidolon-retrospective/\",\n              \"size\": 135512,\n              \"stargazers_count\": 1999,\n              \"watchers_count\": 1999,\n              \"language\": \"Swift\",\n              \"has_issues\": true,\n              \"has_projects\": true,\n              \"has_downloads\": true,\n              \"has_wiki\": false,\n              \"has_pages\": false,\n              \"forks_count\": 267,\n              \"mirror_url\": null,\n              \"archived\": false,\n              \"open_issues_count\": 35,\n              \"forks\": 267,\n              \"open_issues\": 35,\n              \"watchers\": 1999,\n              \"default_branch\": \"master\"\n            }\n          },\n          \"base\": {\n            \"label\": \"artsy:master\",\n            \"ref\": \"master\",\n            \"sha\": \"68c8db83776c1942145f530159a3fffddb812577\",\n            \"user\": {\n              \"login\": \"artsy\",\n              \"id\": 546231,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/546231?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/artsy\",\n              \"html_url\": \"https://github.com/artsy\",\n              \"followers_url\": \"https://api.github.com/users/artsy/followers\",\n              \"following_url\": \"https://api.github.com/users/artsy/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/artsy/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/artsy/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/artsy/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/artsy/orgs\",\n              \"repos_url\": \"https://api.github.com/users/artsy/repos\",\n              \"events_url\": \"https://api.github.com/users/artsy/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/artsy/received_events\",\n              \"type\": \"Organization\",\n              \"site_admin\": false\n            },\n            \"repo\": {\n              \"id\": 22613546,\n              \"name\": \"eidolon\",\n              \"full_name\": \"artsy/eidolon\",\n              \"owner\": {\n                \"login\": \"artsy\",\n                \"id\": 546231,\n                \"avatar_url\": \"https://avatars3.githubusercontent.com/u/546231?v=4\",\n                \"gravatar_id\": \"\",\n                \"url\": \"https://api.github.com/users/artsy\",\n                \"html_url\": \"https://github.com/artsy\",\n                \"followers_url\": \"https://api.github.com/users/artsy/followers\",\n                \"following_url\": \"https://api.github.com/users/artsy/following{/other_user}\",\n                \"gists_url\": \"https://api.github.com/users/artsy/gists{/gist_id}\",\n                \"starred_url\": \"https://api.github.com/users/artsy/starred{/owner}{/repo}\",\n                \"subscriptions_url\": \"https://api.github.com/users/artsy/subscriptions\",\n                \"organizations_url\": \"https://api.github.com/users/artsy/orgs\",\n                \"repos_url\": \"https://api.github.com/users/artsy/repos\",\n                \"events_url\": \"https://api.github.com/users/artsy/events{/privacy}\",\n                \"received_events_url\": \"https://api.github.com/users/artsy/received_events\",\n                \"type\": \"Organization\",\n                \"site_admin\": false\n              },\n              \"private\": false,\n              \"html_url\": \"https://github.com/artsy/eidolon\",\n              \"description\": \"The Artsy Auction Kiosk App\",\n              \"fork\": false,\n              \"url\": \"https://api.github.com/repos/artsy/eidolon\",\n              \"forks_url\": \"https://api.github.com/repos/artsy/eidolon/forks\",\n              \"keys_url\": \"https://api.github.com/repos/artsy/eidolon/keys{/key_id}\",\n              \"collaborators_url\": \"https://api.github.com/repos/artsy/eidolon/collaborators{/collaborator}\",\n              \"teams_url\": \"https://api.github.com/repos/artsy/eidolon/teams\",\n              \"hooks_url\": \"https://api.github.com/repos/artsy/eidolon/hooks\",\n              \"issue_events_url\": \"https://api.github.com/repos/artsy/eidolon/issues/events{/number}\",\n              \"events_url\": \"https://api.github.com/repos/artsy/eidolon/events\",\n              \"assignees_url\": \"https://api.github.com/repos/artsy/eidolon/assignees{/user}\",\n              \"branches_url\": \"https://api.github.com/repos/artsy/eidolon/branches{/branch}\",\n              \"tags_url\": \"https://api.github.com/repos/artsy/eidolon/tags\",\n              \"blobs_url\": \"https://api.github.com/repos/artsy/eidolon/git/blobs{/sha}\",\n              \"git_tags_url\": \"https://api.github.com/repos/artsy/eidolon/git/tags{/sha}\",\n              \"git_refs_url\": \"https://api.github.com/repos/artsy/eidolon/git/refs{/sha}\",\n              \"trees_url\": \"https://api.github.com/repos/artsy/eidolon/git/trees{/sha}\",\n              \"statuses_url\": \"https://api.github.com/repos/artsy/eidolon/statuses/{sha}\",\n              \"languages_url\": \"https://api.github.com/repos/artsy/eidolon/languages\",\n              \"stargazers_url\": \"https://api.github.com/repos/artsy/eidolon/stargazers\",\n              \"contributors_url\": \"https://api.github.com/repos/artsy/eidolon/contributors\",\n              \"subscribers_url\": \"https://api.github.com/repos/artsy/eidolon/subscribers\",\n              \"subscription_url\": \"https://api.github.com/repos/artsy/eidolon/subscription\",\n              \"commits_url\": \"https://api.github.com/repos/artsy/eidolon/commits{/sha}\",\n              \"git_commits_url\": \"https://api.github.com/repos/artsy/eidolon/git/commits{/sha}\",\n              \"comments_url\": \"https://api.github.com/repos/artsy/eidolon/comments{/number}\",\n              \"issue_comment_url\": \"https://api.github.com/repos/artsy/eidolon/issues/comments{/number}\",\n              \"contents_url\": \"https://api.github.com/repos/artsy/eidolon/contents/{+path}\",\n              \"compare_url\": \"https://api.github.com/repos/artsy/eidolon/compare/{base}...{head}\",\n              \"merges_url\": \"https://api.github.com/repos/artsy/eidolon/merges\",\n              \"archive_url\": \"https://api.github.com/repos/artsy/eidolon/{archive_format}{/ref}\",\n              \"downloads_url\": \"https://api.github.com/repos/artsy/eidolon/downloads\",\n              \"issues_url\": \"https://api.github.com/repos/artsy/eidolon/issues{/number}\",\n              \"pulls_url\": \"https://api.github.com/repos/artsy/eidolon/pulls{/number}\",\n              \"milestones_url\": \"https://api.github.com/repos/artsy/eidolon/milestones{/number}\",\n              \"notifications_url\": \"https://api.github.com/repos/artsy/eidolon/notifications{?since,all,participating}\",\n              \"labels_url\": \"https://api.github.com/repos/artsy/eidolon/labels{/name}\",\n              \"releases_url\": \"https://api.github.com/repos/artsy/eidolon/releases{/id}\",\n              \"deployments_url\": \"https://api.github.com/repos/artsy/eidolon/deployments\",\n              \"created_at\": \"2014-08-04T17:38:26Z\",\n              \"updated_at\": \"2017-10-24T08:59:48Z\",\n              \"pushed_at\": \"2017-09-22T21:03:37Z\",\n              \"git_url\": \"git://github.com/artsy/eidolon.git\",\n              \"ssh_url\": \"git@github.com:artsy/eidolon.git\",\n              \"clone_url\": \"https://github.com/artsy/eidolon.git\",\n              \"svn_url\": \"https://github.com/artsy/eidolon\",\n              \"homepage\": \"http://artsy.github.io/blog/2014/11/13/eidolon-retrospective/\",\n              \"size\": 135512,\n              \"stargazers_count\": 1999,\n              \"watchers_count\": 1999,\n              \"language\": \"Swift\",\n              \"has_issues\": true,\n              \"has_projects\": true,\n              \"has_downloads\": true,\n              \"has_wiki\": false,\n              \"has_pages\": false,\n              \"forks_count\": 267,\n              \"mirror_url\": null,\n              \"archived\": false,\n              \"open_issues_count\": 35,\n              \"forks\": 267,\n              \"open_issues\": 35,\n              \"watchers\": 1999,\n              \"default_branch\": \"master\"\n            }\n          },\n          \"_links\": {\n            \"self\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/pulls/609\"\n            },\n            \"html\": {\n              \"href\": \"https://github.com/artsy/eidolon/pull/609\"\n            },\n            \"issue\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/issues/609\"\n            },\n            \"comments\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/issues/609/comments\"\n            },\n            \"review_comments\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/pulls/609/comments\"\n            },\n            \"review_comment\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/pulls/comments{/number}\"\n            },\n            \"commits\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/pulls/609/commits\"\n            },\n            \"statuses\": {\n              \"href\": \"https://api.github.com/repos/artsy/eidolon/statuses/d769f276e066d79169a8bfa5795c8a4853f942f3\"\n            }\n          },\n          \"author_association\": \"MEMBER\",\n          \"merged\": true,\n          \"mergeable\": null,\n          \"rebaseable\": null,\n          \"mergeable_state\": \"unknown\",\n          \"merged_by\": {\n            \"login\": \"ashfurrow\",\n            \"id\": 498212,\n            \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n            \"gravatar_id\": \"\",\n            \"url\": \"https://api.github.com/users/ashfurrow\",\n            \"html_url\": \"https://github.com/ashfurrow\",\n            \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n            \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n            \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n            \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n            \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n            \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n            \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n            \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n            \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n            \"type\": \"User\",\n            \"site_admin\": false\n          },\n          \"comments\": 8,\n          \"review_comments\": 11,\n          \"maintainer_can_modify\": false,\n          \"commits\": 15,\n          \"additions\": 205,\n          \"deletions\": 111,\n          \"changed_files\": 56\n        },\n        \"commits\": [\n          {\n            \"sha\": \"93ae30cf2aee4241c442fb3242543490998cffdb\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-07-26T19:54:16Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-07-26T19:55:00Z\"\n              },\n              \"message\": \"[Xcode] Updates for compatibility with Xcode 7.3.1.\",\n              \"tree\": {\n                \"sha\": \"fb6bc3fda2456c5ff0a4e8f307f24ee73f281fc1\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/fb6bc3fda2456c5ff0a4e8f307f24ee73f281fc1\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/93ae30cf2aee4241c442fb3242543490998cffdb\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXl8AUAAoJEAGZOscENF/tIA8H/Ri9VdHJAzfO1aAtnoQ5W8Kw\\\\n1yYd5BTVnr0nVw95qxBgoRbBLMUIKg0TOPQQa1h7hk6SOr0py6E4HSpCJQq97f8J\\\\nvgeiFHuyfcW/ePSS8WwJbIzTP3xkckvdZIPjXM1KtvzQ1vCoOrOwBxMqH2twoTQk\\\\nuGd5cgfsahUGHcwYA6B4vfkmAGLkOyFVjUzbDgf1nT5CMbPVlbFgss3aEi8Ql81S\\\\ncNjtMGiUm9n3LUG5lMiwOC3898fpE8YYoAPy1CtLuwokGws3Tu9jMSnUCi2Al7KC\\\\nzWMpIS3L2WVoCdhiv2NbXxUDTbaYn8llKGdtzw3QLZ0AL5ZEkuKrxtDQGyimpaw=\\\\n=aGrl\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree fb6bc3fda2456c5ff0a4e8f307f24ee73f281fc1\\\\nparent 68c8db83776c1942145f530159a3fffddb812577\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1469562856 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1469562900 -0400\\\\n\\\\n[Xcode] Updates for compatibility with Xcode 7.3.1.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/93ae30cf2aee4241c442fb3242543490998cffdb\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/93ae30cf2aee4241c442fb3242543490998cffdb\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/93ae30cf2aee4241c442fb3242543490998cffdb/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"68c8db83776c1942145f530159a3fffddb812577\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/68c8db83776c1942145f530159a3fffddb812577\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/68c8db83776c1942145f530159a3fffddb812577\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-07-26T19:55:53Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-07-26T19:55:53Z\"\n              },\n              \"message\": \"[CI] Updates Travis to Xcode 7.3.\",\n              \"tree\": {\n                \"sha\": \"01f7e53a061a1df01e7d6d3a6fb4d2ce9ee0e39a\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/01f7e53a061a1df01e7d6d3a6fb4d2ce9ee0e39a\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXl8BJAAoJEAGZOscENF/tQAcH/0I+QcSDZDEab6mkYSvX88jP\\\\nbd7Y+O/9CGD9srYIVXE8xGSfO4JKU+sQXLiLsN1OKrHVvdH1SUyE+mUKa68s+8dA\\\\nXYo7Ozg3ieL/DearxnCeSkKqIEsVlhvJzbyloWfPwnm9shfgQFnwuBj0A/nMBXBK\\\\nuNfHq9zR7mSe74r1f89FfddWbNmB6z8Ju0GLwLLbnpD1AzB7cTfDgXNjx8Og++LI\\\\n6xGSNmEqApCYdLPhVW71m/FXzSTF71y/j2QzyG6Jr8n0VhRm7YY4q2kZWHE2RsRT\\\\nGIZt1vuFrT8hddsKy0gC3wrrOPn7FOxZWkWvXHzBeuKlDXUD8aOPjm9AEeOBAs8=\\\\n=Xe+7\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 01f7e53a061a1df01e7d6d3a6fb4d2ce9ee0e39a\\\\nparent 93ae30cf2aee4241c442fb3242543490998cffdb\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1469562953 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1469562953 -0400\\\\n\\\\n[CI] Updates Travis to Xcode 7.3.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"93ae30cf2aee4241c442fb3242543490998cffdb\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/93ae30cf2aee4241c442fb3242543490998cffdb\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/93ae30cf2aee4241c442fb3242543490998cffdb\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-07-26T21:17:40Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-07-26T21:17:40Z\"\n              },\n              \"message\": \"[Deps] Updates dependencies for Swift 2.2.\",\n              \"tree\": {\n                \"sha\": \"a30d9d8be16847c33eb50483a653f27475f197a4\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/a30d9d8be16847c33eb50483a653f27475f197a4\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXl9N0AAoJEAGZOscENF/t2dYH/iQP6IdX2P/86gNHmxNcm2n7\\\\n9e84aJ2vlSgBWxiOgRV2mejsz8C/woRvVpa691GCRbWch2j7yzAjIXfmDK8VlxLe\\\\nY98/89fThWcbZIARGRUDFRhnOYMfKWPqDRNV/kwDRTs6I5x/sFKPEAoqO1ldBc9q\\\\nTZmsk3IsnBFH1XoraNkp9Nmc3FC5Mra/9sgtqGHpU2eWksj5LOYUE3BQ7Z5s9NgU\\\\nxptToZfL11Hl4RObSDi12Fzv0prtRHuFW4w1HvxBedgbgD4k531aP3OMPmnecNcO\\\\n3F8U/xVS/jstKP3ODtKc9HggIEp6mrE97xqBqnCzN0gQUkaLS3TofeG5eqn9DE0=\\\\n=uqge\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree a30d9d8be16847c33eb50483a653f27475f197a4\\\\nparent 4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1469567860 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1469567860 -0400\\\\n\\\\n[Deps] Updates dependencies for Swift 2.2.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/4cf1e41f72516a4135f1738c47f7dd3d421ff3c4\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-15T20:41:00Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-15T20:41:00Z\"\n              },\n              \"message\": \"[Tests] Cleans up snapshot tests for Xcode 7.3.1.\",\n              \"tree\": {\n                \"sha\": \"74f18cfa9f377497c46295e5bc254556a9eb159f\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/74f18cfa9f377497c46295e5bc254556a9eb159f\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXsijcAAoJEAGZOscENF/tfzoIAI5sUJAnv8qkMKf9u2CEhhQd\\\\nJ4uUoKeWbObIXx++ps6y3LjyC6h7rxW06wOGZBrFwTseljmIvV7OYspXGNwNOia7\\\\n1nSSRl5d6193wu4FdQdrlrss2Kwbh9PMIeDFQBhEedrDwB6xi+eu/DeFk3jusrIJ\\\\njMcQtC5sp3o5Psdit2zxnwEnbMMoZ31iFd2dY50H6m6MvCaUyNVXJ5QcJccYHYc5\\\\nNLxsCgwkG4ONASjPBRyzwvTVJ82+Aghck6mffdylAILELAR8DH+Z/K2ciqxcEBG4\\\\nAPqh+P08Oxj4CUZcEWUaYKeBMJRQ1KJ2rvCtH4fTjFg/xzZS1jI2ckeuNehkRtI=\\\\n=LzG3\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 74f18cfa9f377497c46295e5bc254556a9eb159f\\\\nparent d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471293660 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471293660 -0400\\\\n\\\\n[Tests] Cleans up snapshot tests for Xcode 7.3.1.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/d0d72ec5b5ee90c2513a8aafb48911ae5bcdf4ac\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"263d74a15e856f563f18864c459167c46c92cf48\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-15T20:42:13Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-15T20:42:13Z\"\n              },\n              \"message\": \"[Tests] Fixes typo, thanks @Gerst20051.\",\n              \"tree\": {\n                \"sha\": \"505840c1fd602e9ce7e44fda47488229aa1284b2\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/505840c1fd602e9ce7e44fda47488229aa1284b2\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/263d74a15e856f563f18864c459167c46c92cf48\",\n              \"comment_count\": 1,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXsiklAAoJEAGZOscENF/ti2QH/1EyaRpCDMxymAfkalCtt9o8\\\\nJWxTJE/SoD5bK9ljLwUsrvM8C3G61MSIqYr3Vn55y5/LLiLUasrLCGE1Io+EUlWb\\\\nxtkd95P2aAyFO9cLspCUU3xm61jSfxVfF3lFNMtH+zrdYmRF21bjyNw9Avh+21um\\\\nHuoDusYiqH92FSrjJzGOrCTn0zpqV7PBDDbocRILDIO98+w8/irfbDZK+up0udzx\\\\nTNoBusGUXoAQ//n+nqH/9c3Dzfl/uZ5chsbeKhM/bkh+MAMDXb+TKSeqUvEzGRGv\\\\nCeL7DTQMsr47WQrNrHHf+vTfhCDVIsJ9P/mdjQNUB4/towT+5HwVO4CJ+KFRgpA=\\\\n=51AP\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 505840c1fd602e9ce7e44fda47488229aa1284b2\\\\nparent c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471293733 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471293733 -0400\\\\n\\\\n[Tests] Fixes typo, thanks @Gerst20051.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/263d74a15e856f563f18864c459167c46c92cf48\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/263d74a15e856f563f18864c459167c46c92cf48\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/263d74a15e856f563f18864c459167c46c92cf48/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/c330e8dfc6ae553a98fb9ffa6347f87d9f00f864\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-15T20:54:06Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-15T20:54:06Z\"\n              },\n              \"message\": \"[Podfile] Adds comment for specific pod commit.\",\n              \"tree\": {\n                \"sha\": \"4589f4905bd0e23710a257ed6560983cbda91838\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/4589f4905bd0e23710a257ed6560983cbda91838\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXsivuAAoJEAGZOscENF/tMV8H/jMqIqotNseYEbpil5nTII9m\\\\nKlxIOw/T/lHkKvTN0/hgXR/xDlXObR349YJYiPoNPAQNJa2TVeZ/PRNYNCcwGx2/\\\\nKtWuU5Fk1yvRW2h0wpq6rEVu/hesz9QeyXYW3esyz6QxWBKvmO8gIIq9mONS8Fz9\\\\nPlB+0ZneYxRwEIOZSyW5gmE1G4q0ZAWqSitfrGpta/c9N3jl/GeSuGFbfPNTFPUy\\\\nboocfJshdJpvEMpdyU05MYFWtxSKp6O0aPgKTqPeO5YCHGPvnPAj2a6N2gQ5TKhp\\\\ndqvzmeljjfZHvAr3Q+dXhHgjUWHHI8FROUTs0Ukssinq/+IrcW3FwauWeBe3l7M=\\\\n=dHWL\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 4589f4905bd0e23710a257ed6560983cbda91838\\\\nparent 263d74a15e856f563f18864c459167c46c92cf48\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471294446 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471294446 -0400\\\\n\\\\n[Podfile] Adds comment for specific pod commit.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"263d74a15e856f563f18864c459167c46c92cf48\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/263d74a15e856f563f18864c459167c46c92cf48\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/263d74a15e856f563f18864c459167c46c92cf48\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-16T23:23:51Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-16T23:23:51Z\"\n              },\n              \"message\": \"[CI] Fix for intermittent CI failures.\",\n              \"tree\": {\n                \"sha\": \"e31f2c677fd09e21e2a056853a9f722c8f6a6c69\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/e31f2c677fd09e21e2a056853a9f722c8f6a6c69\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\n\\\\niQEcBAABAgAGBQJXs6CHAAoJEAGZOscENF/t0I8H/3CIBRZQXX3BB6xRb+J89BWN\\\\nPjWQ1xiW63N6Y9yrIRjZGMov9QeCo3hv9b/sMF2fjwc7NblVL/SjPhStl07uAHGY\\\\nZ9E5Rd1b8Df1DMhEKGqIf0Ne3vMuYfUrrUUwlLXwPy3BXZQNUTlQa08DKXKHb9h0\\\\nrNEhP5WLS5+ycottr7d4tngzJXTBIUyjOYc7qES8+NAHwGm0wiGabvaPuUrcsjPz\\\\nyLvuHxb8e6VVrTH/8OE/On3g546ZDJUEmM5wA8XLkgb0F70vNfU2whNvdBD1shsJ\\\\nBXbQUOL5FjpLbSqcLbAQCIgyfza4SYWD7XUZoMIoVbIVgRe3g/E9oN9+n7y/4fE=\\\\n=2sLb\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree e31f2c677fd09e21e2a056853a9f722c8f6a6c69\\\\nparent b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471389831 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471389831 -0400\\\\n\\\\n[CI] Fix for intermittent CI failures.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/31b4eccb1bba8510485d468a0b73221eead2b0f0/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/b71e4f62e248f2ca166582c4c9a6f15e14eaa15f\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"db2af03f247bec4d12a3e743b4464a70501fac77\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T13:34:47Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T13:34:47Z\"\n              },\n              \"message\": \"[Ruby] Adds version-specifier.\",\n              \"tree\": {\n                \"sha\": \"9226b26bd2cc9f6e50076badff8229bec8ff818b\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/9226b26bd2cc9f6e50076badff8229bec8ff818b\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/db2af03f247bec4d12a3e743b4464a70501fac77\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtGf3AAoJEAGZOscENF/t+wQH+wRvEVBk8csaPgPgG5FdvVw0\\\\nftpSAuYLkJnhouPaERzUc2fW7Aiy9b94KFKtX9FG1Ix8ynBMTprxDdSiZNb/B2Fs\\\\ns2wrTCtUaiKhiP2YOhUku1rMTSR3PGZ1Ixhqumog0FSnDhqWVjOxuSgFL+E5P++S\\\\n8sZjOKVBIsHI4Uun/xQZCXrUpxda0B99GA2mDnxKkkh2oauAwN+K+v6SI6BNastJ\\\\nR+cX4SJWQaP3/TMVbGMXjsiu+8t3R1UXA89pIdk2GA0WGLBhnlecVCJZ2V3bKNvg\\\\ntaxpKE/PDCFmoqRT1iJlpbRgon9HEEuVx3PP2zKfuVuioG7w+lDZjy5B7aEZHYo=\\\\n=HST1\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 9226b26bd2cc9f6e50076badff8229bec8ff818b\\\\nparent 31b4eccb1bba8510485d468a0b73221eead2b0f0\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471440887 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471440887 -0400\\\\n\\\\n[Ruby] Adds version-specifier.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/db2af03f247bec4d12a3e743b4464a70501fac77\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/db2af03f247bec4d12a3e743b4464a70501fac77\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/db2af03f247bec4d12a3e743b4464a70501fac77/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/31b4eccb1bba8510485d468a0b73221eead2b0f0\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/31b4eccb1bba8510485d468a0b73221eead2b0f0\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T13:42:29Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T13:42:29Z\"\n              },\n              \"message\": \"[CI] Split up failing test + switch to syncrhonous testing.\",\n              \"tree\": {\n                \"sha\": \"64bc098d18f98b3363e7a02fefba816140e17b8f\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/64bc098d18f98b3363e7a02fefba816140e17b8f\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtGnFAAoJEAGZOscENF/tt8cH/iJrA3IkA9qOspPV1Ar+S/+4\\\\nUrP0IcXbk3E7CPamdWJwl2d2bRSn99Qpc7BkE1tLEFfdccAceq5A5RnHESoC2U8D\\\\nZ62Z1EMgnzbApr/qp6xulDtqpmhvbbMOoLOCODK2tLpY35HTw+RrmjZ4Zn6ApxvH\\\\namwVVUprHSNuPF7kF+GaKw8W9cCw3zmjRpDQPnvKqzxqFrCkAR0FWslfhjyhdybD\\\\n9YtEGsngEyVqhlcIev06W+POAbfzdVPhKP9wKq5MQF/zsPVHbMUvU/Yv9CRbTzoa\\\\n9FQqe4PcGQg+AEP9XGZ3AXCftcDB0PKZrMoJpBujg20yyFluCVUVrBHDXz7KqpU=\\\\n=6wcW\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 64bc098d18f98b3363e7a02fefba816140e17b8f\\\\nparent db2af03f247bec4d12a3e743b4464a70501fac77\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471441349 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471441349 -0400\\\\n\\\\n[CI] Split up failing test + switch to syncrhonous testing.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/57b041fbbbebd075f7fe186fb754cf7cce85519c/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"db2af03f247bec4d12a3e743b4464a70501fac77\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/db2af03f247bec4d12a3e743b4464a70501fac77\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/db2af03f247bec4d12a3e743b4464a70501fac77\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T13:48:43Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T13:58:30Z\"\n              },\n              \"message\": \"[CI] Fixes pre-launching simulator UUID.\",\n              \"tree\": {\n                \"sha\": \"9cbec8e2436334ac71c0254ff34595d24cf1c134\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/9cbec8e2436334ac71c0254ff34595d24cf1c134\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtG2GAAoJEAGZOscENF/t+aEH/jeWQCppcnOsPt++MtyrkXkZ\\\\nmgnuNTlEO+ujleLrFjKnM/6I1Htv2hdPELqSLN60cYiKvXX/2pJcV2qLrVEVkkEr\\\\njRE2NiGaK+kM4rykmJgM8GGNoFOzbcBmlZMOVCEPmurxUTwI5V2ol7KNKVO8JfUR\\\\nThew4TZA4116MyIytV6jJju86Jsh7d6CEWcm99GV3yILACmipcReLd64jpsTL9lJ\\\\nkiEA9DynuC7c5uzKlhWbqQ3DHPRns55HKq8XL485OXupuRvqBkDRQ+Nz7nq2qMAB\\\\nVtPWz4OayZcYWfUqagbb9k+vQ9prePrUrVdQL5kJxFx9TQQSM5NaL5bCwl7CenQ=\\\\n=Xeq4\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 9cbec8e2436334ac71c0254ff34595d24cf1c134\\\\nparent 57b041fbbbebd075f7fe186fb754cf7cce85519c\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471441723 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471442310 -0400\\\\n\\\\n[CI] Fixes pre-launching simulator UUID.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/851e911b4e8697a0f8e3b84c19df6cec30aead2a/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/57b041fbbbebd075f7fe186fb754cf7cce85519c\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/57b041fbbbebd075f7fe186fb754cf7cce85519c\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:10:05Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:10:05Z\"\n              },\n              \"message\": \"[CI] Fixes intermittently failing test comparing dates.\",\n              \"tree\": {\n                \"sha\": \"2ab689baa382cc918289529955121d17672db7a4\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/2ab689baa382cc918289529955121d17672db7a4\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtHA9AAoJEAGZOscENF/tEmMH/01CQiUbjR1nSrsah3gyFe0S\\\\nJUSXip0aMniLDdkKht/x457w5nmujXjpoOrcbB02G+5q142Psv4otc28lg0XWZCi\\\\ns4Gg5acpZRV/d+Dw0ruOnwGwcz+KPvmD9Pfx1F8h/q519Qmhto6rw3na8uMLG4Zr\\\\ndYS79EcVCceU2BkpTl2PlEe7lIJmUqEv7WJYyH+//Wu7EQfor/Mu0VijwmDx3Nxi\\\\n6NvaPPzayk/lpj4s02vvdfqvl/+mVZ5N3PHTLoDJb8VlJs49C5tGEwhsUjKHqAfF\\\\nwBfFIJEkcqbgrOM7NoHmGjlAiGpWhCc6CuFmsCWMTfo/Vay/VQOtP8B/S5jA9R4=\\\\n=V+Iy\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 2ab689baa382cc918289529955121d17672db7a4\\\\nparent 851e911b4e8697a0f8e3b84c19df6cec30aead2a\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471443005 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471443005 -0400\\\\n\\\\n[CI] Fixes intermittently failing test comparing dates.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/851e911b4e8697a0f8e3b84c19df6cec30aead2a\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/851e911b4e8697a0f8e3b84c19df6cec30aead2a\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:41:27Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:41:27Z\"\n              },\n              \"message\": \"[Deps] Updates dependencies to latest Swift 2.x versions.\",\n              \"tree\": {\n                \"sha\": \"0ef37421cfa8cbd2d729e58de786b77f6219d3ad\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/0ef37421cfa8cbd2d729e58de786b77f6219d3ad\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtHeXAAoJEAGZOscENF/tyyMH/RITs+ltv0iMgnuslqa2sguo\\\\n7LlkBGzCzgiiMh0LRrdeOLlL3/XRj5n/bw3ABY8iO4JDKRgd4XsokArtp60G28Gg\\\\nUCC5XcY8/6Prhgz7xET1GDOSXglwrgvJuxCg7hk20Oui8QRdUXEriWSMwpJyuqSq\\\\nnF8zevD0hHu/v5lMwn6qmiUeF993DOwemzAyydbU6WU4k1Hd+03B9/wk004Df6Mi\\\\nhQVOQLK1D98RqrfM4ZOXIS9YqU/bJ0SiK1OllMD1gjNm3RHEMMeaGSBkTMHoh+JM\\\\nist/zkq2NlxLEQoyeLoOyhM0re/s19qkAQwYCAL146zes53NO3JUR8yTmXXyjwE=\\\\n=DTkl\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 0ef37421cfa8cbd2d729e58de786b77f6219d3ad\\\\nparent 9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471444887 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471444887 -0400\\\\n\\\\n[Deps] Updates dependencies to latest Swift 2.x versions.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/1aa0360bc7a95d7878160ae91eea62324ac3252f/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/9963a5ff97b5dbd423df740c50e01a9dffd0a3ff\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:41:31Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:41:31Z\"\n              },\n              \"message\": \"[CI] Fixes more intermittent tests.\",\n              \"tree\": {\n                \"sha\": \"00271b152921db4988396350eca46ed6b19f6649\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/00271b152921db4988396350eca46ed6b19f6649\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtHebAAoJEAGZOscENF/tpc4IAJO53SzcBv08DG7z0iwZgY0E\\\\nIDiTh7bfvyXrUGP/0nE6n+zLTpDYFHPhWGrlPHn4V/VjZP3ejMWiy4u4qHdlUym0\\\\nREK/pjRCqgcF8nz64DujNOExS/1VLpxv/Ee5dnA4tE7m98yjWwvOEOBmy0IT5BH3\\\\npFwog810/UktH7/Oybe+dJYCDdRPpi9LxBlScm6YNP4ZnBMYmK2UPuivF71yNdYe\\\\n5qoQhSuxSNCrW/1211dB4z3SwbeAKO+SnxA3MKdW2qE92Zx59dQ6h6J5ked0hrlQ\\\\n3r8VfwAT9XHtgAu8SDTTu3kRTb6s80KFkN8C4ZgYog2I8kGafo1wPK+VKEFd/qQ=\\\\n=f2wx\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 00271b152921db4988396350eca46ed6b19f6649\\\\nparent 1aa0360bc7a95d7878160ae91eea62324ac3252f\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471444891 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471444891 -0400\\\\n\\\\n[CI] Fixes more intermittent tests.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/1aa0360bc7a95d7878160ae91eea62324ac3252f\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/1aa0360bc7a95d7878160ae91eea62324ac3252f\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:55:34Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T14:55:34Z\"\n              },\n              \"message\": \"[CI] Removed duplicate simulator launch.\",\n              \"tree\": {\n                \"sha\": \"965807f296e1a3fb30134508062825cf30806786\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/965807f296e1a3fb30134508062825cf30806786\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtHrmAAoJEAGZOscENF/txKwH/i0ESvgDTSI5rhjnTZ/ToLbS\\\\nZFR1P39iGdmsaj/V2kXYPlXZt7DetxHtGIcncP1odJtCtrxOiG8Da9WxmCSUtqCa\\\\nKok4dYVOTRuDeaGBYEUWJmTNRRlAs5JY5vNsC4w3jZjnoelJD17aqupHxHrm5nUl\\\\ntKJ1qt3+qXbNvK1LZZ2U65D1ldyrI03tri0v0Y50sD4VJW5Mj7Nzv8DpmC6MpVqy\\\\nEZMqarkVIjxhzYqVG5Y+Sxu7oDrAujJGO7FwnuMxArek6cHK1oV53/KUrbq+OLLx\\\\nrGL7qvS0bn1gJk7evLTzyUkIw49YoQKKv3MsMYNeyz9f7Hpunk6/ARfDeXc9QHM=\\\\n=1oGo\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 965807f296e1a3fb30134508062825cf30806786\\\\nparent fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471445734 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471445734 -0400\\\\n\\\\n[CI] Removed duplicate simulator launch.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/c6eb849f100cbaa261680ee0d3dc819b91aa8af1/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/fb0688c603ddb48afe0edad336d3a7fac6f5e9f7\"\n              }\n            ]\n          },\n          {\n            \"sha\": \"d769f276e066d79169a8bfa5795c8a4853f942f3\",\n            \"commit\": {\n              \"author\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T15:14:19Z\"\n              },\n              \"committer\": {\n                \"name\": \"Ash Furrow\",\n                \"email\": \"ash@ashfurrow.com\",\n                \"date\": \"2016-08-17T15:20:42Z\"\n              },\n              \"message\": \"[Feedback] Adds clarifying comments as per feedback in #609.\",\n              \"tree\": {\n                \"sha\": \"9004fe3df2b4d7d3285460095c37d9f62b4be26a\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/git/trees/9004fe3df2b4d7d3285460095c37d9f62b4be26a\"\n              },\n              \"url\": \"https://api.github.com/repos/artsy/eidolon/git/commits/d769f276e066d79169a8bfa5795c8a4853f942f3\",\n              \"comment_count\": 0,\n              \"verification\": {\n                \"verified\": true,\n                \"reason\": \"valid\",\n                \"signature\":\n                  \"-----BEGIN PGP SIGNATURE-----\\\\nVersion: GnuPG v1\\\\n\\\\niQEcBAABAgAGBQJXtIDSAAoJEAGZOscENF/t97IIAIpVyF0YdulieeRvqhmG/D9S\\\\nATYdQAyjLbTCVs/ijNU+ZRO7dJpKaetbg93jeKW8uIjrAevu9RR/Y0HKpb0p79Gk\\\\n7SczAaTeADwsX3IU4StOSKG1sS2KZOI2TR9+uYd0O5EcTn5jrfy7GmZBQCgUkuJp\\\\n7a/cqm+5jSH4yaDjV9hrn2HmhfBzOYzW5I+6kfdOhbyQIGTADmyjzfxClAK+7sts\\\\nes52DCOSX3/R/AI6JX/igH9vKcvuN5bYMnoAWI7Ko0AMiWubDY2rzpEl3w3x2ycc\\\\nKRKSNP4NGxq3PU3pfsVzSdFpf8QjvWtGsoZ+yVpq/1hb2PSvMx81CbEJwyf8xoc=\\\\n=RQgX\\\\n-----END PGP SIGNATURE-----\",\n                \"payload\":\n                  \"tree 9004fe3df2b4d7d3285460095c37d9f62b4be26a\\\\nparent c6eb849f100cbaa261680ee0d3dc819b91aa8af1\\\\nauthor Ash Furrow <ash@ashfurrow.com> 1471446859 -0400\\\\ncommitter Ash Furrow <ash@ashfurrow.com> 1471447242 -0400\\\\n\\\\n[Feedback] Adds clarifying comments as per feedback in #609.\\\\n\"\n              }\n            },\n            \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/d769f276e066d79169a8bfa5795c8a4853f942f3\",\n            \"html_url\": \"https://github.com/artsy/eidolon/commit/d769f276e066d79169a8bfa5795c8a4853f942f3\",\n            \"comments_url\":\n              \"https://api.github.com/repos/artsy/eidolon/commits/d769f276e066d79169a8bfa5795c8a4853f942f3/comments\",\n            \"author\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"committer\": {\n              \"login\": \"ashfurrow\",\n              \"id\": 498212,\n              \"avatar_url\": \"https://avatars3.githubusercontent.com/u/498212?v=4\",\n              \"gravatar_id\": \"\",\n              \"url\": \"https://api.github.com/users/ashfurrow\",\n              \"html_url\": \"https://github.com/ashfurrow\",\n              \"followers_url\": \"https://api.github.com/users/ashfurrow/followers\",\n              \"following_url\": \"https://api.github.com/users/ashfurrow/following{/other_user}\",\n              \"gists_url\": \"https://api.github.com/users/ashfurrow/gists{/gist_id}\",\n              \"starred_url\": \"https://api.github.com/users/ashfurrow/starred{/owner}{/repo}\",\n              \"subscriptions_url\": \"https://api.github.com/users/ashfurrow/subscriptions\",\n              \"organizations_url\": \"https://api.github.com/users/ashfurrow/orgs\",\n              \"repos_url\": \"https://api.github.com/users/ashfurrow/repos\",\n              \"events_url\": \"https://api.github.com/users/ashfurrow/events{/privacy}\",\n              \"received_events_url\": \"https://api.github.com/users/ashfurrow/received_events\",\n              \"type\": \"User\",\n              \"site_admin\": false\n            },\n            \"parents\": [\n              {\n                \"sha\": \"c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n                \"url\": \"https://api.github.com/repos/artsy/eidolon/commits/c6eb849f100cbaa261680ee0d3dc819b91aa8af1\",\n                \"html_url\": \"https://github.com/artsy/eidolon/commit/c6eb849f100cbaa261680ee0d3dc819b91aa8af1\"\n              }\n            ]\n          }\n        ],\n        \"reviews\": [],\n        \"requested_reviewers\": {\n          \"users\": [\n                    {\n                    \"login\": \"octocat\",\n                    \"id\": 1,\n                    \"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\",\n                    \"gravatar_id\": \"\",\n                    \"url\": \"https://api.github.com/users/octocat\",\n                    \"html_url\": \"https://github.com/octocat\",\n                    \"followers_url\": \"https://api.github.com/users/octocat/followers\",\n                    \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\",\n                    \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\",\n                    \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\",\n                    \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\",\n                    \"organizations_url\": \"https://api.github.com/users/octocat/orgs\",\n                    \"repos_url\": \"https://api.github.com/users/octocat/repos\",\n                    \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\",\n                    \"received_events_url\": \"https://api.github.com/users/octocat/received_events\",\n                    \"type\": \"User\",\n                    \"site_admin\": false\n                    }\n            ],\n          \"teams\": [\n                    {\n                    \"id\": 1,\n                    \"url\": \"https://api.github.com/teams/1\",\n                    \"name\": \"Justice League\",\n                    \"slug\": \"justice-league\",\n                    \"description\": \"A great team.\",\n                    \"privacy\": \"closed\",\n                    \"permission\": \"admin\",\n                    \"members_url\": \"https://api.github.com/teams/1/members{/member}\",\n                    \"repositories_url\": \"https://api.github.com/teams/1/repos\"\n                    }\n            ]\n        },\n        \"thisPR\": {\n          \"number\": 609,\n          \"repo\": \"eidolon\",\n          \"owner\": \"artsy\"\n        }\n      },\n      \"settings\": {\n        \"github\": {\n          \"accessToken\": \"7bd263f8e4becaa3d29b25d534fe6d5f3b555ccf\",\n          \"additionalHeaders\": {}\n        },\n        \"cliArgs\": {}\n      }\n    }\n}\n\n\"\"\"\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/TestHelpers/TestXcodeSummaryJSON.swift",
    "content": "import Foundation\n\n/// Used for testing the Xcode Summary logic.\npublic let TestXcodeSummaryJSON = \"\"\"\n\n{\n  \"warnings\": [\n\n  ],\n  \"ld_warnings\": [\n    \"ld: linking against a dylib which is not safe for use in application extensions: /Users/antoinevanderlee/Library/Developer/Xcode/DerivedData/Rabbit-ggzydsqyfdvoxobkplrlydytmvsw/Build/Products/Debug-iphonesimulator/Purchases.framework/Purchases\"\n  ],\n  \"compile_warnings\": [\n    {\n      \"file_name\": \"SessionDelegate.swift\",\n      \"file_path\": \"/Users/antoinevanderlee/Documents/GIT-Projects/WeTransfer/Coyote/Submodules/Alamofire/Source/SessionDelegate.swift:554:15\",\n      \"reason\": \"parameter of 'urlSession(_:dataTask:didReceive:)' has different optionality than expected by protocol 'URLSessionDataDelegate'\",\n      \"line\": \"    open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data?) {\",\n      \"cursor\": \"              ^                                                                                    ~\"\n    }\n  ],\n  \"errors\": [\n\n  ],\n  \"compile_errors\": [\n\n  ],\n  \"file_missing_errors\": [\n\n  ],\n  \"undefined_symbols_errors\": [\n\n  ],\n  \"duplicate_symbols_errors\": [\n\n  ],\n  \"tests_failures\": {\n  },\n  \"tests_summary_messages\": [\n    \"\\\\t Executed 964 tests, with 0 failures (0 unexpected) in 135.257 (135.775) seconds\\\\n\"\n  ]\n}\n\n\"\"\"\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/WeTransferLinterTests.swift",
    "content": "@testable import Danger\n@testable import DangerFixtures\nimport Files\n@testable import WeTransferPRLinter\nimport XCTest\n\n// danger:disable unowned_self\n\nfinal class WeTransferLinterTests: XCTestCase {\n    private var buildFolder: Folder!\n\n    override func setUp() {\n        super.setUp()\n        buildFolder = try! Folder.current.createSubfolderIfNeeded(withName: \".filesTest\")\n        try! buildFolder.empty()\n    }\n\n    override func tearDown() {\n        XCTAssertNoThrow(try buildFolder.delete())\n        resetDangerResults()\n        MockedSwiftLintExecutor.lintedFiles = [:]\n        super.tearDown()\n    }\n\n    /// It should not create any warnings or errors if nothing is wrong.\n    func testAllGood() {\n        let danger = githubWithFilesDSL()\n        WeTransferPRLinter.lint(using: danger, swiftLintExecutor: MockedSwiftLintExecutor.self, reportsPath: buildFolder.name)\n\n        XCTAssertEqual(danger.warnings.count, 0)\n        XCTAssertEqual(danger.fails.count, 0)\n    }\n\n    /// It should warn for an empty PR description.\n    func testEmptyPRDescription() {\n        let danger = DangerDSL(testSettings: [\n            .prDescription: \"\"\n        ])\n        WeTransferPRLinter.validatePRDescription(using: danger)\n        XCTAssertEqual(danger.warnings.count, 1)\n        XCTAssertEqual(danger.warnings.first?.message, \"Please provide a summary in the Pull Request description\")\n    }\n\n    /// It should not warn if a PR description is set.\n    func testNonEmptyPRDescription() {\n        let danger = DangerDSL(testSettings: [\n            .prDescription: \"This is a great PR with a lot of fixes\"\n        ])\n        WeTransferPRLinter.validatePRDescription(using: danger)\n        XCTAssertEqual(danger.warnings.count, 0)\n    }\n\n    /// It should warn for work in progress based on the label.\n    func testWorkInProgressLabel() {\n        let danger = DangerDSL(testSettings: [\n            .prLabel: \"WIP\"\n        ])\n        WeTransferPRLinter.validateWorkInProgress(using: danger)\n        XCTAssertEqual(danger.warnings.count, 1)\n        XCTAssertEqual(danger.warnings.first?.message, \"PR is classed as Work in Progress\")\n    }\n\n    /// It should warn for work in progress based on the PR title.\n    func testWorkInProgressTitle() {\n        let danger = DangerDSL(testSettings: [\n            .prTitle: \"A work in progress title [WIP]\"\n        ])\n        WeTransferPRLinter.validateWorkInProgress(using: danger)\n        XCTAssertEqual(danger.warnings.count, 1)\n        XCTAssertEqual(danger.warnings.first?.message, \"PR is classed as Work in Progress\")\n    }\n\n    /// It should show the Bitrise URL if it's set.\n    func testBitriseURL() {\n        let danger = DangerDSL(testSettings: [:])\n        let bitriseURL = \"www.fakeurl.com\"\n        WeTransferPRLinter.showBitriseBuildURL(using: danger, environmentVariables: [\"BITRISE_BUILD_URL\": bitriseURL])\n        XCTAssertEqual(danger.messages.count, 1)\n        XCTAssertEqual(danger.messages.first?.message, \"View more details on <a href=\\\"\\(bitriseURL)\\\" target=\\\"_blank\\\">Bitrise</a>\")\n    }\n\n    /// It should show the Simulator Build Download URL if it's set.\n    func testSimulatorBuildDownloadURL() {\n        let danger = DangerDSL(testSettings: [:])\n        let url = \"https://example.com\"\n        let targetName = \"TargetName\"\n        WeTransferPRLinter.showSimulatorBuildDownloadURL(using: danger, environmentVariables: [\n            \"BITRISE_PERMANENT_DOWNLOAD_URL_MAP\": \"\\(targetName).app.zip=>\\(url)\",\n            \"XCODE_TARGET\": targetName\n        ])\n        XCTAssertEqual(danger.messages.count, 1)\n        XCTAssertEqual(danger.messages.first?.message, \"Download <a href=\\\"\\(url)\\\" target=\\\"_blank\\\">Simulator Build</a>\")\n    }\n\n    func testSwiftLintSkippingIfEnvVariableSet() {\n        let danger = githubWithFilesDSL(created: [\"File.swift\"], fileMap: [:])\n        let mockedSwiftLintExecutor = MockedSwiftLintExecutor.self\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.fileExists = true\n        let customPath = \"/Users/avanderlee/Projects/\"\n        WeTransferPRLinter.swiftLint(\n            using: danger,\n            executor: mockedSwiftLintExecutor,\n            configsFolderPath: customPath,\n            fileManager: stubbedFileManager,\n            environmentVariables: [\"DISABLE_DANGER_SWIFTLINT\": \"true\"]\n        )\n\n        XCTAssertTrue(mockedSwiftLintExecutor.lintedFiles.isEmpty)\n    }\n\n    func testSwiftLintSkippingIfSkipTestsEnvVariableSet() {\n        let danger = githubWithFilesDSL(created: [], fileMap: [:])\n        let mockedSwiftLintExecutor = MockedSwiftLintExecutor.self\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.fileExists = true\n        let customPath = \"/Users/avanderlee/Projects/\"\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: mockedSwiftLintExecutor,\n            reportsPath: \"file://faky/url\",\n            swiftLintConfigsFolderPath: customPath,\n            fileManager: stubbedFileManager,\n            environmentVariables: [\"SKIP_TESTS\": \"true\"]\n        )\n\n        XCTAssertTrue(mockedSwiftLintExecutor.lintedFiles.isEmpty)\n    }\n\n    /// It should not trigger SwiftLint if there's no files to lint.\n    func testSwiftLintSkippingForNoSwiftFiles() {\n        let danger = githubWithFilesDSL(created: [\"Changelog.md\", \"RubyTests.rb\"], fileMap: [:])\n        let mockedSwiftLintExecutor = MockedSwiftLintExecutor.self\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath = \"/Users/tcook/GIT-Projects/WeTransfer\"\n        WeTransferPRLinter.swiftLint(using: danger, executor: mockedSwiftLintExecutor, fileManager: stubbedFileManager)\n\n        XCTAssertEqual(mockedSwiftLintExecutor.lintedFiles, [:])\n    }\n\n    func testSwiftLintBackupConfigsFolder() {\n        let danger = githubWithFilesDSL(created: [\"File.swift\"], fileMap: [:])\n        let mockedSwiftLintExecutor = MockedSwiftLintExecutor.self\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath = \"/Users/tcook/GIT-Projects/WeTransfer\"\n        WeTransferPRLinter.swiftLint(using: danger, executor: mockedSwiftLintExecutor, fileManager: stubbedFileManager)\n\n        XCTAssertEqual(\n            mockedSwiftLintExecutor.lintedFiles.keys.first,\n            \"/Users/tcook/GIT-Projects/WeTransfer/Submodules/WeTransfer-iOS-CI/BuildTools/.swiftlint.yml\"\n        )\n    }\n\n    func testSwiftLintFromGivenConfigsFolder() {\n        let danger = githubWithFilesDSL(created: [\"File.swift\"], fileMap: [:])\n        let mockedSwiftLintExecutor = MockedSwiftLintExecutor.self\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.fileExists = true\n        let customPath = \"/Users/avanderlee/Projects/\"\n        WeTransferPRLinter.swiftLint(\n            using: danger,\n            executor: mockedSwiftLintExecutor,\n            configsFolderPath: customPath,\n            fileManager: stubbedFileManager\n        )\n\n        XCTAssertEqual(mockedSwiftLintExecutor.lintedFiles.keys.first, \"\\(customPath)/.swiftlint.yml\")\n    }\n\n    func testXCResultFileMissing() {\n        let danger = githubWithFilesDSL(created: [], fileMap: [:])\n        WeTransferPRLinter.reportXCResultsSummary(\n            using: danger,\n            summaryReporter: XCResultSummaryReporter.self,\n            reportsPath: \"file://faky/url\",\n            fileManager: .default,\n            environmentVariables: [:]\n        )\n\n        XCTAssertEqual(danger.warnings.count, 0)\n        XCTAssertEqual(danger.messages.count, 0)\n    }\n}\n\nprivate extension URL {\n    /// Creates a copy of the file at the current URL to prevent the original file from being affected.\n    /// Files can get deleted after a test is cleaned up, making future tests fail.\n    func copied() -> URL {\n        guard isFileURL else { fatalError(\"Can't copy a non-file URL\") }\n\n        let destinationDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)\n        try! FileManager.default.createDirectory(at: destinationDirectory, withIntermediateDirectories: false, attributes: nil)\n        let newFileURL = destinationDirectory.appendingPathComponent(lastPathComponent)\n        try! FileManager.default.copyItem(at: self, to: newFileURL)\n        assert(FileManager.default.fileExists(atPath: newFileURL.path), \"Source file should exist\")\n        return newFileURL\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/XCResultSummaryReporterTests.swift",
    "content": "@testable import Danger\n@testable import DangerFixtures\nimport Files\n@testable import WeTransferPRLinter\nimport XCTest\n\n// danger:disable unowned_self\n\nfinal class XCResultSummartReporterTests: XCTestCase {\n    private var buildFolder: Folder!\n\n    override func setUp() {\n        super.setUp()\n        buildFolder = try! Folder.current.createSubfolderIfNeeded(withName: \".filesTest\")\n        try! buildFolder.empty()\n    }\n\n    override func tearDown() {\n        XCTAssertNoThrow(try buildFolder.delete())\n        resetDangerResults()\n        MockedSwiftLintExecutor.lintedFiles = [:]\n        super.tearDown()\n    }\n\n    func testXCResultSummaryReporting() throws {\n        let xcResultFilename = \"Trainer_example_result.xcresult\"\n        let xcResultFile = Bundle.module.url(forResource: \"Resources/\\(xcResultFilename)\", withExtension: nil)!\n        let file = try Folder(path: xcResultFile.deletingLastPathComponent().path).subfolder(named: xcResultFilename)\n        try file.copy(to: buildFolder)\n\n        let danger = githubWithFilesDSL()\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath = \"/Users/josh/Projects/fastlane/\"\n\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: MockedSwiftLintExecutor.self,\n            reportsPath: buildFolder.path,\n            fileManager: stubbedFileManager,\n            environmentVariables: [:]\n        )\n\n        XCTAssertEqual(danger.messages.map(\\.message).prefix(2), [\n            \"TestUITests: Executed 1 tests (0 failed, 0 retried, 0 skipped) in 16.058 seconds\",\n            \"TestThisDude: Executed 6 tests (2 failed, 0 retried, 0 skipped) in 0.534 seconds\"\n        ])\n\n        XCTAssertEqual(danger.warnings.count, 1)\n        XCTAssertEqual(danger.warnings.map(\\.message), [\n            // swiftlint:disable:next line_length\n            \"DEBUG_INFORMATION_FORMAT should be set to dwarf-with-dsym for all configurations. This could also be a timing issue, make sure the Fabric run script build phase is the last build phase and no other scripts have moved the dSYM from the location Xcode generated it. Unable to process Some Test App.app.dSYM at path /Users/josh/Library/Developer/Xcode/DerivedData/Test-appjhtkjaewuhlggerdwreapskfh/Build/Products/Debug-iphonesimulator/Some Test App.app.dSYM\"\n        ])\n        let warning = try XCTUnwrap(danger.warnings.first)\n        XCTAssertNil(warning.file)\n        XCTAssertNil(warning.line)\n\n        XCTAssertEqual(danger.fails.count, 2)\n        let failure = try XCTUnwrap(danger.fails.first)\n        XCTAssertEqual(failure.message, \"**TestTests.testFailureJosh1():**<br/>XCTAssertTrue failed\")\n\n        // This is expected to fail since GitHub currently doesn't support file and line reporting.\n        // This test should succeed again once we re-enable line reporting.\n        XCTExpectFailure {\n            XCTAssertEqual(failure.file, \"test-ios/TestTests/TestTests.swift\")\n            XCTAssertEqual(failure.line, 36)\n        }\n    }\n\n    func testXCResultSummaryReportingFromENV() throws {\n        let xcResultFilename = \"Trainer_example_result.xcresult\"\n        let xcResultFile = Bundle.module.url(forResource: \"Resources/\\(xcResultFilename)\", withExtension: nil)!\n\n        let danger = githubWithFilesDSL()\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath = \"/Users/josh/Projects/fastlane/\"\n\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: MockedSwiftLintExecutor.self,\n            reportsPath: buildFolder.path,\n            fileManager: stubbedFileManager,\n            environmentVariables: [\"BITRISE_TEST_REPORTS_TEST\": xcResultFile.deletingLastPathComponent().path]\n        )\n\n        XCTAssertEqual(danger.messages.map(\\.message).prefix(2), [\n            \"TestUITests: Executed 1 tests (0 failed, 0 retried, 0 skipped) in 16.058 seconds\",\n            \"TestThisDude: Executed 6 tests (2 failed, 0 retried, 0 skipped) in 0.534 seconds\"\n        ])\n    }\n\n    func testSlowestTestsReporting() throws {\n        let xcResultFilename = \"Trainer_example_result.xcresult\"\n        let xcResultFile = Bundle.module.url(forResource: \"Resources/\\(xcResultFilename)\", withExtension: nil)!\n        let file = try Folder(path: xcResultFile.deletingLastPathComponent().path).subfolder(named: xcResultFilename)\n        try file.copy(to: buildFolder)\n\n        let danger = githubWithFilesDSL()\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath = \"/Users/josh/Projects/fastlane/\"\n\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: MockedSwiftLintExecutor.self,\n            reportsPath: buildFolder.path,\n            fileManager: stubbedFileManager,\n            environmentVariables: [:]\n        )\n\n        XCTAssertEqual(danger.messages.map(\\.message).filter { $0.contains(\"Slowest test\") }, [\n            \"Slowest test: TestUITests/testExample() (16.052s)\"\n        ])\n    }\n\n    func testNotReportingRetriedSucceedingTest() throws {\n        let xcResultFilename = \"coverage_fail_flaky_skip_example.xcresult\"\n        let xcResultFile = Bundle.module.url(forResource: \"Resources/\\(xcResultFilename)\", withExtension: nil)!\n        let file = try Folder(path: xcResultFile.deletingLastPathComponent().path).subfolder(named: xcResultFilename)\n        try file.copy(to: buildFolder)\n\n        let danger = githubWithFilesDSL()\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath =\n            \"/Users/avanderlee/Developer/GIT-Projects/WeTransfer/Mule/Submodules/WeTransfer-iOS-CI/WeTransferPRLinter/XCResultGeneratorApp/\"\n\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: MockedSwiftLintExecutor.self,\n            reportsPath: buildFolder.path,\n            fileManager: stubbedFileManager,\n            environmentVariables: [:]\n        )\n\n        XCTAssertEqual(danger.messages.map(\\.message).prefix(1), [\n            \"PRLinterAppTests: Executed 10 tests (1 failed, 1 retried, 1 skipped) in 0.097 seconds\"\n        ], \"It should only report the actual failed test, instead of also the retried succeeded one\")\n\n        XCTAssertEqual(danger.warnings.count, 2)\n        XCTAssertEqual(danger.warnings.map(\\.message), [\n            \"**PRLinterViewModelTests.testFlaky() succeeded after retry:**<br/>XCTAssertTrue failed\",\n            \"**PRLinterViewModelTests/testSkippedExample():**<br/>PRLinterAppTests.swift:32 Test skipped - This test should be skipped\"\n        ], \"It should report a retried test including the retry count\")\n\n        XCTAssertEqual(danger.fails.count, 1)\n        XCTAssertEqual(danger.fails.map(\\.message), [\n            // swiftlint:disable:next line_length\n            \"**PRLinterViewModelTests.testFailingExample():**<br/>XCTAssertEqual failed: (\\\"Antoine and age: 30\\\") is not equal to (\\\"Antoine and age: 22\\\")\"\n        ])\n    }\n\n    func testFilteringWarnings() throws {\n        let xcResultFilename = \"transfer_warnings_example.xcresult\"\n        let xcResultFile = Bundle.module.url(forResource: \"Resources/\\(xcResultFilename)\", withExtension: nil)!\n        let file = try Folder(path: xcResultFile.deletingLastPathComponent().path).subfolder(named: xcResultFilename)\n        try file.copy(to: buildFolder)\n\n        let danger = githubWithFilesDSL()\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath =\n            \"/Users/avanderlee/Developer/GIT-Projects/WeTransfer/Mule/Submodules/WeTransfer-iOS-CI/WeTransferPRLinter/XCResultGeneratorApp/\"\n\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: MockedSwiftLintExecutor.self,\n            reportsPath: buildFolder.path,\n            fileManager: stubbedFileManager,\n            environmentVariables: [:]\n        )\n\n        XCTAssertEqual(danger.messages.map(\\.message).prefix(1), [\n            \"TransferTests: Executed 519 tests (0 failed, 0 retried, 0 skipped) in 39.226 seconds\"\n        ], \"It should only report the actual failed test, instead of also the retried succeeded one\")\n\n        XCTAssertEqual(danger.warnings.count, 0)\n        XCTAssertEqual(danger.fails.count, 0)\n    }\n\n    func testXCResultCoverageReporting() throws {\n        let xcResultFilename = \"coverage_fail_flaky_skip_example.xcresult\"\n        let xcResultFile = Bundle.module.url(forResource: \"Resources/\\(xcResultFilename)\", withExtension: nil)!\n        let xcResultFileTwo = xcResultFile.copied(newFileName: \"coverage_fail_flaky_skip_example_two.xcresult\")\n        let fileOne = try Folder(path: xcResultFile.deletingLastPathComponent().path).subfolder(named: xcResultFilename)\n        try fileOne.copy(to: buildFolder)\n\n        let fileTwo = try Folder(path: xcResultFileTwo.deletingLastPathComponent().path)\n            .subfolder(named: \"coverage_fail_flaky_skip_example_two.xcresult\")\n        try fileTwo.copy(to: buildFolder)\n\n        let danger = githubWithFilesDSL()\n        let stubbedFileManager = StubbedFileManager()\n        stubbedFileManager.stubbedCurrentDirectoryPath =\n            \"/Users/avanderlee/Developer/GIT-Projects/WeTransfer/Mule/Submodules/WeTransfer-iOS-CI/WeTransferPRLinter/XCResultGeneratorApp\"\n\n        WeTransferPRLinter.lint(\n            using: danger,\n            swiftLintExecutor: MockedSwiftLintExecutor.self,\n            reportsPath: buildFolder.path,\n            fileManager: stubbedFileManager,\n            environmentVariables: [:]\n        )\n\n        XCTAssertEqual(danger.messages.map(\\.message).filter { $0.contains(\"Executed\") }, [\n            \"PRLinterAppTests: Executed 10 tests (1 failed, 1 retried, 1 skipped) in 0.097 seconds\",\n            \"PRLinterAppTests: Executed 10 tests (1 failed, 1 retried, 1 skipped) in 0.097 seconds\"\n        ], \"Both reports should be handled\")\n\n        XCTAssertEqual(danger.markdowns.count, 1, \"Coverage reports should be combined\")\n        let coverageReport = try XCTUnwrap(danger.markdowns.first)\n        XCTAssertEqual(coverageReport.message, \"\"\"\n        ## Code Coverage Report\n        | Name | Coverage ||\n        | --- | --- | --- |\n        PRLinterApp.framework | 71.43% | ⚠️\n        PRLinterApp.framework | 71.43% | ⚠️\\n\n        \"\"\")\n    }\n}\n\nprivate extension URL {\n    /// Creates a copy of the file at the current URL to prevent the original file from being affected.\n    /// Files can get deleted after a test is cleaned up, making future tests fail.\n    func copied(newFileName: String? = nil) -> URL {\n        guard isFileURL else { fatalError(\"Can't copy a non-file URL\") }\n\n        let destinationDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)\n        try! FileManager.default.createDirectory(at: destinationDirectory, withIntermediateDirectories: false, attributes: nil)\n        let newFileURL = destinationDirectory.appendingPathComponent(newFileName ?? lastPathComponent)\n        try! FileManager.default.copyItem(at: self, to: newFileURL)\n        assert(FileManager.default.fileExists(atPath: newFileURL.path), \"Source file should exist\")\n        return newFileURL\n    }\n}\n\nfinal class StubbedFileManager: FileManager {\n    var stubbedCurrentDirectoryPath: String!\n    var fileExists = false\n\n    override var currentDirectoryPath: String {\n        stubbedCurrentDirectoryPath\n    }\n\n    override func fileExists(atPath path: String, isDirectory: UnsafeMutablePointer<ObjCBool>?) -> Bool {\n        fileExists\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/Tests/WeTransferPRLinterTests/XCTestManifests.swift",
    "content": "import XCTest\n\n#if !canImport(ObjectiveC)\n    public func allTests() -> [XCTestCaseEntry] {\n        [\n            testCase(WeTransferLinterTests.allTests)\n        ]\n    }\n#endif\n"
  },
  {
    "path": "WeTransferPRLinter/XCResultGeneratorApp/PRLinterApp/PRLinterApp.h",
    "content": "#import <Foundation/Foundation.h>\n\n//! Project version number for PRLinterApp.\nFOUNDATION_EXPORT double PRLinterAppVersionNumber;\n\n//! Project version string for PRLinterApp.\nFOUNDATION_EXPORT const unsigned char PRLinterAppVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <PRLinterApp/PublicHeader.h>\n\n\n"
  },
  {
    "path": "WeTransferPRLinter/XCResultGeneratorApp/PRLinterApp/PRLinterViewModel.swift",
    "content": "import Foundation\n\nstruct PRLinterViewModel {\n    let name = \"Antoine\"\n    let age = 30\n\n    func printDescription() -> String {\n        guard age > 20 else {\n            return \"To young\"\n        }\n\n        return name + \" and age: \\(30)\"\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/XCResultGeneratorApp/PRLinterAppTests/PRLinterAppTests.swift",
    "content": "@testable import PRLinterApp\nimport XCTest\n\nclass PRLinterViewModelTests: XCTestCase {\n    func testSuccessExample() {\n        let viewModel = PRLinterViewModel()\n        XCTAssertEqual(viewModel.printDescription(), \"Antoine and age: 30\")\n    }\n\n    func testFailingExample() {\n        let viewModel = PRLinterViewModel()\n        XCTAssertEqual(viewModel.printDescription(), \"Antoine and age: 22\")\n    }\n\n    func testSkippedExample() throws {\n        try XCTSkipIf(true, \"This test should be skipped\")\n    }\n\n    func testFlaky() {\n        XCTAssertTrue(Bool.random())\n    }\n}\n"
  },
  {
    "path": "WeTransferPRLinter/XCResultGeneratorApp/README.md",
    "content": "#  Readme\nThis project can be used to generate `xcresult` sample files to use for our `WeTransferPRLinter` tests.\n\n## How to\n1. Run tests\n2. Show the Report navigator\n3. Right-click a test result\n4. Copy the `xcresult` file to the test resources folder for `WeTransferPRLinter`\n\n"
  },
  {
    "path": "bitrise.yml",
    "content": "---\nformat_version: '8'\ndefault_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git\nproject_type: ios\ntrigger_map:\n- pull_request_source_branch: \"*\"\n  workflow: wetransfer_pr_testing\n- tag: \"*\"\n  workflow: wetransfer_tag_releasing\nworkflows:\n  wetransfer_pr_testing_local:\n    steps:\n    - script:\n        title: Setup environment variables\n        inputs:\n        - content: |-\n            #!/bin/bash\n            # Change these for your current local session.\n            export BITRISE_IO=\"fake_bitrise\"\n            export BITRISEIO_GIT_REPOSITORY_OWNER=\"WeTransfer\"\n            export BITRISEIO_GIT_REPOSITORY_SLUG=\"WeTransfer-iOS-CI\"\n            export BITRISE_PULL_REQUEST=117\n\n            bitrise run wetransfer_pr_testing\n  wetransfer_pr_testing:\n    steps:\n    - activate-ssh-key:\n        run_if: '{{getenv \"SSH_RSA_PRIVATE_KEY\" | ne \"\"}}'\n    - git-clone: {}\n    - script:\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            # fail if any commands fails\n            set -e\n            # debug log\n            set -x\n            env\n    - script:\n        title: Continue from WeTransfer-iOS-CI repo\n        inputs:\n        - content: |-\n            #!/bin/bash\n            set -ex\n            bitrise run --config ./Bitrise/testing_bitrise.yml \"${BITRISE_TRIGGERED_WORKFLOW_ID}\"\n    envs:\n    - opts:\n        is_expand: false\n      FASTLANE_LANE: test_pr_linter\n  wetransfer_tag_releasing:\n    steps:\n    - activate-ssh-key:\n        run_if: '{{getenv \"SSH_RSA_PRIVATE_KEY\" | ne \"\"}}'\n    - script:\n        title: Force SSH\n        inputs:\n        - content: |-\n            #!/usr/bin/env bash\n            # As we work with submodules, make sure we use SSH for this config so we can push our PR later on.\n            # See for more info: https://discuss.bitrise.io/t/git-force-to-use-ssh-url-instead-of-https-for-github-com/4384\n            git config --global url.\"git@github.com:\".insteadOf \"https://github.com/\"\n    - git-clone: {}\n    - script:\n        title: Continue from WeTransfer-iOS-CI repo\n        inputs:\n        - content: |-\n            #!/bin/bash\n            set -ex\n            bitrise run --config ./Bitrise/tag_releasing_bitrise.yml \"${BITRISE_TRIGGERED_WORKFLOW_ID}\"\nmeta:\n  bitrise.io:\n    machine_type: standard\n    stack: osx-xcode-16.0.x\n    machine_type_id: g2-m1.4core\n"
  },
  {
    "path": "sample_fastlane_env",
    "content": "# The id of the JWT token used to authenticate with an App manager role.\nAPP_MANAGER_KEY_ID=\n# The path to the file containing the private key for the app manager token.\nAPP_MANAGER_KEY_PATH=\n# The id of the JWT token used to authenticate with a developer role.\nDEVELOPER_KEY_ID=\n# The path to the file containing the private key for the developer token.\nDEVELOPER_KEY_PATH=\n# The identifier of the issuer of the JWT token used to authenticate with App Store Connect.\nJWT_ISSUER_ID=\n\n# A script that can be used to prepare for a CI run. (optional).\nPREPARE_CI_SCRIPT=\n\n# The ID of your Developer Portal team (Required if you are a member of multiple teams).\nFASTLANE_TEAM_ID=\n# The ID of your App Store Connect team.\nFASTLANE_ITC_TEAM_ID=\n\n# The bundle identifier of the app to build and deploy.\nAPP_IDENTIFIER=\n# A comma separated string containing all bundle identifiers, e.g. app + extensions.\nAPP_IDENTIFIERS=\n\n# The path to the Xcode project file.\nXCODEPROJ=\n# The target to build.\nXCODE_TARGET=\n# The project's scheme.\nXCODE_SCHEME=\n\n# A xcconfig file to use to when building the app for beta distribution (optional).\nBETA_XCCONFIG=\n# A xconfig file to use when building the app for app store distribution (optional).\nRELEASE_XCCONFIG=\n\n# The contact email for beta review.\nBETA_CONTACT_EMAIL=\n# The first name of the contact for beta review.\nBETA_CONTACT_FIRST_NAME=\n# The last name of the contact for beta review.\nBETA_CONTACT_LAST_NAME=\n# The phone number of the contact for beta review.\nBETA_CONTACT_PHONE=\n# The name of the demo account for beta review.\nBETA_DEMO_ACCOUNT_NAME=\n# The passwords for the demo account for beta review.\nBETA_DEMO_ACCOUNT_PASSWORD=\n\n# A list of TestFlight groups that should get access to the beta build (optional).\nTESTFLIGHT_GROUPS_BETA=\n# A list of TestFlight groups that should get access to the release build (optional).\nTESTFLIGHT_GROUPS_RELEASE=\n\n# The url of the incoming Webhook used to post build status messaged to a specific Slack channel.\nSLACK_URL=\"\n"
  }
]