Add Slack changelog artifact handoff#11493
Conversation
Resolve repo-sync PRs from warp-internal back to public warp PR metadata before changelog generation, and omit private internal PRs that were not created by the sync bot. Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-Authored-By: Oz <oz-agent@warp.dev>
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds a Python Slack changelog payload builder, uploads the raw stable-release Markdown changelog as a workflow artifact, and adds a workflow-dispatch validation path for the representative Slack payload.
Concerns
- The Slack Markdown converter escapes link labels and surrounding text, but copies Markdown link URLs directly into Slack's
<url|label>syntax. Changelog entries can include PR-authored Markdown, so URLs containing Slack delimiters can break the link boundary and inject unintended mrkdwn into the release Slack post.
Security
- Validate or encode Slack link delimiters in Markdown URLs before converting arbitrary changelog text to Slack mrkdwn.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| for match in MARKDOWN_LINK_RE.finditer(text): | ||
| parts.append(escape_slack_text(text[last_end : match.start()])) | ||
| label, url = match.groups() | ||
| parts.append(f"<{url}|{escape_slack_text(label)}>") |
There was a problem hiding this comment.
url is inserted directly into Slack <url|label> syntax. Since changelog entries can include PR-authored Markdown, a URL containing | or > can break the link boundary and inject mrkdwn into the release Slack post; validate or encode Slack delimiters before converting the link.
danielpeng2
left a comment
There was a problem hiding this comment.
Generally looks good! Can we get an example of the changelog that's posted to Slack with the link to the artifact?
| post_slack_changelog_payload: | ||
| description: "Post the representative Slack changelog format preview to #release." | ||
| type: boolean | ||
| default: false |
There was a problem hiding this comment.
I think true is the right default here? We should make sure the behaviour is the same as before -- IIRC we'd automatically post a changelog by default before.
| validate_slack_changelog_payload: | ||
| name: Validate Slack changelog payload | ||
| if: ${{ github.event_name == 'workflow_dispatch' && (inputs.validate_slack_changelog_payload == true || inputs.post_slack_changelog_payload == true) }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| - name: Write representative raw Markdown changelog artifact | ||
| shell: bash | ||
| run: | | ||
| cat > "${{ runner.temp }}/changelog-draft.md" <<'MARKDOWN' | ||
| # Changelog draft preview | ||
|
|
||
| * Representative raw Markdown changelog artifact for workflow validation. | ||
| MARKDOWN | ||
| - name: Upload representative raw Markdown changelog artifact | ||
| id: upload_validation_markdown_artifact | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: changelog-draft-markdown-validation | ||
| path: ${{ runner.temp }}/changelog-draft.md | ||
| if-no-files-found: error | ||
|
|
||
| - name: Build representative Slack changelog payload | ||
| id: build_slack_changelog_payload | ||
| shell: bash | ||
| env: | ||
| MARKDOWN_ARTIFACT_URL: ${{ steps.upload_validation_markdown_artifact.outputs.artifact-url }} | ||
| run: | | ||
| CHANGELOG_INPUT="${{ runner.temp }}/slack-changelog-input.json" | ||
| SLACK_PAYLOAD="${{ runner.temp }}/slack-changelog-payload.json" | ||
| cat > "$CHANGELOG_INPUT" <<'JSON' | ||
| { | ||
| "newFeatures": [ | ||
| "Added tab dragging between windows. ([#9275](https://github.com/warpdotdev/warp/pull/9275))" | ||
| ], | ||
| "improvements": [ | ||
| "Added `warposs://pane/{uuid}` deep links. ([#9655](https://github.com/warpdotdev/warp/pull/9655)) — [@Akeuuh](https://github.com/Akeuuh) ✨" | ||
| ], | ||
| "bugFixes": [ | ||
| "Fixed file picker path truncation. ([#9885](https://github.com/warpdotdev/warp/pull/9885)) — [@bradleyjames](https://github.com/bradleyjames) ✨" | ||
| ], | ||
| "oz_updates": [ | ||
| "Configurable max context window per profile. ([#9352](https://github.com/warpdotdev/warp/pull/9352))" | ||
| ] | ||
| } | ||
| JSON | ||
|
|
||
| python3 .agents/skills/changelog-draft/scripts/build_slack_payload.py \ | ||
| --input "$CHANGELOG_INPUT" \ | ||
| --release-tag "FORMAT PREVIEW — not a release" \ | ||
| --markdown-artifact-url "$MARKDOWN_ARTIFACT_URL" \ | ||
| --output "$SLACK_PAYLOAD" | ||
|
|
||
| jq -e --arg markdown_artifact_url "$MARKDOWN_ARTIFACT_URL" ' | ||
| (.blocks | length) == 3 and | ||
| .blocks[0].type == "header" and | ||
| .blocks[0].text.text == "Changelog for FORMAT PREVIEW — not a release" and | ||
| .blocks[1].type == "section" and | ||
| (.blocks[1].text.text | contains("<\($markdown_artifact_url)|Download raw Markdown changelog artifact>")) and | ||
| .blocks[2].type == "section" and | ||
| .blocks[2].expand == true and | ||
| (.blocks[2].text.text | contains("<https://github.com/warpdotdev/warp/pull/9275|#9275>")) and | ||
| (.blocks[2].text.text | contains("<https://github.com/Akeuuh|@Akeuuh>")) and | ||
| (.blocks[2].text.text | contains("<https://github.com/bradleyjames|@bradleyjames>")) | ||
| ' "$SLACK_PAYLOAD" >/dev/null | ||
| cat "$SLACK_PAYLOAD" | ||
| echo "payload<<SLACK_PAYLOAD_EOF" >> $GITHUB_OUTPUT | ||
| cat "$SLACK_PAYLOAD" >> $GITHUB_OUTPUT | ||
| echo "SLACK_PAYLOAD_EOF" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: "Post Slack changelog format preview to #release" | ||
| if: ${{ inputs.post_slack_changelog_payload == true }} | ||
| uses: slackapi/slack-github-action@410ae57cff5c6b682b106440be0e6c7eb8c98c9d # v1.16.0 | ||
| with: | ||
| channel-id: "#release" | ||
| payload: ${{ steps.build_slack_changelog_payload.outputs.payload }} | ||
| env: | ||
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_CHANGELOG_BOT }} | ||
|
|
||
| - name: Upload Slack payload artifact | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 | ||
| with: | ||
| name: slack-changelog-payload-validation | ||
| path: ${{ runner.temp }}/slack-changelog-payload.json |
There was a problem hiding this comment.
Is this just code for testing? Let's remove it if it's not actually being used.
There was a problem hiding this comment.
Yup, this was just for testing. Will remove.
Co-Authored-By: Oz <oz-agent@warp.dev>
|
Yes! Here's a link to the changelog artifact that was just generated running this workflow. The full message is posted to Slack in the # releases channel with the same link + rendered mrkdwn for Slack https://github.com/warpdotdev/warp-internal/actions/runs/26298742929/artifacts/7165330151 |
Description
Linked Issue
N/A — release workflow follow-up.
ready-to-specorready-to-implement.Testing
python3 -m py_compile .agents/skills/changelog-draft/scripts/build_slack_payload.py .agents/skills/changelog-draft/scripts/convert_to_release_json.py .agents/skills/changelog-draft/scripts/fetch_issue_reporters.pyLocal Slack payload regression covering:
<url|label>links|,<,>) in Markdown URLs and artifact URLsRuby YAML parse of
.github/workflows/create_release.ymlgit diff --checkcargo fmtcargo clippy --workspace --all-targets --all-features --tests -- -D warningsI have manually tested my changes locally with
./script/runExample Slack output
Representative generated Slack text after this PR, with the artifact URL shortened here for readability:
Header
Changelog for v0.2026.05.20.09.21.stable_00
Artifact block
Raw Markdown changelog: <https://github.com/warpdotdev/warp-internal/actions/runs/.../artifacts/...|Download raw Markdown changelog artifact>
Changelog block
New Features
• Added tab dragging between windows. (https://github.com/warpdotdev/warp/pull/9275|#9275)
Improvements
• Added
warposs://pane/{uuid}deep links. (https://github.com/warpdotdev/warp/pull/9655|#9655) — https://github.com/Akeuuh|@Akeuuh ✨Bug Fixes
• Fixed file picker path truncation. (https://github.com/warpdotdev/warp/pull/9885|#9885) — https://github.com/bradleyjames|@bradleyjames ✨
oz_updates
• Configurable max context window per profile. (https://github.com/warpdotdev/warp/pull/9352|#9352)
Screenshots / Videos
Not applicable for this release workflow change.
Agent Mode
Agent context
Co-Authored-By: Oz oz-agent@warp.dev