Skip to content

Commit

Permalink
ci: comment and close issues when stable, just comment on nightly (#4072
Browse files Browse the repository at this point in the history
)
  • Loading branch information
mcansh authored Sep 29, 2022
1 parent aeb1fbb commit e260b2b
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 52 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/merged-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 📦 Merged PR

on:
pull_request:
types: [closed]
branches:
- dev

permissions:
pull-requests: write

jobs:
if_merged:
name: Add label to merged PR
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "awaiting release"
number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
14 changes: 7 additions & 7 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,12 @@ jobs:
SHORT_SHA=${SHA::7}
# get latest nightly tag
LATEST_NIGHTLY_TAG=$(git tag -l v0.0.0-nightly-\* --sort=-taggerdate | head -n 1)
LATEST_NIGHTLY_TAG=$(git tag -l v0.0.0-nightly-\* --sort=-committerdate | head -n 1)
# check if last commit to dev starts would be the nightly tag we're about to create (minus the date)
# if it is, we'll skip the nightly creation
# if not, we'll create a new nightly tag
if [[ ${LATEST_NIGHTLY_TAG} == v0.0.0-nightly-${SHORT_SHA}-* ]]; then
echo "🛑 Latest nightly tag is the same as the latest commit sha, skipping nightly release"
else
CHANGES=$(git diff $LATEST_NIGHTLY_TAG..dev -- ./packages/ -- ':!packages/**/package.json')
# check if there are changes to ./packages
if [[ -n $(echo $CHANGES | xargs) ]]; then
git config --local user.email "[email protected]"
git config --local user.name "Remix Run Bot"
Expand All @@ -75,6 +73,8 @@ jobs:
fi
yarn run version ${NEXT_VERSION} --skip-prompt
else
echo "🛑 no changes since last nightly, skipping..."
fi
- name: 🏗 Build
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/postrelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ on:

jobs:
comment:
needs: [release]
name: 📝 Comment on related issues and pull requests
if: github.repository == 'remix-run/remix'
uses: remix-run/remix/.github/workflows/release-comments.yml@main
with:
ref: ${{ github.ref }}
# this should match the above tag to watch not including the trailing "@"
# this should match the above tag to watch excluding the trailing "@"
packageVersionToFollow: "remix"

deployments:
needs: [release]
name: 🚀 Deployment Tests
if: github.repository == 'remix-run/remix'
uses: remix-run/remix/.github/workflows/deployments.yml@main
Expand All @@ -37,7 +35,6 @@ jobs:
TEST_VERCEL_USER_ID: ${{ secrets.TEST_VERCEL_USER_ID }}

stacks:
needs: [release]
name: 🥞 Remix Stacks Test
if: github.repository == 'remix-run/remix'
uses: remix-run/remix/.github/workflows/stacks.yml@main
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/release-comments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ jobs:
steps:
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
with:
ref: ${{ inputs.ref }}

- name: ⎔ Setup node
uses: actions/setup-node@v3
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
release:
name: 🦋 Changesets Release
# we need to check for `nightly` refs and skip them as we dont want to
# double publish a version as it would fail. unfortantely even using curl
# double publish a version as it would fail. unfortunately even using curl
# and a `repository_dispatch` trigger, actions still aren't ran if a version
# is published using the default secrets.GITHUB_TOKEN.
if: |
Expand All @@ -28,6 +28,7 @@ jobs:
uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.NIGHTLY_PAT }}

- name: ⎔ Setup node
uses: actions/setup-node@v3
Expand Down
62 changes: 49 additions & 13 deletions scripts/release/comment.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { VERSION, OWNER, REPO, PR_FILES_STARTS_WITH } from "./constants";
import {
VERSION,
OWNER,
REPO,
PR_FILES_STARTS_WITH,
IS_NIGHTLY_RELEASE,
AWAITING_RELEASE_LABEL,
} from "./constants";
import {
closeIssue,
commentOnIssue,
commentOnPullRequest,
getIssuesClosedByPullRequests,
prsMergedSinceLastTag,
removeLabel,
} from "./github";
import { getGitHubUrl } from "./utils";

Expand Down Expand Up @@ -41,27 +50,54 @@ async function commentOnIssuesAndPrsAboutRelease() {
})
);

let prLabels = pr.labels.map((label) => label.name);
let prIsAwaitingRelease = prLabels.includes(AWAITING_RELEASE_LABEL);

if (!IS_NIGHTLY_RELEASE && prIsAwaitingRelease) {
promises.push(
removeLabel({ owner: OWNER, repo: REPO, issue: pr.number })
);
}

let issuesClosed = await getIssuesClosedByPullRequests(
pr.html_url,
pr.body
);

for (let issueNumber of issuesClosed) {
if (issuesCommentedOn.has(issueNumber)) {
for (let issue of issuesClosed) {
if (issuesCommentedOn.has(issue.number)) {
// we already commented on this issue
// so we don't need to do it again
continue;
}
issuesCommentedOn.add(issueNumber);
console.log(`commenting on issue ${getGitHubUrl("issue", issueNumber)}`);
promises.push(
commentOnIssue({
issue: issueNumber,
owner: OWNER,
repo: REPO,
version: VERSION,
})
);

issuesCommentedOn.add(issue.number);
let issueUrl = getGitHubUrl("issue", issue.number);

if (IS_NIGHTLY_RELEASE || !prIsAwaitingRelease) {
console.log(`commenting on ${issueUrl}`);
promises.push(
commentOnIssue({
owner: OWNER,
repo: REPO,
issue: issue.number,
version: VERSION,
})
);
} else {
console.log(`commenting on and closing ${issueUrl}`);
promises.push(
commentOnIssue({
owner: OWNER,
repo: REPO,
issue: issue.number,
version: VERSION,
})
);
promises.push(
closeIssue({ owner: OWNER, repo: REPO, issue: issue.number })
);
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion scripts/release/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cleanupRef, cleanupTagName } from "./utils";
import { cleanupRef, cleanupTagName, isNightly } from "./utils";

if (!process.env.DEFAULT_BRANCH) {
throw new Error("DEFAULT_BRANCH is required");
Expand Down Expand Up @@ -30,3 +30,5 @@ export const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY;
export const DEFAULT_BRANCH = process.env.DEFAULT_BRANCH;
export const NIGHTLY_BRANCH = process.env.NIGHTLY_BRANCH;
export const PR_FILES_STARTS_WITH = ["packages/"];
export const IS_NIGHTLY_RELEASE = isNightly(VERSION);
export const AWAITING_RELEASE_LABEL = "awaiting release";
100 changes: 82 additions & 18 deletions scripts/release/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
NIGHTLY_BRANCH,
DEFAULT_BRANCH,
PACKAGE_VERSION_TO_FOLLOW,
AWAITING_RELEASE_LABEL,
} from "./constants";
import { gql, graphqlWithAuth, octokit } from "./octokit";
import type { MinimalTag } from "./utils";
import { cleanupTagName } from "./utils";
import { checkIfStringStartsWith, sortByDate } from "./utils";
import { checkIfStringStartsWith } from "./utils";

type PullRequest =
RestEndpointMethodTypes["pulls"]["list"]["response"]["data"][number];
Expand Down Expand Up @@ -129,14 +130,17 @@ function getPreviousTagFromCurrentTag(
let tagName = cleanupTagName(tag.name);
let isPrerelease = semver.prerelease(tagName) !== null;

return {
tag: tagName,
date: new Date(tag.target.tagger.date),
isPrerelease,
};
let date = tag.target.committer?.date
? new Date(tag.target.committer.date)
: tag.target.tagger?.date
? new Date(tag.target.tagger.date)
: undefined;

if (!date) return undefined;

return { tag: tagName, date, isPrerelease };
})
.filter((v: any): v is MinimalTag => typeof v !== "undefined")
.sort(sortByDate);
.filter((v: any): v is MinimalTag => typeof v !== "undefined");

let currentTagIndex = validTags.findIndex((tag) => tag.tag === currentTag);
let currentTagInfo: MinimalTag | undefined = validTags.at(currentTagIndex);
Expand Down Expand Up @@ -217,7 +221,10 @@ interface GitHubGraphqlTag {
name: string;
target: {
oid: string;
tagger: {
committer?: {
date: string;
};
tagger?: {
date: string;
};
};
Expand All @@ -244,6 +251,11 @@ async function getTags(owner: string, repo: string) {
name
target {
oid
... on Commit {
committer {
date
}
}
... on Tag {
tagger {
date
Expand All @@ -269,9 +281,13 @@ async function getTags(owner: string, repo: string) {
export async function getIssuesClosedByPullRequests(
prHtmlUrl: string,
prBody: string | null
): Promise<Array<number>> {
): Promise<Array<{ number: number }>> {
let linkedIssues = await getIssuesLinkedToPullRequest(prHtmlUrl);
if (!prBody) return linkedIssues.map((issue) => issue.number);
if (!prBody) {
return linkedIssues.map((issue) => {
return { number: issue.number };
});
}

/**
* This regex matches for one of github's issue references for auto linking an issue to a PR
Expand All @@ -281,16 +297,24 @@ export async function getIssuesClosedByPullRequests(
let regex =
/(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)(:)?\s#([0-9]+)/gi;
let matches = prBody.match(regex);
if (!matches) return linkedIssues.map((issue) => issue.number);
if (!matches) {
return linkedIssues.map((issue) => {
return { number: issue.number };
});
}

let issues = matches.map((match) => {
let issuesMatch = matches.map((match) => {
let [, issueNumber] = match.split(" #");
return { number: parseInt(issueNumber, 10) };
});

return [...linkedIssues, ...issues.filter((issue) => issue !== null)].map(
(issue) => issue.number
let issues = await Promise.all(
issuesMatch.map(async (issue) => {
return { number: issue.number };
})
);

return [...linkedIssues, ...issues.filter((issue) => issue !== null)];
}

interface GitHubClosingIssueReference {
Expand All @@ -305,11 +329,13 @@ interface GitHubClosingIssueReference {
};
}

type IssuesLinkedToPullRequest = Array<{ number: number }>;

async function getIssuesLinkedToPullRequest(
prHtmlUrl: string,
nodes: Array<{ number: number }> = [],
nodes: IssuesLinkedToPullRequest = [],
after?: string
): Promise<Array<{ number: number }>> {
): Promise<IssuesLinkedToPullRequest> {
let res: GitHubClosingIssueReference = await graphqlWithAuth(
gql`
query GET_ISSUES_CLOSED_BY_PR($prHtmlUrl: URI!, $after: String) {
Expand All @@ -332,7 +358,11 @@ async function getIssuesLinkedToPullRequest(
);

let newNodes = res?.resource?.closingIssuesReferences?.nodes ?? [];
nodes.push(...newNodes);
nodes.push(
...newNodes.map((node) => {
return { number: node.number };
})
);

if (res?.resource?.closingIssuesReferences?.pageInfo?.hasNextPage) {
return getIssuesLinkedToPullRequest(
Expand Down Expand Up @@ -382,3 +412,37 @@ export async function commentOnIssue({
body: `🤖 Hello there,\n\nWe just published version \`${version}\` which involves this issue. If you'd like to take it for a test run please try it out and let us know what you think!\n\nThanks!`,
});
}

export async function closeIssue({
owner,
repo,
issue,
}: {
owner: string;
repo: string;
issue: number;
}) {
await octokit.issues.update({
owner,
repo,
issue_number: issue,
state: "closed",
});
}

export async function removeLabel({
owner,
repo,
issue,
}: {
owner: string;
repo: string;
issue: number;
}) {
await octokit.issues.removeLabel({
owner,
repo,
issue_number: issue,
name: AWAITING_RELEASE_LABEL,
});
}
6 changes: 4 additions & 2 deletions scripts/release/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e260b2b

Please sign in to comment.