-
Notifications
You must be signed in to change notification settings - Fork 373
180 lines (163 loc) · 7.05 KB
/
Copy pathcpflow-delete-review-app.yml
File metadata and controls
180 lines (163 loc) · 7.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
name: Delete Review App
on:
pull_request_target:
types: [closed]
issue_comment:
types: [created]
workflow_dispatch:
inputs:
pr_number:
description: Pull request number targeted for deletion
required: true
type: number
permissions:
contents: read
deployments: write
issues: write
pull-requests: write
concurrency:
group: cpflow-delete-review-app-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
# Deletions must not cancel each other mid-flight — a cancelled `cpln` delete can leave
# partial state behind. Let the in-progress deletion finish before the next run starts.
cancel-in-progress: false
env:
APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
jobs:
delete-review-app:
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.body == '/delete-review-app' &&
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_target' && github.event.action == 'closed') ||
github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
# pull_request_target is intentional: PR-close events from forks need access
# to staging secrets so this workflow can delete review apps and update PR
# comments. This checkout is safe because it does not set `ref:`; GitHub checks
# out the base branch's trusted workflow code, not the fork head. Do not add
# `ref: ${{ github.event.pull_request.head.sha }}` here without re-evaluating
# the trust boundary. All local composite actions below are therefore loaded from
# trusted base-branch code; keep them that way when changing this workflow.
- name: Checkout repository
uses: actions/checkout@v4
with:
# Delete only invokes `cpln`/`cpflow`; no git push happens, so drop the
# GITHUB_TOKEN credential helper to keep the token out of .git/config under
# `pull_request_target`, which has access to repository secrets.
persist-credentials: false
- name: Validate required secrets and variables
id: config
uses: ./.github/actions/cpflow-validate-config
env:
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
with:
required: |
secret:CPLN_TOKEN_STAGING
variable:CPLN_ORG_STAGING
variable:REVIEW_APP_PREFIX
pull_request_friendly: "true"
- name: Setup environment
if: steps.config.outputs.ready == 'true'
uses: ./.github/actions/cpflow-setup-environment
with:
token: ${{ secrets.CPLN_TOKEN_STAGING }}
org: ${{ vars.CPLN_ORG_STAGING }}
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
cpflow_version: ${{ vars.CPFLOW_VERSION }}
- name: Set workflow links
if: steps.config.outputs.ready == 'true'
uses: actions/github-script@v7
with:
script: |
const workflowUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
core.exportVariable("WORKFLOW_URL", workflowUrl);
core.exportVariable(
"CONSOLE_URL",
`https://console.cpln.io/console/org/${process.env.CPLN_ORG}/-info`
);
- name: Create initial PR comment
if: steps.config.outputs.ready == 'true'
id: create-comment
uses: actions/github-script@v7
with:
script: |
const comment = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: Number(process.env.PR_NUMBER),
body: "🗑️ Deleting Control Plane review app..."
});
core.setOutput("comment-id", comment.data.id);
- name: Delete review app
if: steps.config.outputs.ready == 'true'
uses: ./.github/actions/cpflow-delete-control-plane-app
env:
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
with:
app_name: ${{ env.APP_NAME }}
cpln_org: ${{ vars.CPLN_ORG_STAGING }}
review_app_prefix: ${{ vars.REVIEW_APP_PREFIX }}
- name: Mark GitHub deployment inactive
if: steps.config.outputs.ready == 'true'
uses: actions/github-script@v7
with:
script: |
const environment = `review/${process.env.APP_NAME}`;
const deployments = await github.paginate(github.rest.repos.listDeployments, {
owner: context.repo.owner,
repo: context.repo.repo,
environment,
per_page: 100
});
if (deployments.length === 0) {
core.info(`No GitHub deployments found for ${environment}.`);
return;
}
for (const deployment of deployments) {
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment.id,
state: "inactive",
environment,
log_url: process.env.WORKFLOW_URL,
description: "Review app deleted"
});
}
- name: Finalize delete status
if: always() && steps.config.outputs.ready == 'true'
uses: actions/github-script@v7
with:
script: |
const commentId = Number("${{ steps.create-comment.outputs.comment-id }}");
const success = "${{ job.status }}" === "success";
const body = success
? [
`✅ Review app for PR #${process.env.PR_NUMBER} is deleted`,
"",
`[Open organization console](${process.env.CONSOLE_URL})`,
`[View workflow logs](${process.env.WORKFLOW_URL})`
].join("\n")
: [
`❌ Failed to delete review app for PR #${process.env.PR_NUMBER}`,
"",
`[Open organization console](${process.env.CONSOLE_URL})`,
`[View workflow logs](${process.env.WORKFLOW_URL})`
].join("\n");
if (!Number.isFinite(commentId) || commentId <= 0) {
core.warning("Skipping delete status comment update because no comment id was created.");
return;
}
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: commentId,
body
});