Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [CYCLOUD-1447] Auto-detect PR numbers #1009

Merged
merged 44 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ade6071
WIP - need to ask for ideal way to check existing variables
ax-vasquez Aug 28, 2023
afef3a6
check for existing variables
ax-vasquez Aug 28, 2023
2e6067c
consolidate comments
ax-vasquez Aug 28, 2023
d83963a
remove yarn lock file
ax-vasquez Aug 30, 2023
e277f50
Merge branch 'master' into armando/fix/CYCLOUD-1447
ax-vasquez Aug 30, 2023
6a7498b
run commands from PR feedback
ax-vasquez Aug 30, 2023
1ccad80
Merge remote-tracking branch 'origin/armando/fix/CYCLOUD-1447' into a…
ax-vasquez Aug 30, 2023
12dcc6e
Merge branch 'master' into armando/fix/CYCLOUD-1447
ax-vasquez Aug 30, 2023
adebbb7
logging for testing purposes only
ax-vasquez Aug 30, 2023
19380ba
Merge remote-tracking branch 'origin/armando/fix/CYCLOUD-1447' into a…
ax-vasquez Aug 30, 2023
9051d08
more logging
ax-vasquez Aug 30, 2023
2e38a45
more logging
ax-vasquez Aug 30, 2023
89fe794
simplify URL logic
ax-vasquez Aug 30, 2023
9321be8
more logging
ax-vasquez Aug 30, 2023
3a17a1f
remove logging - fix url string
ax-vasquez Aug 30, 2023
d984062
log response for fallback logic
ax-vasquez Aug 30, 2023
d2df9c5
docs: rewrite readme working directory description (#1005)
MikeMcC399 Aug 25, 2023
2aceb30
chore(deps): update dependency @types/node to v20.5.7 (#1008)
renovate[bot] Aug 28, 2023
34055c5
docs: rework requirements for contributors (#1010)
MikeMcC399 Aug 29, 2023
a4ecbdd
feat(deps): update cypress to 13.0.0 (#1012)
MikeMcC399 Aug 29, 2023
44670f1
logging for testing purposes only
ax-vasquez Aug 30, 2023
a28c1f3
test: run component test example from current branch (#1013)
MikeMcC399 Aug 30, 2023
b32c154
more logging
ax-vasquez Aug 30, 2023
f9b9475
more logging
ax-vasquez Aug 30, 2023
34aa09a
simplify URL logic
ax-vasquez Aug 30, 2023
c63a89b
more logging
ax-vasquez Aug 30, 2023
25c2040
remove logging - fix url string
ax-vasquez Aug 30, 2023
6210cf7
log response for fallback logic
ax-vasquez Aug 30, 2023
73dc6c5
cleanup
ax-vasquez Aug 30, 2023
f0541c7
doc update
ax-vasquez Aug 30, 2023
25b5378
Merge remote-tracking branch 'origin/armando/fix/CYCLOUD-1447' into a…
ax-vasquez Aug 30, 2023
75b5f49
Update README.md
ax-vasquez Aug 31, 2023
7f93823
Update README.md
ax-vasquez Aug 31, 2023
3995680
exit detectPrNumber if variables already defined
ax-vasquez Aug 31, 2023
ee4e102
Merge remote-tracking branch 'origin/armando/fix/CYCLOUD-1447' into a…
ax-vasquez Aug 31, 2023
976d235
Update README.md
ax-vasquez Aug 31, 2023
8456632
docs update - formatting fix for readability
ax-vasquez Aug 31, 2023
0ccc977
Merge remote-tracking branch 'origin/armando/fix/CYCLOUD-1447' into a…
ax-vasquez Aug 31, 2023
620df0d
Update README.md
ax-vasquez Aug 31, 2023
74dbf08
Update README.md
ax-vasquez Sep 1, 2023
d108631
try catch pr data request
ax-vasquez Sep 1, 2023
7896153
Readme update
ax-vasquez Sep 1, 2023
0a94c6d
Merge branch 'master' into armando/fix/CYCLOUD-1447
ax-vasquez Sep 1, 2023
f8f90f7
Update README.md
ax-vasquez Sep 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,52 @@ jobs:
publish-summary: false
```

### Automatic PR number & URL detection

When recording runs to Cypress Cloud, the PR number and URL can be automatically detected if you pass `GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}`
via the workflow `env`. When set, this value enables the Action to perform additional logic that grabs the related PR number and URL (if they
exist) and sets them in the environment variables `CYPRESS_PULL_REQUEST_ID` and `CYPRESS_PULL_REQUEST_URL`, respectively.
* See Cypress' documentation on [CI Build Information](https://docs.cypress.io/guides/continuous-integration/introduction#CI-Build-Information)
ax-vasquez marked this conversation as resolved.
Show resolved Hide resolved

Example workflow using the variables:
```yml
name: Example echo PR number and URL
on: push
jobs:
cypress-run:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cypress run
uses: cypress-io/github-action@v5
tbiethman marked this conversation as resolved.
Show resolved Hide resolved
ax-vasquez marked this conversation as resolved.
Show resolved Hide resolved
ax-vasquez marked this conversation as resolved.
Show resolved Hide resolved
with:
record: true
- run: echo "PR number is $CYPRESS_PULL_REQUEST_ID"
- run: echo "PR URL is $CYPRESS_PULL_REQUEST_URL"
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

#### Branch with PR

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than focusing these sections around branches/PRs, it might make more sense to specify the behavior based on the various workflow event types.

For example, if the action executes on a push event, we'll still need to make the request, even if there is a PR open, as the GITHUB_HEAD_REF env will not be set for that event.

We could do something like:

<example yaml here>

The behavior of the action varies based on the triggering event type.

#### Triggering event: `pull_request`/`pull_request_target`

...

#### Triggering event: `push`

...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! I'll update this 👍 That's much clearer.


If the workflow was triggered by a commit for a branch with an open PR, then the PR number and URL should simply point to the branch PR.

#### Branch without PR

If there is no PR for a branch, there are two paths:
1. *With related PRs*
2. *Without related PRs*

##### With related PRs
When a commit on a branch without a PR is made, the Cypress GitHub Action checks to see if the commit that triggered the workflow has a
related PR. If the commit exists in any other PRs, it's considered a related PR. When there are related PRs, we grab the first related PR
and use that PR's number and URL for `CYPRESS_PULL_REQUEST_ID` and `CYPRESS_PULL_REQUEST_URL`, respectively.

##### Without related PRs
When there are no related PRs detected, `CYPRESS_PULL_REQUEST_ID` and `CYPRESS_PULL_REQUEST_URL` will be undefined

## Node.js

### Support
Expand Down
64 changes: 64 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74832,6 +74832,68 @@ const waitOnMaybe = () => {

const I = (x) => x

const detectPrNumber = async () => {
const {
GITHUB_SHA,
GITHUB_TOKEN,
GITHUB_RUN_ID,
GITHUB_REPOSITORY,
GITHUB_HEAD_REF,
GITHUB_REF,
GITHUB_SERVER_URL,
CYPRESS_PULL_REQUEST_ID,
CYPRESS_PULL_REQUEST_URL
} = process.env

if (CYPRESS_PULL_REQUEST_ID && CYPRESS_PULL_REQUEST_URL) {
// Both pull request envs are already defined - no need to do anything else
return
}

const [owner, repo] = GITHUB_REPOSITORY.split('/')
let prNumber

if (GITHUB_TOKEN) {
debug(
`Detecting PR number by asking GitHub about run ${GITHUB_RUN_ID}`
)

const client = new Octokit({
auth: GITHUB_TOKEN
})

if (GITHUB_HEAD_REF) {
// GITHUB_HEAD_REF is only defined when the event that triggered it was 'pull_request' or 'pull_request_target' (meaning a PR number should be readily-available)
// should have format refs/pull/<pr_number>/merge when triggered by pull_request workflow
prNumber = parseInt(GITHUB_REF.split('/')[2])
} else {
const resp = await client.request(
'GET /repos/:owner/:repo/commits/:commit_sha/pulls',
{
owner,
repo,
commit_sha: GITHUB_SHA
}
)

if (resp && resp.data && resp.data[0] && resp.data[0].number) {
prNumber = resp.data[0].number
}
}

if (prNumber) {
if (!CYPRESS_PULL_REQUEST_ID) {
core.exportVariable('CYPRESS_PULL_REQUEST_ID', prNumber)
}

const url = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/${prNumber}`
if (!CYPRESS_PULL_REQUEST_URL) {
core.exportVariable('CYPRESS_PULL_REQUEST_URL', url)
}
}
}
}

/**
* Asks Cypress API if there were already builds for this commit.
* In that case increments the count to get unique parallel id.
Expand Down Expand Up @@ -75065,6 +75127,8 @@ const runTests = async () => {
core.exportVariable('CYPRESS_CACHE_FOLDER', CYPRESS_CACHE_FOLDER)
core.exportVariable('TERM', 'xterm')

await detectPrNumber()

if (customCommand) {
console.log('Using custom test command: %s', customCommand)
return execCommand(customCommand, true, 'run tests')
Expand Down
64 changes: 64 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,68 @@ const waitOnMaybe = () => {

const I = (x) => x

const detectPrNumber = async () => {
const {
GITHUB_SHA,
GITHUB_TOKEN,
GITHUB_RUN_ID,
GITHUB_REPOSITORY,
GITHUB_HEAD_REF,
GITHUB_REF,
GITHUB_SERVER_URL,
CYPRESS_PULL_REQUEST_ID,
CYPRESS_PULL_REQUEST_URL
} = process.env

tbiethman marked this conversation as resolved.
Show resolved Hide resolved
if (CYPRESS_PULL_REQUEST_ID && CYPRESS_PULL_REQUEST_URL) {
// Both pull request envs are already defined - no need to do anything else
return
}

const [owner, repo] = GITHUB_REPOSITORY.split('/')
let prNumber

if (GITHUB_TOKEN) {
debug(
`Detecting PR number by asking GitHub about run ${GITHUB_RUN_ID}`
)

const client = new Octokit({
auth: GITHUB_TOKEN
})

if (GITHUB_HEAD_REF) {
// GITHUB_HEAD_REF is only defined when the event that triggered it was 'pull_request' or 'pull_request_target' (meaning a PR number should be readily-available)
// should have format refs/pull/<pr_number>/merge when triggered by pull_request workflow
prNumber = parseInt(GITHUB_REF.split('/')[2])
} else {
const resp = await client.request(
Copy link

@tbiethman tbiethman Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might also be worth adding a try/catch around this request in the event of a partial outage or something. I don't think we'd want to halt a recording by throwing in that case.

'GET /repos/:owner/:repo/commits/:commit_sha/pulls',
{
owner,
repo,
commit_sha: GITHUB_SHA
}
)

if (resp && resp.data && resp.data[0] && resp.data[0].number) {
prNumber = resp.data[0].number
}
}

if (prNumber) {
if (!CYPRESS_PULL_REQUEST_ID) {
core.exportVariable('CYPRESS_PULL_REQUEST_ID', prNumber)
}

const url = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/${prNumber}`
if (!CYPRESS_PULL_REQUEST_URL) {
core.exportVariable('CYPRESS_PULL_REQUEST_URL', url)
}
}
}
}

/**
* Asks Cypress API if there were already builds for this commit.
* In that case increments the count to get unique parallel id.
Expand Down Expand Up @@ -669,6 +731,8 @@ const runTests = async () => {
core.exportVariable('CYPRESS_CACHE_FOLDER', CYPRESS_CACHE_FOLDER)
core.exportVariable('TERM', 'xterm')

await detectPrNumber()

if (customCommand) {
console.log('Using custom test command: %s', customCommand)
return execCommand(customCommand, true, 'run tests')
Expand Down