Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
smac89 committed Nov 18, 2023
1 parent a01a139 commit de8f384
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 265 deletions.
16 changes: 8 additions & 8 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@

<h2 style="color: red; font-weight: bold">DON'T</h2>

### **Never create a pull request for master.**
- #### Never create a pull request for master.

<h2 style="color: green; font-weight: bold">DO</h2>

- ### Checkout a release branch corresponding to the version you want to contribute to
- ### Make your changes and create a pull request for that branch
- ### Your request will be merged to master once it is reviewed
- **Checkout a release branch corresponding to the version you want to contribute to**
- **Make your changes and create a pull request for that branch**
- **Your request will be merged to master once it is reviewed**

---
## Development
-
```bash
npm install
npm run test
yarn install
yarn test
```
- Make your changes
- Add tests if you want
- Push to your branch
- Ping maintainer (@smac89) when PR is ready

Expand All @@ -26,8 +27,7 @@
- Make other changes if necessary
- If this warrants a new release, then do the following
- Bump version in `package.json` to next release version
- Create a temporary branch which will contain `lib/index.js`
- Run `npm run build` in that branch and commit the changes
- Run `scripts/releaser.sh`
- Create a new release based on this temporary branch and add release notes
- Delete temporary branch
- If the release branch is the latest
Expand Down
1 change: 1 addition & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const config: JestConfigWithTsJest = {
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
prefix: '<rootDir>/',
}),
verbose: true,
globalSetup: '<rootDir>/tests/test-setup.ts',
};

Expand Down
26 changes: 14 additions & 12 deletions scripts/releaser.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

version="${1//[[:space:]]/}"

if [ -n "$version" ]; then
git stash
yarn build
git add lib
git commit -m "release files for version $version"
git tag "v$version"
git rm -rf lib
git reset --soft HEAD~1
git stash pop
exit 0
if [ -z "$version" ]; then
echo "Must specify a release version"
exit 1
fi

echo "Must specify a release version"
exit 1
git stash
git fetch origin --tags
jq --arg version "$version" '.version = $version' package.json > package.json.tmp
mv package.json.tmp package.json
yarn build
git add lib
git commit -m "release files for version $version"
git tag "v$version"
git rm -rf lib
git reset --soft HEAD~1
git stash pop
198 changes: 15 additions & 183 deletions src/functions/index.ts
Original file line number Diff line number Diff line change
@@ -1,205 +1,32 @@
import * as core from '@actions/core';
import { context } from '@actions/github';
import SemVer from 'semver/classes/semver';
import coerce from 'semver/functions/coerce';
import semverGt from 'semver/functions/gt';
import major from 'semver/functions/major';
import semverParse from 'semver/functions/parse';
import valid from 'semver/functions/valid';
import { preferences, queryAllRefs } from '@actionstagger/util';
import type { GitHub, GraphQlQueryRepository, TaggedRef, LatestRef } from './types';
import { preferences } from '@actionstagger/util';
import type { GitHub, TaggedRef, LatestRef } from './types';
import Private from '@actionstagger/functions/private';

namespace Functions {
/**
* Checks if the event that triggered this action was a release
* See: https://docs.github.com/en/webhooks/webhook-events-and-payloads#release
*/
function isRelease(): boolean {
return context.eventName === 'release';
}

/**
* Check if the event that triggered this actions was as a result
* of a prerelease or not
*
* For some reason, it is not enough to check if the action is
* prereleased, because even prereleases have the action of "published"
* See: https://github.com/orgs/community/discussions/26281
* See also: https://docs.github.com/en/webhooks/webhook-events-and-payloads#release
*/
function isPreRelease(): boolean {
return context.payload.release?.prerelease === true;
}

/**
* Is a release available to the public?
* A pre-release is usually considered "not ready" for public use
*/
function isPublicRelease(): boolean {
return isRelease() && !isPreRelease();
}

/**
* Checks if the event that triggered this action was a push
* See: https://docs.github.com/en/webhooks/webhook-events-and-payloads#push
*/
function isPush(): boolean {
return context.eventName === 'push';
}

/**
* Check if the push event created a new ref
*/
function isNewRefPush(): boolean {
return isPush() && context.payload.created === true;
}

function isBranchPush(): boolean {
return isNewRefPush() && context.payload.ref.startsWith(`refs/heads/`);
}

function isTagPush(): boolean {
return isNewRefPush() && context.payload.ref.startsWith(`refs/tags/`);
}

/**
* Creates the given ref for this release
* refName must begin with tags/ or heads/
*
* @param github The github client
* @param refName The name of the ref to use. ex tags/latest, heads/v1, etc
*/
async function createRef(github: GitHub, refName: string) {
const { data: matchingRefs } = await github.rest.git.listMatchingRefs({
...context.repo,
ref: refName,
});

const matchingRef = matchingRefs.find((refObj: { ref: string }) => {
return refObj.ref.endsWith(refName);
});

let upstreamRef: unknown;

if (matchingRef !== undefined) {
core.info(`Updating ref: ${refName} to: ${process.env.GITHUB_SHA}`);
({ data: upstreamRef } = await github.rest.git.updateRef({
...context.repo,
force: true,
ref: refName,
sha: process.env.GITHUB_SHA,
}));
} else {
core.info(`Creating ref: refs/${refName} for: ${process.env.GITHUB_SHA}`);
({ data: upstreamRef } = await github.rest.git.createRef({
...context.repo,
ref: `refs/${refName}`,
sha: process.env.GITHUB_SHA,
}));
}

if (core.isDebug()) {
core.debug(
`${JSON.stringify(upstreamRef)} now points to: "${
process.env.GITHUB_SHA
}"`
);
}
}

/**
* List all the refs in the repository based on user's preferred ref
*
* @param github The github client
*/
async function* listAllRefs(github: GitHub) {
for (let nextPage: string; true; ) {
const { repository }: { repository: GraphQlQueryRepository } =
await github.graphql(queryAllRefs, {
repoName: context.repo.repo,
repoOwner: context.repo.owner,
majorRef: `refs/${Functions.getPreferredRef()}/`,
pagination: nextPage,
});

for (const { ref } of repository.refs.refsList) {
const semverRef = semverParse(ref.name);
if (semverRef !== null) {
if (core.isDebug()) {
core.debug(`checking ${ref.name}`);
}
yield [semverRef, ref.object.shaId] as const;
} else if (core.isDebug()) {
core.debug(`ignoring ${ref.name}`);
}
}

if (repository.refs.pageInfo.hasNextPage) {
nextPage = repository.refs.pageInfo.endCursor;
} else {
break;
}
}
}

/**
* Get the ref version for the current push
*
* @returns the ref for this release (if any)
*/
function getPushRefVersion(): SemVer {
let refName: string | SemVer = (context.payload.ref as string)?.replace(
new RegExp(`^refs/${Functions.getPreferredRef()}/`),
''
);
return semverParse(refName);
}

/**
* Get the actual tag version for this release. It also takes into account
* whether or not this is a prerelease
*
* @returns the tag for this release (if any)
*/
function getReleaseTag(): SemVer {
let tagName: string | SemVer = context.payload.release?.tag_name;
if (isPreRelease()) {
tagName = coerce(tagName);
}
return semverParse(tagName);
}

/**
* Check if this release is publically available and has been published
*/
export function isPublishedRelease(): boolean {
return isPublicRelease() && context.payload.action === 'published';
return Private.isPublicRelease() && context.payload.action === 'published';
}

/**
* Check if this release is publically available and has been edited
*/
export function isEditedRelease(): boolean {
return isPublicRelease() && context.payload.action === 'edited';
return Private.isPublicRelease() && context.payload.action === 'edited';
}

/**
* Check if this event was a new tag push
*/
export function isRefPush(): boolean {
return isBranchPush() || isTagPush();
}

export async function isRefLatestMajor(github: GitHub): Promise<boolean> {
if (Functions.isRefPush()) {
const major = majorVersion();
const { data: majorRef } = await github.rest.git.getRef({
...context.repo,
ref: `${Functions.getPreferredRef()}/v${major}`,
});
return majorRef?.object.sha === process.env.GITHUB_SHA;
}
return false;
return Private.isBranchPush() || Private.isTagPush();
}

/**
Expand All @@ -208,7 +35,9 @@ namespace Functions {
* @returns The tag being published
*/
export function getPublishRefVersion(): SemVer {
return Functions.isRefPush() ? getPushRefVersion() : getReleaseTag();
return Functions.isRefPush()
? Private.getPushRefVersion(Functions.getPreferredRef())
: Private.getReleaseTag();
}

/**
Expand Down Expand Up @@ -257,7 +86,10 @@ namespace Functions {
let [repoLatest, repoSha] = [majorLatest, majorSha];

const major = majorLatest.major;
for await (const [semverRef, shaId] of listAllRefs(github)) {
for await (const [semverRef, shaId] of Private.listAllRefs(
github,
Functions.getPreferredRef()
)) {
if (semverRef.major === major && semverGt(semverRef, majorLatest)) {
[majorLatest, majorSha] = [semverRef, shaId];
}
Expand Down Expand Up @@ -285,12 +117,12 @@ namespace Functions {
const mayor = Functions.majorVersion();

const ref = `${Functions.getPreferredRef()}/v${mayor}`;
await createRef(github, ref);
await Private.createRef(github, ref);

const publishLatest: boolean = overridePublishLatest ?? preferences.publishLatest;
if (publishLatest) {
// TODO v3: `${getPreferredRef()}/latest`
await createRef(github, 'tags/latest');
await Private.createRef(github, 'tags/latest');
}

return {
Expand Down
Loading

0 comments on commit de8f384

Please sign in to comment.