Skip to content

Commit

Permalink
Merge branch 'dominik/nightly-internal-releases' into dominik/test-ba…
Browse files Browse the repository at this point in the history
…se-branch
  • Loading branch information
ayoy committed Mar 7, 2024
2 parents a74f79f + e683fa3 commit 866200d
Show file tree
Hide file tree
Showing 17 changed files with 407 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
data:
html_text: |
<body>
Build ${TAG} is now available for internal testing through Sparkle and TestFlight.
Added in this release:
${TASKS_SINCE_LAST_INTERNAL_RELEASE}
<a href='${DMG_URL}'>📥 DMG download link</a>
</body>
31 changes: 31 additions & 0 deletions .github/actions/asana-find-release-task/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Find Release Task in Asana
description: |
Searches macOS App Development Asana project for an active release task matching the latest version
(as specified by GitHub releases). Returns an error when no release task is found, or when there's
an active (incomplete) hotfix release task. Tasks are identified by the name.
inputs:
access-token:
description: "Asana access token"
required: true
type: string
github-token:
description: "GitHub Token"
required: false
type: string
outputs:
task-id:
description: "Release task ID"
value: ${{ steps.find-release-task.outputs.task-id }}
task-url:
description: "Release task URL"
value: ${{ steps.find-release-task.outputs.task-url }}
runs:
using: "composite"
steps:
- id: find-release-task
shell: bash
env:
ASANA_ACCESS_TOKEN: ${{ inputs.access-token }}
GITHUB_TOKEN: ${{ inputs.github-token || github.token }}
run: |
${{ github.action_path }}/find-release-task.sh
93 changes: 93 additions & 0 deletions .github/actions/asana-find-release-task/find_release_task.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash
#
# This script is used to find the current release task.
#

set -e

asana_app_url="https://app.asana.com/0/0"
asana_api_url="https://app.asana.com/api/1.0"
default_release_and_maintenance_section_id="1202202395298964"

find_latest_marketing_version() {
local latest_tag
latest_tag="$(gh api /repos/duckduckgo/macos-browser/releases?per_page=1 --jq .[0].tag_name)"
echo "${latest_tag%-*}" # remove everything after - (including -) i.e. x.y.z-N becomes x.y.z
}

# Find the release task in 'Release & Maintenance' section of the 'macOS App Development' Asana project.
# - If there is no release task, return nothing.
# - If there is an active (incomplete) hotfix task, return nothing.
find_release_task() {
local version="$1"
local task_name="macOS App Release ${version}"
local hotfix_task_name_prefix="macOS App Hotfix Release"
local section_id="${RELEASE_AND_MAINTENANCE_SECTION_ID:-$default_release_and_maintenance_section_id}"

# `completed_since=now` returns only incomplete tasks
local url="${asana_api_url}/sections/${section_id}/tasks?opt_fields=name,created_at&limit=100&completed_since=now"
local response
local hotfix_task_id
local created_at

# go through all tasks in the section (there may be multiple requests in case there are more than 100 tasks in the section)
# repeat until no more pages (next_page.uri is null)
while true; do
response="$(curl -fLSs "$url" -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}")"
# echo "$response"

# find task id only if not found yet
if [[ -z "$release_task_id" || "$release_task_id" == "null" ]]; then
release_task_id="$(jq -r ".data[] | select(.name == \"${task_name}\").gid" <<< "$response")"
created_at="$(jq -r ".data[] | select(.name == \"${task_name}\").created_at" <<< "$response")"

# Only consider release tasks created in the last 4 days.
# - We don't want to bump internal release automatically for release tasks that are open for more than a week.
# - The automatic check is only done Tuesday-Friday. If the release task is still open next Tuesday, it's unexpected,
# and likely something went wrong.
if [[ -n "$created_at" && "$created_at" != "null" ]]; then
created_at_timestamp="$(TZ=UTC date -j -f "%Y-%m-%dT%H:%M:%S." "$created_at" +%s)"
four_days_ago="$(date -j -v-4d +%s)"
if [[ "$created_at_timestamp" -le "$four_days_ago" ]]; then
echo "::error::Found release task: ${asana_app_url}/${release_task_id} but it's older than 4 days, skipping."
exit 1
fi
fi
fi

# find hotfix task id only if not found yet
if [[ -z "$hotfix_task_id" || "$hotfix_task_id" == "null" ]]; then
hotfix_task_id="$(jq -r ".data[] | select(.name | startswith(\"${hotfix_task_name_prefix}\")).gid" <<< "$response")"
fi

url="$(jq -r .next_page.uri <<< "$response")"

# break on last page
if [[ "$url" == "null" ]]; then
break
fi
done

if [[ -n "$hotfix_task_id" && "$hotfix_task_id" != "null" ]]; then
echo "::error::Found active hotfix task: ${asana_app_url}/${hotfix_task_id}"
exit 1
fi
}

main() {
local latest_marketing_version
local release_task_id
latest_marketing_version="$(find_latest_marketing_version)"
echo "Latest marketing version: ${latest_marketing_version}"
find_release_task "$latest_marketing_version"

if [[ -n "$release_task_id" && "$release_task_id" != "null" ]]; then
echo "Found ${latest_marketing_version} release task: ${asana_app_url}/${release_task_id}/f"
echo "task-id=${release_task_id}" >> "$GITHUB_OUTPUT"
echo "task-url=${asana_app_url}/${release_task_id}/f" >> "$GITHUB_OUTPUT"
else
echo "::warning::No release task found for version: ${latest_marketing_version}"
fi
}

main "%@"
72 changes: 59 additions & 13 deletions .github/workflows/bump_internal_release.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
name: Bump Internal Release

on:
schedule:
- cron: '0 5 * * 2,3,4,5' # Run at 05:00 UTC on Tuesday through Friday
workflow_dispatch:
inputs:
asana-task-url:
description: "Asana release task URL"
required: true
required: false
type: string
base-branch:
description: "Base branch (defaults to main, only override for testing)"
Expand All @@ -14,13 +16,22 @@ on:

jobs:

assert_release_branch:
# when on schedule:
# 1. find the release branch - check out the repository, find the latest tag, strip build number, check out the branch.
# 2. find asana task - "macOS App Release x.y.z", incomplete, in macOS App Development.
# 3. find hotfix task - if there's any 'macOS App Hotfix Release a.b.c', incomplete, in macOS App Development, skip the release.

validate_input_conditions:

name: Assert Release Branch
name: Validate Input Conditions

runs-on: ubuntu-latest
timeout-minutes: 10

outputs:
skip-release: ${{ steps.check-for-changes.outputs.skip-release }}
asana-task-url: ${{ steps.set-parameters.outputs.asana-task-url }}

steps:

- name: Assert release branch
Expand All @@ -33,17 +44,52 @@ jobs:
- name: Check out the code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history and tags in order to extract Asana task URLs from git log
ref: ${{ github.ref_name }}


- name: Check if there are changes to the release branch
id: check-for-changes
run: |
if [[ "${{ github.event_name }}" != "schedule" ]]; then
echo "skip-release=false" >> $GITHUB_OUTPUT
else
latest_tag="$(git describe --tags --abbrev=0)"
changed_files="$(git diff --name-only "$latest_tag" | grep -v -E '.github|scripts')"
if [[ ${#changed_files} == 0 ]]; then
echo "::warning::No changes to the release branch (or only scripts and workflows). Skipping automatic release."
echo "skip-release=true" >> $GITHUB_OUTPUT
else
echo "skip-release=false" >> $GITHUB_OUTPUT
fi
fi
- name: Find Asana release task
id: find-asana-task
if: github.event.inputs.asana-task-url == null
uses: ./.github/actions/asana-find-release-task
with:
access-token: ${{ secrets.ASANA_ACCESS_TOKEN }}

- name: Extract Asana Task ID
id: task-id
if: github.event.inputs.asana-task-url
uses: ./.github/actions/asana-extract-task-id
with:
task-url: ${{ github.event.inputs.asana-task-url }}

- name: Set parameters
id: set-parameters
env:
TASK_ID: ${{ steps.find-asana-task.outputs.task-id || steps.task-id.outputs.task-id }}
ASANA_TASK_URL: ${{ steps.find-asana-task.outputs.task-url || github.event.inputs.asana-task-url }}
run: |
echo "task-id=${TASK_ID}" >> $GITHUB_OUTPUT
echo "asana-task-url=${ASANA_TASK_URL}" >> $GITHUB_OUTPUT
- name: Validate release notes
env:
TASK_ID: ${{ steps.task-id.outputs.task-id }}
TASK_ID: ${{ steps.set-parameters.outputs.task-id }}
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
run: |
curl -fLSs "https://app.asana.com/api/1.0/tasks/${TASK_ID}?opt_fields=notes" \
Expand All @@ -60,7 +106,7 @@ jobs:

name: Increment Build Number

needs: assert_release_branch
needs: validate_input_conditions
runs-on: macos-13-xlarge
timeout-minutes: 10

Expand Down Expand Up @@ -93,7 +139,7 @@ jobs:
id: task-id
uses: ./.github/actions/asana-extract-task-id
with:
task-url: ${{ github.event.inputs.asana-task-url }}
task-url: ${{ needs.validate_input_conditions.outputs.asana-task-url }}

- name: Update Asana tasks for the release
env:
Expand All @@ -106,10 +152,10 @@ jobs:
prepare_release:
name: Prepare Release
needs: increment_build_number
needs: [ validate_input_conditions, increment_build_number ]
uses: ./.github/workflows/release.yml
with:
asana-task-url: ${{ github.event.inputs.asana-task-url }}
asana-task-url: ${{ needs.validate_input_conditions.outputs.asana-task-url }}
secrets:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
Expand Down Expand Up @@ -139,10 +185,10 @@ jobs:

tag_and_merge:
name: Tag and Merge Branch
needs: [ prepare_release ]
needs: [ validate_input_conditions, prepare_release ]
uses: ./.github/workflows/tag_release.yml
with:
asana-task-url: ${{ github.event.inputs.asana-task-url }}
asana-task-url: ${{ needs.validate_input_conditions.outputs.asana-task-url }}
branch: ${{ github.ref_name }}
base-branch: ${{ github.event.inputs.base-branch || 'main' }}
prerelease: true
Expand All @@ -153,10 +199,10 @@ jobs:

publish_release:
name: Publish DMG Release
needs: [ tag_and_merge ]
needs: [ validate_input_conditions, tag_and_merge ]
uses: ./.github/workflows/publish_dmg_release.yml
with:
asana-task-url: ${{ github.event.inputs.asana-task-url }}
asana-task-url: ${{ needs.validate_input_conditions.outputs.asana-task-url }}
secrets:
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
TEST_AWS_ACCESS_KEY_ID_RELEASE_S3: ${{ secrets.TEST_AWS_ACCESS_KEY_ID_RELEASE_S3 }}
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/code_freeze.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ jobs:
access-token: ${{ secrets.ASANA_ACCESS_TOKEN }}
github-handle: ${{ github.actor }}

- name: Get Asana user ID
id: get-asana-user-id
uses: duckduckgo/apple-infra/actions/asana-get-user-id-for-github-handle@main
with:
access-token: ${{ secrets.ASANA_ACCESS_TOKEN }}
github-handle: ${{ github.actor }}

- name: Create release task
id: create_release_task
env:
Expand Down
17 changes: 16 additions & 1 deletion .github/workflows/publish_dmg_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ jobs:
- name: Check out the code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history and tags in order to extract Asana task URLs from git log
submodules: recursive

- name: Select Xcode
Expand Down Expand Up @@ -241,6 +242,15 @@ jobs:
announcement-task-contents.txt
echo "announcement-task-contents=$(sed 's/"/\\"/g' < announcement-task-contents.txt)" >> $GITHUB_OUTPUT
- name: Get tasks since last internal release
id: get-tasks-since-last-internal-release
if: contains(github.event.inputs.release-type, '') == false
env:
GH_TOKEN: ${{ github.token }}
run: |
tasks="$(./scripts/update_asana_for_release.sh list-tasks-in-last-internal-release)"
echo "tasks=$tasks" >> $GITHUB_OUTPUT
- name: Set common environment variables
if: always()
env:
Expand All @@ -252,6 +262,7 @@ jobs:
echo "RELEASE_BUCKET_NAME=${{ vars.TEST_RELEASE_BUCKET_NAME }}" >> $GITHUB_ENV
echo "RELEASE_BUCKET_PREFIX=${{ vars.TEST_RELEASE_BUCKET_PREFIX }}" >> $GITHUB_ENV
echo "RELEASE_TASK_ID=${{ steps.task-id.outputs.task-id }}" >> $GITHUB_ENV
echo "TASKS_SINCE_LAST_INTERNAL_RELEASE=${{ steps.get-tasks-since-last-internal-release.outputs.tasks }}" >> $GITHUB_ENV
echo "VERSION=${{ steps.verify-tag.outputs.release-version }}" >> $GITHUB_ENV
echo "WORKFLOW_URL=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_ENV
Expand All @@ -263,7 +274,11 @@ jobs:
if [[ "${RELEASE_TYPE}" == "internal" ]]; then
echo "task-template=validate-check-for-updates-internal" >> $GITHUB_OUTPUT
echo "comment-template=validate-check-for-updates-internal" >> $GITHUB_OUTPUT
echo "release-task-comment-template=internal-release-complete" >> $GITHUB_OUTPUT
if [[ -n "${TASKS_SINCE_LAST_INTERNAL_RELEASE}" ]]; then
echo "release-task-comment-template=internal-release-complete-with-tasks" >> $GITHUB_OUTPUT
else
echo "release-task-comment-template=internal-release-complete" >> $GITHUB_OUTPUT
fi
else
echo "task-template=validate-check-for-updates-public" >> $GITHUB_OUTPUT
echo "comment-template=validate-check-for-updates-public" >> $GITHUB_OUTPUT
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13612,7 +13612,7 @@
repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 114.1.0;
version = "114.1.0-2";
};
};
AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/BrowserServicesKit",
"state" : {
"revision" : "045a8782c3dbbf79fc088b38120dea1efadc13e1",
"version" : "114.1.0"
"revision" : "b8763fdca7848d110b92e1a719e0ba84c2e7b114",
"version" : "114.1.0-2"
}
},
{
"identity" : "content-scope-scripts",
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/content-scope-scripts",
"state" : {
"revision" : "a3690b7666a3617693383d948cb492513f6aa569",
"version" : "5.0.0"
"revision" : "f6241631fc14cc2d0f47950bfdc4d6c30bf90130",
"version" : "5.4.0"
}
},
{
Expand Down
Loading

0 comments on commit 866200d

Please sign in to comment.