diff --git a/.github/workflows/bump_internal_release.yml b/.github/workflows/bump_internal_release.yml index 4d0d9f440a..13280743b5 100644 --- a/.github/workflows/bump_internal_release.yml +++ b/.github/workflows/bump_internal_release.yml @@ -118,10 +118,10 @@ jobs: curl -fLSs "https://app.asana.com/api/1.0/tasks/${TASK_ID}?opt_fields=notes" \ -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ | jq -r .data.notes \ - | ./scripts/extract_release_notes.sh > release_notes.txt - release_notes="$(" ]]; then - echo "::error::Release notes are empty. Please add release notes to the Asana task and restart the workflow." + | ./scripts/extract_release_notes.sh -r > raw_release_notes.txt + raw_release_notes="$("* ]]; then + echo "::error::Release notes are empty or contain a placeholder. Please add release notes to the Asana task and restart the workflow." exit 1 fi diff --git a/.github/workflows/code_freeze.yml b/.github/workflows/code_freeze.yml index 2da53a932a..755282af5e 100644 --- a/.github/workflows/code_freeze.yml +++ b/.github/workflows/code_freeze.yml @@ -172,6 +172,7 @@ jobs: uses: ./.github/workflows/tag_release.yml with: asana-task-url: ${{ needs.create_release_branch.outputs.asana_task_url }} + base-branch: ${{ github.ref_name }} branch: ${{ needs.create_release_branch.outputs.release_branch_name }} prerelease: true secrets: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 528b219281..fd2341e1b6 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -54,6 +54,36 @@ jobs: env: SHELLCHECK_OPTS: -x -P scripts -P scripts/helpers + bats: + + name: Test Shell Scripts + + runs-on: macos-13 + + steps: + - name: Check out the code + if: github.event_name == 'pull_request' || github.event_name == 'push' + uses: actions/checkout@v4 + + - name: Check out the code + if: github.event_name != 'pull_request' && github.event_name != 'push' + uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch || github.ref_name }} + + - name: Install Bats + run: brew install bats-core + + - name: Run Bats tests + run: bats --formatter junit scripts/tests/* > bats-tests.xml + + - name: Publish unit tests report + uses: mikepenz/action-junit-report@v3 + if: always() # always run even if the previous step fails + with: + check_name: "Test Report: Shell Scripts" + report_paths: 'bats-tests.xml' + tests: name: Test @@ -343,7 +373,7 @@ jobs: create-asana-task: name: Create Asana Task - needs: [swiftlint, tests, release-build, verify-autoconsent-bundle, private-api] + needs: [swiftlint, bats, tests, release-build, verify-autoconsent-bundle, private-api] if: failure() && github.ref_name == 'main' && github.run_attempt == 1 @@ -360,7 +390,7 @@ jobs: close-asana-task: name: Close Asana Task - needs: [swiftlint, tests, release-build, verify-autoconsent-bundle, private-api] + needs: [swiftlint, bats, tests, release-build, verify-autoconsent-bundle, private-api] if: success() && github.ref_name == 'main' && github.run_attempt > 1 diff --git a/.github/workflows/publish_dmg_release.yml b/.github/workflows/publish_dmg_release.yml index 8daecea7be..2dd82d53ed 100644 --- a/.github/workflows/publish_dmg_release.yml +++ b/.github/workflows/publish_dmg_release.yml @@ -145,14 +145,14 @@ jobs: run: | curl -fLSs "https://app.asana.com/api/1.0/tasks/${TASK_ID}?opt_fields=notes" \ -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ - | jq -r .data.notes \ - | ./scripts/extract_release_notes.sh > release_notes.txt - release_notes="$(" ]]; then - echo "::error::Release notes are empty. Please add release notes to the Asana task and restart the workflow." + | jq -r .data.notes > release_task_content.txt + raw_release_notes="$(./scripts/extract_release_notes.sh -r < release_task_content.txt)" + if [[ ${#raw_release_notes} == 0 || "$raw_release_notes" == *"<-- Add release notes here -->"* ]]; then + echo "::error::Release notes are empty or contain a placeholder. Please add release notes to the Asana task and restart the workflow." exit 1 fi - echo "RELEASE_NOTES_FILE=release_notes.txt" >> $GITHUB_ENV + ./scripts/extract_release_notes.sh < release_task_content.txt > release_notes.html + echo "RELEASE_NOTES_FILE=release_notes.html" >> $GITHUB_ENV - name: Set up Sparkle tools env: @@ -189,21 +189,21 @@ jobs: ./scripts/appcast_manager/appcastManager.swift \ --release-to-internal-channel \ --dmg ${DMG_PATH} \ - --release-notes release_notes.txt \ + --release-notes-html release_notes.html \ --key sparkle_private_key ;; "public") ./scripts/appcast_manager/appcastManager.swift \ --release-to-public-channel \ --version ${VERSION} \ - --release-notes release_notes.txt \ + --release-notes-html release_notes.html \ --key sparkle_private_key ;; "hotfix") ./scripts/appcast_manager/appcastManager.swift \ --release-hotfix-to-public-channel \ --dmg ${DMG_PATH} \ - --release-notes release_notes.txt \ + --release-notes-html release_notes.html \ --key sparkle_private_key ;; *) diff --git a/scripts/appcast_manager/appcastManager.swift b/scripts/appcast_manager/appcastManager.swift index c3906a3cae..e7d28209e5 100755 --- a/scripts/appcast_manager/appcastManager.swift +++ b/scripts/appcast_manager/appcastManager.swift @@ -80,6 +80,9 @@ SYNOPSIS appcastManager --release-to-internal-channel --dmg --release-notes [--key ] appcastManager --release-to-public-channel --version [--release-notes ] [--key ] appcastManager --release-hotfix-to-public-channel --dmg --release-notes [--key ] + appcastManager --release-to-internal-channel --dmg --release-notes-html [--key ] + appcastManager --release-to-public-channel --version [--release-notes-html ] [--key ] + appcastManager --release-hotfix-to-public-channel --dmg --release-notes-html [--key ] appcastManager --help DESCRIPTION @@ -109,7 +112,13 @@ DESCRIPTION exit(0) case .releaseToInternalChannel, .releaseHotfixToPublicChannel: - guard let dmgPath = arguments.parameters["--dmg"], let releaseNotesPath = arguments.parameters["--release-notes"] else { + guard let dmgPath = arguments.parameters["--dmg"] else { + print("Missing required parameters") + exit(1) + } + let releaseNotesPath = arguments.parameters["--release-notes"] + let releaseNotesHTMLPath = arguments.parameters["--release-notes-html"] + guard releaseNotesPath != nil || releaseNotesHTMLPath != nil else { print("Missing required parameters") exit(1) } @@ -117,7 +126,11 @@ case .releaseToInternalChannel, .releaseHotfixToPublicChannel: print("➡️ Action: Add to internal channel") print("➡️ DMG Path: \(dmgPath)") - print("➡️ Release Notes Path: \(releaseNotesPath)") + if let releaseNotesPath { + print("➡️ Release Notes Path: \(releaseNotesPath)") + } else if let releaseNotesHTMLPath { + print("➡️ Release Notes HTML Path: \(releaseNotesHTMLPath)") + } if isCI, let keyFile { print("➡️ Key file: \(keyFile)") } @@ -130,7 +143,11 @@ case .releaseToInternalChannel, .releaseHotfixToPublicChannel: } // Handle release notes file - handleReleaseNotesFile(path: releaseNotesPath, updatesDirectoryURL: specificDir, dmgURL: dmgURL) + if let releaseNotesPath { + handleReleaseNotesFile(path: releaseNotesPath, updatesDirectoryURL: specificDir, dmgURL: dmgURL) + } else if let releaseNotesHTMLPath { + handleReleaseNotesHTML(path: releaseNotesHTMLPath, updatesDirectoryURL: specificDir, dmgURL: dmgURL) + } // Extract version number from DMG file name let versionNumber = getVersionNumberFromDMGFileName(dmgURL: dmgURL) @@ -170,6 +187,10 @@ case .releaseToPublicChannel: print("Release Notes Path: \(releaseNotesPath)") let dmgURLForPublic = specificDir.appendingPathComponent(dmgFileName) handleReleaseNotesFile(path: releaseNotesPath, updatesDirectoryURL: specificDir, dmgURL: dmgURLForPublic) + } else if let releaseNotesHTMLPath = arguments.parameters["--release-notes-html"] { + print("Release Notes Path: \(releaseNotesHTMLPath)") + let dmgURLForPublic = specificDir.appendingPathComponent(dmgFileName) + handleReleaseNotesHTML(path: releaseNotesHTMLPath, updatesDirectoryURL: specificDir, dmgURL: dmgURLForPublic) } else { print("👀 No new release notes provided. Keeping existing release notes.") } @@ -605,6 +626,27 @@ final class AppcastDownloader { // MARK: - Handling of Release Notes +func handleReleaseNotesHTML(path: String, updatesDirectoryURL: URL, dmgURL: URL) { + // Copy release notes file and rename it to match the dmg filename + let releaseNotesURL = URL(fileURLWithPath: path) + let destinationReleaseNotesURL = updatesDirectoryURL.appendingPathComponent(dmgURL.deletingPathExtension().lastPathComponent + ".html") + + do { + if FileManager.default.fileExists(atPath: destinationReleaseNotesURL.path) { + try FileManager.default.removeItem(at: destinationReleaseNotesURL) + print("Old release notes file removed.") + } + + // Save the converted release notes to the destination file + try FileManager.default.copyItem(at: releaseNotesURL, to: destinationReleaseNotesURL) + print("✅ New release notes HTML file copied to the updates directory.") + + } catch { + print("❌ Failed to copy and convert release notes HTML file: \(error).") + exit(1) + } +} + func handleReleaseNotesFile(path: String, updatesDirectoryURL: URL, dmgURL: URL) { // Copy release notes file and rename it to match the dmg filename let releaseNotesURL = URL(fileURLWithPath: path) diff --git a/scripts/extract_release_notes.sh b/scripts/extract_release_notes.sh index 9c7db812a6..f995620dfe 100755 --- a/scripts/extract_release_notes.sh +++ b/scripts/extract_release_notes.sh @@ -7,30 +7,133 @@ # start_marker="release notes" +pp_marker="^for privacy pro subscribers:?$" end_marker="this release includes:" +placeholder="add release notes here" is_capturing=0 +is_capturing_pp=0 has_content=0 +notes= +pp_notes= -if [[ "$1" == "-t" ]]; then - # capture included tasks instead of release notes - start_marker="this release includes:" - end_marker= -fi +output="html" + +case "$1" in + -a) + # Generate Asana rich text output + output="asana" + ;; + -r) + # Generate raw output instead of HTML + output="raw" + ;; + -t) + # Capture raw included tasks' URLs instead of release notes + output="tasks" + start_marker="this release includes:" + pp_marker= + end_marker= + ;; + *) + ;; +esac + +html_escape() { + local input="$1" + sed -e 's/&/\&/g' -e 's//\>/g' <<< "$input" +} + +make_links() { + local input="$1" + sed -E 's|(https://[^ ]*)|\1|' <<< "$input" +} + +lowercase() { + local input="$1" + tr '[:upper:]' '[:lower:]' <<< "$input" +} + +print_and_exit() { + echo -ne "$notes" + exit 0 +} + +add_to_notes() { + notes+="$1" + if [[ "$output" != "asana" ]]; then + notes+="\\n" + fi +} + +add_to_pp_notes() { + pp_notes+="$1" + if [[ "$output" != "asana" ]]; then + pp_notes+="\\n" + fi +} + +add_release_note() { + local release_note="$1" + local processed_release_note= + if [[ "$output" == "raw" || "$output" == "tasks" ]]; then + processed_release_note="$release_note" + else + processed_release_note="
  • $(make_links "$(html_escape "$release_note")")
  • " + fi + if [[ $is_capturing_pp -eq 1 ]]; then + add_to_pp_notes "$processed_release_note" + else + add_to_notes "$processed_release_note" + fi +} while read -r line do - if [[ $(tr '[:upper:]' '[:lower:]' <<< "$line") == "$start_marker" ]]; then - is_capturing=1 - elif [[ -n "$end_marker" && $(tr '[:upper:]' '[:lower:]' <<< "$line") == "$end_marker" ]]; then - exit 0 - elif [[ $is_capturing -eq 1 && -n "$line" ]]; then - has_content=1 - echo "$line" - fi + # Lowercase each line to compare with markers + lowercase_line="$(lowercase "$line")" + + if [[ "$lowercase_line" == "$start_marker" ]]; then + # Only start capturing here + is_capturing=1 + if [[ "$output" == "asana" ]]; then + add_to_notes "
      " + elif [[ "$output" == "html" ]]; then + # Add HTML header and start the list + add_to_notes "

      What's new

      " + add_to_notes "
        " + fi + elif [[ -n "$pp_marker" && "$lowercase_line" =~ $pp_marker ]]; then + is_capturing_pp=1 + if [[ "$output" == "asana" ]]; then + add_to_pp_notes "

      For Privacy Pro subscribers

        " + elif [[ "$output" == "html" ]]; then + # If we've reached the PP marker, end the list and start the PP list + add_to_pp_notes "
      " + add_to_pp_notes "

      For Privacy Pro subscribers

      " + add_to_pp_notes "
        " + else + add_to_pp_notes "$line" + fi + elif [[ -n "$end_marker" && "$lowercase_line" == "$end_marker" ]]; then + # If we've reached the end marker, check if PP notes are present and not a placeholder, and add them verbatim to notes + # shellcheck disable=SC2076 + if [[ -n "$pp_notes" && ! "$(lowercase "$pp_notes")" =~ "$placeholder" ]]; then + notes+="$pp_notes" # never add extra newline here (that's why we don't use `add_to_notes`) + fi + if [[ "$output" != "raw" ]]; then + # End the list on end marker + add_to_notes "
      " + fi + # Print output and exit + print_and_exit + elif [[ $is_capturing -eq 1 && -n "$line" ]]; then + has_content=1 + add_release_note "$line" + fi done if [[ $has_content -eq 0 ]]; then - exit 1 + exit 1 fi -exit 0 +print_and_exit diff --git a/scripts/tests/extract_release_notes/extract_release_notes.bats b/scripts/tests/extract_release_notes/extract_release_notes.bats new file mode 100644 index 0000000000..49f9a31e40 --- /dev/null +++ b/scripts/tests/extract_release_notes/extract_release_notes.bats @@ -0,0 +1,349 @@ +#!/usr/bin/env bats + +setup() { + DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" + # make executables in ./../../ visible to PATH + PATH="$DIR/../..:$PATH" +} + +main() { + bash extract_release_notes.sh "$@" +} + +# +# Functions below define inputs and expected outputs for the tests +# + +# Placeholder release notes with placeholder Privacy Pro section +placeholder() { + local mode="${1:-input}" + case "$mode" in + input) + cat <<-EOF + Note: This task's description is managed automatically. + Only the Release notes section below should be modified manually. + Please do not adjust formatting. + + Release notes + + <-- Add release notes here --> + + For Privacy Pro subscribers + + <-- Add release notes here --> + + This release includes: + EOF + ;; + raw) + cat <<-EOF + <-- Add release notes here --> + EOF + ;; + html) + cat <<-EOF +

      What's new

      +
        +
      • <-- Add release notes here -->
      • +
      + EOF + ;; + asana) + cat <<-EOF +
      • <-- Add release notes here -->
      + EOF + ;; + esac +} + +# Non-empty release notes with non-empty Privacy Pro section +full() { + local mode="${1:-input}" + case "$mode" in + input) + cat <<-EOF + Note: This task's description is managed automatically. + Only the Release notes section below should be modified manually. + Please do not adjust formatting. + + Release notes + + You can now find browser windows listed in the "Window" app menu and in the Dock menu. + We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts. + When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab. + The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed. + + For Privacy Pro subscribers + + VPN updates! More detailed connection info in the VPN dashboard, plus animations and usability improvements. + Visit https://duckduckgo.com/pro for more information. Privacy Pro is currently available to U.S. residents only. + + This release includes: + + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + EOF + ;; + raw) + cat <<-EOF + You can now find browser windows listed in the "Window" app menu and in the Dock menu. + We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts. + When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab. + The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed. + For Privacy Pro subscribers + VPN updates! More detailed connection info in the VPN dashboard, plus animations and usability improvements. + Visit https://duckduckgo.com/pro for more information. Privacy Pro is currently available to U.S. residents only. + EOF + ;; + html) + cat <<-EOF +

      What's new

      +
        +
      • You can now find browser windows listed in the "Window" app menu and in the Dock menu.
      • +
      • We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts.
      • +
      • When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab.
      • +
      • The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed.
      • +
      +

      For Privacy Pro subscribers

      +
        +
      • VPN updates! More detailed connection info in the VPN dashboard, plus animations and usability improvements.
      • +
      • Visit https://duckduckgo.com/pro for more information. Privacy Pro is currently available to U.S. residents only.
      • +
      + EOF + ;; + asana) + cat <<-EOF +
      • You can now find browser windows listed in the "Window" app menu and in the Dock menu.
      • We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts.
      • When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab.
      • The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed.

      For Privacy Pro subscribers

      • VPN updates! More detailed connection info in the VPN dashboard, plus animations and usability improvements.
      • Visit https://duckduckgo.com/pro for more information. Privacy Pro is currently available to U.S. residents only.
      + EOF + ;; + esac +} + +# Non-empty release notes and missing Privacy Pro section +without_privacy_pro_section() { + local mode="${1:-input}" + case "$mode" in + input) + cat <<-EOF + Note: This task's description is managed automatically. + Only the Release notes section below should be modified manually. + Please do not adjust formatting. + + Release notes + + You can now find browser windows listed in the "Window" app menu and in the Dock menu. + We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts. + When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab. + The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed. + + This release includes: + + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + EOF + ;; + raw) + cat <<-EOF + You can now find browser windows listed in the "Window" app menu and in the Dock menu. + We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts. + When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab. + The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed. + EOF + ;; + html) + cat <<-EOF +

      What's new

      +
        +
      • You can now find browser windows listed in the "Window" app menu and in the Dock menu.
      • +
      • We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts.
      • +
      • When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab.
      • +
      • The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed.
      • +
      + EOF + ;; + asana) + cat <<-EOF +
      • You can now find browser windows listed in the "Window" app menu and in the Dock menu.
      • We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts.
      • When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab.
      • The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed.
      + EOF + ;; + esac +} + +# Non-empty release notes and a placeholder Privacy Pro section +placeholder_privacy_pro_section() { + local mode="${1:-input}" + case "$mode" in + input) + cat <<-EOF + Note: This task's description is managed automatically. + Only the Release notes section below should be modified manually. + Please do not adjust formatting. + + Release notes + + You can now find browser windows listed in the "Window" app menu and in the Dock menu. + We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts. + When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab. + The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed. + + For Privacy Pro subscribers + + <-- Add release notes here --> + + This release includes: + + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + EOF + ;; + *) + without_privacy_pro_section "$mode" + ;; + esac +} + +# Non-empty release notes and Privacy Pro release header as a bullet point inside regular release notes +# Privacy Pro section header should be recognized and interpreted as a separate section (like in the full example) +privacy_pro_in_regular_release_notes() { + local mode="${1:-input}" + case "$mode" in + input) + cat <<-EOF + Note: This task's description is managed automatically. + Only the Release notes section below should be modified manually. + Please do not adjust formatting. + + Release notes + + You can now find browser windows listed in the "Window" app menu and in the Dock menu. + We also added "Duplicate Tab" to the app menu so you can use it as an action in Apple Shortcuts. + When watching videos in Duck Player, clicking endscreen recommendations will now open those videos in the same tab. + The bug that duplicated sites in your browsing history has been fixed, and the visual glitching that sometimes occurred during session restore and app launch has been addressed. + For Privacy Pro subscribers + VPN updates! More detailed connection info in the VPN dashboard, plus animations and usability improvements. + Visit https://duckduckgo.com/pro for more information. Privacy Pro is currently available to U.S. residents only. + + This release includes: + + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + https://app.asana.com/0/0/0/f/ + EOF + ;; + *) + full "$mode" + ;; + esac +} + +# +# Test cases start here +# + +# bats test_tags=placeholder, raw +@test "input: placeholder | output: raw" { + run main -r <<< "$(placeholder)" + [ "$status" -eq 0 ] + [ "$output" == "$(placeholder raw)" ] +} + +# bats test_tags=placeholder, html +@test "input: placeholder | output: html" { + run main -h <<< "$(placeholder)" + [ "$status" -eq 0 ] + [ "$output" == "$(placeholder html)" ] +} + +# bats test_tags=placeholder, asana +@test "input: placeholder | output: asana" { + run main -a <<< "$(placeholder)" + [ "$status" -eq 0 ] + [ "$output" == "$(placeholder asana)" ] +} + +# bats test_tags=full, raw +@test "input: full | output: raw" { + run main -r <<< "$(full)" + [ "$status" -eq 0 ] + [ "$output" == "$(full raw)" ] +} + +# bats test_tags=full, html +@test "input: full | output: html" { + run main -h <<< "$(full)" + [ "$status" -eq 0 ] + [ "$output" == "$(full html)" ] +} + +# bats test_tags=full, asana +@test "input: full | output: asana" { + run main -a <<< "$(full)" + [ "$status" -eq 0 ] + [ "$output" == "$(full asana)" ] +} + +# bats test_tags=no-pp, raw +@test "input: without_privacy_pro_section | output: raw" { + run main -r <<< "$(without_privacy_pro_section)" + [ "$status" -eq 0 ] + [ "$output" == "$(without_privacy_pro_section raw)" ] +} + +# bats test_tags=no-pp, html +@test "input: without_privacy_pro_section | output: html" { + run main -h <<< "$(without_privacy_pro_section)" + [ "$status" -eq 0 ] + [ "$output" == "$(without_privacy_pro_section html)" ] +} + +# bats test_tags=no-pp, asana +@test "input: without_privacy_pro_section | output: asana" { + run main -a <<< "$(without_privacy_pro_section)" + [ "$status" -eq 0 ] + [ "$output" == "$(without_privacy_pro_section asana)" ] +} + +# bats test_tags=placeholder-pp, raw +@test "input: placeholder_privacy_pro_section | output: raw" { + run main -r <<< "$(placeholder_privacy_pro_section)" + [ "$status" -eq 0 ] + [ "$output" == "$(placeholder_privacy_pro_section raw)" ] +} + +# bats test_tags=placeholder-pp, html +@test "input: placeholder_privacy_pro_section | output: html" { + run main -h <<< "$(placeholder_privacy_pro_section)" + [ "$status" -eq 0 ] + [ "$output" == "$(placeholder_privacy_pro_section html)" ] +} + +# bats test_tags=placeholder-pp, asana +@test "input: placeholder_privacy_pro_section | output: asana" { + run main -a <<< "$(placeholder_privacy_pro_section)" + [ "$status" -eq 0 ] + [ "$output" == "$(placeholder_privacy_pro_section asana)" ] +} + +# bats test_tags=inline-pp, raw +@test "input: privacy_pro_in_regular_release_notes | output: raw" { + run main -r <<< "$(privacy_pro_in_regular_release_notes)" + [ "$status" -eq 0 ] + [ "$output" == "$(privacy_pro_in_regular_release_notes raw)" ] +} + +# bats test_tags=inline-pp, html +@test "input: privacy_pro_in_regular_release_notes | output: html" { + run main -h <<< "$(privacy_pro_in_regular_release_notes)" + [ "$status" -eq 0 ] + [ "$output" == "$(privacy_pro_in_regular_release_notes html)" ] +} + +# bats test_tags=inline-pp, asana +@test "input: privacy_pro_in_regular_release_notes | output: asana" { + run main -a <<< "$(privacy_pro_in_regular_release_notes)" + [ "$status" -eq 0 ] + [ "$output" == "$(privacy_pro_in_regular_release_notes asana)" ] +} diff --git a/scripts/update_asana_for_release.sh b/scripts/update_asana_for_release.sh index a0aef9c83e..b5610faed7 100755 --- a/scripts/update_asana_for_release.sh +++ b/scripts/update_asana_for_release.sh @@ -48,7 +48,7 @@ fetch_current_release_notes() { curl -fLSs "${asana_api_url}/tasks/${release_task_id}?opt_fields=notes" \ -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ | jq -r .data.notes \ - | "${cwd}"/extract_release_notes.sh + | "${cwd}"/extract_release_notes.sh -a } get_task_id() { @@ -58,19 +58,6 @@ get_task_id() { fi } -construct_release_notes() { - local escaped_release_note - - if [[ -n "${release_notes[*]}" ]]; then - printf '%s' '
        ' - for release_note in "${release_notes[@]}"; do - escaped_release_note="$(sed -e 's/&/\&/g' -e 's//\>/g' <<< "${release_note}")" - printf '%s' "
      • ${escaped_release_note}
      • " - done - printf '%s' '
      ' - fi -} - construct_this_release_includes() { if [[ -n "${task_ids[*]}" ]]; then printf '%s' '
        ' @@ -89,7 +76,7 @@ construct_release_task_description() { printf '%s' 'Please do not adjust formatting.' printf '%s' '

        Release notes

        ' - construct_release_notes + printf '%s' "$release_notes" printf '%s' '

        This release includes:

        ' construct_this_release_includes @@ -105,7 +92,7 @@ construct_release_announcement_task_description() { printf '%s' '
      \n
      ' printf '%s' '

      Release notes

      ' - construct_release_notes + printf '%s' "$release_notes" printf '%s' '\n' printf '%s' '

      This release includes:

      ' @@ -282,10 +269,8 @@ handle_internal_release() { done <<< "$(find_task_urls_in_git_log "$last_release_tag")" # 2. Fetch current release notes from Asana release task. - local release_notes=() - while read -r line; do - release_notes+=("$line") - done <<< "$(fetch_current_release_notes "${release_task_id}")" + local release_notes + release_notes="$(fetch_current_release_notes "${release_task_id}")" # 3. Construct new release task description local html_notes @@ -325,10 +310,8 @@ handle_public_release() { complete_tasks "${task_ids[@]}" # 5. Fetch current release notes from Asana release task. - local release_notes=() - while read -r line; do - release_notes+=("$line") - done <<< "$(fetch_current_release_notes "${release_task_id}")" + local release_notes + release_notes="$(fetch_current_release_notes "${release_task_id}")" # 6. Construct release announcement task description local html_notes