diff --git a/.github/DangerFiles/Gemfile b/.github/DangerFiles/Gemfile new file mode 100644 index 0000000000..9535244ac3 --- /dev/null +++ b/.github/DangerFiles/Gemfile @@ -0,0 +1,5 @@ +source("https://rubygems.org") + +gem 'danger' +gem 'plist' +gem 'danger-xcode_summary' diff --git a/.github/DangerFiles/Gemfile.lock b/.github/DangerFiles/Gemfile.lock new file mode 100644 index 0000000000..c31ad32b20 --- /dev/null +++ b/.github/DangerFiles/Gemfile.lock @@ -0,0 +1,82 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + base64 (0.2.0) + claide (1.1.0) + claide-plugins (0.9.2) + cork + nap + open4 (~> 1.3) + colored2 (3.1.2) + cork (0.3.0) + colored2 (~> 3.1) + danger (9.5.1) + base64 (~> 0.2) + claide (~> 1.0) + claide-plugins (>= 0.9.2) + colored2 (~> 3.1) + cork (~> 0.1) + faraday (>= 0.9.0, < 3.0) + faraday-http-cache (~> 2.0) + git (~> 1.13) + kramdown (~> 2.3) + kramdown-parser-gfm (~> 1.0) + octokit (>= 4.0) + pstore (~> 0.1) + terminal-table (>= 1, < 4) + danger-plugin-api (1.0.0) + danger (> 2.0) + danger-xcode_summary (1.3.1) + danger-plugin-api (~> 1.0) + xcresult (~> 0.2.2) + faraday (2.12.0) + faraday-net_http (>= 2.0, < 3.4) + json + logger + faraday-http-cache (2.5.1) + faraday (>= 0.8) + faraday-net_http (3.3.0) + net-http + git (1.19.1) + addressable (~> 2.8) + rchardet (~> 1.8) + json (2.7.5) + kramdown (2.4.0) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + logger (1.6.1) + nap (1.1.0) + net-http (0.4.1) + uri + octokit (9.2.0) + faraday (>= 1, < 3) + sawyer (~> 0.9) + open4 (1.3.4) + plist (3.7.1) + pstore (0.1.3) + public_suffix (6.0.1) + rchardet (1.8.0) + rexml (3.3.9) + sawyer (0.9.2) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + unicode-display_width (2.6.0) + uri (0.13.1) + xcresult (0.2.2) + +PLATFORMS + arm64-darwin-23 + ruby + +DEPENDENCIES + danger + danger-xcode_summary + plist + +BUNDLED WITH + 2.5.22 diff --git a/.github/DangerFiles/StaticAnalysis.rb b/.github/DangerFiles/StaticAnalysis.rb new file mode 100644 index 0000000000..f0566fa04e --- /dev/null +++ b/.github/DangerFiles/StaticAnalysis.rb @@ -0,0 +1,44 @@ +require 'plist' + +# Markdown table character length without any issues +MAKRDOWN_LENGTH = 138 +LIBS = ['SalesforceSDKCommon', 'SalesforceAnalytics', 'SalesforceSDKCore', 'SmartStore', 'MobileSync'] + +files = Set[] +for lib in LIBS; + files.merge(Dir["../../libs/#{lib}/clangReport/StaticAnalyzer/#{lib}/#{lib}/normal/**/*.plist"]) +end +print "Found #{files.count} classes with static analysis files." + +modified_file_names = git.modified_files.map { |file| File.basename(file, File.extname(file)) } +added_file_names = git.added_files.map { |file| File.basename(file, File.extname(file)) } + +# Github PR comment header +message = "### Clang Static Analysis Issues\n\n" +message << "File | Type | Category | Description | Line | Col |\n" +message << " --- | ---- | -------- | ----------- | ---- | --- |\n" + +# Parse Clang Plist files and report issues associated with files modified or added in this PR. +for file in files; + report = Plist.parse_xml(file) + report_file_name = File.basename(file, File.extname(file)) + print "file name: #{report_file_name}\n" + + if modified_file_names.include?(report_file_name) || added_file_names.include?(report_file_name) + print "file match! #{file}\n" + issues = report['diagnostics'] + print "issue count: #{issues.count}\n" + for i in 0..issues.count-1 + unless issues[i].nil? + print "#{report_file_name} | #{issues[i]['type']} | #{issues[i]['category']} | #{issues[i]['description']} | #{issues[i]['location']['line']} | #{issues[i]['location']['col']}\n" + message << "#{report_file_name} | #{issues[i]['type']} | #{issues[i]['category']} | #{issues[i]['description']} | #{issues[i]['location']['line']} | #{issues[i]['location']['col']}\n" + end + end + end +end + +# Only print Static Analysis table if there are issues +if message.length > MAKRDOWN_LENGTH + warn('Static Analysis found an issue with one or more files you modified. Please fix the issue(s).') + markdown message +end \ No newline at end of file diff --git a/.github/DangerFiles/TestOrchestrator.rb b/.github/DangerFiles/TestOrchestrator.rb new file mode 100644 index 0000000000..bc1b41e902 --- /dev/null +++ b/.github/DangerFiles/TestOrchestrator.rb @@ -0,0 +1,24 @@ +# List of supported xcode schemes for testing +# SCHEMES = ['SalesforceSDKCore', 'MobileSync', 'SmartStore'] +SCHEMES = ['SalesforceSDKCommon', 'SalesforceAnalytics', 'SalesforceSDKCore', 'SmartStore', 'MobileSync'] + +modifed_libs = Set[] +for file in (git.modified_files + git.added_files); + scheme = file.split("libs/").last.split("/").first + print "lib: #{scheme}\n" + if scheme == '.github' + # If CI files are modified, run all tests + modifed_libs.merge(SCHEMES) + elsif SCHEMES.include?(scheme) + modifed_libs.add(scheme) + end +end + +# TODO: REMOVE THIS +modifed_libs.delete(".github") +print "modifed libs: #{modifed_libs}\n" +print "modifed libs as list: [#{modifed_libs.join(", ")}]\n" + +# Set Github Job output so we know which tests to run +json_libs = modifed_libs.map { |l| "'#{l}'"}.join(", ") +`echo "libs=[#{json_libs}]" >> $GITHUB_OUTPUT` diff --git a/.github/DangerFiles/TestResults.rb b/.github/DangerFiles/TestResults.rb new file mode 100644 index 0000000000..5fb45580c8 --- /dev/null +++ b/.github/DangerFiles/TestResults.rb @@ -0,0 +1,8 @@ +xcode_summary.ignores_warnings = true +xcode_summary.inline_mode = true + +if File.exist?('../../test.xcresult') + xcode_summary.report '../../test.xcresult' +else + fail "No test results found." +end \ No newline at end of file diff --git a/.github/Gemfile.lock b/.github/Gemfile.lock new file mode 100644 index 0000000000..c31ad32b20 --- /dev/null +++ b/.github/Gemfile.lock @@ -0,0 +1,82 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + base64 (0.2.0) + claide (1.1.0) + claide-plugins (0.9.2) + cork + nap + open4 (~> 1.3) + colored2 (3.1.2) + cork (0.3.0) + colored2 (~> 3.1) + danger (9.5.1) + base64 (~> 0.2) + claide (~> 1.0) + claide-plugins (>= 0.9.2) + colored2 (~> 3.1) + cork (~> 0.1) + faraday (>= 0.9.0, < 3.0) + faraday-http-cache (~> 2.0) + git (~> 1.13) + kramdown (~> 2.3) + kramdown-parser-gfm (~> 1.0) + octokit (>= 4.0) + pstore (~> 0.1) + terminal-table (>= 1, < 4) + danger-plugin-api (1.0.0) + danger (> 2.0) + danger-xcode_summary (1.3.1) + danger-plugin-api (~> 1.0) + xcresult (~> 0.2.2) + faraday (2.12.0) + faraday-net_http (>= 2.0, < 3.4) + json + logger + faraday-http-cache (2.5.1) + faraday (>= 0.8) + faraday-net_http (3.3.0) + net-http + git (1.19.1) + addressable (~> 2.8) + rchardet (~> 1.8) + json (2.7.5) + kramdown (2.4.0) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + logger (1.6.1) + nap (1.1.0) + net-http (0.4.1) + uri + octokit (9.2.0) + faraday (>= 1, < 3) + sawyer (~> 0.9) + open4 (1.3.4) + plist (3.7.1) + pstore (0.1.3) + public_suffix (6.0.1) + rchardet (1.8.0) + rexml (3.3.9) + sawyer (0.9.2) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + unicode-display_width (2.6.0) + uri (0.13.1) + xcresult (0.2.2) + +PLATFORMS + arm64-darwin-23 + ruby + +DEPENDENCIES + danger + danger-xcode_summary + plist + +BUNDLED WITH + 2.5.22 diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml new file mode 100644 index 0000000000..f51407be22 --- /dev/null +++ b/.github/workflows/nightly.yaml @@ -0,0 +1,23 @@ +name: Nightly Tests + +on: + schedule: + - cron: "0 5 * * 3,5" # cron is UTC, this translates to 10 PM PST Tues and Thur. + +jobs: + ios-pr: + strategy: + fail-fast: false + matrix: + lib: [SalesforceSDKCommon, SalesforceAnalytics, SalesforceSDKCore, SmartStore, MobileSync] + ios: [^18, ^17] + include: + - ios: ^18 + macos: macos-15 + - ios: ^17 + macos: macos-14 + uses: ./.github/workflows/reusable-workflow.yaml + with: + lib: ${{ matrix.lib }} + ios: ${{ matrix.ios }} + macos: ${{ matrix.macos }} \ No newline at end of file diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000000..34c8395017 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,61 @@ +name: Pull Request + +on: + pull_request: + # branches: + # - dev + +jobs: + static-analysis: + runs-on: macos-15 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Install Dependencies + run: | + npm install shelljs@0.8.5 + ./install.sh + # - name: Run Static Analysis + # run: set -o pipefail && xcodebuild analyze -workspace SalesforceMobileSDK.xcworkspace -scheme MobileSync -sdk 'iphonesimulator' \ + # CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR=./clangReport RUN_CLANG_STATIC_ANALYZER=YES | xcbeautify --renderer github-actions + - name: Run Static Analysis + run: xcodebuild analyze -workspace SalesforceMobileSDK.xcworkspace -scheme MobileSync -sdk 'iphonesimulator' \ + CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR=./clangReport RUN_CLANG_STATIC_ANALYZER=YES + - name: Report Static Analysis + env: + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd .github/DangerFiles + bundle update && bundle install + bundle exec danger --dangerfile=StaticAnalysis.rb --danger_id=StaticAnalysis + + test-orchestrator: + runs-on: macos-15 + outputs: + libs: ${{ steps.test-orchestrator.outputs.libs }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 100 + - name: Determine Tests to Run + id: test-orchestrator + env: + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd .github/DangerFiles + bundle update && bundle install + bundle exec danger --dangerfile=TestOrchestrator.rb + + ios-pr: + needs: [test-orchestrator] + strategy: + fail-fast: false + matrix: + lib: ${{ fromJson(needs.test-orchestrator.outputs.libs) }} + uses: ./.github/workflows/reusable-workflow.yaml + with: + lib: ${{ matrix.lib }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/reusable-workflow.yaml b/.github/workflows/reusable-workflow.yaml new file mode 100644 index 0000000000..2787b786c2 --- /dev/null +++ b/.github/workflows/reusable-workflow.yaml @@ -0,0 +1,59 @@ +on: + workflow_dispatch: + workflow_call: + inputs: + lib: + required: true + type: string + ios: + default: '^18' + required: false + type: string + xcode: + default: '^16' + required: false + type: string + macos: + default: macos-15 + required: false + type: string + +jobs: + test-ios: + runs-on: ${{ inputs.macos }} + steps: + - uses: actions/checkout@v4 + # needs this + with: + fetch-depth: 100 + - name: Install Dependencies + env: + TEST_CREDENTIALS: ${{ secrets.TEST_CREDENTIALS }} + run: | + npm install shelljs@0.8.5 + ./install.sh + echo $TEST_CREDENTIALS > ./shared/test/test_credentials.json + - uses: mxcl/xcodebuild@v3 + with: + xcode: ${{ inputs.xcode }} + platform: iOS + platform-version: ${{ inputs.ios }} + workspace: SalesforceMobileSDK.xcworkspace + scheme: ${{ inputs.lib }} + code-coverage: true + upload-logs: always + verbosity: xcbeautify + - name: Danger Test Results + if: (github.event_name == 'pull_request') && failure() + env: + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd .github/DangerFiles + bundle update && bundle install + bundle exec danger --dangerfile=TestResults.rb --danger_id=${{ inputs.lib }} + - uses: codecov/codecov-action@v4 + with: + flags: ${{ inputs.lib }} + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + if: success() || failure() \ No newline at end of file diff --git a/.gitignore b/.gitignore index d84a467e08..9223f072bf 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,6 @@ shared/test/test_credentials.json /libs/MobileSync/build/ /native/SampleApps/RestAPIExplorer/build/ node_modules/ -.github/ .idea/ package-lock.json npm-debug.log diff --git a/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Manager/SFSDKAnalyticsManager.h b/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Manager/SFSDKAnalyticsManager.h index 6c87010c49..775f21274c 100644 --- a/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Manager/SFSDKAnalyticsManager.h +++ b/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Manager/SFSDKAnalyticsManager.h @@ -25,6 +25,7 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #import diff --git a/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.h b/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.h index 4c012cd072..1481b445f2 100644 --- a/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.h +++ b/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.h @@ -27,6 +27,7 @@ WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #import extern NSString * _Nonnull const kSFSDKAnalyticsComponentName; diff --git a/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.m b/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.m index 21f319ef02..e88dee47b4 100644 --- a/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.m +++ b/libs/SalesforceAnalytics/SalesforceAnalytics/Classes/Util/SFSDKAnalyticsLogger.m @@ -27,6 +27,7 @@ WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #import "SFSDKAnalyticsLogger.h" NSString * const kSFSDKAnalyticsComponentName = @"SalesforceAnalytics"; diff --git a/libs/SalesforceAnalytics/SalesforceAnalyticsTests/EventStoreManagerTests.m b/libs/SalesforceAnalytics/SalesforceAnalyticsTests/EventStoreManagerTests.m index 92642d5b60..13fa1286b5 100644 --- a/libs/SalesforceAnalytics/SalesforceAnalyticsTests/EventStoreManagerTests.m +++ b/libs/SalesforceAnalytics/SalesforceAnalyticsTests/EventStoreManagerTests.m @@ -68,7 +68,7 @@ - (void) testStoreOneEvent { [self.storeManager storeEvent:event]; NSArray *events = [self.storeManager fetchAllEvents]; XCTAssertTrue(events != nil, @"List of events should not be nil"); - XCTAssertEqual(1, events.count, @"Number of events stored should be 1"); + XCTAssertEqual(2, events.count, @"Number of events stored should be 1"); XCTAssertEqualObjects(event, [events firstObject], @"Stored event should be the same as generated event"); } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.m index d7152b4074..121d3861e7 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.m @@ -21,6 +21,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #import #import diff --git a/test_rb.rb b/test_rb.rb new file mode 100644 index 0000000000..8eba45e576 --- /dev/null +++ b/test_rb.rb @@ -0,0 +1,9 @@ +require 'json' + +puts "contents of env var: #{ENV['creds']}" + + +file = File.open "./shared/test/test_credentials.json" +data = JSON.load file + +puts "redirect from file: #{data['test_redirect_uri']}" \ No newline at end of file