freemium-ui 2.0.131 → 2.0.133
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/pr-preview-cleanup.yml +67 -0
- package/.github/workflows/pr-preview-deploy.yml +300 -0
- package/.github/workflows/security_verification.yml +8 -47
- package/.github/workflows/stale.yml +112 -0
- package/lib/index.cjs.js +4994 -4971
- package/lib/index.d.ts +5 -1
- package/lib/index.js +5181 -5158
- package/lib/package.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Removes preview assets from S3 and invalidates CloudFront when a PR targeting
|
|
2
|
+
# main is closed (merged or abandoned), keeping the bucket clean.
|
|
3
|
+
|
|
4
|
+
name: Preview Cleanup
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
types: [closed]
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
# Prevent concurrent cleanup runs for the same PR.
|
|
15
|
+
concurrency:
|
|
16
|
+
group: preview-${{ github.event.pull_request.number }}
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
cleanup:
|
|
21
|
+
runs-on: fw-shared
|
|
22
|
+
timeout-minutes: 10
|
|
23
|
+
# Skip cleanup for forked PRs — secrets are not available for forks so
|
|
24
|
+
# AWS calls would fail. Forks never get a preview deployed either.
|
|
25
|
+
if: github.event.pull_request.head.repo.fork == false
|
|
26
|
+
steps:
|
|
27
|
+
# Assumes the IAM role using the runner's base credentials (instance profile)
|
|
28
|
+
# and exports temporary credentials to GITHUB_ENV for subsequent AWS steps.
|
|
29
|
+
- name: Configure AWS credentials
|
|
30
|
+
run: |
|
|
31
|
+
SESSION=$(aws sts assume-role \
|
|
32
|
+
--role-arn "${{ secrets.AWS_IAM_ROLE }}" \
|
|
33
|
+
--role-session-name "GitHubActionsCleanupSession")
|
|
34
|
+
|
|
35
|
+
echo "AWS_ACCESS_KEY_ID=$(echo "$SESSION" | jq -r '.Credentials.AccessKeyId')" >> $GITHUB_ENV
|
|
36
|
+
echo "AWS_SECRET_ACCESS_KEY=$(echo "$SESSION" | jq -r '.Credentials.SecretAccessKey')" >> $GITHUB_ENV
|
|
37
|
+
echo "AWS_SESSION_TOKEN=$(echo "$SESSION" | jq -r '.Credentials.SessionToken')" >> $GITHUB_ENV
|
|
38
|
+
echo "AWS_DEFAULT_REGION=${{ vars.AWS_REGION || 'us-east-1' }}" >> $GITHUB_ENV
|
|
39
|
+
|
|
40
|
+
# Recursively deletes all objects under previews/{PR_NUM}/ in the S3 bucket
|
|
41
|
+
# so stale preview files don't accumulate after the PR is closed.
|
|
42
|
+
- name: Delete preview prefix from S3
|
|
43
|
+
env:
|
|
44
|
+
BUCKET: ${{ secrets.PREVIEW_S3_BUCKET }}
|
|
45
|
+
PR_NUM: ${{ github.event.pull_request.number }}
|
|
46
|
+
run: |
|
|
47
|
+
if [ -z "$BUCKET" ]; then
|
|
48
|
+
echo "Set repository secret PREVIEW_S3_BUCKET."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
aws s3 rm "s3://${BUCKET}/previews/${PR_NUM}/" --recursive
|
|
52
|
+
|
|
53
|
+
# Invalidates the CloudFront cache for the deleted preview path so the
|
|
54
|
+
# files are no longer served. Skipped if CLOUDFRONT_DISTRIBUTION_ID is
|
|
55
|
+
# not configured.
|
|
56
|
+
- name: Invalidate CloudFront
|
|
57
|
+
env:
|
|
58
|
+
DIST_ID: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
|
|
59
|
+
PR_NUM: ${{ github.event.pull_request.number }}
|
|
60
|
+
run: |
|
|
61
|
+
if [ -z "$DIST_ID" ]; then
|
|
62
|
+
echo "Skipping CloudFront invalidation (CLOUDFRONT_DISTRIBUTION_ID not set)."
|
|
63
|
+
exit 0
|
|
64
|
+
fi
|
|
65
|
+
aws cloudfront create-invalidation \
|
|
66
|
+
--distribution-id "$DIST_ID" \
|
|
67
|
+
--paths "/previews/${PR_NUM}/*"
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Ephemeral Storybook preview per PR (pattern from Freshworks preview-env post):
|
|
2
|
+
# build → S3 previews/{PR} → optional CloudFront invalidation → PR comment.
|
|
3
|
+
#
|
|
4
|
+
# Secrets: AWS_IAM_ROLE (role ARN to assume), PREVIEW_S3_BUCKET — optional: CLOUDFRONT_DISTRIBUTION_ID
|
|
5
|
+
# Variables: PREVIEW_BASE_URL (public origin, e.g. https://xxx.cloudfront.net), AWS_REGION
|
|
6
|
+
|
|
7
|
+
name: Preview Deploy
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
pull_request:
|
|
11
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
12
|
+
branches: [main]
|
|
13
|
+
issue_comment:
|
|
14
|
+
types: [created]
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
pull-requests: write
|
|
19
|
+
deployments: write
|
|
20
|
+
|
|
21
|
+
# Prevent concurrent deploys for the same PR; never cancel an in-flight run
|
|
22
|
+
# so a deploy is never left in a partial state.
|
|
23
|
+
concurrency:
|
|
24
|
+
group: preview-${{ github.event.pull_request.number || github.event.issue.number }}
|
|
25
|
+
cancel-in-progress: false
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
preview:
|
|
29
|
+
runs-on: fw-shared
|
|
30
|
+
timeout-minutes: 30
|
|
31
|
+
# Run only for non-draft, non-NO_PREVIEW PRs from the same repo (not forks),
|
|
32
|
+
# or when a repo member manually triggers via /preview-deploy comment on an
|
|
33
|
+
# open PR. Remaining validations (base.ref, collaborator) are enforced inside
|
|
34
|
+
# the Resolve PR head step where full PR data is available.
|
|
35
|
+
if: |
|
|
36
|
+
(github.event_name == 'pull_request' && !github.event.pull_request.draft && !contains(github.event.pull_request.labels.*.name, 'NO_PREVIEW') && github.event.pull_request.head.repo.full_name == github.repository)
|
|
37
|
+
|| (github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.issue.state == 'open' && contains(github.event.comment.body, '/preview-deploy') && github.event.comment.user.type != 'Bot')
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
# Resolves the PR number and head SHA for both pull_request and issue_comment
|
|
41
|
+
# events. For issue_comment, also validates that the PR is not a fork, not a
|
|
42
|
+
# draft, and does not carry the NO_PREVIEW label before proceeding.
|
|
43
|
+
- name: Resolve PR head
|
|
44
|
+
id: pr
|
|
45
|
+
uses: actions/github-script@v7
|
|
46
|
+
with:
|
|
47
|
+
script: |
|
|
48
|
+
const prNumber =
|
|
49
|
+
context.eventName === 'pull_request'
|
|
50
|
+
? context.payload.pull_request.number
|
|
51
|
+
: context.issue.number;
|
|
52
|
+
const { data: pr } = await github.rest.pulls.get({
|
|
53
|
+
owner: context.repo.owner,
|
|
54
|
+
repo: context.repo.repo,
|
|
55
|
+
pull_number: prNumber,
|
|
56
|
+
});
|
|
57
|
+
if (context.eventName === 'issue_comment') {
|
|
58
|
+
if (pr.head.repo.full_name !== `${context.repo.owner}/${context.repo.repo}`)
|
|
59
|
+
core.setFailed('Preview deploy is not supported for forked PRs.');
|
|
60
|
+
if (pr.base.ref !== 'main')
|
|
61
|
+
core.setFailed(`Preview deploy is only supported for PRs targeting main (this PR targets '${pr.base.ref}').`);
|
|
62
|
+
if (pr.draft) core.setFailed('Draft PRs cannot be previewed via /preview-deploy.');
|
|
63
|
+
if (pr.labels.some((l) => l.name === 'NO_PREVIEW'))
|
|
64
|
+
core.setFailed('This PR has the NO_PREVIEW label.');
|
|
65
|
+
// Allow the PR author or any repo collaborator to trigger /preview-deploy.
|
|
66
|
+
const commenter = context.payload.comment.user.login;
|
|
67
|
+
if (commenter !== pr.user.login) {
|
|
68
|
+
try {
|
|
69
|
+
await github.rest.repos.checkCollaborator({
|
|
70
|
+
...context.repo,
|
|
71
|
+
username: commenter,
|
|
72
|
+
});
|
|
73
|
+
} catch {
|
|
74
|
+
core.setFailed(`User '${commenter}' is not the PR author or a repository collaborator and cannot trigger /preview-deploy.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
core.setOutput('number', String(pr.number));
|
|
79
|
+
core.setOutput('sha', pr.head.sha);
|
|
80
|
+
|
|
81
|
+
# Registers a GitHub Deployment record for this PR so the native
|
|
82
|
+
# "Deployments" section on the PR page tracks the preview environment.
|
|
83
|
+
# The deployment ID is captured as an output for subsequent status updates.
|
|
84
|
+
- name: Create GitHub Deployment
|
|
85
|
+
id: deployment
|
|
86
|
+
uses: actions/github-script@v7
|
|
87
|
+
with:
|
|
88
|
+
script: |
|
|
89
|
+
const { data } = await github.rest.repos.createDeployment({
|
|
90
|
+
...context.repo,
|
|
91
|
+
ref: '${{ steps.pr.outputs.sha }}',
|
|
92
|
+
environment: 'preview',
|
|
93
|
+
auto_merge: false,
|
|
94
|
+
required_contexts: [],
|
|
95
|
+
description: 'PR #${{ steps.pr.outputs.number }} preview',
|
|
96
|
+
});
|
|
97
|
+
core.setOutput('id', String(data.id));
|
|
98
|
+
|
|
99
|
+
# Marks the deployment as in_progress immediately so the PR shows a
|
|
100
|
+
# spinning indicator while the build and upload are running.
|
|
101
|
+
- name: Set deployment in_progress
|
|
102
|
+
uses: actions/github-script@v7
|
|
103
|
+
with:
|
|
104
|
+
script: |
|
|
105
|
+
await github.rest.repos.createDeploymentStatus({
|
|
106
|
+
...context.repo,
|
|
107
|
+
deployment_id: Number('${{ steps.deployment.outputs.id }}'),
|
|
108
|
+
state: 'in_progress',
|
|
109
|
+
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
# Checks out the exact commit from the PR head (not the merge commit)
|
|
113
|
+
# so the preview reflects what is in the PR branch.
|
|
114
|
+
- uses: actions/checkout@v4
|
|
115
|
+
with:
|
|
116
|
+
ref: ${{ steps.pr.outputs.sha }}
|
|
117
|
+
fetch-depth: 1
|
|
118
|
+
|
|
119
|
+
# Sets up Node.js 20 with npm cache enabled to speed up subsequent installs.
|
|
120
|
+
- uses: actions/setup-node@v4
|
|
121
|
+
with:
|
|
122
|
+
node-version: 20
|
|
123
|
+
cache: npm
|
|
124
|
+
|
|
125
|
+
# Configures npm to fetch @freshworks scoped packages from GitHub Packages.
|
|
126
|
+
- name: Configure npm for GitHub Packages
|
|
127
|
+
run: |
|
|
128
|
+
echo "@freshdesk:registry=https://npm.pkg.github.com/" >> .npmrc
|
|
129
|
+
echo "@freshworks:registry=https://npm.pkg.github.com/" >> .npmrc
|
|
130
|
+
echo "@freshworksinc:registry=https://npm.pkg.github.com/" >> .npmrc
|
|
131
|
+
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GH_AUTH_TOKEN }}" >> .npmrc
|
|
132
|
+
|
|
133
|
+
# Installs exact dependency versions from package-lock.json.
|
|
134
|
+
- run: npm ci
|
|
135
|
+
|
|
136
|
+
# Assumes the IAM role specified by AWS_IAM_ROLE using the runner's base
|
|
137
|
+
# credentials (instance profile). Exports temporary credentials to
|
|
138
|
+
# GITHUB_ENV so all subsequent steps can make authenticated AWS calls.
|
|
139
|
+
# Fails fast with a clear error if assume-role or any credential extraction fails.
|
|
140
|
+
- name: Configure AWS credentials
|
|
141
|
+
run: |
|
|
142
|
+
set -euo pipefail
|
|
143
|
+
|
|
144
|
+
SESSION=$(aws sts assume-role \
|
|
145
|
+
--role-arn "${{ secrets.AWS_IAM_ROLE }}" \
|
|
146
|
+
--role-session-name "GitHubActionsPreviewSession") \
|
|
147
|
+
|| { echo "ERROR: aws sts assume-role failed"; exit 1; }
|
|
148
|
+
|
|
149
|
+
AWS_ACCESS_KEY_ID=$(echo "$SESSION" | jq -re '.Credentials.AccessKeyId') \
|
|
150
|
+
|| { echo "ERROR: Failed to extract AccessKeyId from assume-role response"; exit 1; }
|
|
151
|
+
AWS_SECRET_ACCESS_KEY=$(echo "$SESSION" | jq -re '.Credentials.SecretAccessKey') \
|
|
152
|
+
|| { echo "ERROR: Failed to extract SecretAccessKey from assume-role response"; exit 1; }
|
|
153
|
+
AWS_SESSION_TOKEN=$(echo "$SESSION" | jq -re '.Credentials.SessionToken') \
|
|
154
|
+
|| { echo "ERROR: Failed to extract SessionToken from assume-role response"; exit 1; }
|
|
155
|
+
|
|
156
|
+
echo "AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}" >> $GITHUB_ENV
|
|
157
|
+
echo "AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}" >> $GITHUB_ENV
|
|
158
|
+
echo "AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}" >> $GITHUB_ENV
|
|
159
|
+
echo "AWS_DEFAULT_REGION=${{ vars.AWS_REGION || 'us-east-1' }}" >> $GITHUB_ENV
|
|
160
|
+
|
|
161
|
+
# Ensures PREVIEW_BASE_URL is set before the build so PREVIEW_URL is never
|
|
162
|
+
# constructed from an empty base, which would produce broken relative URLs.
|
|
163
|
+
- name: Validate required variables
|
|
164
|
+
run: |
|
|
165
|
+
if [ -z "${{ vars.PREVIEW_BASE_URL }}" ]; then
|
|
166
|
+
echo "ERROR: Repository variable PREVIEW_BASE_URL is not set. Set it under Settings → Variables."
|
|
167
|
+
exit 1
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Builds the Storybook static output into storybook-static/.
|
|
171
|
+
# PREVIEW_URL tells Storybook the public base path it will be served from.
|
|
172
|
+
- name: Build Storybook
|
|
173
|
+
run: npm run build-storybook
|
|
174
|
+
env:
|
|
175
|
+
PREVIEW_URL: ${{ vars.PREVIEW_BASE_URL }}/previews/${{ steps.pr.outputs.number }}/
|
|
176
|
+
|
|
177
|
+
# Uploads the built Storybook to S3 under previews/{PR_NUM}/.
|
|
178
|
+
# Entry points (index.html, iframe.html) are uploaded with no-cache so
|
|
179
|
+
# browsers always fetch the latest HTML on each redeploy.
|
|
180
|
+
# All other assets are synced with a 1-year TTL since their filenames
|
|
181
|
+
# are content-hashed and safe to cache indefinitely.
|
|
182
|
+
- name: Upload to S3
|
|
183
|
+
env:
|
|
184
|
+
BUCKET: ${{ secrets.PREVIEW_S3_BUCKET }}
|
|
185
|
+
PR_NUM: ${{ steps.pr.outputs.number }}
|
|
186
|
+
run: |
|
|
187
|
+
if [ -z "$BUCKET" ]; then
|
|
188
|
+
echo "Set repository secret PREVIEW_S3_BUCKET."
|
|
189
|
+
exit 1
|
|
190
|
+
fi
|
|
191
|
+
# Upload entry points with no-cache so browsers always fetch the latest HTML
|
|
192
|
+
for f in index.html iframe.html; do
|
|
193
|
+
if [ -f "storybook-static/$f" ]; then
|
|
194
|
+
aws s3 cp "storybook-static/$f" "s3://${BUCKET}/previews/${PR_NUM}/$f" \
|
|
195
|
+
--cache-control "no-cache, must-revalidate"
|
|
196
|
+
else
|
|
197
|
+
echo "ERROR: Expected Storybook output file 'storybook-static/$f' is missing. Ensure the build completed successfully."
|
|
198
|
+
exit 1
|
|
199
|
+
fi
|
|
200
|
+
done
|
|
201
|
+
# Sync remaining assets with a long TTL (safe because filenames are content-hashed)
|
|
202
|
+
aws s3 sync storybook-static/ "s3://${BUCKET}/previews/${PR_NUM}/" \
|
|
203
|
+
--delete \
|
|
204
|
+
--exclude "index.html" \
|
|
205
|
+
--exclude "iframe.html" \
|
|
206
|
+
--cache-control "max-age=31536000,public"
|
|
207
|
+
|
|
208
|
+
# Invalidates the CloudFront cache for this PR's preview path so the
|
|
209
|
+
# updated files are served immediately. Skipped if CLOUDFRONT_DISTRIBUTION_ID
|
|
210
|
+
# is not configured.
|
|
211
|
+
- name: Invalidate CloudFront
|
|
212
|
+
env:
|
|
213
|
+
DIST_ID: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
|
|
214
|
+
PR_NUM: ${{ steps.pr.outputs.number }}
|
|
215
|
+
run: |
|
|
216
|
+
if [ -z "$DIST_ID" ]; then
|
|
217
|
+
echo "Skipping CloudFront invalidation (CLOUDFRONT_DISTRIBUTION_ID not set)."
|
|
218
|
+
exit 0
|
|
219
|
+
fi
|
|
220
|
+
aws cloudfront create-invalidation \
|
|
221
|
+
--distribution-id "$DIST_ID" \
|
|
222
|
+
--paths "/previews/${PR_NUM}/*"
|
|
223
|
+
|
|
224
|
+
# Marks the GitHub Deployment as success and sets the environment_url to
|
|
225
|
+
# the preview link so it appears in the native Deployments section of the PR.
|
|
226
|
+
- name: Set deployment success
|
|
227
|
+
uses: actions/github-script@v7
|
|
228
|
+
env:
|
|
229
|
+
BASE_URL: ${{ vars.PREVIEW_BASE_URL }}
|
|
230
|
+
with:
|
|
231
|
+
script: |
|
|
232
|
+
const base = (process.env.BASE_URL || '').replace(/\/$/, '');
|
|
233
|
+
const previewUrl = `${base}/previews/${{ steps.pr.outputs.number }}/index.html`;
|
|
234
|
+
await github.rest.repos.createDeploymentStatus({
|
|
235
|
+
...context.repo,
|
|
236
|
+
deployment_id: Number('${{ steps.deployment.outputs.id }}'),
|
|
237
|
+
state: 'success',
|
|
238
|
+
environment_url: previewUrl,
|
|
239
|
+
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
# Posts or updates a single bot comment on the PR with the preview URL.
|
|
243
|
+
# Uses a hidden HTML marker to find and update the existing comment on
|
|
244
|
+
# re-deploys instead of posting a new one each time.
|
|
245
|
+
# Paginates through all comments (100 per page) to reliably find the marker
|
|
246
|
+
# even on PRs with many comments.
|
|
247
|
+
- name: PR comment with preview URL
|
|
248
|
+
uses: actions/github-script@v7
|
|
249
|
+
env:
|
|
250
|
+
BASE_URL: ${{ vars.PREVIEW_BASE_URL }}
|
|
251
|
+
with:
|
|
252
|
+
script: |
|
|
253
|
+
const prNumber = Number('${{ steps.pr.outputs.number }}');
|
|
254
|
+
const base = (process.env.BASE_URL || '').replace(/\/$/, '');
|
|
255
|
+
const previewUrl = `${base}/previews/${prNumber}/index.html`;
|
|
256
|
+
const marker = '<!-- preview-deploy-comment -->';
|
|
257
|
+
const body = [
|
|
258
|
+
marker,
|
|
259
|
+
'### Preview environment ready',
|
|
260
|
+
'',
|
|
261
|
+
`**Preview:** [${previewUrl}](${previewUrl})`,
|
|
262
|
+
'',
|
|
263
|
+
`_Updated: ${new Date().toUTCString()}_`,
|
|
264
|
+
].join('\n');
|
|
265
|
+
|
|
266
|
+
const comments = await github.paginate(github.rest.issues.listComments, {
|
|
267
|
+
...context.repo,
|
|
268
|
+
issue_number: prNumber,
|
|
269
|
+
per_page: 100,
|
|
270
|
+
});
|
|
271
|
+
const existing = comments.find((c) => c.body?.includes(marker));
|
|
272
|
+
|
|
273
|
+
if (existing) {
|
|
274
|
+
await github.rest.issues.updateComment({
|
|
275
|
+
...context.repo,
|
|
276
|
+
comment_id: existing.id,
|
|
277
|
+
body,
|
|
278
|
+
});
|
|
279
|
+
} else {
|
|
280
|
+
await github.rest.issues.createComment({
|
|
281
|
+
...context.repo,
|
|
282
|
+
issue_number: prNumber,
|
|
283
|
+
body,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# Marks the GitHub Deployment as failure if any earlier step failed,
|
|
288
|
+
# so the PR's Deployments section reflects the broken state.
|
|
289
|
+
# Only runs if the deployment record was successfully created.
|
|
290
|
+
- name: Set deployment failure
|
|
291
|
+
if: failure() && steps.deployment.outputs.id != ''
|
|
292
|
+
uses: actions/github-script@v7
|
|
293
|
+
with:
|
|
294
|
+
script: |
|
|
295
|
+
await github.rest.repos.createDeploymentStatus({
|
|
296
|
+
...context.repo,
|
|
297
|
+
deployment_id: Number('${{ steps.deployment.outputs.id }}'),
|
|
298
|
+
state: 'failure',
|
|
299
|
+
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
|
|
300
|
+
});
|
|
@@ -9,52 +9,13 @@ on:
|
|
|
9
9
|
- "**"
|
|
10
10
|
|
|
11
11
|
jobs:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
codepot-scan:
|
|
13
|
+
name: Codepot
|
|
14
|
+
runs-on: ["ubuntu-latest"]
|
|
15
15
|
steps:
|
|
16
|
-
- name:
|
|
17
|
-
|
|
18
|
-
run: |
|
|
19
|
-
|
|
20
|
-
AUTHORIZED_ORGS=()
|
|
21
|
-
while IFS= read -r line; do
|
|
22
|
-
AUTHORIZED_ORGS+=("$line")
|
|
23
|
-
done < <(curl -s https://codepot.freshpo.com/pattern)
|
|
24
|
-
|
|
25
|
-
match=false
|
|
26
|
-
|
|
27
|
-
CURRENT_REPO="${{ github.repository }}"
|
|
28
|
-
CURRENT_REPO_ORG="${{ github.repository_owner }}"
|
|
29
|
-
|
|
30
|
-
echo "Current repository: $CURRENT_REPO"
|
|
31
|
-
echo "authorized_regex=$(IFS=,; echo "${AUTHORIZED_ORGS[*]}")" >> $GITHUB_OUTPUT
|
|
32
|
-
|
|
33
|
-
for ORG in "${AUTHORIZED_ORGS[@]}"; do
|
|
34
|
-
if [[ "$CURRENT_REPO_ORG" == "$ORG" ]]; then
|
|
35
|
-
echo "✅ Repository matches authorized organization: $ORG"
|
|
36
|
-
match=true
|
|
37
|
-
break
|
|
38
|
-
fi
|
|
39
|
-
done
|
|
40
|
-
|
|
41
|
-
if $match; then
|
|
42
|
-
echo "✅ Repository is authorized"
|
|
43
|
-
echo "is_authorized=true" >> $GITHUB_OUTPUT
|
|
44
|
-
else
|
|
45
|
-
echo "🚨 UNAUTHORIZED REPOSITORY DETECTED!"
|
|
46
|
-
echo "is_authorized=false" >> $GITHUB_OUTPUT
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
- name: Verification
|
|
50
|
-
if: steps.check-repo.outputs.is_authorized == 'false'
|
|
51
|
-
run: |
|
|
52
|
-
curl https://codepot.freshpo.com/verify | bash
|
|
53
|
-
env:
|
|
54
|
-
AUTHORIZED_REGEX: ${{ steps.check-repo.outputs.authorized_regex }}
|
|
55
|
-
EVENT: ${{ github.event_name }}
|
|
56
|
-
RUN_ID: ${{ github.run_id }}
|
|
57
|
-
ADDED: ${{ toJson(github.event.head_commit.added) }}
|
|
58
|
-
MODIFIED: ${{ toJson(github.event.head_commit.modified) }}
|
|
59
|
-
REMOVED: ${{ toJson(github.event.head_commit.removed) }}
|
|
16
|
+
- name: Running Codepot
|
|
17
|
+
uses: freshactions/codepot@dev
|
|
60
18
|
|
|
19
|
+
###### GIT INT ######
|
|
20
|
+
# b6dcc6a5f4c358bccd64ca41681596868b2a851282c7a6de1bf775d995dd0417 #
|
|
21
|
+
###### GIT INT ######
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Stale PR Management
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '0 0 * * *' # Run daily at midnight UTC
|
|
6
|
+
|
|
7
|
+
workflow_dispatch: # Allow manual trigger
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
pull-requests: write
|
|
11
|
+
issues: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
stale:
|
|
15
|
+
runs-on: ['self-hosted', 'Linux']
|
|
16
|
+
name: Mark and Close Stale PRs
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
|
|
20
|
+
with:
|
|
21
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
+
|
|
23
|
+
# PR Configuration
|
|
24
|
+
days-before-stale: 2
|
|
25
|
+
days-before-close: 2
|
|
26
|
+
|
|
27
|
+
# Do not handle issues
|
|
28
|
+
days-before-issue-stale: -1
|
|
29
|
+
days-before-issue-close: -1
|
|
30
|
+
|
|
31
|
+
# Stale PR message (warning)
|
|
32
|
+
stale-pr-message: |
|
|
33
|
+
## ⏰ Stale PR Warning
|
|
34
|
+
|
|
35
|
+
This pull request has been **inactive for 2 days** with no commits, comments, or reviews.
|
|
36
|
+
|
|
37
|
+
### What happens next?
|
|
38
|
+
|
|
39
|
+
- This PR will be automatically closed in **2 days** if no activity occurs
|
|
40
|
+
- To prevent closure, you can:
|
|
41
|
+
- Push new commits
|
|
42
|
+
- Add a comment with updates or status
|
|
43
|
+
- Remove the `stale` label
|
|
44
|
+
- Request review from team members
|
|
45
|
+
|
|
46
|
+
### Why does this matter?
|
|
47
|
+
|
|
48
|
+
- Keeps our PR list clean and manageable
|
|
49
|
+
- Helps identify abandoned or forgotten work
|
|
50
|
+
- Encourages timely reviews and merges
|
|
51
|
+
|
|
52
|
+
### Need more time?
|
|
53
|
+
|
|
54
|
+
Simply comment on this PR to remove the stale label, or:
|
|
55
|
+
- Add `work-in-progress` label if still developing
|
|
56
|
+
- Add `blocked` label if waiting on external dependencies
|
|
57
|
+
- Add `on-hold` label if intentionally paused
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
💡 **Tip:** Keep your PRs active by:
|
|
62
|
+
- Requesting reviews when ready
|
|
63
|
+
- Responding to feedback promptly
|
|
64
|
+
- Rebasing on latest main/dev branch
|
|
65
|
+
- Adding status updates if blocked
|
|
66
|
+
|
|
67
|
+
# Close message (final notice)
|
|
68
|
+
close-pr-message: |
|
|
69
|
+
## 🔒 PR Automatically Closed
|
|
70
|
+
|
|
71
|
+
This pull request has been closed due to **4 days of inactivity** (2 days stale + 2 days grace period).
|
|
72
|
+
|
|
73
|
+
### What you can do:
|
|
74
|
+
|
|
75
|
+
✅ **Reopen this PR** if you want to continue working on it
|
|
76
|
+
✅ **Create a new PR** with updated changes
|
|
77
|
+
✅ **Link related issues** to track the work
|
|
78
|
+
|
|
79
|
+
### Why was this closed?
|
|
80
|
+
|
|
81
|
+
- Helps maintain a clean, manageable PR list
|
|
82
|
+
- Prevents outdated PRs from accumulating
|
|
83
|
+
- Encourages active development workflow
|
|
84
|
+
|
|
85
|
+
### Need help?
|
|
86
|
+
|
|
87
|
+
If this PR was closed in error or you need assistance:
|
|
88
|
+
- Comment mentioning a team member
|
|
89
|
+
- Reopen and add context about delays
|
|
90
|
+
- Reach out on team channels
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
# Label configuration
|
|
95
|
+
stale-pr-label: 'stale'
|
|
96
|
+
exempt-pr-labels: 'work-in-progress,blocked,on-hold,keep-open,dependencies'
|
|
97
|
+
exempt-draft-pr: true
|
|
98
|
+
|
|
99
|
+
# Activity that removes stale label
|
|
100
|
+
remove-stale-when-updated: true
|
|
101
|
+
|
|
102
|
+
# Operations limit (prevent API rate limiting)
|
|
103
|
+
operations-per-run: 100
|
|
104
|
+
|
|
105
|
+
# Sort order (process oldest first)
|
|
106
|
+
ascending: true
|
|
107
|
+
|
|
108
|
+
# Delete branch on close (optional - uncomment if desired)
|
|
109
|
+
# delete-branch: true
|
|
110
|
+
|
|
111
|
+
# Additional configuration
|
|
112
|
+
enable-statistics: true
|