Skip to content

Commit

Permalink
feat: history-limit input
Browse files Browse the repository at this point in the history
  • Loading branch information
tranhl committed Dec 18, 2024
1 parent 2813391 commit 1072a10
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 41 deletions.
75 changes: 59 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ your repository.

### Modify the Pull Request Template

By default, this action will append the visualization to the bottom of the PR description.
By default, the action will append the visualization to the bottom of the PR description.
If you are using a [pull request template](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository),
you can specify the location of the visualization in the template by adding a [HTML comment](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#hiding-content-with-comments)
that contains `branch-stack` inside of it:
Expand All @@ -76,7 +76,7 @@ that contains `branch-stack` inside of it:
[ ] Baz
```

This action will look for this comment and insert the visualization underneath the comment
The action will look for this comment and insert the visualization underneath the comment
when it runs. It will also leave behind the comment, so that the next time it runs, it will
be able to use it again to update the visualization:

Expand All @@ -98,17 +98,17 @@ be able to use it again to update the visualization:

> [!WARNING]
> Be careful not to add content between the comment and the
> visualization, as this action will replace that content each time it
> visualization, as the action will replace that content each time it
> updates your PR. Adding content above the tag, or below the list is
> safe though!
### Manual Configuration
## Manual Configuration

If you are using Git Town v11 and below, or are setting up this action for a repository
that doesn't have a `.git-branches.toml`, you will need to tell this action what the
If you are using Git Town v11 and below, or are setting up the action for a repository
that doesn't have a `.git-branches.toml`, you will need to tell the action what the
main branch and perennial branches are for your repository.

#### Main Branch
### Main Branch

The main branch is the default parent branch for new feature branches, and can be
specified using the `main-branch` input:
Expand All @@ -119,10 +119,10 @@ specified using the `main-branch` input:
main-branch: 'main'
```
This action will default to your repository's default branch, which it fetches via
The action will default to your repository's default branch, which it fetches via
the GitHub REST API.
#### Perennial Branches
### Perennial Branches
Perennial branches are long lived branches and are never shipped.
Expand All @@ -139,27 +139,70 @@ be done with the `perennial-branches` and `perennial-regex` inputs respectively:
perennial-regex: '^release-.*$'
```

Both inputs can be used at the same time. This action will merge the perennial
Both inputs can be used at the same time. The action will merge the perennial
branches given into a single, de-duplicated list.

## Customization

### Skip Single Stacks

If you don't want the stack description to appear on pull requests which are not part of a stack, you can add `skip-single-stacks: true` to the job.
If you don't want the stack visualization to appear on pull requests which are **not** part
of a stack, add `skip-single-stacks: true` to the action's inputs.

This skips all pull requests which point to a main or perennial branch and have no children pull requests pointing to it.
A pull request is considered to be **not** a part of a stack if:
- It has no child pull requests.
- It's parent is the main branch or a perennial branch.

```yaml
- uses: git-town/action@v1
with:
perennial-branches: |
dev
staging
prod
skip-single-stacks: true
```

### History Limit

In order to accurately visualize stacked changes, the action needs to fetch _all_ open
and closed pull requests. This can problematic for larger/older repositories that have
a large number of closed pull requests.

The action can be configured to fetch a limited number of closed pull requests. This is
customizable with the `history-limit` input:

```yaml
- uses: git-town/action@v1
with:
history-limit: '500' # Only fetch the latest 500 closed pull requests
```

> [!NOTE]
> This only applies to closed pull requests. Open pull requests will be completely fetched
> regardless of the `history-limit`.

## Reference

```yaml
inputs:
github-token:
required: true
default: ${{ github.token }}
main-branch:
required: false
default: ''
perennial-branches:
required: false
default: ''
perennial-regex:
required: false
default: ''
skip-single-stacks:
required: false
default: false
history-limit:
required: false
default: '0'
```


## License

The scripts and documentation in this project are released under the [MIT License](LICENSE).
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ inputs:
default: false
history-limit:
required: false
default: 0
default: '0'

runs:
using: 'node20'
Expand Down
73 changes: 54 additions & 19 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47076,12 +47076,26 @@ var inputs = {
return core2.getInput("github-token", { required: true, trimWhitespace: true });
},
getSkipSingleStacks() {
const input = core2.getBooleanInput("skip-single-stacks", {
required: false,
trimWhitespace: true
});
core2.startGroup("Inputs: Skip single stacks");
const input = core2.getBooleanInput("skip-single-stacks", { required: false });
core2.info(input.toString());
core2.endGroup();
return input;
},
getHistoryLimit() {
const input = core2.getInput("history-limit", {
required: false,
trimWhitespace: true
});
const historyLimit = Number.parseInt(input, 10);
core2.startGroup("Inputs: History limit");
core2.info(input);
core2.endGroup();
return historyLimit;
},
async getMainBranch(octokit, config2, context3) {
const {
data: { default_branch: defaultBranch }
Expand Down Expand Up @@ -47155,24 +47169,44 @@ var inputs = {
throw error;
}
},
async getPullRequests(octokit, context3) {
const pullRequests = await octokit.paginate(
"GET /repos/{owner}/{repo}/pulls",
{
...context3.repo,
state: "all",
per_page: 100
},
(response) => response.data.map(
(item) => ({
number: item.number,
base: { ref: item.base.ref },
head: { ref: item.head.ref },
body: item.body ?? void 0,
state: item.state
})
async getPullRequests(octokit, context3, historyLimit) {
function toPullRequest(item) {
return {
number: item.number,
base: { ref: item.base.ref },
head: { ref: item.head.ref },
body: item.body ?? void 0,
state: item.state
};
}
let closedPullRequestCount = 0;
const [openPullRequests, closedPullRequests] = await Promise.all([
octokit.paginate(
"GET /repos/{owner}/{repo}/pulls",
{
...context3.repo,
state: "open",
per_page: 100
},
(response) => response.data.map(toPullRequest)
),
octokit.paginate(
"GET /repos/{owner}/{repo}/pulls",
{
...context3.repo,
state: "closed",
per_page: 100
},
(response, done) => {
closedPullRequestCount += response.data.length;
if (historyLimit > 0 && closedPullRequestCount >= historyLimit) {
done();
}
return response.data.map(toPullRequest);
}
)
);
]);
const pullRequests = [...openPullRequests, ...closedPullRequests];
pullRequests.sort((a, b) => b.number - a.number);
core2.startGroup("Inputs: Pull requests");
core2.info(
Expand Down Expand Up @@ -47224,10 +47258,11 @@ async function run() {
return;
}
const octokit = github2.getOctokit(inputs.getToken());
const historyLimit = inputs.getHistoryLimit();
const [mainBranch, remoteBranches, pullRequests] = await Promise.all([
inputs.getMainBranch(octokit, config, github2.context),
inputs.getRemoteBranches(octokit, github2.context),
inputs.getPullRequests(octokit, github2.context)
inputs.getPullRequests(octokit, github2.context, historyLimit)
]);
const perennialBranches = await inputs.getPerennialBranches(config, remoteBranches);
const context3 = {
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ async function run() {

const octokit = github.getOctokit(inputs.getToken())

const historyLimit = inputs.getHistoryLimit()
const [mainBranch, remoteBranches, pullRequests] = await Promise.all([
inputs.getMainBranch(octokit, config, github.context),
inputs.getRemoteBranches(octokit, github.context),
inputs.getPullRequests(octokit, github.context),
inputs.getPullRequests(octokit, github.context, historyLimit),
])
const perennialBranches = await inputs.getPerennialBranches(config, remoteBranches)

Expand Down
24 changes: 20 additions & 4 deletions src/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,29 @@ export const inputs = {
},

getSkipSingleStacks() {
core.startGroup('Inputs: Skip single stacks')
const input = core.getBooleanInput('skip-single-stacks', {
required: false,
trimWhitespace: true,
})

core.startGroup('Inputs: Skip single stacks')
core.info(input.toString())
core.endGroup()

return input
},

getHistoryLimit() {
core.startGroup('Inputs: History limit')
getHistoryLimit(): number {
const input = core.getInput('history-limit', {
required: false,
trimWhitespace: true,
})
const historyLimit = Number.parseInt(input, 10)

core.startGroup('Inputs: History limit')
core.info(input)
core.endGroup()

return historyLimit
},

Expand Down Expand Up @@ -132,7 +136,11 @@ export const inputs = {
}
},

async getPullRequests(octokit: Octokit, context: typeof github.context) {
async getPullRequests(
octokit: Octokit,
context: typeof github.context,
historyLimit: number
) {
function toPullRequest(
item: Endpoints['GET /repos/{owner}/{repo}/pulls']['response']['data'][number]
): PullRequest {
Expand All @@ -145,6 +153,8 @@ export const inputs = {
}
}

let closedPullRequestCount = 0

const [openPullRequests, closedPullRequests] = await Promise.all([
octokit.paginate(
'GET /repos/{owner}/{repo}/pulls',
Expand All @@ -164,6 +174,12 @@ export const inputs = {
per_page: 100,
},
(response, done) => {
closedPullRequestCount += response.data.length

if (historyLimit > 0 && closedPullRequestCount >= historyLimit) {
done()
}

return response.data.map(toPullRequest)
}
),
Expand Down

0 comments on commit 1072a10

Please sign in to comment.