Skip to content

Commit

Permalink
Update Publish DMG Release workflow to support public and hotfix rele…
Browse files Browse the repository at this point in the history
…ases (#2239)

Task/Issue URL: https://app.asana.com/0/1199230911884351/1206616537326298/f

Description:
This change updates publish_dmg_release.yml workflow to take an extra parameter called release-type
(internal, public or hotfix) and adjust calls to appcastManager and upload_to_s3.sh so that they
perform necessary work for public and hotfix release as needed.
  • Loading branch information
ayoy authored Feb 22, 2024
1 parent 32da4eb commit e8bf262
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 231 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data:
html_text: |
<body>
<h2>[ACTION NEEDED] Publishing ${TAG} hotfix release to Sparkle failed</h2>
<a data-asana-gid='${ASSIGNEE_ID}'/>, please proceed with generating appcast2.xml and uploading files to S3 from your local machine, <a data-asana-gid='${TASK_ID}' data-asana-dynamic='false'>according to instructions</a>.
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data:
html_text: |
<body>
<h2>[ACTION NEEDED] Publishing ${TAG} release to Sparkle failed</h2>
<a data-asana-gid='${ASSIGNEE_ID}'/>, please proceed with generating appcast2.xml and uploading files to S3 from your local machine, <a data-asana-gid='${TASK_ID}' data-asana-dynamic='false'>according to instructions</a>.
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
data:
html_text: |
<body>
Build ${TAG} is now available publicly through Sparkle and TestFlight.
<a href='${DMG_URL}'>📥 DMG download link</a>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
data:
html_text: |
<body>
<h2>Build ${TAG} is available publicly through Sparkle 🚀</h2>
<ul>
<li>🌟 New appcast file has been generated and uploaded to S3, together with binary delta files.</li>
<li>👀 <a data-asana-gid='${ASSIGNEE_ID}'/>, please proceed by following instructions in <a data-asana-gid='${TASK_ID}'/> which concludes the release process.</li>
</ul>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
data:
name: Generate appcast2.xml for ${TAG} hotfix release and upload assets to S3
assignee: "${ASSIGNEE_ID}"
html_notes: |
<body>
Publishing ${TAG} hotfix release failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.
<ol>
<li>Create a new file called <code>release-notes.txt</code> on your disk.
<ul>
<li>Add each release note as a separate line and don't add bullet points (•) – the script will add them automatically.</li>
</ul></li>
<li>Run <code>appcastManager</code>:
<ul>
<li><code>./scripts/appcast_manager/appcastManager.swift --release-hotfix-to-public-channel --dmg ~/Downloads/${DMG_NAME} --release-notes release-notes.txt</code></li>
</ul></li>
<li>Verify that the new build is in the appcast file with the latest release notes and no internal channel tag. The phased rollout tag should <em>not</em> be present:
<ul>
<li><code>&lt;sparkle:phasedRolloutInterval&gt;43200&lt;/sparkle:phasedRolloutInterval&gt;</code></li>
</ul></li>
<li>Run <code>upload_to_s3.sh</code> script:
<ul>
<li><code>./scripts/upload_to_s3/upload_to_s3.sh --run --overwrite-duckduckgo-dmg ${VERSION}</code></li>
</ul></li>
</ol>
When done, please verify that "Check for Updates" works correctly:
<ol>
<li>Launch a debug version of the app with an old version number.</li>
<li>Make sure you're not identified as an internal user in the app.</li>
<li>Go to Main Menu → DuckDuckGo → Check for Updates...</li>
<li>Verify that you're being offered to update to ${TAG}.</li>
<li>Verify that the update works.</li>
</ol>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ data:
assignee: "${ASSIGNEE_ID}"
html_notes: |
<body>
Publishing internal release ${TAG} failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.
Publishing ${TAG} internal release failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.
<ol>
<li>Download <a href='${DMG_URL}'>the DMG for ${TAG} release</a>.</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
data:
name: Generate appcast2.xml for ${TAG} public release and upload assets to S3
assignee: "${ASSIGNEE_ID}"
html_notes: |
<body>
Publishing ${TAG} release failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.
<ol>
<li>Create a new file called <code>release-notes.txt</code> on your disk.
<ul>
<li>Add each release note as a separate line and don't add bullet points (•) – the script will add them automatically.</li>
</ul></li>
<li>Run <code>appcastManager</code>:
<ul>
<li><code>./scripts/appcast_manager/appcastManager.swift --release-to-public-channel --version ${VERSION} --release-notes release-notes.txt</code></li>
</ul></li>
<li>Verify that the new build is in the appcast file with the latest release notes, the phased rollout tag (below) and no internal channel tag:
<ul>
<li><code>&lt;sparkle:phasedRolloutInterval&gt;43200&lt;/sparkle:phasedRolloutInterval&gt;</code></li>
</ul></li>
<li>Run <code>upload_to_s3.sh</code> script:
<ul>
<li><code>./scripts/upload_to_s3/upload_to_s3.sh --run --overwrite-duckduckgo-dmg ${VERSION}</code></li>
</ul></li>
</ol>
When done, please verify that "Check for Updates" works correctly:
<ol>
<li>Launch a debug version of the app with an old version number.</li>
<li>Make sure you're not identified as an internal user in the app.</li>
<li>Go to Main Menu → DuckDuckGo → Check for Updates...</li>
<li>Verify that you're being offered to update to ${TAG}.</li>
<li>Verify that the update works.</li>
</ol>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
data:
name: Validate that 'Check For Updates' upgrades to ${TAG}
assignee: "${ASSIGNEE_ID}"
html_notes: |
<body>
<h1>Build ${TAG} has been released publicly via Sparkle 🎉</h1>
Please verify that "Check for Updates" works correctly:
<ol>
<li>Launch a debug version of the app with an old version number.</li>
<li>Make sure you're not identified as an internal user in the app.</li>
<li>Go to Main Menu → DuckDuckGo → Check for Updates...</li>
<li>Verify that you're being offered to update to ${TAG}.</li>
<li>Verify that the update works.</li>
</ol>
<h1>🚨In case "Check for Updates" is broken</h1>
You can restore previous version of the appcast2.xml:
<ol>
<li>Download the ${OLD_APPCAST_NAME} file attached to this task.</li>
<li>Log in to AWS session:
<ul>
<li><code>aws --profile ddg-macos sso login</code></li>
</ul></li>
<li>Overwrite appcast2.xml with the old version:
<ul>
<li><code>aws --profile ddg-macos s3 cp ${OLD_APPCAST_NAME} s3://${RELEASE_BUCKET_NAME}/${RELEASE_BUCKET_PREFIX}/appcast2.xml --acl public-read</code></li>
</ul></li>
</ol>
<hr>
<h1>Summary of automated changes</h1>
<h2>Changes to appcast2.xml</h2>
See the attached <em>${APPCAST_PATCH_NAME}</em> file.
<h2>Release notes</h2>
See the attached <em>${RELEASE_NOTES_FILE}</em> file for release notes extracted automatically from <a data-asana-gid='${RELEASE_TASK_ID}' data-asana-dynamic='false'>the release task</a> description.
<h2>List of files uploaded to S3</h2>
<ol>
${FILES_UPLOADED}
</ol>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
86 changes: 66 additions & 20 deletions .github/workflows/publish_dmg_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@ on:
description: "Tag to publish"
required: true
type: string
release-type:
description: "Release type"
required: true
type: choice
options:
- internal
- public
- hotfix

jobs:

publish-to-sparkle:

name: Publish internal release to Sparkle
name: Publish a release to Sparkle

runs-on: macos-13-xlarge
timeout-minutes: 10
Expand All @@ -37,13 +45,16 @@ jobs:
echo "::error::The provided tag ($tag) has incorrect format (attempted to match ${tag_regex})."
exit 1
fi
echo "tag-in-filename=${tag//-/.}" >> $GITHUB_OUTPUT
echo "release-version=${tag//-/.}" >> $GITHUB_OUTPUT
- name: Check out the code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer

- name: Set up Sparkle tools
env:
SPARKLE_URL: https://github.com/sparkle-project/Sparkle/releases/download/${{ vars.SPARKLE_VERSION }}/Sparkle-${{ vars.SPARKLE_VERSION }}.tar.xz
Expand All @@ -53,8 +64,9 @@ jobs:
- name: Fetch DMG
id: fetch-dmg
if: ${{ github.event.inputs.release-type != 'public' }}
env:
DMG_NAME: duckduckgo-${{ steps.verify-tag.outputs.tag-in-filename }}.dmg
DMG_NAME: duckduckgo-${{ steps.verify-tag.outputs.release-version }}.dmg
run: |
DMG_URL="${{ vars.DMG_URL_ROOT }}${DMG_NAME}"
curl -fLSs -o "$DMG_NAME" "$DMG_URL"
Expand All @@ -78,25 +90,44 @@ jobs:
| ./scripts/extract_release_notes.sh > release_notes.txt
echo "RELEASE_NOTES_FILE=release_notes.txt" >> $GITHUB_ENV
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer

- name: Generate appcast
id: appcast
env:
DMG_PATH: ${{ steps.fetch-dmg.outputs.dmg-path }}
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
RELEASE_TYPE: ${{ github.event.inputs.release-type }}
VERSION: ${{ steps.verify-tag.outputs.release-version }}
run: |
echo -n "$SPARKLE_PRIVATE_KEY" > sparkle_private_key
chmod 600 sparkle_private_key
./scripts/appcast_manager/appcastManager.swift \
--release-to-internal-channel \
--dmg ${DMG_PATH} \
--release-notes release_notes.txt \
--key sparkle_private_key
case "$RELEASE_TYPE" in
"internal")
./scripts/appcast_manager/appcastManager.swift \
--release-to-internal-channel \
--dmg ${DMG_PATH} \
--release-notes release_notes.txt \
--key sparkle_private_key
;;
"public")
./scripts/appcast_manager/appcastManager.swift \
--release-to-public-channel \
--version ${VERSION} \
--release-notes release_notes.txt \
--key sparkle_private_key
;;
"hotfix")
./scripts/appcast_manager/appcastManager.swift \
--release-hotfix-to-public-channel \
--dmg ${DMG_PATH} \
--release-notes release_notes.txt \
--key sparkle_private_key
;;
*)
;;
esac
appcast_patch_name="appcast2-${{ steps.verify-tag.outputs.tag-in-filename }}.patch"
appcast_patch_name="appcast2-${VERSION}.patch"
mv -f ${{ env.SPARKLE_DIR }}/appcast_diff.txt ${{ env.SPARKLE_DIR }}/${appcast_patch_name}
echo "appcast-patch-name=${appcast_patch_name}" >> $GITHUB_OUTPUT
Expand All @@ -112,14 +143,20 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_RELEASE_S3 }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_RELEASE_S3 }}
AWS_DEFAULT_REGION: ${{ vars.AWS_DEFAULT_REGION }}
RELEASE_TYPE: ${{ github.event.inputs.release-type }}
VERSION: ${{ steps.verify-tag.outputs.release-version }}
run: |
# Back up existing appcast2.xml
OLD_APPCAST_NAME=appcast2_old.xml
echo "OLD_APPCAST_NAME=${OLD_APPCAST_NAME}" >> $GITHUB_ENV
curl -fLSs "${{ vars.DMG_URL_ROOT }}appcast2.xml" --output "${OLD_APPCAST_NAME}"
# Upload files to S3
./scripts/upload_to_s3/upload_to_s3.sh --run --force
if [[ "${RELEASE_TYPE}" == "internal" ]]; then
./scripts/upload_to_s3/upload_to_s3.sh --run --force
else
./scripts/upload_to_s3/upload_to_s3.sh --run --force --overwrite-duckduckgo-dmg "${VERSION}"
fi
if [[ -f "${{ env.SPARKLE_DIR }}/uploaded_files_list.txt" ]]; then
echo "FILES_UPLOADED=$(awk '{ print "<li><code>"$1"</code></li>"; }' < ${{ env.SPARKLE_DIR }}/uploaded_files_list.txt | tr '\n' ' ')" >> $GITHUB_ENV
Expand All @@ -139,19 +176,28 @@ jobs:
echo "RELEASE_BUCKET_PREFIX=${{ vars.RELEASE_BUCKET_PREFIX }}" >> $GITHUB_ENV
echo "RELEASE_TASK_ID=${{ steps.task-id.outputs.task-id }}" >> $GITHUB_ENV
echo "TAG=${{ github.event.inputs.tag }}" >> $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
- name: Set up Asana templates
if: always()
id: asana-templates
env:
RELEASE_TYPE: ${{ github.event.inputs.release-type }}
run: |
if [[ ${{ steps.upload.outcome }} == "success" ]]; 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 [[ ${{ steps.upload.outcome }} == "success" ]]; then
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
else
echo "task-template=validate-check-for-updates-public" >> $GITHUB_OUTPUT
echo "comment-template=validate-check-for-updates-public" >> $GITHUB_OUTPUT
echo "release-task-comment-template=public-release-complete" >> $GITHUB_OUTPUT
fi
else
echo "task-template=appcast-failed" >> $GITHUB_OUTPUT
echo "comment-template=appcast-failed" >> $GITHUB_OUTPUT
echo "task-template=appcast-failed-${RELEASE_TYPE}" >> $GITHUB_OUTPUT
echo "comment-template=appcast-failed-${RELEASE_TYPE}" >> $GITHUB_OUTPUT
fi
- name: Create Asana task
Expand Down Expand Up @@ -207,4 +253,4 @@ jobs:
with:
access-token: ${{ secrets.ASANA_ACCESS_TOKEN }}
task-url: ${{ github.event.inputs.asana-task-url }}
template-name: internal-release-complete
template-name: ${{ steps.asana-templates.outputs.release-task-comment-template }}
Loading

0 comments on commit e8bf262

Please sign in to comment.