From 4b5d48497681044183b3b48c50391da90fa736b0 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 14 Dec 2023 23:32:09 +0100 Subject: [PATCH 1/8] Add code_freeze.yml --- .github/workflows/build_appstore.yml | 22 +++-- .github/workflows/build_notarized.yml | 6 +- .github/workflows/code_freeze.yml | 127 ++++++++++++++++++++++++++ .github/workflows/pr.yml | 9 +- .github/workflows/release.yml | 6 ++ fastlane/Fastfile | 58 ++++++++++-- 6 files changed, 210 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/code_freeze.yml diff --git a/.github/workflows/build_appstore.yml b/.github/workflows/build_appstore.yml index 3ed67cdd61..cb64f90b32 100644 --- a/.github/workflows/build_appstore.yml +++ b/.github/workflows/build_appstore.yml @@ -26,6 +26,10 @@ on: description: "Asana release task URL" required: true type: string + branch: + description: "Branch name" + required: false + type: string secrets: SSH_PRIVATE_KEY_FASTLANE_MATCH: required: true @@ -57,14 +61,14 @@ jobs: steps: - - name: Assert release branch - if: env.destination == 'appstore' - run: | - case "${{ github.ref }}" in - refs/heads/release/*) ;; - refs/heads/hotfix/*) ;; - *) echo "👎 Not a release or hotfix branch"; exit 1 ;; - esac + # - name: Assert release branch + # if: env.destination == 'appstore' + # run: | + # case "${{ github.ref }}" in + # refs/heads/release/*) ;; + # refs/heads/hotfix/*) ;; + # *) echo "👎 Not a release or hotfix branch"; exit 1 ;; + # esac - name: Register SSH keys for submodules access uses: webfactory/ssh-agent@v0.7.0 @@ -76,7 +80,7 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive - ref: ${{ github.ref_name }} + ref: ${{ inputs.branch || github.ref_name }} - name: Select Xcode run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer diff --git a/.github/workflows/build_notarized.yml b/.github/workflows/build_notarized.yml index e6486a1877..86a7d55a9f 100644 --- a/.github/workflows/build_notarized.yml +++ b/.github/workflows/build_notarized.yml @@ -38,6 +38,10 @@ on: description: "Asana release task URL" required: true type: string + branch: + description: "Branch name" + required: false + type: string secrets: BUILD_CERTIFICATE_BASE64: required: true @@ -103,7 +107,7 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive - ref: ${{ github.ref_name }} + ref: ${{ inputs.branch || github.ref_name }} - name: Install Apple Developer ID Application certificate uses: ./.github/actions/install-certs-and-profiles diff --git a/.github/workflows/code_freeze.yml b/.github/workflows/code_freeze.yml new file mode 100644 index 0000000000..676de8e938 --- /dev/null +++ b/.github/workflows/code_freeze.yml @@ -0,0 +1,127 @@ +name: Code Freeze + +on: + workflow_dispatch: + inputs: + asana-task-url: + description: "Asana release task URL" + required: true + type: string + +jobs: + + create_release_branch: + + name: Create Release Branch + + runs-on: macos-13-xlarge + timeout-minutes: 10 + + outputs: + release_branch_name: ${{ steps.make_release_branch.outputs.release_branch_name }} + + steps: + + # - name: Assert main branch + # run: | + # if [ "${{ github.ref_name }}" != "main" ]; then + # echo "👎 Not the main branch" + # exit 1 + # fi + + - name: Check out the code + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer + + - name: Prepare fastlane + run: bundle install + + - name: Make release branch + id: make_release_branch + env: + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} + run: | + git config --global user.name "Dax the Duck" + git config --global user.email "dax@duckduckgo.com" + bundle exec fastlane make_release_branch + + run_tests: + + name: Run Tests + + needs: create_release_branch + uses: ./.github/workflows/pr.yml + with: + branch: ${{ needs.create_release_branch.outputs.release_branch_name }} + secrets: + ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} + + increment_build_number: + + name: Increment Build Number + + needs: [ create_release_branch, run_tests ] + runs-on: macos-13-xlarge + timeout-minutes: 10 + + steps: + + - name: Check out the code + uses: actions/checkout@v3 + with: + submodules: recursive + ref: ${{ needs.create_release_branch.outputs.release_branch_name }} + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer + + - name: Prepare fastlane + run: bundle install + + - name: Increment build number + env: + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} + run: | + git config --global user.name "Dax the Duck" + git config --global user.email "dax@duckduckgo.com" + bundle exec fastlane bump_internal_release update_embedded_files:false + + prepare_release: + name: Prepare Release + needs: [ create_release_branch, increment_build_number ] + uses: ./.github/workflows/release.yml + with: + asana-task-url: ${{ github.event.inputs.asana-task-url }} + branch: ${{ needs.create_release_branch.outputs.release_branch_name }} + secrets: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} + RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} + NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64 }} + NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64 }} + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} + ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} + MM_HANDLES_BASE64: ${{ secrets.MM_HANDLES_BASE64 }} + MM_WEBHOOK_URL: ${{ secrets.MM_WEBHOOK_URL }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + SSH_PRIVATE_KEY_FASTLANE_MATCH: ${{ secrets.SSH_PRIVATE_KEY_FASTLANE_MATCH }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index b3400f2850..7e6529e922 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -5,6 +5,11 @@ on: branches: [ main, "release/**" ] pull_request: workflow_call: + inputs: + branch: + description: "Branch name" + required: false + type: string secrets: ASANA_ACCESS_TOKEN: required: true @@ -38,7 +43,7 @@ jobs: if: github.event_name != 'pull_request' && github.event_name != 'push' uses: actions/checkout@v3 with: - ref: ${{ github.ref_name }} + ref: ${{ inputs.branch || github.ref_name }} - name: Run ShellCheck uses: ludeeus/action-shellcheck@master @@ -100,7 +105,7 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive - ref: ${{ github.ref_name }} + ref: ${{ inputs.branch || github.ref_name }} - name: Set cache key hash run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33b902609d..7ea14e28c8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,10 @@ on: description: "Asana release task URL" required: true type: string + branch: + description: "Branch name" + required: false + type: string secrets: BUILD_CERTIFICATE_BASE64: required: true @@ -70,6 +74,7 @@ jobs: release-type: release create-dmg: true asana-task-url: ${{ github.event.inputs.asana-task-url || inputs.asana-task-url }} + branch: ${{ inputs.branch }} secrets: BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} P12_PASSWORD: ${{ secrets.P12_PASSWORD }} @@ -99,6 +104,7 @@ jobs: with: destination: appstore asana-task-url: ${{ github.event.inputs.asana-task-url || inputs.asana-task-url }} + branch: ${{ inputs.branch }} secrets: SSH_PRIVATE_KEY_FASTLANE_MATCH: ${{ secrets.SSH_PRIVATE_KEY_FASTLANE_MATCH }} APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 75e14c98df..91d20c3c18 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -100,6 +100,41 @@ platform :mac do })) end + # Creates a new release branch and updates embedded files. + # + # - Cuts a new release branch + # - Updates submodules and embedded files + # - Pushes changes to remote + # + # @option [String] version (default: nil) Marketing version string + # + desc 'Executes the release preparation work in the repository' + lane :make_release_branch do |options| + begin + macos_codefreeze_prechecks + new_version = validate_new_version(options) + macos_create_release_branch(version: new_version) + macos_update_embedded_files + macos_update_version_config(version: new_version) + sh('git', 'push') + + sh("echo \"release_branch_name=#{RELEASE_BRANCH}/#{new_version}\" >> $GITHUB_OUTPUT") if is_ci + + rescue => exception + if exception.message == "Tests have failed" + UI.user_error! %{Tests have failed. +* If you believe the failing test is flaky, please retry the same fastlane command, + appending `resume:true`. +* If the failure looks legitimate, try to fix it, commit the fix (be sure to only + include the files you've changed while making a fix and leave other changed files + unmodified), and run the command again appending `resume:true`. + } + else + raise exception + end + end + end + # Executes the release preparation work in the repository # # - Cuts a new release branch @@ -307,7 +342,7 @@ platform :mac do private_lane :macos_codefreeze_prechecks do ensure_git_status_clean - ensure_git_branch(branch: DEFAULT_BRANCH) + # ensure_git_branch(branch: DEFAULT_BRANCH) git_pull git_submodule_update(recursive: true, init: true) @@ -500,10 +535,8 @@ release in progress and you're making a follow-up internal release that includes end end - unless is_ci - # Run tests (CI will run them separately) - run_tests(scheme: 'DuckDuckGo Privacy Browser') - end + # Run tests (CI will run them separately) + run_tests(scheme: 'DuckDuckGo Privacy Browser') unless is_ci # Every thing looks good: commit and push unless modified_files.empty? @@ -513,7 +546,7 @@ release in progress and you're making a follow-up internal release that includes end end - # Updates version in the config file + # Updates version and build number in respective config files # # @option [String] version Marketing version string # @option [String] build_number Build number @@ -532,6 +565,19 @@ release in progress and you're making a follow-up internal release that includes ) end + # Updates version in the config file + # + # @option [String] version Marketing version string + # + private_lane :macos_update_version_config do |options| + version = options[:version] + File.write(VERSION_CONFIG_PATH, "#{VERSION_CONFIG_DEFINITION} = #{version}\n") + git_commit( + path: VERSION_CONFIG_PATH, + message: "Set marketing version to #{version}" + ) + end + # Reads build number from the config file # # @return [String] build number read from the file, or nil in case of failure From fde028799a0108134e1ad90a558e7bc3b9799b8f Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 14 Dec 2023 23:57:36 +0100 Subject: [PATCH 2/8] Disable flaky unit test --- .../Tests/PixelKitTests/PixelKitTests.swift | 87 ++++++++++--------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift index 8450c0df9c..4e8d1e3dfa 100644 --- a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift +++ b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift @@ -229,49 +229,50 @@ final class PixelKitTests: XCTestCase { } /// Test firing a daily pixel a few times - func testDailyPixelFrequency() { - // Prepare test parameters - let appVersion = "1.0.5" - let headers = ["a": "2", "b": "3", "c": "2000"] - let log = OSLog(subsystem: "TestSubsystem", category: "TestCategory") - let event = TestEvent.dailyEvent - let userDefaults = userDefaults() - - let timeMachine = TimeMachine() - - // Set expectations - let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") - fireCallbackCalled.expectedFulfillmentCount = 3 - fireCallbackCalled.assertForOverFulfill = true - - // Prepare mock to validate expectations - let pixelKit = PixelKit(dryRun: false, - appVersion: appVersion, - defaultHeaders: headers, - log: log, - dailyPixelCalendar: nil, - dateGenerator: timeMachine.now, - defaults: userDefaults) { _, _, _, _, _, _ in - fireCallbackCalled.fulfill() - } - - // Run test - pixelKit.fire(event, frequency: .dailyOnly) // Fired - - timeMachine.travel(by: 60 * 60 * 2) - pixelKit.fire(event, frequency: .dailyOnly) // Skipped (2 hours since last fire) - - timeMachine.travel(by: 60 * 60 * 24 + 1000) - pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours + 1000 seconds since last fire) - - timeMachine.travel(by: 60 * 60 * 10) - pixelKit.fire(event, frequency: .dailyOnly) // Skipped (10 hours since last fire) - - timeMachine.travel(by: 60 * 60 * 14) - pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours since last fire) - - // Wait for expectations to be fulfilled - wait(for: [fireCallbackCalled], timeout: 0.5) + func testDailyPixelFrequency() throws { + throw XCTSkip() +// // Prepare test parameters +// let appVersion = "1.0.5" +// let headers = ["a": "2", "b": "3", "c": "2000"] +// let log = OSLog(subsystem: "TestSubsystem", category: "TestCategory") +// let event = TestEvent.dailyEvent +// let userDefaults = userDefaults() +// +// let timeMachine = TimeMachine() +// +// // Set expectations +// let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") +// fireCallbackCalled.expectedFulfillmentCount = 3 +// fireCallbackCalled.assertForOverFulfill = true +// +// // Prepare mock to validate expectations +// let pixelKit = PixelKit(dryRun: false, +// appVersion: appVersion, +// defaultHeaders: headers, +// log: log, +// dailyPixelCalendar: nil, +// dateGenerator: timeMachine.now, +// defaults: userDefaults) { _, _, _, _, _, _ in +// fireCallbackCalled.fulfill() +// } +// +// // Run test +// pixelKit.fire(event, frequency: .dailyOnly) // Fired +// +// timeMachine.travel(by: 60 * 60 * 2) +// pixelKit.fire(event, frequency: .dailyOnly) // Skipped (2 hours since last fire) +// +// timeMachine.travel(by: 60 * 60 * 24 + 1000) +// pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours + 1000 seconds since last fire) +// +// timeMachine.travel(by: 60 * 60 * 10) +// pixelKit.fire(event, frequency: .dailyOnly) // Skipped (10 hours since last fire) +// +// timeMachine.travel(by: 60 * 60 * 14) +// pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours since last fire) +// +// // Wait for expectations to be fulfilled +// wait(for: [fireCallbackCalled], timeout: 0.5) } /// Test firing a unique pixel From 56a9c2e6bb55c0950ec5e112ef5360646ca288a2 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 15 Dec 2023 00:00:14 +0100 Subject: [PATCH 3/8] Update upload/download artifact to v4 --- .github/workflows/build_appstore.yml | 2 +- .github/workflows/build_notarized.yml | 8 ++++---- .github/workflows/pr.yml | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_appstore.yml b/.github/workflows/build_appstore.yml index cb64f90b32..0a428223d1 100644 --- a/.github/workflows/build_appstore.yml +++ b/.github/workflows/build_appstore.yml @@ -108,7 +108,7 @@ jobs: echo "app_version=${version}.${build_number}" >> $GITHUB_ENV - name: Upload dSYMs artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: DuckDuckGo-${{ env.destination }}-dSYM-${{ env.app_version }} path: ${{ env.dsyms_path }} diff --git a/.github/workflows/build_notarized.yml b/.github/workflows/build_notarized.yml index 86a7d55a9f..99fd243a0a 100644 --- a/.github/workflows/build_notarized.yml +++ b/.github/workflows/build_notarized.yml @@ -159,13 +159,13 @@ jobs: echo "app-name=${{ env.app-name }}" >> $GITHUB_OUTPUT - name: Upload app artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: DuckDuckGo-${{ env.release-type }}-${{ env.app-version }}.app path: ${{ github.workspace }}/release/DuckDuckGo-${{ env.app-version }}.zip - name: Upload dSYMs artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: DuckDuckGo-${{ env.release-type }}-dSYM-${{ env.app-version }} path: ${{ github.workspace }}/release/DuckDuckGo-${{ env.app-version }}-dSYM.zip @@ -209,7 +209,7 @@ jobs: steps: - name: Fetch app bundle - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: DuckDuckGo-${{ env.release-type }}-${{ env.app-version }}.app path: ${{ github.workspace }}/dmg @@ -238,7 +238,7 @@ jobs: "dmg" - name: Upload DMG artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: DuckDuckGo-${{ env.release-type }}-${{ env.app-version }}.dmg path: ${{ github.workspace }}/duckduckgo*-${{ env.app-version }}.dmg diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7e6529e922..4567c11889 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -210,7 +210,7 @@ jobs: | xargs -L 1 ./scripts/report-failed-unit-test.sh - name: Upload failed unit tests log - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: ${{ matrix.flavor }}-unittests-xcodebuild.log @@ -218,7 +218,7 @@ jobs: retention-days: 7 - name: Upload failed unit tests xcresult - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: ${{ matrix.flavor }}-unittests.xcresult @@ -226,7 +226,7 @@ jobs: retention-days: 7 - name: Upload failed integration tests log - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() && matrix.flavor != 'DBP' with: name: ${{ matrix.flavor }}-integrationtests-xcodebuild.log @@ -234,7 +234,7 @@ jobs: retention-days: 7 - name: Upload failed integration tests xcresult - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() && matrix.flavor != 'DBP' with: name: ${{ matrix.flavor }}-integrationtests.xcresult @@ -333,7 +333,7 @@ jobs: | xcbeautify - name: Upload failed test log - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: release-xcodebuild.log From c9cbed42c84fbad18812f68e4c4db0cb72e75cdf Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 15 Dec 2023 00:51:52 +0100 Subject: [PATCH 4/8] Create release task in Asana --- .github/workflows/build_appstore.yml | 16 ++++++------ .github/workflows/code_freeze.yml | 37 +++++++++++++++++++--------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build_appstore.yml b/.github/workflows/build_appstore.yml index 0a428223d1..fe5fdb9add 100644 --- a/.github/workflows/build_appstore.yml +++ b/.github/workflows/build_appstore.yml @@ -61,14 +61,14 @@ jobs: steps: - # - name: Assert release branch - # if: env.destination == 'appstore' - # run: | - # case "${{ github.ref }}" in - # refs/heads/release/*) ;; - # refs/heads/hotfix/*) ;; - # *) echo "👎 Not a release or hotfix branch"; exit 1 ;; - # esac + - name: Assert release branch + if: env.destination == 'appstore' + run: | + case "${{ inputs.branch || github.ref_name }}" in + release/*) ;; + hotfix/*) ;; + *) echo "👎 Not a release or hotfix branch"; exit 1 ;; + esac - name: Register SSH keys for submodules access uses: webfactory/ssh-agent@v0.7.0 diff --git a/.github/workflows/code_freeze.yml b/.github/workflows/code_freeze.yml index 676de8e938..ebeb82e487 100644 --- a/.github/workflows/code_freeze.yml +++ b/.github/workflows/code_freeze.yml @@ -2,11 +2,6 @@ name: Code Freeze on: workflow_dispatch: - inputs: - asana-task-url: - description: "Asana release task URL" - required: true - type: string jobs: @@ -19,6 +14,7 @@ jobs: outputs: release_branch_name: ${{ steps.make_release_branch.outputs.release_branch_name }} + asana_task_url: ${{ steps.create_release_task.outputs.asana_task_url }} steps: @@ -34,9 +30,6 @@ jobs: with: submodules: recursive - - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer - - name: Prepare fastlane run: bundle install @@ -51,6 +44,29 @@ jobs: git config --global user.email "dax@duckduckgo.com" bundle exec fastlane make_release_branch + - name: Create release task + id: create_release_task + env: + ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} + run: | + version="$(echo ${{ steps.make_release_branch.outputs.release_branch_name }} | cut -d '/' -f 2)" + task_name="macOS App Release $version" + asana_task_id="$(curl -fLSs -X POST "https://app.asana.com/api/1.0/task_templates/${{ vars.MACOS_RELEASE_TASK_TEMPLATE_ID }}/instantiateTask" \ + -H "Authorization: Bearer ${{ env.ASANA_ACCESS_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d "{ \"data\": { \"name\": \"$task_name\" }}" \ + | jq -r .data.new_task.gid)" + echo "asana_task_url=https://app.asana.com/0/0/${asana_task_id}/f" >> $GITHUB_OUTPUT + + assignee_id="$(curl -fLSs https://raw.githubusercontent.com/duckduckgo/BrowserServicesKit/main/.github/actions/asana-failed-pr-checks/user_ids.json \ + | jq -r .${{ github.actor }})" + + curl -fLSs -X PUT "https://app.asana.com/api/1.0/tasks/${asana_task_id}" \ + -H "Authorization: Bearer ${{ env.ASANA_ACCESS_TOKEN }}" \ + -H "Content-Type: application/json" \ + --output /dev/null \ + -d "{ \"data\": { \"assignee\": \"$assignee_id\" }}" + run_tests: name: Run Tests @@ -78,9 +94,6 @@ jobs: submodules: recursive ref: ${{ needs.create_release_branch.outputs.release_branch_name }} - - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer - - name: Prepare fastlane run: bundle install @@ -99,7 +112,7 @@ jobs: needs: [ create_release_branch, increment_build_number ] uses: ./.github/workflows/release.yml with: - asana-task-url: ${{ github.event.inputs.asana-task-url }} + asana-task-url: ${{ needs.create_release_branch.outputs.asana_task_url }} branch: ${{ needs.create_release_branch.outputs.release_branch_name }} secrets: BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} From 7a5723ad94f9a4cf215b9af977da55e3a5ebfa1e Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 15 Dec 2023 09:21:51 +0100 Subject: [PATCH 5/8] Re-enable main branch check --- .github/workflows/code_freeze.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/code_freeze.yml b/.github/workflows/code_freeze.yml index ebeb82e487..7883f9200c 100644 --- a/.github/workflows/code_freeze.yml +++ b/.github/workflows/code_freeze.yml @@ -18,12 +18,12 @@ jobs: steps: - # - name: Assert main branch - # run: | - # if [ "${{ github.ref_name }}" != "main" ]; then - # echo "👎 Not the main branch" - # exit 1 - # fi + - name: Assert main branch + run: | + if [ "${{ github.ref_name }}" != "main" ]; then + echo "👎 Not the main branch" + exit 1 + fi - name: Check out the code uses: actions/checkout@v3 From 2f49b0a8bbd2d8711d4b884b1f769df058c4c9eb Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 15 Dec 2023 09:24:51 +0100 Subject: [PATCH 6/8] Revert "Disable flaky unit test" This reverts commit fde028799a0108134e1ad90a558e7bc3b9799b8f. --- .../Tests/PixelKitTests/PixelKitTests.swift | 87 +++++++++---------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift index 4e8d1e3dfa..8450c0df9c 100644 --- a/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift +++ b/LocalPackages/PixelKit/Tests/PixelKitTests/PixelKitTests.swift @@ -229,50 +229,49 @@ final class PixelKitTests: XCTestCase { } /// Test firing a daily pixel a few times - func testDailyPixelFrequency() throws { - throw XCTSkip() -// // Prepare test parameters -// let appVersion = "1.0.5" -// let headers = ["a": "2", "b": "3", "c": "2000"] -// let log = OSLog(subsystem: "TestSubsystem", category: "TestCategory") -// let event = TestEvent.dailyEvent -// let userDefaults = userDefaults() -// -// let timeMachine = TimeMachine() -// -// // Set expectations -// let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") -// fireCallbackCalled.expectedFulfillmentCount = 3 -// fireCallbackCalled.assertForOverFulfill = true -// -// // Prepare mock to validate expectations -// let pixelKit = PixelKit(dryRun: false, -// appVersion: appVersion, -// defaultHeaders: headers, -// log: log, -// dailyPixelCalendar: nil, -// dateGenerator: timeMachine.now, -// defaults: userDefaults) { _, _, _, _, _, _ in -// fireCallbackCalled.fulfill() -// } -// -// // Run test -// pixelKit.fire(event, frequency: .dailyOnly) // Fired -// -// timeMachine.travel(by: 60 * 60 * 2) -// pixelKit.fire(event, frequency: .dailyOnly) // Skipped (2 hours since last fire) -// -// timeMachine.travel(by: 60 * 60 * 24 + 1000) -// pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours + 1000 seconds since last fire) -// -// timeMachine.travel(by: 60 * 60 * 10) -// pixelKit.fire(event, frequency: .dailyOnly) // Skipped (10 hours since last fire) -// -// timeMachine.travel(by: 60 * 60 * 14) -// pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours since last fire) -// -// // Wait for expectations to be fulfilled -// wait(for: [fireCallbackCalled], timeout: 0.5) + func testDailyPixelFrequency() { + // Prepare test parameters + let appVersion = "1.0.5" + let headers = ["a": "2", "b": "3", "c": "2000"] + let log = OSLog(subsystem: "TestSubsystem", category: "TestCategory") + let event = TestEvent.dailyEvent + let userDefaults = userDefaults() + + let timeMachine = TimeMachine() + + // Set expectations + let fireCallbackCalled = expectation(description: "Expect the pixel firing callback to be called") + fireCallbackCalled.expectedFulfillmentCount = 3 + fireCallbackCalled.assertForOverFulfill = true + + // Prepare mock to validate expectations + let pixelKit = PixelKit(dryRun: false, + appVersion: appVersion, + defaultHeaders: headers, + log: log, + dailyPixelCalendar: nil, + dateGenerator: timeMachine.now, + defaults: userDefaults) { _, _, _, _, _, _ in + fireCallbackCalled.fulfill() + } + + // Run test + pixelKit.fire(event, frequency: .dailyOnly) // Fired + + timeMachine.travel(by: 60 * 60 * 2) + pixelKit.fire(event, frequency: .dailyOnly) // Skipped (2 hours since last fire) + + timeMachine.travel(by: 60 * 60 * 24 + 1000) + pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours + 1000 seconds since last fire) + + timeMachine.travel(by: 60 * 60 * 10) + pixelKit.fire(event, frequency: .dailyOnly) // Skipped (10 hours since last fire) + + timeMachine.travel(by: 60 * 60 * 14) + pixelKit.fire(event, frequency: .dailyOnly) // Fired (24 hours since last fire) + + // Wait for expectations to be fulfilled + wait(for: [fireCallbackCalled], timeout: 0.5) } /// Test firing a unique pixel From a26b37cc6ef2441e7ec7214344b70b3a3bba04b3 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 15 Dec 2023 09:25:53 +0100 Subject: [PATCH 7/8] Restore default branch check in Fastfile --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 91d20c3c18..5e67e77929 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -342,7 +342,7 @@ platform :mac do private_lane :macos_codefreeze_prechecks do ensure_git_status_clean - # ensure_git_branch(branch: DEFAULT_BRANCH) + ensure_git_branch(branch: DEFAULT_BRANCH) git_pull git_submodule_update(recursive: true, init: true) From f1916ad8f86eb9582e7617d00cc3b1870cc859f9 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 15 Dec 2023 09:27:01 +0100 Subject: [PATCH 8/8] Update Fastlane readme --- fastlane/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fastlane/README.md b/fastlane/README.md index bd417f28d9..13752cbc3f 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -47,6 +47,14 @@ Makes App Store release build and uploads it to App Store Connect Updates App Store metadata +### mac make_release_branch + +```sh +[bundle exec] fastlane mac make_release_branch +``` + +Executes the release preparation work in the repository + ### mac code_freeze ```sh @@ -71,6 +79,14 @@ Prepares new internal release on top of an existing one Executes the hotfix release preparation work in the repository +### mac update_embedded_files + +```sh +[bundle exec] fastlane mac update_embedded_files +``` + +Updates embedded files and pushes to remote. + ### mac set_version ```sh