first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: "Found a bug? Please search through our open issues and docs, to make sure it isn't already submitted. If you have an SSH related issue, please use the SSH Template below"
|
||||
labels: ["bug", "ready-to-implement"]
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
@@ -134,4 +134,3 @@ body:
|
||||
- Ignore
|
||||
validations:
|
||||
required: false
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ body:
|
||||
attributes:
|
||||
label: "Pre-submit Checks"
|
||||
options:
|
||||
- label: "I have [searched Warp feature requests](https://github.com/warpdotdev/warp/issues?q=is%3Aissue+label%3AFEATURE) and there are no duplicates"
|
||||
- label: "I have [searched Warp feature requests](https://github.com/warpdotdev/warp/issues?q=is%3Aissue+label%3Aenhancement) and there are no duplicates"
|
||||
required: true
|
||||
- label: "I have [searched Warp docs](https://docs.warp.dev) and my feature is not there"
|
||||
required: true
|
||||
@@ -42,6 +42,7 @@ body:
|
||||
- macOS
|
||||
- Linux
|
||||
- Windows
|
||||
- Cross-platform
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
||||
+80
-17
@@ -7,7 +7,7 @@
|
||||
# Source of truth: warpdotdev/feedback-triage-bot ownership-areas.md
|
||||
|
||||
# Default fallback: FA leads are tagged when no more specific path matches
|
||||
/ @vorporeal @alokedesai @zachbai @bnavetta @szgupta @jefflloyd
|
||||
/ @warpdotdev/oss-maintainers
|
||||
|
||||
###########################################################################
|
||||
# Team: App
|
||||
@@ -33,7 +33,8 @@
|
||||
/crates/ai/src/index/ @kevinyang372
|
||||
/crates/ai/src/project_context/ @kevinyang372
|
||||
/crates/editor/ @kevinyang372 @bnavetta
|
||||
/crates/lsp/ @kevinyang372
|
||||
/crates/languages/ @kevinyang372 @bnavetta
|
||||
/crates/lsp/ @kevinyang372 @moirahuang
|
||||
/crates/repo_metadata/ @kevinyang372
|
||||
|
||||
# Settings and keybindings
|
||||
@@ -45,7 +46,7 @@
|
||||
/app/src/terminal/input/ @vkodithala
|
||||
/app/src/pane_group/ @vkodithala
|
||||
/app/src/tab.rs @vkodithala
|
||||
/crates/warp_ripgrep/ @vkodithala @moirahuang @szgupta
|
||||
/crates/warp_ripgrep/ @moirahuang @szgupta
|
||||
|
||||
# Command palette
|
||||
/app/src/command_palette.rs @acarl005
|
||||
@@ -53,7 +54,6 @@
|
||||
/app/src/search/command_palette/ @acarl005
|
||||
|
||||
# @ context, slash commands, and global search / file tree
|
||||
/app/src/context_chips/ @moirahuang
|
||||
/app/src/search/ai_context_menu/ @moirahuang
|
||||
/app/src/search/files/ @moirahuang
|
||||
/app/src/search/search_results_menu/ @moirahuang
|
||||
@@ -62,6 +62,11 @@
|
||||
/app/src/code/file_tree/ @moirahuang
|
||||
/app/src/workspace/view/global_search/ @moirahuang
|
||||
|
||||
# Tab configs and worktrees
|
||||
/app/src/tab_configs/ @moirahuang
|
||||
/app/resources/tab_configs/ @moirahuang
|
||||
/crates/warp_util/src/worktree_names.rs @moirahuang
|
||||
|
||||
# Onboarding / code review and git diff
|
||||
/app/src/ai/onboarding.rs @kevinchevalier
|
||||
/app/src/code_review/ @kevinchevalier
|
||||
@@ -70,9 +75,18 @@
|
||||
/crates/onboarding/ @kevinchevalier
|
||||
|
||||
# MCP and skills
|
||||
/app/src/ai/mcp/ @peicodes
|
||||
/app/src/ai/skills/ @peicodes
|
||||
/crates/mcp/ @peicodes
|
||||
/app/src/ai/mcp/ @peicodes @vkodithala
|
||||
/app/src/ai/skills/ @peicodes @vkodithala
|
||||
/crates/mcp/ @peicodes @vkodithala
|
||||
/resources/bundled/skills/feedback/ @captainsafia
|
||||
|
||||
# File-based MCP (overrides MCP and skills above)
|
||||
/app/src/ai/mcp/file_based_manager.rs @vkodithala
|
||||
/app/src/ai/mcp/file_based_manager_tests.rs @vkodithala
|
||||
/app/src/ai/mcp/file_mcp_watcher.rs @vkodithala
|
||||
/app/src/ai/mcp/file_mcp_watcher_tests.rs @vkodithala
|
||||
/app/src/ai/mcp/dummy_file_based_manager.rs @vkodithala
|
||||
/app/src/ai/mcp/dummy_file_mcp_watcher.rs @vkodithala
|
||||
|
||||
# Conversation management / credit usage footer / input UI / natural-language detection
|
||||
/app/src/ai/active_agent_views_model.rs @harryalbert
|
||||
@@ -86,18 +100,27 @@
|
||||
/crates/input_classifier/ @harryalbert
|
||||
/crates/natural_language_detection/ @harryalbert
|
||||
|
||||
# Notifications
|
||||
/app/src/notification.rs @harryalbert
|
||||
/app/src/ai/agent_management/notifications/ @harryalbert
|
||||
/app/src/terminal/view/inline_banner/ @harryalbert
|
||||
|
||||
# Blocklist UX / modality and cloud mode UI / shell compatibility / completions and bootstrap / warpifying
|
||||
/app/src/ai/blocklist/ @zachbai
|
||||
/app/src/root_view.rs @zachbai
|
||||
/app/src/ai/blocklist/ @zachbai @MaggieShan
|
||||
/app/src/root_view.rs @zachbai @MaggieShan
|
||||
/app/src/terminal/bootstrap.rs @zachbai
|
||||
/app/src/terminal/warpify/ @zachbai
|
||||
/app/src/settings_view/warpify_page.rs @zachbai
|
||||
/app/src/terminal/warpify/ @zachbai @MaggieShan
|
||||
/app/src/settings_view/warpify_page.rs @zachbai @MaggieShan
|
||||
/app/assets/bundled/bootstrap/ @zachbai
|
||||
/crates/warp_completer/ @zachbai @szgupta @alokedesai
|
||||
/crates/warp_completer/ @zachbai @szgupta @alokedesai @acarl005
|
||||
|
||||
# Agent mode
|
||||
/app/src/ai/agent/ @zachbai
|
||||
|
||||
# Vertical tabs
|
||||
/app/src/workspace/view/vertical_tabs.rs @johnturcoo
|
||||
/app/src/workspace/view/vertical_tabs/ @johnturcoo
|
||||
|
||||
# Image attachment, voice input, and passive suggestions
|
||||
/app/src/ai/attachment_utils.rs @Advait-M
|
||||
/app/src/ai/voice/ @Advait-M
|
||||
@@ -106,26 +129,58 @@
|
||||
/app/src/voice/ @Advait-M
|
||||
/crates/voice_input/ @Advait-M
|
||||
|
||||
# Rich input
|
||||
/app/src/terminal/view/use_agent_footer/ @Advait-M
|
||||
/app/src/terminal/view/use_agent_footer/warpify_footer.rs @MaggieShan
|
||||
/app/src/terminal/input/cli_agent.rs @Advait-M
|
||||
|
||||
# UI framework
|
||||
/crates/warpui/ @vorporeal
|
||||
/crates/warpui_core/ @vorporeal
|
||||
/crates/warpui/ @vorporeal @alokedesai @acarl005
|
||||
/crates/warpui_core/ @vorporeal @alokedesai
|
||||
/crates/warpui_extras/ @vorporeal
|
||||
/crates/ui_components/ @vorporeal
|
||||
/crates/warpui_extras/src/user_preferences @danielpeng
|
||||
/crates/ui_components/ @vorporeal @acarl005 @zachbai @bnavetta
|
||||
|
||||
# Conversation rewind / CLI agent UI / macOS/Linux platform issues / performance issues
|
||||
/app/src/terminal/cli_agent.rs @zachbai
|
||||
/app/src/terminal/cli_agent_sessions/ @zachbai
|
||||
/app/src/terminal/cli_agent.rs @zachbai @harryalbert
|
||||
/app/src/terminal/cli_agent_tests.rs @zachbai @harryalbert
|
||||
/app/src/terminal/cli_agent_sessions/ @zachbai @harryalbert
|
||||
/app/src/terminal/input/rewind/ @alokedesai
|
||||
/app/src/workspace/rewind_confirmation_dialog.rs @alokedesai
|
||||
/app/src/platform/mac/ @alokedesai
|
||||
/resources/linux/ @acarl005
|
||||
|
||||
# Windows and Linux (and winit) platform
|
||||
/crates/warpui/src/windowing/winit/ @acarl005 @vorporeal @alokedesai
|
||||
/app/src/terminal/local_tty/windows/ @abhishekp106 @vorporeal @acarl005
|
||||
/app/src/autoupdate/windows.rs @acarl005
|
||||
/app/src/autoupdate/linux.rs @vorporeal
|
||||
/app/src/app_services/windows/ @acarl005
|
||||
/app/src/app_services/linux/ @vorporeal
|
||||
/app/src/terminal/writeable_pty/bootstrap_file/windows.rs @acarl005
|
||||
/app/assets/bundled/bootstrap/pwsh.ps1 @acarl005
|
||||
/app/assets/bundled/bootstrap/pwsh_init_shell.ps1 @acarl005
|
||||
|
||||
# /pr-comments
|
||||
/app/src/search/slash_command_menu/static_commands/commands.rs @lucieleblanc
|
||||
|
||||
# Grep tool call UI
|
||||
/app/src/ai/blocklist/action_model/execute/grep.rs @vkodithala
|
||||
|
||||
# Long-running shell commands
|
||||
/app/src/ai/blocklist/action_model/execute/shell_command.rs @vkodithala @MaggieShan
|
||||
/app/src/ai/blocklist/block/cli.rs @vkodithala @MaggieShan
|
||||
/app/src/ai/blocklist/block/cli_controller.rs @vkodithala @MaggieShan
|
||||
|
||||
# Vim
|
||||
/crates/vim/ @liliwilson
|
||||
/app/src/vim_registers.rs @liliwilson
|
||||
/app/src/code/editor/view/vim_handler.rs @liliwilson
|
||||
/app/src/code/editor/view/vim_handler_tests.rs @liliwilson
|
||||
/app/src/editor/view/vim_handler_test.rs @liliwilson
|
||||
/app/src/terminal/view/inline_banner/vim_mode.rs @liliwilson
|
||||
/app/src/settings/vim_banner.rs @liliwilson
|
||||
|
||||
###########################################################################
|
||||
# Team: Platform
|
||||
###########################################################################
|
||||
@@ -178,5 +233,13 @@
|
||||
/crates/managed_secrets/ @bnavetta @ianhodge
|
||||
/crates/warp_web_event_bus/ @bnavetta @ianhodge
|
||||
|
||||
# Command signatures v2
|
||||
/command-signatures-v2/ @zachbai
|
||||
|
||||
# OS-level bootstrap scripts
|
||||
/script/linux/bootstrap @acarl005
|
||||
/script/macos/bootstrap @acarl005
|
||||
/script/windows/bootstrap.ps1 @acarl005
|
||||
|
||||
# Shell completions in the Warp CLI
|
||||
/crates/warp_cli/src/completions.rs @zachbai @szgupta @alokedesai
|
||||
|
||||
@@ -37,5 +37,6 @@ runs:
|
||||
-e GIT_RELEASE_TAG="$GIT_RELEASE_TAG" \
|
||||
-e GITHUB_ACTIONS="$GITHUB_ACTIONS" \
|
||||
-e GITHUB_OUTPUT="/dev/null" \
|
||||
${SETTINGS_SCHEMA_CACHE:+-e SETTINGS_SCHEMA_CACHE=/github/workspace/.settings_schema_cache.json} \
|
||||
arch-bundle-builder \
|
||||
${{ inputs.channel }} ${{ inputs.release-tag }} ${{ inputs.arch }} ${{ inputs.artifact }}
|
||||
|
||||
@@ -53,6 +53,22 @@ runs:
|
||||
echo "is-workspace-root=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Materialize Git LFS objects
|
||||
- name: Fetch Git LFS objects
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ steps.repo-root.outputs.path }}"
|
||||
git lfs install --local
|
||||
git lfs pull
|
||||
|
||||
# Print a per-file listing of the LFS payloads in debug mode
|
||||
- name: Verify LFS payloads
|
||||
if: ${{ runner.debug == '1' }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ steps.repo-root.outputs.path }}"
|
||||
git lfs ls-files --size
|
||||
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
if: ${{ inputs.is_self_hosted != 'true' && !startsWith(runner.name, 'nsc-runner') }}
|
||||
with:
|
||||
@@ -85,6 +101,11 @@ runs:
|
||||
with:
|
||||
ssh-private-key: ${{ inputs.ssh_key }}
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
|
||||
if: ${{ inputs.target_os == 'macos' && inputs.is_self_hosted != 'true' }}
|
||||
with:
|
||||
xcode-version: '26'
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -127,7 +148,7 @@ runs:
|
||||
fi
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20.9.0
|
||||
|
||||
@@ -159,7 +180,3 @@ runs:
|
||||
echo "::error::protoc install step failed on ${{ inputs.target_os }}"
|
||||
exit 1
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
|
||||
if: ${{ inputs.target_os == 'macos' && inputs.is_self_hosted != 'true' }}
|
||||
with:
|
||||
xcode-version: '26'
|
||||
|
||||
@@ -7,7 +7,7 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
assignees:
|
||||
- "warpdotdev/tech-leads"
|
||||
registries:
|
||||
- github-private
|
||||
@@ -17,7 +17,7 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
assignees:
|
||||
- "warpdotdev/tech-leads"
|
||||
cooldown:
|
||||
# Don't update to any action release that is less than two weeks old.
|
||||
|
||||
@@ -1,34 +1,41 @@
|
||||
## Description
|
||||
<!-- Please remember to add your design buddy onto the PR for review, if it contains any UI changes! -->
|
||||
|
||||
## Linked Issue
|
||||
<!--
|
||||
Link the GitHub issue this PR addresses. Before opening this PR, please confirm:
|
||||
-->
|
||||
- [ ] The linked issue is labeled `ready-to-spec` or `ready-to-implement`.
|
||||
- [ ] Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes).
|
||||
|
||||
## Testing
|
||||
<!--
|
||||
How did you test this change? What automated tests did you add? If you didn't add any new tests, what's your justification for not adding any?
|
||||
How did you test this change? What automated tests did you add? If you didn't add any new tests, what's your justification for not adding any?
|
||||
|
||||
If you're not sure whether you should add a test, check our testing policy: https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
|
||||
Manual testing is required for changes that can be manually tested, and almost all changes can be manually tested. If your change can be manually tested, please include screenshots or a screen recording that show it working end to end.
|
||||
|
||||
You can run the app locally using `./script/run` - see AGENTS.md for more details on how to get set up.
|
||||
-->
|
||||
|
||||
## Server API dependencies
|
||||
<!-- You may remove this section if your PR does not have any server dependencies. -->
|
||||
- [ ] Is this change necessary to make the client compatible with a desired [server API breaking change](https://www.notion.so/warpdev/How-to-safely-introduce-server-API-breaking-changes-0aa805ff5d5d41fd8834f3c95caba0b4?pvs=4#d55ecf8aea3449949d3c33b0e67f6800)?
|
||||
- [ ] Does this change rely on a [new server API](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#04da1e6a493542d68b3e998c7d339640)?
|
||||
- [ ] If so, is the use of this API restricted to client channels that rely on the staging server (e.g. WarpDev)?
|
||||
- [ ] Is this change enabling the use of a server API on client channels that rely on the production server (e.g. WarpStable)?
|
||||
- [ ] If so, has the new server API been stable on production for at least one server release cycle? See [here](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#73b202f939834b97ab1fbdf7fc82cd53) for more details.
|
||||
- [ ] I have manually tested my changes locally with `./script/run`
|
||||
|
||||
### Screenshots / Videos
|
||||
<!-- Attach screenshots or a short video demonstrating the change, where appropriate. Remove this section if it is not relevant to your PR. -->
|
||||
|
||||
## Agent Mode
|
||||
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
|
||||
|
||||
## Changelog Entries for Stable
|
||||
<!--
|
||||
## Changelog Entries for Stable
|
||||
|
||||
The entries below will be used when constructing a soft-copy of the stable release changelog. Leave blank or remove the lines if no entry in the stable changelog is needed. Entries should be on the same line, without the `{{` `}}` brackets. You can use multiple lines, even of the same type. The valid suffixes are:
|
||||
|
||||
* NEW-FEATURE: for new, relatively sizable features. Features listed here will likely have docs / social media posts / marketing launches associated with them, so use sparingly.
|
||||
* IMPROVEMENT: for new functionality of existing features.
|
||||
* BUG-FIX: for fixes related to known bugs or regressions.
|
||||
* IMAGE: the image specified by the URL (hosted on GCP) will be added to Dev & Preview releases. For Stable releases, see the pinned doc in the #release Slack channel.
|
||||
* OZ: Oz-related updates. Use `CHANGELOG-OZ`. At most 4 Oz updates are shown in-app per release.
|
||||
-->
|
||||
- NEW-FEATURE: for new, relatively sizable features. Features listed here will likely have docs / social media posts / marketing launches associated with them, so use sparingly.
|
||||
- IMPROVEMENT: for new functionality of existing features.
|
||||
- BUG-FIX: for fixes related to known bugs or regressions.
|
||||
- IMAGE: the image specified by the URL (hosted on GCP) will be added to Dev & Preview releases. For Stable releases, see the pinned doc in the #release Slack channel.
|
||||
- OZ: Oz-related updates. Use `CHANGELOG-OZ`. At most 4 Oz updates are shown in-app per release.
|
||||
- NONE: Explicitly opt out of changelog inclusion. Use `CHANGELOG-NONE` for PRs that should never appear in the changelog (e.g. refactors, internal tooling, CI changes). This prevents the changelog agent from inferring an entry.
|
||||
|
||||
CHANGELOG-NEW-FEATURE: {{text goes here...}}
|
||||
CHANGELOG-IMPROVEMENT: {{text goes here...}}
|
||||
@@ -36,3 +43,5 @@ CHANGELOG-BUG-FIX: {{text goes here...}}
|
||||
CHANGELOG-BUG-FIX: {{more text goes here...}}
|
||||
CHANGELOG-IMAGE: {{GCP-hosted URL goes here...}}
|
||||
CHANGELOG-OZ: {{text goes here...}}
|
||||
CHANGELOG-NONE
|
||||
-->
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Follows up on stale external-contributor PRs with active requested-changes
|
||||
// reviews: posts escalating reminders, then closes after the final warning.
|
||||
// Invoked from .github/workflows/stale_requested_changes_prs.yml via
|
||||
// actions/github-script; `github` and `context` are injected by that action.
|
||||
module.exports = async ({ github, context }) => {
|
||||
const { owner, repo } = context.repo;
|
||||
// Default to "full" if unset, because scheduled (cron) runs don't provide inputs
|
||||
const mode = (context.payload.inputs && context.payload.inputs.mode) || 'full';
|
||||
const canRemind = mode === 'reminder-only' || mode === 'full';
|
||||
const canClose = mode === 'full';
|
||||
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
const REMINDER_DAYS = [7, 10];
|
||||
const FINAL_WARNING_DAY = 10;
|
||||
const CLOSE_DAY = 14;
|
||||
const EXTERNAL_LABEL = 'external-contributor';
|
||||
const EXEMPT_LABEL = 'no-autoclose';
|
||||
const BOT_LOGIN = 'github-actions[bot]';
|
||||
const markerFor = (stage) => `<!-- stale-requested-changes:stage=${stage} -->`;
|
||||
|
||||
const now = Date.now();
|
||||
const ts = (value) => (value ? new Date(value).getTime() : 0);
|
||||
|
||||
// Returns the submitted_at (ms) of the most recent active requested-changes
|
||||
// review, or 0 when no reviewer currently has changes requested. A reviewer's
|
||||
// latest *decisive* review (APPROVED / CHANGES_REQUESTED / DISMISSED, tracked
|
||||
// separately from COMMENTED so a later comment-reply doesn't flip state)
|
||||
// determines their effective state.
|
||||
const latestActiveChangesRequestedAt = (reviews) => {
|
||||
const decisive = new Map();
|
||||
const latest = new Map();
|
||||
for (const r of reviews) {
|
||||
const login = r.user && r.user.login;
|
||||
if (!login) continue;
|
||||
const at = ts(r.submitted_at);
|
||||
if (!latest.has(login) || at > latest.get(login).at) {
|
||||
latest.set(login, { state: r.state, at });
|
||||
}
|
||||
if (['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED'].includes(r.state)) {
|
||||
if (!decisive.has(login) || at > decisive.get(login).at) {
|
||||
decisive.set(login, { state: r.state, at });
|
||||
}
|
||||
}
|
||||
}
|
||||
let latestAt = 0;
|
||||
for (const login of latest.keys()) {
|
||||
const eff = decisive.get(login) || latest.get(login);
|
||||
if (eff.state === 'CHANGES_REQUESTED') latestAt = Math.max(latestAt, eff.at);
|
||||
}
|
||||
return latestAt;
|
||||
};
|
||||
|
||||
const openPRs = await github.paginate(github.rest.pulls.list, {
|
||||
owner,
|
||||
repo,
|
||||
state: 'open',
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const summary = [];
|
||||
|
||||
for (const pr of openPRs) {
|
||||
const labels = (pr.labels || []).map((l) => l.name);
|
||||
const author = pr.user && pr.user.login;
|
||||
if (pr.draft) continue;
|
||||
if (pr.user && pr.user.type === 'Bot') continue;
|
||||
// Skip internal member PRs and PRs with the no-autoclose label
|
||||
if (!labels.includes(EXTERNAL_LABEL)) continue;
|
||||
if (labels.includes(EXEMPT_LABEL)) continue;
|
||||
|
||||
const reviews = await github.paginate(github.rest.pulls.listReviews, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pr.number,
|
||||
per_page: 100,
|
||||
});
|
||||
const changesRequestedAt = latestActiveChangesRequestedAt(reviews);
|
||||
if (!changesRequestedAt) continue;
|
||||
|
||||
const [issueComments, reviewComments] = await Promise.all([
|
||||
github.paginate(github.rest.issues.listComments, { owner, repo, issue_number: pr.number, per_page: 100 }),
|
||||
github.paginate(github.rest.pulls.listReviewComments, { owner, repo, pull_number: pr.number, per_page: 100 }),
|
||||
]);
|
||||
|
||||
// Server-recorded head-branch push time. commit.pushedDate and the
|
||||
// force-push event timestamp are GitHub-controlled, so a backdated or
|
||||
// force-pushed commit still resets the timer (unlike commit author/committer
|
||||
// dates, which the contributor controls).
|
||||
const pushData = await github.graphql(
|
||||
`query($owner: String!, $repo: String!, $number: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
pullRequest(number: $number) {
|
||||
commits(last: 1) { nodes { commit { pushedDate committedDate } } }
|
||||
timelineItems(last: 50, itemTypes: [HEAD_REF_FORCE_PUSHED_EVENT]) {
|
||||
nodes { ... on HeadRefForcePushedEvent { createdAt } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{ owner, repo, number: pr.number }
|
||||
);
|
||||
const prGraph = pushData.repository.pullRequest;
|
||||
const headCommit = (prGraph.commits.nodes[0] || {}).commit || {};
|
||||
|
||||
// Staleness anchor: the most recent active requested-changes review, plus
|
||||
// author-driven events that reset the timer (PR creation, head-branch push,
|
||||
// and comments by the PR author). Anchoring on the latest review ensures a
|
||||
// subsequent requested-changes review restarts the window instead of
|
||||
// measuring from stale, pre-review author activity. Maintainer/third-party/
|
||||
// bot activity is otherwise ignored.
|
||||
let lastActivity = Math.max(ts(pr.created_at), changesRequestedAt);
|
||||
lastActivity = Math.max(lastActivity, ts(headCommit.pushedDate || headCommit.committedDate));
|
||||
for (const ev of prGraph.timelineItems.nodes) {
|
||||
lastActivity = Math.max(lastActivity, ts(ev.createdAt));
|
||||
}
|
||||
for (const c of issueComments) {
|
||||
if (c.user && c.user.login === author) lastActivity = Math.max(lastActivity, ts(c.created_at));
|
||||
}
|
||||
for (const c of reviewComments) {
|
||||
if (c.user && c.user.login === author) lastActivity = Math.max(lastActivity, ts(c.created_at));
|
||||
}
|
||||
|
||||
const inactiveDays = (now - lastActivity) / DAY_MS;
|
||||
|
||||
// A stage counts as sent only when its marker comment was posted by our own
|
||||
// workflow identity in the current window (at/after the last activity).
|
||||
const sentStages = new Set();
|
||||
for (const c of issueComments) {
|
||||
if (!c.user || c.user.login !== BOT_LOGIN) continue;
|
||||
if (ts(c.created_at) < lastActivity) continue;
|
||||
for (const stage of REMINDER_DAYS) {
|
||||
if ((c.body || '').includes(markerFor(stage))) sentStages.add(stage);
|
||||
}
|
||||
}
|
||||
|
||||
const dueStage = [...REMINDER_DAYS].reverse().find((s) => inactiveDays >= s);
|
||||
const finalWarningSent = sentStages.has(FINAL_WARNING_DAY);
|
||||
const shouldClose = inactiveDays >= CLOSE_DAY && finalWarningSent;
|
||||
|
||||
let action = 'none';
|
||||
if (shouldClose) action = 'close';
|
||||
else if (dueStage !== undefined && !sentStages.has(dueStage)) action = `remind:${dueStage}`;
|
||||
|
||||
const days = Math.floor(inactiveDays);
|
||||
console.log(`PR #${pr.number} (@${author}, inactive ${days}d): ${action}${action === 'none' ? '' : ` [mode=${mode}]`}`);
|
||||
if (action === 'none') continue;
|
||||
summary.push(`#${pr.number} ${action} (${days}d)`);
|
||||
|
||||
if (action === 'close') {
|
||||
if (!canClose) continue;
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pr.number,
|
||||
body: `Closing this pull request because the requested changes have gone unaddressed for over ${CLOSE_DAY} days. If you'd like to continue, push your updates and reopen the PR (or comment to ask a maintainer to reopen) — we'd be glad to pick it back up.`,
|
||||
});
|
||||
await github.rest.pulls.update({ owner, repo, pull_number: pr.number, state: 'closed' });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!canRemind) continue;
|
||||
const stage = Number(action.split(':')[1]);
|
||||
const remaining = Math.max(1, CLOSE_DAY - days);
|
||||
const body = stage === FINAL_WARNING_DAY
|
||||
? `Hi @${author} — final reminder: a reviewer requested changes on this PR and it has been inactive for ${days} days. It will be **automatically closed in about ${remaining} day(s)** unless you push updates or reply. Maintainers can apply the \`${EXEMPT_LABEL}\` label to keep it open.\n\n${markerFor(stage)}`
|
||||
: `Hi @${author} — a reviewer requested changes on this PR and it hasn't had activity from you in ${days} days. When you get a chance, please push updates or reply to the review so a reviewer can take another look. Without activity, this PR will be automatically closed after ${CLOSE_DAY} days of inactivity.\n\n${markerFor(stage)}`;
|
||||
await github.rest.issues.createComment({ owner, repo, issue_number: pr.number, body });
|
||||
}
|
||||
|
||||
console.log(`mode=${mode}; acted on ${summary.length} PR(s): ${summary.join(', ') || 'none'}`);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
name: Changelog Draft
|
||||
|
||||
on:
|
||||
# workflow_dispatch is restricted to users with write access to the repo.
|
||||
# External contributors (fork-based) cannot trigger this workflow.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
channel:
|
||||
description: "Release channel (stable, preview, dev)"
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- stable
|
||||
- preview
|
||||
- dev
|
||||
release_tag:
|
||||
description: "Release tag (e.g. v0.2026.05.06.09.12.stable_00)"
|
||||
required: true
|
||||
type: string
|
||||
attribution:
|
||||
description: "Attribution mode"
|
||||
required: false
|
||||
type: choice
|
||||
options:
|
||||
- external-only
|
||||
- all
|
||||
- none
|
||||
default: external-only
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
draft:
|
||||
name: Generate changelog draft
|
||||
runs-on: namespace-profile-ubuntu-small
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1
|
||||
with:
|
||||
# Check out the default branch (not the release tag) so the skill
|
||||
# files and scripts are always available — older release tags may
|
||||
# not contain them. The release_tag is used only as the git range
|
||||
# endpoint by the skill.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate changelog draft
|
||||
uses: warpdotdev/oz-agent-action@ce1621abf6a8ed8afdd4e4cc994545ede8fe1c6f # main
|
||||
with:
|
||||
prompt: |
|
||||
Generate a changelog draft for the ${{ inputs.channel }} channel, release tag ${{ inputs.release_tag }}.
|
||||
|
||||
Attribution mode: ${{ inputs.attribution }}
|
||||
Output directory: ${{ runner.temp }}/changelog-draft
|
||||
|
||||
Follow the workflow in .agents/skills/changelog-draft/SKILL.md exactly.
|
||||
When fetching PR data, pass the checked-out repository ("${{ github.repository }}") to fetch_prs.py and rely on the script's repo-sync normalization to resolve public warpdotdev/warp PR numbers, URLs, and authors. The script intentionally omits non-repo-sync PRs from warp-internal because they are private internal changes. Do not infer or synthesize public PR links manually.
|
||||
|
||||
After writing the output files, print the full contents of changelog-draft.md to stdout so it appears in the workflow log.
|
||||
|
||||
You are running in a GitHub Actions workflow. The repo is checked out at the default branch (HEAD). Use the release_tag input as the git range endpoint — do NOT check out the release tag. `gh` is authenticated. Do not commit, push, or create PRs.
|
||||
warp_api_key: ${{ secrets.WARP_API_KEY }}
|
||||
share: team
|
||||
|
||||
- name: Upload changelog artifacts
|
||||
uses: namespace-actions/upload-artifact@f6ccaacc655aec41b93af180d1d7eef21af862d2 # v1.0.3
|
||||
with:
|
||||
name: changelog-draft
|
||||
path: |
|
||||
${{ runner.temp }}/changelog-draft/changelog-draft.md
|
||||
${{ runner.temp }}/changelog-draft/changelog-draft.json
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
if: github.event.pull_request.draft == false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# We don't actually need the contents of the files, just their names.
|
||||
|
||||
+134
-22
@@ -57,7 +57,7 @@ jobs:
|
||||
wasm-runner: ${{ steps.wasm_runner_type.outputs.value }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
|
||||
- name: Check changed files
|
||||
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||
@@ -93,11 +93,13 @@ jobs:
|
||||
# Federation provider is configured to only trust the base repository.
|
||||
# We skip the auth + gcloud install steps in those runs and exclude SSH
|
||||
# integration tests (which require gcloud to tunnel into a GCP test VM)
|
||||
# via the filter suffix below. Tests that need gcloud all have `_ssh_`
|
||||
# in their name. Fork PRs lose SSH integration test coverage; those
|
||||
# tests still run post-merge against `master`.
|
||||
# via the filter suffix below. Tests that need gcloud either have
|
||||
# `_ssh_` in their name or exercise the remote-server SSH path. Fork PRs
|
||||
# lose SSH integration test coverage; those tests still run post-merge
|
||||
# against `master`.
|
||||
HAS_GCP_AUTH: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
EXCLUDE_SSH_TESTS_FILTER: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && ' and not test(/_ssh_/)' || '' }}
|
||||
EXCLUDE_SSH_TESTS_FILTER: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) && ' and not test(/(_ssh_|remote_server)/)' || '' }}
|
||||
EXCLUDE_REMOTE_SERVER_TESTS_FILTER: " and not test(/remote_server/)"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -131,7 +133,7 @@ jobs:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -204,7 +206,7 @@ jobs:
|
||||
|
||||
- name: Install cargo nextest
|
||||
if: ${{ matrix.is_self_hosted == false }}
|
||||
uses: taiki-e/install-action@9a29ce630c67077a359246f3e4f84941e05f28b5 # v1
|
||||
uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 # v2.79.3
|
||||
with:
|
||||
tool: nextest
|
||||
|
||||
@@ -282,7 +284,7 @@ jobs:
|
||||
if: matrix.os != 'windows' && (success() || failure())
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and not test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}"
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and not test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}${{ env.EXCLUDE_REMOTE_SERVER_TESTS_FILTER }}"
|
||||
env:
|
||||
# We run shell-agnostic tests against zsh, as it has the shortest
|
||||
# bootstrap times and tends to be the most reliable.
|
||||
@@ -307,7 +309,7 @@ jobs:
|
||||
if: matrix.os != 'windows' && (success() || failure())
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}"
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}${{ env.EXCLUDE_REMOTE_SERVER_TESTS_FILTER }}"
|
||||
env:
|
||||
WARP_SHELL_PATH: ${{ steps.echo_shells_unix.outputs.default_bash_path }}
|
||||
|
||||
@@ -333,7 +335,7 @@ jobs:
|
||||
if: (success() || failure()) && runner.os == 'macos'
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}"
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}${{ env.EXCLUDE_REMOTE_SERVER_TESTS_FILTER }}"
|
||||
env:
|
||||
WARP_SHELL_PATH: ${{ steps.echo_shells_unix.outputs.latest_bash_path }}
|
||||
|
||||
@@ -356,7 +358,7 @@ jobs:
|
||||
if: matrix.os != 'windows' && (success() || failure())
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}"
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}${{ env.EXCLUDE_REMOTE_SERVER_TESTS_FILTER }}"
|
||||
env:
|
||||
WARP_SHELL_PATH: ${{ steps.echo_shells_unix.outputs.fish_path }}
|
||||
|
||||
@@ -379,7 +381,7 @@ jobs:
|
||||
if: matrix.os != 'windows' && (success() || failure())
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}"
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}${{ env.EXCLUDE_REMOTE_SERVER_TESTS_FILTER }}"
|
||||
env:
|
||||
WARP_SHELL_PATH: ${{ steps.echo_shells_unix.outputs.zsh_path }}
|
||||
|
||||
@@ -402,7 +404,7 @@ jobs:
|
||||
if: matrix.os != 'windows' && (success() || failure())
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}"
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} ${{ matrix.extra_test_args }} -E "package(integration) and test(shell_integration_tests)${{ env.EXCLUDE_SSH_TESTS_FILTER }}${{ env.EXCLUDE_REMOTE_SERVER_TESTS_FILTER }}"
|
||||
env:
|
||||
WARP_SHELL_PATH: ${{ steps.echo_shells_unix.outputs.powershell_path }}
|
||||
|
||||
@@ -441,6 +443,94 @@ jobs:
|
||||
# The maximum timeout for the entire job is 6 hours:
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes
|
||||
|
||||
remote-server-tests:
|
||||
name: Run Linux remote-server integration tests
|
||||
# Temporarily disabled while reconsidering the approach.
|
||||
if: false
|
||||
timeout-minutes: 25
|
||||
runs-on: ubuntu-latest-large
|
||||
needs: params
|
||||
concurrency:
|
||||
# The dedicated VM uses a fixed binary path, so serialize remote-server
|
||||
# deploy/test jobs across workflow runs to avoid cross-run clobbering.
|
||||
group: remote-server-test-vm
|
||||
cancel-in-progress: false
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
target_os: linux
|
||||
is_self_hosted: false
|
||||
install_test_deps: true
|
||||
|
||||
- name: Install Shells
|
||||
uses: ConorMacBride/install-package@3e7ad059e07782ee54fa35f827df52aae0626f30 # v1
|
||||
with:
|
||||
apt: zsh fish
|
||||
|
||||
- name: Echo default Bash
|
||||
id: echo_bash
|
||||
shell: bash
|
||||
run: |
|
||||
DEFAULT_BASH_PATH="$(command -pv bash)"
|
||||
echo "default_bash_path=$DEFAULT_BASH_PATH" >> $GITHUB_OUTPUT
|
||||
DEFAULT_BASH_VERSION="$($DEFAULT_BASH_PATH --version)"
|
||||
echo "::notice title=Remote Server Tests - Default Bash Version::$DEFAULT_BASH_VERSION"
|
||||
|
||||
- name: Install cargo nextest
|
||||
uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 # v2.79.3
|
||||
with:
|
||||
tool: nextest
|
||||
|
||||
- name: Set up gcloud authentication for remote-server tests
|
||||
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
|
||||
with:
|
||||
workload_identity_provider: projects/63595664881/locations/global/workloadIdentityPools/github-pool/providers/github-provider
|
||||
service_account: github-ci-workflow@warp-ssh-integration-testing.iam.gserviceaccount.com
|
||||
|
||||
- name: Install gcloud CLI tool
|
||||
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
|
||||
with:
|
||||
version: '>= 397.0.0'
|
||||
|
||||
- name: Install remote server deploy dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get install -y curl sshpass xz-utils
|
||||
MUSL_CROSS_TARGET="x86_64-unknown-linux-musl"
|
||||
source script/linux/configure_musl_toolchain "$MUSL_CROSS_TARGET"
|
||||
MUSL_CROSS_BIN="$(dirname "$WARP_MUSL_CC")"
|
||||
echo "$MUSL_CROSS_BIN" >> "$GITHUB_PATH"
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
|
||||
- name: Deploy remote server binary to test VM
|
||||
run: script/deploy_remote_server_to_test_vm
|
||||
|
||||
- name: Run remote-server integration tests
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
with:
|
||||
run: cargo nextest run ${{ env.WORKSPACE_TEST_ARGS }} -E "package(integration) and test(/remote_server/)"
|
||||
env:
|
||||
WARP_SHELL_PATH: ${{ steps.echo_bash.outputs.default_bash_path }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload results of remote-server integration tests to trunk.io
|
||||
if: ${{ !cancelled() }}
|
||||
continue-on-error: true
|
||||
uses: trunk-io/analytics-uploader@95a0fb8b29e45b6068304261fb518644b426a803 # v2.0.8
|
||||
with:
|
||||
junit-paths: target/nextest/ci/junit.xml
|
||||
cli-version: 0.12.5
|
||||
org-slug: warp
|
||||
token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
tags: type=integration,category=remote-server
|
||||
variant: linux
|
||||
use-cache: true
|
||||
|
||||
database-migration:
|
||||
name: Database Migration (Diesel)
|
||||
timeout-minutes: 5
|
||||
@@ -449,7 +539,7 @@ jobs:
|
||||
if: ${{ needs.params.outputs.affects-database-schema == 'true' }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
|
||||
- name: Install cargo-binstall
|
||||
uses: cargo-bins/cargo-binstall@dc19f1e48450eefe5a29b8da6c6b00a87d730b37 # v1.18.1
|
||||
@@ -503,7 +593,7 @@ jobs:
|
||||
needs: params
|
||||
# if: ${{ needs.params.outputs.affects-rust-sources == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -514,8 +604,9 @@ jobs:
|
||||
run:
|
||||
cargo metadata --locked --format-version=1 > ${{ matrix.null_device }} || (echo "::error::Cargo.lock is out-of-date with Cargo.toml. Run 'cargo check' to update." && exit 1)
|
||||
|
||||
- name: Run cargo fmt
|
||||
run: cargo fmt --check
|
||||
- name: Run ./script/format
|
||||
shell: bash
|
||||
run: ./script/format --check
|
||||
|
||||
- name: Run cargo clippy
|
||||
shell: bash
|
||||
@@ -554,7 +645,7 @@ jobs:
|
||||
needs: params
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
with:
|
||||
@@ -589,6 +680,20 @@ jobs:
|
||||
- name: Validate repo-sync markers
|
||||
uses: warpdotdev/repo-sync/actions/validate-markers@main
|
||||
|
||||
- name: Check for incorrectly named test files
|
||||
run: |
|
||||
# Test files should end in _tests.rs, not _test.rs.
|
||||
bad_files=$(find . -name '*_test.rs')
|
||||
if [ -n "$bad_files" ]; then
|
||||
while IFS= read -r f; do
|
||||
echo "::error file=$f::Test file should be named ${f/_test.rs/_tests.rs} (use _tests.rs, not _test.rs)"
|
||||
done <<< "$bad_files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check for inline Rust test modules
|
||||
run: ./script/check_no_inline_test_modules
|
||||
|
||||
wasm-lint:
|
||||
name: Formatting + Clippy (wasm)
|
||||
timeout-minutes: 20
|
||||
@@ -603,7 +708,7 @@ jobs:
|
||||
IS_SELF_HOSTED="${{ contains(fromJSON(needs.params.outputs.wasm-runner), 'self-hosted') }}"
|
||||
echo "value=$IS_SELF_HOSTED" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -614,8 +719,15 @@ jobs:
|
||||
run:
|
||||
cargo metadata --locked --format-version=1 >/dev/null || (echo "::error::Cargo.lock is out-of-date with Cargo.toml. Run 'cargo check' to update." && exit 1)
|
||||
|
||||
- name: Run cargo fmt
|
||||
run: cargo fmt --check
|
||||
- name: Check Rust formatting
|
||||
shell: bash
|
||||
run: |
|
||||
# TODO(vorporeal): Once people have gotten used to ./script/format, in a week or so,
|
||||
# we can have CI enforce the new formatting.
|
||||
#./script/format --check
|
||||
|
||||
# Until then, we'll keep running the traditional formatting check.
|
||||
cargo fmt --check
|
||||
|
||||
- name: Run cargo clippy
|
||||
run: |
|
||||
@@ -658,7 +770,7 @@ jobs:
|
||||
runs-on: ${{ matrix.runner }}
|
||||
needs: params
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
name: Comment on Unready Assigned Issue (Local)
|
||||
on:
|
||||
issues:
|
||||
types: [assigned]
|
||||
concurrency:
|
||||
group: comment-on-unready-assigned-issue-${{ github.event.issue.number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
comment_when_unready:
|
||||
if: github.event.assignee.login == 'oz-agent' && !contains(github.event.issue.labels.*.name, 'ready-to-spec') && !contains(github.event.issue.labels.*.name, 'ready-to-implement')
|
||||
permissions:
|
||||
issues: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/comment-on-unready-assigned-issue.yml@main
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Create Implementation from Issue (Local)
|
||||
on:
|
||||
issues:
|
||||
types: [assigned, labeled]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: Issue number to create an implementation for
|
||||
required: true
|
||||
type: string
|
||||
concurrency:
|
||||
group: create-implementation-issue-${{ github.event.issue.number || inputs.issue_number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
# Mention, bot, event-type, and trust gates all live in the reusable
|
||||
# workflow (``create-implementation-from-issue.yml``). This adapter
|
||||
# exists only to subscribe to the GitHub events that can trigger
|
||||
# implementation work (``issues`` assign/label by a maintainer, or a
|
||||
# trusted ``@oz-agent`` issue comment) and delegate them through
|
||||
# ``workflow_call``.
|
||||
create_implementation:
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/create-implementation-from-issue.yml@main
|
||||
with:
|
||||
issue_number: ${{ github.event.inputs.issue_number || '' }}
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Create Spec from Issue (Local)
|
||||
on:
|
||||
issues:
|
||||
types: [assigned, labeled]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: Issue number to create a spec for
|
||||
required: true
|
||||
type: string
|
||||
concurrency:
|
||||
group: create-spec-issue-${{ github.event.issue.number || inputs.issue_number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
# Mention, bot, event-type, and trust gates all live in the reusable
|
||||
# workflow (``create-spec-from-issue.yml``). This adapter exists only
|
||||
# to subscribe to the GitHub events that can trigger spec creation
|
||||
# (``issues`` assign/label by a maintainer, or a trusted
|
||||
# ``@oz-agent`` issue comment) and delegate them through
|
||||
# ``workflow_call``.
|
||||
create_spec:
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/create-spec-from-issue.yml@main
|
||||
with:
|
||||
issue_number: ${{ github.event.inputs.issue_number || '' }}
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
should_publish: ${{ steps.set_publish.outputs.should_publish }}
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
|
||||
- name: Get channel configuration
|
||||
id: get-config
|
||||
@@ -111,6 +111,9 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
CHANNEL: ${{ steps.get-config.outputs.channel }}
|
||||
# See https://github.com/orgs/community/discussions/151442 for why we need to use
|
||||
# a PAT here.
|
||||
GITHUB_TOKEN: ${{ secrets.CREATE_RELEASE_TAG_PUSH_PAT }}
|
||||
|
||||
- name: Create GitHub release
|
||||
if: ${{ steps.set_publish.outputs.should_publish == 'true' }}
|
||||
@@ -150,7 +153,7 @@ jobs:
|
||||
- arch: x86_64
|
||||
dmg_name_suffix: x86_64
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -270,7 +273,7 @@ jobs:
|
||||
if: ${{ inputs.build_macos != false }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -417,7 +420,7 @@ jobs:
|
||||
- arch: aarch64
|
||||
- arch: x86_64
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -513,14 +516,17 @@ jobs:
|
||||
runs-on: namespace-profile-ubuntu-20-04
|
||||
needs: prepare_release
|
||||
if: ${{ inputs.build_linux != false }}
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
# Automatically extract AppImages before running them instead of mounting
|
||||
# them with FUSE, which isn't available on GitHub runners (and this is
|
||||
# easier and less error-prone than trying to install it).
|
||||
APPIMAGE_EXTRACT_AND_RUN: "1"
|
||||
# Cache the generated settings schema so prepare_bundled_resources only
|
||||
# compiles and runs the generator once per job instead of per-package.
|
||||
SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -588,7 +594,10 @@ jobs:
|
||||
# Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can
|
||||
# leave stale packages from a previous channel's build in the linux bundle output dir.
|
||||
- name: Clean stale bundle output
|
||||
run: rm -rf target/*/bundle/linux
|
||||
run: |
|
||||
if [[ -d target ]]; then
|
||||
find target -path '*/bundle/linux' -type d -prune -exec rm -rf {} +
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Bundle app
|
||||
@@ -665,12 +674,16 @@ jobs:
|
||||
|
||||
release_linux_cli_x86:
|
||||
name: Build Release (Linux CLI x86_64)
|
||||
runs-on: namespace-profile-ubuntu-20-04
|
||||
runs-on: namespace-profile-ubuntu-22-04
|
||||
needs: prepare_release
|
||||
if: ${{ inputs.build_linux != false }}
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
# Cache the generated settings schema so prepare_bundled_resources only
|
||||
# compiles and runs the generator once per job instead of per-package.
|
||||
SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -735,7 +748,10 @@ jobs:
|
||||
# Namespace's User Bundled Cache persists target/ between jobs on the same profile, which can
|
||||
# leave stale packages from a previous channel's build in the linux bundle output dir.
|
||||
- name: Clean stale bundle output
|
||||
run: rm -rf target/*/bundle/linux
|
||||
run: |
|
||||
if [[ -d target ]]; then
|
||||
find target -path '*/bundle/linux' -type d -prune -exec rm -rf {} +
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Bundle CLI
|
||||
@@ -839,14 +855,17 @@ jobs:
|
||||
runs-on: namespace-profile-ubuntu-20-04-arm
|
||||
needs: prepare_release
|
||||
if: ${{ inputs.build_linux != false }}
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
# Automatically extract AppImages before running them instead of mounting
|
||||
# them with FUSE, which isn't available on GitHub runners (and this is
|
||||
# easier and less error-prone than trying to install it).
|
||||
APPIMAGE_EXTRACT_AND_RUN: "1"
|
||||
# Cache the generated settings schema so prepare_bundled_resources only
|
||||
# compiles and runs the generator once per job instead of per-package.
|
||||
SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -930,12 +949,12 @@ jobs:
|
||||
|
||||
build_linux_cli_arm_binaries:
|
||||
name: Build Release (Linux CLI ARM)
|
||||
runs-on: namespace-profile-ubuntu-20-04-arm
|
||||
runs-on: namespace-profile-ubuntu-22-04
|
||||
needs: prepare_release
|
||||
if: ${{ inputs.build_linux != false }}
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -976,7 +995,7 @@ jobs:
|
||||
id: build_cli
|
||||
run: |
|
||||
# Build the CLI only
|
||||
script/bundle --channel $CHANNEL --artifact cli --packages none
|
||||
script/bundle --channel $CHANNEL --artifact cli --packages none --arch aarch64
|
||||
shell: bash
|
||||
env:
|
||||
CHANNEL: ${{ steps.get-config.outputs.channel }}
|
||||
@@ -1011,9 +1030,13 @@ jobs:
|
||||
needs: [ prepare_release, build_linux_arm_binaries, build_linux_cli_arm_binaries ]
|
||||
if: ${{ inputs.build_linux != false }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
# Cache the generated settings schema so prepare_bundled_resources only
|
||||
# compiles and runs the generator once per job instead of per-package.
|
||||
SETTINGS_SCHEMA_CACHE: ${{ github.workspace }}/.settings_schema_cache.json
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
ref: ${{ needs.prepare_release.outputs.release_branch }}
|
||||
|
||||
@@ -1269,7 +1292,7 @@ jobs:
|
||||
if: ${{ inputs.build_web != false }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -1394,7 +1417,7 @@ jobs:
|
||||
TRUSTED_SIGNING_ACCOUNT: warpdotdev
|
||||
TRUSTED_SIGNING_CERT_PROFILE: warpterminal
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
|
||||
- uses: ./.github/actions/prepare_environment
|
||||
with:
|
||||
@@ -1615,7 +1638,7 @@ jobs:
|
||||
- release_web
|
||||
- release_windows
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
name: Checkout sources
|
||||
with:
|
||||
# Fetch history for all tags and branches so we can compare revisions
|
||||
@@ -1629,75 +1652,116 @@ jobs:
|
||||
config_file: ${{ env.CONFIG_FILE }}
|
||||
channel: ${{ inputs.channel }}
|
||||
|
||||
- name: Obtain a GitHub App Installation Access Token
|
||||
# Stable releases use the Oz changelog-draft agent for higher-quality,
|
||||
# human-reviewable output. Non-stable channels (dev/preview/beta) use the
|
||||
# legacy generate-changelog action to avoid spending Oz agent tokens on
|
||||
# daily dev cuts and preview RCs.
|
||||
- name: Generate changelog via Oz (stable only)
|
||||
if: inputs.channel == 'stable'
|
||||
uses: warpdotdev/oz-agent-action@ce1621abf6a8ed8afdd4e4cc994545ede8fe1c6f # main
|
||||
with:
|
||||
prompt: |
|
||||
Generate a changelog draft for the ${{ inputs.channel }} channel, release tag ${{ needs.prepare_release.outputs.release_tag }}.
|
||||
|
||||
Output directory: ${{ runner.temp }}/changelog-draft
|
||||
|
||||
Follow the workflow in .agents/skills/changelog-draft/SKILL.md exactly.
|
||||
Make sure to produce both output files: changelog-draft.md and changelog-draft.json.
|
||||
The release workflow may run from warpdotdev/warp-internal. When fetching PR data, pass the checked-out repository ("${{ github.repository }}") to fetch_prs.py and rely on the script's repo-sync normalization to resolve public warpdotdev/warp PR numbers, URLs, and authors. The script intentionally omits non-repo-sync PRs from warp-internal because they are private internal changes. Do not infer or synthesize public PR links manually.
|
||||
|
||||
After writing the output files, print the full contents of changelog-draft.md to stdout so it appears in the workflow log.
|
||||
|
||||
You are running in a GitHub Actions workflow. The repo is checked out at the default branch (HEAD) with full history. Use the release_tag input as the git range endpoint — do NOT check out the release tag. `gh` is authenticated. Do not commit, push, or create PRs.
|
||||
warp_api_key: ${{ secrets.WARP_API_KEY }}
|
||||
share: team
|
||||
- name: Upload raw Markdown changelog artifact (stable only)
|
||||
if: inputs.channel == 'stable'
|
||||
id: upload_changelog_draft_markdown
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: changelog-draft-markdown
|
||||
path: ${{ runner.temp }}/changelog-draft/changelog-draft.md
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Convert draft JSON to release format (stable only)
|
||||
if: inputs.channel == 'stable'
|
||||
shell: bash
|
||||
run: |
|
||||
python3 .agents/skills/changelog-draft/scripts/convert_to_release_json.py \
|
||||
--input "${{ runner.temp }}/changelog-draft/changelog-draft.json" \
|
||||
--output "${{ runner.temp }}/changelog-draft/changelog-release.json"
|
||||
|
||||
- name: Obtain a GitHub App Installation Access Token (non-stable only)
|
||||
if: inputs.channel != 'stable'
|
||||
id: github_app_auth
|
||||
run: |
|
||||
TOKEN="$(npx obtain-github-app-installation-access-token ci ${{ secrets.GH_APP_CREDENTIALS_TOKEN }})"
|
||||
echo "::add-mask::$TOKEN"
|
||||
echo "token=$TOKEN" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate changelog
|
||||
uses: warpdotdev/generate-changelog@main
|
||||
id: generate_changelog
|
||||
- name: Generate changelog via legacy action (non-stable only)
|
||||
if: inputs.channel != 'stable'
|
||||
id: legacy_changelog
|
||||
uses: warpdotdev/generate-changelog@70f534c1e030dafb45046ae57e4aa4d43a2f5c84 # main
|
||||
with:
|
||||
channel: ${{ inputs.channel }}
|
||||
github_auth_token: ${{ steps.github_app_auth.outputs.token }}
|
||||
version: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
|
||||
- name: Load changelog into step output
|
||||
id: generate_changelog
|
||||
shell: bash
|
||||
env:
|
||||
LEGACY_CHANGELOG: ${{ steps.legacy_changelog.outputs.changelog }}
|
||||
run: |
|
||||
# Bridge step: picks whichever generator ran for this channel and
|
||||
# re-emits the changelog as outputs.changelog so downstream Slack/GCS
|
||||
# steps work unchanged.
|
||||
if [[ "${{ inputs.channel }}" == "stable" ]]; then
|
||||
CHANGELOG_FILE="${{ runner.temp }}/changelog-draft/changelog-release.json"
|
||||
if [ ! -f "$CHANGELOG_FILE" ]; then
|
||||
echo "::error::changelog-release.json not found at $CHANGELOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
jq empty "$CHANGELOG_FILE"
|
||||
{
|
||||
echo "changelog<<CHANGELOG_EOF"
|
||||
cat "$CHANGELOG_FILE"
|
||||
echo "CHANGELOG_EOF"
|
||||
} >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "$LEGACY_CHANGELOG" | jq empty
|
||||
{
|
||||
echo "changelog<<CHANGELOG_EOF"
|
||||
printf '%s\n' "$LEGACY_CHANGELOG"
|
||||
echo "CHANGELOG_EOF"
|
||||
} >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build Slack changelog payload
|
||||
id: build_slack_payload
|
||||
shell: bash
|
||||
env:
|
||||
CHANGELOG_MD: ${{ steps.generate_changelog.outputs.changelog }}
|
||||
CHANGELOG_JSON: ${{ steps.generate_changelog.outputs.changelog }}
|
||||
RELEASE_TAG: ${{ needs.prepare_release.outputs.release_tag }}
|
||||
MARKDOWN_ARTIFACT_URL: ${{ steps.upload_changelog_draft_markdown.outputs.artifact-url }}
|
||||
run: |
|
||||
# Rename the keys in the Changelog JSON to something more human readable.
|
||||
# This is the changelog that goes to slack so it doesn't need to be extremely filtered.
|
||||
NEW_CHANGELOG=$(echo $CHANGELOG_MD | jq 'with_entries(if .key == "newFeatures" then .key = "New Features" else . end)' | jq 'with_entries(if .key == "improvements" then .key = "Improvements" else . end)' | jq 'with_entries(if .key == "bugFixes" then .key = "Bug Fixes" else . end)' | jq 'with_entries(if .key == "images" then .key = "Image" else . end)')
|
||||
|
||||
# Generate the full markdown text as individual lines.
|
||||
MARKDOWN=$(echo "$NEW_CHANGELOG" | jq -r 'to_entries[] | select(.value | length > 0) | "*\(.key)*", (.value[] | " \u2022 \(.)")')
|
||||
|
||||
if [ -z "$MARKDOWN" ]; then
|
||||
CHANGELOG_INPUT="${{ runner.temp }}/slack-changelog-input.json"
|
||||
SLACK_PAYLOAD="${{ runner.temp }}/slack-changelog-payload.json"
|
||||
printf '%s\n' "$CHANGELOG_JSON" > "$CHANGELOG_INPUT"
|
||||
python3 .agents/skills/changelog-draft/scripts/build_slack_payload.py \
|
||||
--input "$CHANGELOG_INPUT" \
|
||||
--release-tag "$RELEASE_TAG" \
|
||||
--markdown-artifact-url "$MARKDOWN_ARTIFACT_URL" \
|
||||
--output "$SLACK_PAYLOAD"
|
||||
if ! jq -e '.blocks | length > 0' "$SLACK_PAYLOAD" >/dev/null; then
|
||||
echo "has_content=" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
echo "has_content=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Split markdown into chunks of <= 3000 characters at newline boundaries.
|
||||
# Each chunk will become its own section block in the Slack payload.
|
||||
CHUNKS='[]'
|
||||
BUFFER=""
|
||||
while IFS= read -r line; do
|
||||
if [ -z "$BUFFER" ]; then
|
||||
CANDIDATE="$line"
|
||||
else
|
||||
CANDIDATE="$BUFFER"
|
||||
CANDIDATE+=$'\n'
|
||||
CANDIDATE+="$line"
|
||||
fi
|
||||
if [ ${#CANDIDATE} -gt 3000 ]; then
|
||||
# Flush the current buffer as a chunk (if non-empty), start a new one with this line.
|
||||
if [ -n "$BUFFER" ]; then
|
||||
CHUNKS=$(echo "$CHUNKS" | jq --arg chunk "$BUFFER" '. + [$chunk]')
|
||||
fi
|
||||
BUFFER="$line"
|
||||
else
|
||||
BUFFER="$CANDIDATE"
|
||||
fi
|
||||
done <<< "$MARKDOWN"
|
||||
# Flush the remaining buffer.
|
||||
if [ -n "$BUFFER" ]; then
|
||||
CHUNKS=$(echo "$CHUNKS" | jq --arg chunk "$BUFFER" '. + [$chunk]')
|
||||
fi
|
||||
|
||||
# Build the full Slack Block Kit payload: header block + one section block per chunk.
|
||||
PAYLOAD=$(echo "$CHUNKS" | jq -c \
|
||||
--arg version "$RELEASE_TAG" \
|
||||
'{blocks: ([{type: "header", text: {type: "plain_text", text: ("Changelog for " + $version)}}] + [.[] | {type: "section", text: {type: "mrkdwn", text: .}}])}')
|
||||
|
||||
echo "payload<<SLACK_PAYLOAD_EOF" >> $GITHUB_OUTPUT
|
||||
echo "$PAYLOAD" >> $GITHUB_OUTPUT
|
||||
cat "$SLACK_PAYLOAD" >> $GITHUB_OUTPUT
|
||||
echo "SLACK_PAYLOAD_EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Post to a Slack channel
|
||||
@@ -1728,7 +1792,7 @@ jobs:
|
||||
NEW_FEATURES=$(echo $CHANGELOG_SECTIONS | jq 'with_entries(select(.key == "New features"))' | jq -r 'to_entries[] | "* \(.value[])"' | awk -v ORS='\n' '1')
|
||||
IMPROVEMENTS=$(echo $CHANGELOG_SECTIONS | jq 'with_entries(select(.key == "Improvements"))' | jq -r 'to_entries[] | "* \(.value[])"' | awk -v ORS='\n' '1')
|
||||
# Extract the image URL from the list, and use the latest URL even if there are multiple
|
||||
IMAGE=$(echo $CHANGELOG | jq -r '.image | if length > 0 then .[-1] else "" end')
|
||||
IMAGE=$(echo $CHANGELOG | jq -r '.images | if length > 0 then .[-1] else "" end')
|
||||
# Extract Oz updates as a JSON array
|
||||
OZ_UPDATES=$(echo $CHANGELOG | jq -c '.oz_updates // []')
|
||||
# Tweak the structure of the JSON, add in a top-level date field, and add in the markdown_sections field
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
run: |
|
||||
[ $GITHUB_REF == "refs/heads/master" ] || (echo "::error::Can only cut new releases on the master branch" && exit 1)
|
||||
shell: bash
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- id: get-config
|
||||
run: |
|
||||
# Check to see if this was auto-run as a cron job. If so, set the
|
||||
|
||||
@@ -89,10 +89,9 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Rename branch to deleted/
|
||||
env:
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
&& github.actor != 'github-actions[bot]'
|
||||
runs-on: namespace-profile-ubuntu-20-04
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
# Check out the appropriate branch based on trigger type
|
||||
# TODO: do this in sdk?
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
name: Enforce PR Issue State Logic
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: Pull request number to evaluate
|
||||
required: true
|
||||
type: string
|
||||
requester:
|
||||
description: Login of the user whose action triggered enforcement, if any
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID:
|
||||
required: true
|
||||
OZ_MGMT_GHA_PRIVATE_KEY:
|
||||
required: true
|
||||
OSS_WARP_API_KEY:
|
||||
required: true
|
||||
outputs:
|
||||
allow_review:
|
||||
description: Whether downstream PR hooks may continue after enforcement.
|
||||
value: ${{ jobs.enforce_issue_state.outputs.allow_review }}
|
||||
jobs:
|
||||
enforce_issue_state:
|
||||
name: Enforce PR issue state
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/enforce-pr-issue-state.yml@main
|
||||
with:
|
||||
pr_number: ${{ inputs.pr_number }}
|
||||
requester: ${{ inputs.requester }}
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
* "date_enabled" - the date on which the feature flag was enabled by default
|
||||
* "enabling_commit" - the Git commit in which the feature flag was enabled by default
|
||||
* You are running as part of a GitHub automation and must not commit or push any changes. Another agent will process the file you produce.
|
||||
warp_api_key: ${{ secrets.WARP_API_KEY }}
|
||||
warp_api_key: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
share: team
|
||||
|
||||
- name: Upload feature flag log
|
||||
@@ -178,7 +178,7 @@ jobs:
|
||||
|
||||
You are running as part of a GitHub automation that runs with a read-only token and will package your changes into a patch for a separate job to commit. Do not create a branch, do not commit, do not push, do not create a PR, and do not call `gh`. Leave your changes in the working tree only.
|
||||
share: team
|
||||
warp_api_key: ${{ secrets.WARP_API_KEY }}
|
||||
warp_api_key: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
|
||||
- name: Generate cleanup patch
|
||||
env:
|
||||
@@ -227,11 +227,18 @@ jobs:
|
||||
run: |
|
||||
git apply --binary --whitespace=nowarn "$RUNNER_TEMP/cleanup.patch"
|
||||
|
||||
- name: Generate GitHub App token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
app-id: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
private-key: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
|
||||
- name: Create Pull Request
|
||||
id: create_pr
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
base: ${{ github.event.repository.default_branch }}
|
||||
commit-message: "Clean up ${{ needs.analyze.outputs.flag_name }} feature flag"
|
||||
branch: "oz-agent/cleanup-feature-flag-${{ needs.analyze.outputs.flag_name }}"
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# ======================================================================================
|
||||
# Workflow: Label External Contributors
|
||||
# ======================================================================================
|
||||
# Usage:
|
||||
# - Runs whenever a pull request is opened.
|
||||
# - Adds the `external-contributor` label to the PR if the PR head repository is
|
||||
# a fork (i.e. it does not belong to the same repository as the base), and the
|
||||
# PR is not authored by a bot.
|
||||
#
|
||||
# Notes:
|
||||
# - The workflow triggers on `pull_request_target` rather than `pull_request` so
|
||||
# that it has the `pull-requests: write` permission needed to apply labels even
|
||||
# when the PR is opened from a fork. Because we never check out the PR's code
|
||||
# and only read the event payload, this trigger is safe.
|
||||
# ======================================================================================
|
||||
|
||||
name: Label External Contributors
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
# Default to a read-only token. The job below widens permissions explicitly.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
label-external-contributor:
|
||||
name: Label external-contributor PRs
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Determine and apply external-contributor label
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const author = pr.user.login;
|
||||
|
||||
// Ignore PRs authored by bots.
|
||||
if (pr.user.type === 'Bot' || author.endsWith('[bot]')) {
|
||||
console.log(`Skipping bot user: ${author}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// The PR comes from a fork if its head repo differs from its base repo.
|
||||
const isFork =
|
||||
!pr.head.repo ||
|
||||
pr.head.repo.full_name !== pr.base.repo.full_name;
|
||||
|
||||
console.log(
|
||||
`PR #${pr.number} by ${author}: isFork=${isFork}`,
|
||||
);
|
||||
|
||||
if (!isFork) {
|
||||
return;
|
||||
}
|
||||
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
labels: ['external-contributor'],
|
||||
});
|
||||
console.log(`Labeled PR #${pr.number} as external-contributor`);
|
||||
@@ -1,20 +0,0 @@
|
||||
name: Remove Stale Issue Labels on Plan Approved (Local)
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
concurrency:
|
||||
group: remove-stale-labels-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
remove_stale_labels:
|
||||
if: github.event.label.name == 'plan-approved'
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: read
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/remove-stale-issue-labels-on-plan-approved.yml@main
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Respond to PR Comment (Local)
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
jobs:
|
||||
# Mention, bot, event-type, and trust gates all live in the reusable
|
||||
# workflow (``respond-to-pr-comment.yml``). This adapter exists only
|
||||
# to subscribe to the three GitHub events that can carry an
|
||||
# ``@oz-agent`` mention on a PR and delegate them through
|
||||
# ``workflow_call``.
|
||||
respond:
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/respond-to-pr-comment.yml@main
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Respond to Triaged Issue Comment (Local)
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
concurrency:
|
||||
group: respond-to-triaged-issue-comment-${{ github.event.comment.id || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
# Mention, bot, event-type, and trust gates all live in the reusable
|
||||
# workflow (``respond-to-triaged-issue-comment.yml``). This adapter
|
||||
# exists only to subscribe to the GitHub event that can carry an
|
||||
# ``@oz-agent`` mention on a triaged issue and delegate it through
|
||||
# ``workflow_call``.
|
||||
respond_inline:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/respond-to-triaged-issue-comment.yml@main
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -1,129 +0,0 @@
|
||||
name: Review Pull Request
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: Pull request number to review
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
trigger_source:
|
||||
description: Source that requested the review
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
requester:
|
||||
description: Login of the user who requested the review, if any
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
comment_id:
|
||||
description: Issue comment ID to react to for slash-command reviews
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID:
|
||||
required: true
|
||||
OZ_MGMT_GHA_PRIVATE_KEY:
|
||||
required: true
|
||||
OSS_WARP_API_KEY:
|
||||
required: true
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- ready_for_review
|
||||
- review_requested
|
||||
- labeled
|
||||
jobs:
|
||||
resolve:
|
||||
runs-on: ubuntu-slim
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
should_run: ${{ steps.resolve.outputs.should_run }}
|
||||
pr_number: ${{ steps.resolve.outputs.pr_number }}
|
||||
trigger_source: ${{ steps.resolve.outputs.trigger_source }}
|
||||
requester: ${{ steps.resolve.outputs.requester }}
|
||||
comment_id: ${{ steps.resolve.outputs.comment_id }}
|
||||
skip_reason: ${{ steps.resolve.outputs.skip_reason }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- name: Resolve review context
|
||||
id: resolve
|
||||
env:
|
||||
INPUT_PR_NUMBER: ${{ inputs.pr_number || '' }}
|
||||
INPUT_TRIGGER_SOURCE: ${{ inputs.trigger_source || '' }}
|
||||
INPUT_REQUESTER: ${{ inputs.requester || '' }}
|
||||
INPUT_COMMENT_ID: ${{ inputs.comment_id || '' }}
|
||||
GITHUB_ACTOR_LOGIN: ${{ github.actor }}
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
event = json.loads(Path(os.environ["GITHUB_EVENT_PATH"]).read_text())
|
||||
event_name = os.environ.get("GITHUB_EVENT_NAME", "")
|
||||
input_pr_number = os.environ.get("INPUT_PR_NUMBER", "").strip()
|
||||
pr = event.get("pull_request") or {}
|
||||
head_ref = ((pr.get("head") or {}).get("ref") or "").strip()
|
||||
action = (event.get("action") or "").strip()
|
||||
requested_reviewer = ((event.get("requested_reviewer") or {}).get("login") or "").strip()
|
||||
label_name = ((event.get("label") or {}).get("name") or "").strip()
|
||||
has_pr_hooks = Path(".github/workflows/pr-hooks.yml").exists()
|
||||
trigger_source = os.environ.get("INPUT_TRIGGER_SOURCE", "").strip() or event_name
|
||||
requester = os.environ.get("INPUT_REQUESTER", "").strip() or os.environ.get("GITHUB_ACTOR_LOGIN", "")
|
||||
comment_id = os.environ.get("INPUT_COMMENT_ID", "")
|
||||
pr_number = input_pr_number or str(pr.get("number") or "")
|
||||
matches_direct_trigger = (
|
||||
(action == "opened" and not pr.get("draft", False))
|
||||
or action == "ready_for_review"
|
||||
or (action == "review_requested" and requested_reviewer == "oz-agent")
|
||||
or (action == "labeled" and label_name == "oz-review")
|
||||
)
|
||||
if input_pr_number:
|
||||
should_run = True
|
||||
elif head_ref.startswith("cherrypick"):
|
||||
should_run = False
|
||||
elif has_pr_hooks and event_name == "pull_request_target":
|
||||
should_run = False
|
||||
else:
|
||||
should_run = matches_direct_trigger and bool(pr_number)
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
|
||||
fh.write(f"should_run={'true' if should_run else 'false'}\n")
|
||||
fh.write(f"pr_number={pr_number}\n")
|
||||
fh.write(f"trigger_source={trigger_source}\n")
|
||||
fh.write(f"requester={requester}\n")
|
||||
fh.write(f"comment_id={comment_id}\n")
|
||||
if has_pr_hooks and event_name == "pull_request_target" and not input_pr_number:
|
||||
fh.write("skip_reason=pr-hooks-present\n")
|
||||
elif head_ref.startswith("cherrypick"):
|
||||
fh.write("skip_reason=cherrypick-branch\n")
|
||||
elif not should_run:
|
||||
fh.write("skip_reason=event-not-enabled\n")
|
||||
PY
|
||||
skip_direct_trigger:
|
||||
needs: resolve
|
||||
if: needs.resolve.outputs.should_run != 'true' && needs.resolve.outputs.skip_reason == 'pr-hooks-present'
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Explain skip
|
||||
run: echo "PR review orchestration skipped because .github/workflows/pr-hooks.yml is present."
|
||||
review_pr:
|
||||
needs: resolve
|
||||
if: needs.resolve.outputs.should_run == 'true'
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/review-pull-request.yml@main
|
||||
with:
|
||||
pr_number: ${{ needs.resolve.outputs.pr_number }}
|
||||
trigger_source: ${{ needs.resolve.outputs.trigger_source }}
|
||||
requester: ${{ needs.resolve.outputs.requester }}
|
||||
comment_id: ${{ needs.resolve.outputs.comment_id }}
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
# ======================================================================================
|
||||
# Workflow: Stale Requested-Changes PRs
|
||||
# ======================================================================================
|
||||
# Usage:
|
||||
# - Runs daily and follows up on external-contributor PRs that have an active
|
||||
# requested-changes review and have gone inactive.
|
||||
# - Posts reminder comments at 7 and 10 days of author inactivity, then closes
|
||||
# the PR at 14 days — but only after the day-10 final warning has been posted.
|
||||
# - Inactivity is author-driven: a head-branch push (GitHub-recorded) or a comment by
|
||||
# the PR author resets the timer; maintainer/third-party/bot comments do not.
|
||||
# - Reminder progress is tracked via marker comments authored by github-actions[bot],
|
||||
# so no datastore is needed.
|
||||
#
|
||||
# Modes (workflow_dispatch `mode` input; scheduled runs use `full`):
|
||||
# - dry-run: log eligible PRs and intended actions, write nothing.
|
||||
# - reminder-only: post reminders, never close.
|
||||
# - full: post reminders and close.
|
||||
# ======================================================================================
|
||||
|
||||
name: Stale Requested-Changes PRs
|
||||
on:
|
||||
schedule:
|
||||
- cron: '7 12 * * *' # 12:07 UTC daily (minute 7 avoids top-of-hour scheduler congestion)
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
mode:
|
||||
description: 'Write mode'
|
||||
type: choice
|
||||
default: full
|
||||
options:
|
||||
- dry-run
|
||||
- reminder-only
|
||||
- full
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
stale-requested-changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
# Only the follow-up script is needed; skip blob content for speed.
|
||||
sparse-checkout: .github/scripts
|
||||
filter: blob:none
|
||||
|
||||
- name: Follow up on stale requested-changes PRs
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const run = require('./.github/scripts/stale-requested-changes-prs.js')
|
||||
await run({ github, context })
|
||||
@@ -1,60 +0,0 @@
|
||||
name: Triage New Issues (Local)
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: Optional issue number to triage immediately
|
||||
required: false
|
||||
default: ''
|
||||
type: string
|
||||
lookback_minutes:
|
||||
description: Minutes of issue history to scan when no issue number is provided
|
||||
required: false
|
||||
default: '60'
|
||||
type: string
|
||||
concurrency:
|
||||
group: triage-new-issues-${{ github.event.issue.number || inputs.issue_number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
triage_issues:
|
||||
# A needs-info reply by the original reporter triggers re-triage
|
||||
# even if it mentions @oz-agent, because the respond-to-triaged
|
||||
# workflow handles explicit mentions on triaged issues separately.
|
||||
if: |
|
||||
(
|
||||
github.event_name != 'issue_comment' &&
|
||||
!contains(github.event.issue.labels.*.name, 'triaged') &&
|
||||
!contains(github.event.issue.labels.*.name, 'ready-to-spec') &&
|
||||
!contains(github.event.issue.labels.*.name, 'ready-to-implement')
|
||||
) || (
|
||||
github.event_name == 'issue_comment' &&
|
||||
!github.event.issue.pull_request &&
|
||||
github.event.comment.user.type != 'Bot' &&
|
||||
!endsWith(github.event.comment.user.login, '[bot]') &&
|
||||
(
|
||||
(
|
||||
contains(github.event.comment.body, '@oz-agent') &&
|
||||
!contains(github.event.issue.labels.*.name, 'triaged')
|
||||
) ||
|
||||
(
|
||||
contains(github.event.issue.labels.*.name, 'needs-info') &&
|
||||
github.event.comment.user.login == github.event.issue.user.login &&
|
||||
!contains(github.event.comment.body, '@oz-agent')
|
||||
)
|
||||
)
|
||||
)
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/triage-new-issues.yml@main
|
||||
with:
|
||||
issue_number: ${{ github.event.issue.number || github.event.inputs.issue_number || '' }}
|
||||
lookback_minutes: ${{ github.event.inputs.lookback_minutes || '60' }}
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Trigger Implementation on Plan Approved (Local)
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
concurrency:
|
||||
group: trigger-impl-plan-approved-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
trigger_implementation:
|
||||
if: >-
|
||||
github.event.label.name == 'plan-approved' &&
|
||||
github.event.pull_request.state == 'open'
|
||||
name: Trigger implementation for approved plan
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/trigger-implementation-on-plan-approved.yml@main
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Verify PR Comment (Local)
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
jobs:
|
||||
# Slash-command parsing, bot gating, and trust admission live in the
|
||||
# reusable workflow. This local adapter only subscribes to PR issue
|
||||
# comments and delegates through ``workflow_call``.
|
||||
verify:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
uses: warpdotdev/oz-for-oss/.github/workflows/verify-pr-comment.yml@main
|
||||
secrets:
|
||||
OZ_MGMT_GHA_APP_ID: ${{ secrets.OZ_MGMT_GHA_APP_ID }}
|
||||
OZ_MGMT_GHA_PRIVATE_KEY: ${{ secrets.OZ_MGMT_GHA_PRIVATE_KEY }}
|
||||
OSS_WARP_API_KEY: ${{ secrets.OSS_WARP_API_KEY }}
|
||||
Reference in New Issue
Block a user