Skip to content

Commit 1dc8553

Browse files
authored
Merge pull request #7806 from plotly/fail-if-no-pr-number
CI: upload-dev-build: Require manual approval for forks, and exit if PR number is empty
2 parents b41c1dc + ee2f88c commit 1dc8553

2 files changed

Lines changed: 111 additions & 34 deletions

File tree

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
name: Upload dev build from PR
22

3+
# See https://github.com/plotly/plotly.js/blob/master/CONTRIBUTING.md#live-links-to-dev-builds
4+
# for documentation on the usage of this workflow.
5+
36
on:
47
workflow_run:
58
workflows: ["Publish Dist"] # publish-dist.yml
@@ -9,49 +12,103 @@ on:
912
inputs:
1013
pr_number:
1114
description: 'PR Number to deploy'
12-
required: true
13-
run_id:
14-
description: 'The Run ID of the CI workflow that has the artifact'
15-
required: true
15+
required: false
16+
17+
env:
18+
ARTIFACT_UPLOAD_WORKFLOW_NAME: "Publish Dist"
19+
UPLOAD_DIR_NAME: "upload"
1620

1721
jobs:
1822
upload:
1923
runs-on: ubuntu-latest
24+
# Only run on manual dispatch,
25+
# OR if the parent run succeeded and was triggered by a PR from
26+
# a branch in the main repo (not a fork)
2027
if: |
2128
github.event_name == 'workflow_dispatch' ||
2229
(
2330
github.event_name == 'workflow_run' &&
2431
github.event.workflow_run.event == 'pull_request' &&
25-
github.event.workflow_run.conclusion == 'success'
32+
github.event.workflow_run.conclusion == 'success' &&
33+
github.event.workflow_run.head_repository.full_name == github.repository
2634
)
2735
steps:
36+
- name: Get required metadata (PR number, commit SHA, workflow run ID containing artifacts)
37+
id: get-metadata
38+
env:
39+
GH_TOKEN: ${{ github.token }}
40+
GH_EVENT_NAME: ${{ github.event_name }}
41+
GH_REPO: ${{ github.repository }}
42+
SHA: ${{ github.event.workflow_run.sha }}
43+
RUN_ID: ${{ github.event.workflow_run.id }}
44+
PR_NUM: ${{ github.event.workflow_run.pull_requests[0].number || inputs.pr_number }}
45+
run: |
46+
# Get SHA from manually-provided PR number if triggered by workflow_dispatch
47+
if [ "${GH_EVENT_NAME}" == "workflow_dispatch" ]; then
48+
if [ -n "${PR_NUM}" ]; then
49+
SHA=$(gh pr view "${PR_NUM}" --repo "${GH_REPO}" --json headRefOid --template '{{.headRefOid}}')
50+
fi
51+
fi
52+
53+
# At this point, SHA should be defined. If not, fail the workflow
54+
if [ -z "${SHA}" ]; then
55+
echo "Failed to get commit SHA, exiting"
56+
exit 1
57+
fi
58+
59+
# If PR_NUM is empty, get PR number using SHA
60+
if [ -z "${PR_NUM}" ]; then
61+
PR_NUM=$(gh pr list --search "sha:${SHA}" --state open --json number --jq '.[0].number')
62+
fi
63+
64+
# Validate that we have a valid PR number
65+
if [ -z "${PR_NUM}" ] || [[ ! "${PR_NUM}" =~ ^[1-9][0-9]{0,4}$ ]]; then
66+
echo "Failed to get PR number, exiting (PR_NUM=${PR_NUM})"
67+
exit 1
68+
fi
69+
70+
# If RUN_ID is empty, use the gh CLI to get the most recent run ID for SHA
71+
if [ -z "${RUN_ID}" ]; then
72+
RUN_ID=$(gh run list \
73+
--workflow "${ARTIFACT_UPLOAD_WORKFLOW_NAME}" \
74+
--commit "${SHA}" \
75+
--limit 1 \
76+
--json databaseId \
77+
--jq '.[0].databaseId')
78+
fi
79+
80+
# At this point, RUN_ID should be defined. If not, fail the workflow
81+
if [ -z "${RUN_ID}" ]; then
82+
echo "Failed to get workflow run ID, exiting"
83+
exit 1
84+
fi
85+
86+
# Save PR number, commit SHA, short SHA, and run ID to output
87+
echo "PR_NUM=${PR_NUM}" >> $GITHUB_OUTPUT
88+
echo "SHA=${SHA}" >> $GITHUB_OUTPUT
89+
echo "SHORT_SHA=${SHA:0:7}" >> $GITHUB_OUTPUT
90+
echo "RUN_ID=${RUN_ID}" >> $GITHUB_OUTPUT
91+
2892
- name: Download build artifact
2993
id: download-artifact
3094
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
3195
with:
3296
name: dist # uploaded by publish-dist.yml > publish-dist
33-
run-id: ${{ github.event.workflow_run.id || inputs.run_id }}
97+
run-id: ${{ steps.get-metadata.outputs.RUN_ID }}
3498
github-token: ${{ secrets.GITHUB_TOKEN }}
3599
path: temp-dist
36100

37-
- name: Setup metadata and prepare folders
101+
- name: Prepare folders
38102
id: setup-metadata
39103
env:
40104
GH_TOKEN: ${{ github.token }}
41-
PR_NUM: ${{ github.event.workflow_run.pull_requests[0].number || inputs.pr_number }}
105+
PR_NUM: ${{ steps.get-metadata.outputs.PR_NUM }}
106+
SHA: ${{ steps.get-metadata.outputs.SHA }}
107+
SHORT_SHA: ${{ steps.get-metadata.outputs.SHORT_SHA }}
42108
run: |
43-
# Get SHA from triggering workflow, or from manual input
44-
if [ "${{ github.event_name }}" == "workflow_run" ]; then
45-
SHA="${{ github.event.workflow_run.head_sha }}"
46-
else
47-
echo "Fetching latest SHA for PR #$PR_NUM..."
48-
SHA=$(gh pr view "$PR_NUM" --repo ${{ github.repository }} --json headRefOid --template '{{.headRefOid}}')
49-
fi
50-
SHORT_SHA=${SHA::7}
51-
UPLOAD_DIR_NAME="upload"
52-
53-
echo "Using SHA: ${SHA}"
109+
echo "SHA: ${SHA}"
54110
echo "Short SHA: ${SHORT_SHA}"
111+
echo "PR number: ${PR_NUM}"
55112
mkdir -p "${UPLOAD_DIR_NAME}/pr-${PR_NUM}/latest"
56113
mkdir -p "${UPLOAD_DIR_NAME}/pr-${PR_NUM}/${SHORT_SHA}"
57114
# Copy all 3 artifacts (plotly.js, plotly.min.js, plot-schema.json) to /latest/
@@ -65,10 +122,6 @@ jobs:
65122
echo "Created directory ${UPLOAD_DIR_FULL_PATH} with the following contents:"
66123
echo "$(ls -lR ${UPLOAD_DIR_FULL_PATH})"
67124
68-
echo "PR_NUM=${PR_NUM}" >> $GITHUB_OUTPUT
69-
echo "SHA=${SHA}" >> $GITHUB_OUTPUT
70-
echo "SHORT_SHA=${SHORT_SHA}" >> $GITHUB_OUTPUT
71-
72125
- name: Generate GitHub App token
73126
id: generate-token
74127
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 #v3.1.1
@@ -87,32 +140,45 @@ jobs:
87140

88141
- name: Commit and push files
89142
id: commit-and-push
143+
env:
144+
PR_NUM: ${{ steps.get-metadata.outputs.PR_NUM }}
145+
SHORT_SHA: ${{ steps.get-metadata.outputs.SHORT_SHA }}
90146
run: |
91-
# 1. Move 'upload' directory into repo folder and cd into repo root
92-
mkdir -p plotly.js-dev-builds/upload/
93-
cp -r upload/ plotly.js-dev-builds/
147+
# Move 'pr-NNNN/' directory into upload directory inside repo and cd into repo root
148+
TARGET_DIR="${UPLOAD_DIR_NAME}/pr-${PR_NUM}"
149+
mkdir -p "plotly.js-dev-builds/${UPLOAD_DIR_NAME}"
150+
cp -r "${TARGET_DIR}" "plotly.js-dev-builds/${UPLOAD_DIR_NAME}"
94151
cd plotly.js-dev-builds
95152
96-
# 2. Configure git
153+
# Configure git
97154
git config user.name "plotly.js-pr-upload"
98155
git config user.email "<>"
99156
100-
# 3. add, commit, and push
101-
git add upload/
157+
# Add files
158+
git add "${TARGET_DIR}/"
159+
160+
# Ensure that only files in upload/pr-NNNN/ are staged
161+
if git diff --name-only --cached | grep -qv "^${TARGET_DIR}/"; then
162+
echo "Error: Changes detected outside ${TARGET_DIR}/"
163+
exit 1
164+
fi
102165
103166
# Only commit if there are changes
104167
if git diff --staged --quiet; then
105168
echo "No changes to commit"
106169
else
107-
git commit -m "Deploy build for PR #${{ steps.setup-metadata.outputs.PR_NUM }} (commit ${{ steps.setup-metadata.outputs.SHORT_SHA }})"
170+
git commit -m "Deploy build for PR #${PR_NUM} (commit ${SHORT_SHA})"
108171
git push origin main
109172
fi
110173
111174
- name: Generate summary
175+
env:
176+
PR_NUM: ${{ steps.get-metadata.outputs.PR_NUM }}
177+
SHORT_SHA: ${{ steps.get-metadata.outputs.SHORT_SHA }}
112178
run: |
113-
BASE="https://plotly.github.io/plotly.js-dev-builds/upload/pr-${{ steps.setup-metadata.outputs.PR_NUM }}"
179+
BASE_URL="https://plotly.github.io/plotly.js-dev-builds/${UPLOAD_DIR_NAME}/pr-${PR_NUM}"
114180
echo "### PR Build Uploaded" >> $GITHUB_STEP_SUMMARY
115-
echo "Builds for PR #${{ steps.setup-metadata.outputs.PR_NUM }} can be accessed at:" >> $GITHUB_STEP_SUMMARY
116-
echo "- Latest build for this PR: [$BASE/latest/plotly.min.js]($BASE/latest/plotly.min.js)" >> $GITHUB_STEP_SUMMARY
117-
echo "- Build for this commit: [$BASE/${{ steps.setup-metadata.outputs.SHA }}/plotly.min.js]($BASE/${{ steps.setup-metadata.outputs.SHA }}/plotly.min.js)" >> $GITHUB_STEP_SUMMARY
181+
echo "Builds for PR #${PR_NUM} can be accessed at:" >> $GITHUB_STEP_SUMMARY
182+
echo "- Latest build for this PR: [${BASE_URL}/latest/plotly.min.js](${BASE_URL}/latest/plotly.min.js)" >> $GITHUB_STEP_SUMMARY
183+
echo "- Build for this commit: [${BASE_URL}/${SHORT_SHA}/plotly.min.js](${BASE_URL}/${SHORT_SHA}/plotly.min.js)" >> $GITHUB_STEP_SUMMARY
118184
echo "The above links should start working a minute or two after this job completes." >> $GITHUB_STEP_SUMMARY

CONTRIBUTING.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,17 @@ This will produce the following plot, and say you want to simulate a selection p
326326

327327
<img src="https://user-images.githubusercontent.com/31989842/38890553-0bc6190c-4282-11e8-8efc-077bf05ca565.png">
328328

329+
### Live links to dev builds
330+
331+
The [Upload dev build from PR](.github/workflows/upload-dev-build.yml) workflow can be used to upload a dev build for a PR to the plotly.js-dev-builds repo, creating a live link to the plotly.js dev build which can be used in online coding environments to test and demo the PR.
332+
333+
It is triggered in one of two ways:
334+
- Automatically on completion of the Publish Dist workflow, if triggered by a PR from a branch in the main repo (not a fork).
335+
- Manually via the Actions tab in the GitHub UI, by entering a PR number in the workflow inputs
336+
- Only users with write access to the plotly.js repo can trigger workflows manually
337+
338+
If you would like a link to the dev build for your PR but don't have permission to trigger the workflow, tag a maintainer to request a run for your PR.
339+
329340
## Repo organization
330341

331342
- Distributed files are in `dist/`

0 commit comments

Comments
 (0)