Skip to content

Commit 2eec050

Browse files
authored
feat: switch to tagless workflow success check (#2)
1 parent 592a04e commit 2eec050

10 files changed

Lines changed: 406 additions & 48 deletions

File tree

.github/assets/nx-logo.png

28.6 KB
Loading

.github/assets/nx.png

107 KB
Loading

.gitignore

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
7+
# Unplanned lock files
8+
yarn.lock
9+
pnpm-lock.yml
10+
11+
# Runtime data
12+
pids
13+
*.pid
14+
*.seed
15+
*.pid.lock
16+
17+
# Dependency directories
18+
node_modules/
19+
jspm_packages/
20+
21+
# Compiled files
22+
dist
23+
tmp
24+
25+
# Optional npm cache directory
26+
.npm
27+
28+
# Optional eslint cache
29+
.eslintcache
30+
31+
# Yarn Integrity file
32+
.yarn-integrity
33+
34+
# yarn v2
35+
.yarn/cache
36+
.yarn/unplugged
37+
.yarn/build-state.yml
38+
.yarn/install-state.gz
39+
.pnp.*
40+
41+
# dotenv environment variables file
42+
.env
43+
.env.test
44+
45+
# parcel-bundler cache (https://parceljs.org/)
46+
.cache
47+
.parcel-cache
48+
49+
# IDE
50+
.idea
51+
.vscode
52+
53+
.DS_Store

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2021-present Narwhal Technologies Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
# nx-set-shas
1+
<p style="text-align: center;"><img src=".github/assets/nx.png"
2+
width="100%" alt="Nx - Smart, Extensible Build Framework"></p>
3+
4+
<h1 align="center">Set SHAs Action</h2>
5+
6+
> ✨ A Github Action which sets the base and head SHAs required for `nx affected` commands in CI
7+
8+
- [Example Usage](#example-usage)
9+
- [Configuration Options](#configuration-options)
10+
- [Background](#background)
11+
- [License](#license)
12+
13+
> This documentation is for version 2.x.x. You can find documentation for version 1.x.x [here](https://github.com/nrwl/nx-set-shas/blob/c8f5a54f6ee7f2127f3df063f36a0242faee4cb7/README.md).
214
315
## Example Usage
416

@@ -25,7 +37,7 @@ jobs:
2537
# OPTION 1) Environment variables
2638
# ===========================================================================
2739
- name: Derive appropriate SHAs for base and head for `nx affected` commands
28-
uses: nrwl/nx-set-shas@v1
40+
uses: nrwl/nx-set-shas@v2
2941

3042
- run: |
3143
echo "BASE: ${{ env.NX_BASE }}"
@@ -36,7 +48,9 @@ jobs:
3648
# ===========================================================================
3749
- name: Derive appropriate SHAs for base and head for `nx affected` commands
3850
id: setSHAs
39-
uses: nrwl/nx-set-shas@v1
51+
uses: nrwl/nx-set-shas@v2
52+
with:
53+
set-environment-variables-for-job: 'false'
4054

4155
- run: |
4256
echo "BASE: ${{ steps.setSHAs.outputs.base }}"
@@ -58,22 +72,54 @@ jobs:
5872
# Default: main
5973
main-branch-name: ''
6074

61-
# The glob(7) pattern to be provided to `git describe --match` in order to match against
62-
# the latest relevant tag on the specified "main" branch.
63-
#
64-
# The default pattern aligns with the default behavior of the complementary `nrwl/nx-tag-successful-ci-run` action.
65-
#
66-
# Default: nx_successful_ci_run*
67-
tag-match-pattern: ''
68-
6975
# Applies the derived SHAs for base and head as NX_BASE and NX_HEAD environment variables within the current Job.
7076
#
7177
# Default: true
7278
set-environment-variables-for-job: ''
7379

74-
# By default, if no matching tags are found on the main branch to determine the SHA, we will log a warning and use HEAD~1. Enable this option to error and exit instead.
80+
# By default, if no successful workflow run is found on the main branch to determine the SHA, we will log a warning and use HEAD~1. Enable this option to error and exit instead.
7581
#
7682
# Default: false
77-
error-on-no-matching-tags: ''
83+
error-on-no-successful-workflow: ''
84+
85+
# The ID of the github action workflow to check for successful run or the name of the file name containing the workflow.
86+
# E.g. 'ci.yml'. If not provided, current workflow id will be used
87+
#
88+
workflow-id: ''
7889
```
79-
<!-- end configuration-options -->
90+
<!-- end configuration-options -->
91+
92+
## Background
93+
94+
When we run `affected` command on [Nx](https://nx.dev/), we can specify 2 git history positions - base and head, and it calculates [which projects in your repository changed
95+
between those 2 commits](https://nx.dev/latest/angular/tutorial/11-test-affected-projects#step-11-test-affected-projects
96+
). We can then run a set of tasks (like building or linting) only on those **affected** projects.
97+
98+
This makes it easy to set-up a CI system that scales well with the continous growth of your repository, as you add more and more projects.
99+
100+
101+
### Problem
102+
103+
Figuring out what these two git commits are might not be as simple as it seems.
104+
105+
On a CI system that runs on submitted PRs, we determine what commits to include in the **affected** calculation by comparing our `HEAD-commit-of-PR-branch` to the commit in main branch (`master` or `main` usually) from which the PR branch originated. This will ensure the entirety of our PR is always being tested.
106+
107+
But what if we want to set up a continuous deployment system
108+
that, as changes get pushed to `master`, it builds and deploys
109+
only the affected projects?
110+
111+
What are the `FROM` and `TO` commits in that case?
112+
113+
Conceptually, what we want is to use the absolute latest commit on the `master` branch as the HEAD, and the previous _successful_ commit on `master` as the BASE. Note, we want the previous _successful_ one because it is still possible for commits on the `master` branch to fail for a variety of reasons.
114+
115+
The commits therefore can't just be `HEAD` and `HEAD~1`. If a few deployments fail one after another, that means that we're accumulating a list of affected projects that are not getting deployed. Anytime we retry the deployment, we want to include **every commit since the last time we deployed successfully**. That way we ensure we don't accidentally skip deploying a project that has changed.
116+
117+
This action enables you to find:
118+
* Commit SHA from which PR originated (in the case of `pull_request`)
119+
* Commit SHA of the last successful CI run
120+
121+
## License
122+
123+
[MIT](http://opensource.org/licenses/MIT)
124+
125+
Copyright (c) 2021-present Narwhal Technologies Inc.

action.yml

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
name: 'Nx set SHAs'
2-
description: 'Derives appropriate SHAs for base and head for use in `nx affected` commands, optionally setting them as environment variables for the current job'
1+
name: "Nx set SHAs"
2+
description: "Derives appropriate SHAs for base and head for use in `nx affected` commands, optionally setting them as environment variables for the current job"
33

44
inputs:
55
main-branch-name:
6-
description: 'The name of the main branch in your repo, used as the target of PRs. E.g. main, master etc'
7-
default: 'main'
8-
tag-match-pattern:
9-
description: 'The glob(7) pattern to be provided to `git describe --match` in order to match against the latest relevant tag on the specified main branch'
10-
default: 'nx_successful_ci_run*'
6+
description: "The name of the main branch in your repo, used as the target of PRs. E.g. main, master etc"
7+
default: "main"
118
set-environment-variables-for-job:
12-
description: 'Applies the derived SHAs for base and head as NX_BASE and NX_HEAD environment variables within the current Job'
13-
default: 'true'
14-
error-on-no-matching-tags:
15-
description: 'By default, if no matching tags are found on the main branch to determine the SHA, we will log a warning and use HEAD~1. Enable this option to error and exit instead.'
9+
description: "Applies the derived SHAs for base and head as NX_BASE and NX_HEAD environment variables within the current Job"
10+
default: "true"
11+
error-on-no-successful-workflow:
12+
description: "By default, if no successful workflow is found on the main branch to determine the SHA, we will log a warning and use HEAD~1. Enable this option to error and exit instead."
13+
workflow-id:
14+
description: "The ID of the workflow to track or name of the file name. E.g. ci.yml. Defaults to current workflow"
1615

1716
outputs:
1817
base:
@@ -23,12 +22,12 @@ outputs:
2322
value: ${{ steps.setSHAs.outputs.head }}
2423

2524
runs:
26-
using: 'composite'
25+
using: "composite"
2726
steps:
2827
- name: Set base and head SHAs used for nx affected
2928
id: setSHAs
3029
shell: bash
31-
run: ${{ github.action_path }}/run.sh '${{ github.event_name }}' '${{ inputs.main-branch-name }}' '${{ inputs.tag-match-pattern }}' '${{ inputs.error-on-no-matching-tags }}'
30+
run: ${{ github.action_path }}/run.sh ${{ github.token }} ${{ github.event_name }} ${{ inputs.main-branch-name }} ${{ inputs.error-on-no-successful-workflow }} ${{ inputs.workflow-id }}
3231

3332
- name: Log base and head SHAs used for nx affected
3433
shell: bash

find-successful-workflow.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const { Octokit } = require("@octokit/action");
2+
const core = require("@actions/core");
3+
const { execSync } = require('child_process');
4+
5+
const token = process.argv[2];
6+
const branch = process.argv[3];
7+
const workflowId = process.argv[4];
8+
const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/");
9+
const run_id = process.env.GITHUB_RUN_ID;
10+
process.env.GITHUB_TOKEN = token;
11+
12+
(async () => {
13+
try {
14+
const octokit = new Octokit();
15+
let workflow_id = workflowId;
16+
if (!workflow_id) {
17+
// retrieve workflow-id
18+
workflow_id = await octokit.request(`GET /repos/${owner}/${repo}/actions/runs/${run_id}`, {
19+
owner,
20+
repo,
21+
branch,
22+
run_id
23+
}).then(({ data: { workflow_id } }) => workflow_id);
24+
}
25+
// fetch all workflow runs on a given repo/branch/workflow with push and success
26+
const shas = await octokit.request(`GET /repos/${owner}/${repo}/actions/workflows/${workflow_id}/runs`, {
27+
owner,
28+
repo,
29+
branch,
30+
workflow_id,
31+
event: 'push',
32+
status: 'success'
33+
}).then(({ data: { workflow_runs } }) => workflow_runs.map(run => run.head_sha));
34+
35+
const sha = await findExistingCommit(shas);
36+
console.log(sha);
37+
} catch (e) {
38+
core.setFailed(e.message);
39+
process.exit(1);
40+
}
41+
})();
42+
43+
/**
44+
* Get first existing commit
45+
* @param {string[]} commit_shas
46+
* @returns {string?}
47+
*/
48+
async function findExistingCommit(shas) {
49+
for (const commitSha of shas) {
50+
if (await commitExists(commitSha)) {
51+
return commitSha;
52+
}
53+
}
54+
return undefined;
55+
}
56+
57+
/**
58+
* Check if given commit is valid
59+
* @param {string} commitSha
60+
* @returns {boolean}
61+
*/
62+
async function commitExists(commitSha) {
63+
try {
64+
execSync(`git cat-file -e ${commitSha} 2> /dev/null`);
65+
return true;
66+
} catch {
67+
return false;
68+
}
69+
}

0 commit comments

Comments
 (0)