Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ A simple tool to automate version bumps, changelogs, and releases using [Convent
| [`@simple-release/config`](packages/config#readme) | A simple-release config loader. | [![NPM version][config-npm]][config-npm-url] | [![Dependencies status][config-deps]][config-deps-url] |
| [`@simple-release/npm`](packages/npm#readme) | A npm addon for simple-release. | [![NPM version][npm-npm]][npm-npm-url] | [![Dependencies status][npm-deps]][npm-deps-url] |
| [`@simple-release/pnpm`](packages/pnpm#readme) | A pnpm addon for simple-release. | [![NPM version][pnpm-npm]][pnpm-npm-url] | [![Dependencies status][pnpm-deps]][pnpm-deps-url] |
| [`@simple-release/node-gha`](packages/node-gha#readme) | A Node.js GitHub Actions addon for simple-release. | [![NPM version][node-gha-npm]][node-gha-npm-url] | [![Dependencies status][node-gha-deps]][node-gha-deps-url] |
| [`@simple-release/github`](packages/github#readme) | A github release addon for simple-release. | [![NPM version][github-npm]][github-npm-url] | [![Dependencies status][github-deps]][github-deps-url] |
| [`@simple-release/github-action`](packages/github-action#readme) | A simple-release api for github action. | [![NPM version][github-action-npm]][github-action-npm-url] | [![Dependencies status][github-action-deps]][github-action-deps-url] |
| [`simple-github-release`](packages/simple-github-release#readme) | A simple tool to create GitHub releases. | [![NPM version][simple-github-release-npm]][simple-github-release-npm-url] | [![Dependencies status][simple-github-release-deps]][simple-github-release-deps-url] |
Expand Down Expand Up @@ -63,6 +64,14 @@ A simple tool to automate version bumps, changelogs, and releases using [Convent
[pnpm-deps]: https://img.shields.io/librariesio/release/npm/@simple-release/pnpm
[pnpm-deps-url]: https://libraries.io/npm/@simple-release%2Fpnpm

<!-- node-gha -->

[node-gha-npm]: https://img.shields.io/npm/v/@simple-release/node-gha.svg
[node-gha-npm-url]: https://www.npmjs.com/package/@simple-release/node-gha

[node-gha-deps]: https://img.shields.io/librariesio/release/npm/@simple-release/node-gha
[node-gha-deps-url]: https://libraries.io/npm/@simple-release%2Fnode-gha

<!-- github -->

[github-npm]: https://img.shields.io/npm/v/@simple-release/github.svg
Expand Down
2 changes: 1 addition & 1 deletion packages/github-action/src/releaser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ export class ReleaserGithubAction<P extends Project = Project> extends Releaser<
.maintenanceBranch()
.tag()
.push()
.release()
.publish()
.release()
.run(check ? ifReleaseCommit : undefined)
}

Expand Down
118 changes: 118 additions & 0 deletions packages/node-gha/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# @simple-release/node-gha

[![ESM-only package][package]][package-url]
[![NPM version][npm]][npm-url]
[![Node version][node]][node-url]
[![Dependencies status][deps]][deps-url]
[![Install size][size]][size-url]
[![Build status][build]][build-url]
[![Coverage status][coverage]][coverage-url]

[package]: https://img.shields.io/badge/package-ESM--only-ffe536.svg
[package-url]: https://nodejs.org/api/esm.html

[npm]: https://img.shields.io/npm/v/@simple-release/node-gha.svg
[npm-url]: https://www.npmjs.com/package/@simple-release/node-gha

[node]: https://img.shields.io/node/v/@simple-release/node-gha.svg
[node-url]: https://nodejs.org

[deps]: https://img.shields.io/librariesio/release/npm/@simple-release/node-gha
[deps-url]: https://libraries.io/npm/@simple-release%2Fnode-gha

[size]: https://packagephobia.com/badge?p=@simple-release/node-gha
[size-url]: https://packagephobia.com/result?p=@simple-release/node-gha

[build]: https://img.shields.io/github/actions/workflow/status/TrigenSoftware/simple-release/tests.yml?branch=main
[build-url]: https://github.com/TrigenSoftware/simple-release/actions

[coverage]: https://coveralls.io/repos/github/TrigenSoftware/simple-release/badge.svg?branch=main
[coverage-url]: https://coveralls.io/github/TrigenSoftware/simple-release?branch=main

A Node.js GitHub Actions addon for simple-release.

## Install

```bash
# pnpm
pnpm add @simple-release/node-gha
# yarn
yarn add @simple-release/node-gha
# npm
npm i @simple-release/node-gha
```

## Usage

```js
import { Releaser } from '@simple-release/core'
import { NodeGhaProject } from '@simple-release/node-gha'

await new Releaser({
project: new NodeGhaProject()
})
.publish({
build: 'pnpm install --prod',
files: [
'node_modules',
'dist'
]
})
.run()
```

`NodeGhaProject` publishes a built Node.js GitHub Action state by creating or updating:

- `latest` branch from the current release commit.
- `v{major}` branch from the built `latest` state.
- `v{version}` tag from the built `latest` state.

If `build` is provided, the command runs on the `latest` branch. After the command completes, files from the publish option `files` are force-added and the release commit is amended before refs are pushed. If `files` is not provided, package.json `files` is used.

## Options

### NodeGhaProject

#### `path`

Path to the `package.json` manifest file. Defaults to `'package.json'`.

#### `changelogFile`

Path to the changelog file. Defaults to `'CHANGELOG.md'`.

#### `compose`

Function to compose the main manifest with secondaries. It can be needed if you have some secondary manifests where version also should be updated. Optional.

### publish

Publish options for `NodeGhaProject`.

#### `skip`

If true, skip publishing. Optional.

#### `latestBranch`

Branch that points to the latest built GitHub Action state. Defaults to `'latest'`.

#### `majorBranchPrefix`

Prefix for the major branch. Defaults to `'v'`.

#### `tagPrefix`

Prefix for version tags. Defaults to `'v'`.

#### `build`

Build or install command to run before publishing refs. Optional.

#### `files`

Files to stage after `build`. Defaults to package.json `files`.

#### `env`

Environment variables to set before running build commands. Defaults to `process.env`.
12 changes: 12 additions & 0 deletions packages/node-gha/oxlint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineConfig } from '@trigen/oxlint'
import testConfig from '@trigen/oxlint-config/test'
import tsTypeCheckedConfig from '@trigen/oxlint-config/typescript-type-checked'
import rootConfig from '../../oxlint.config.ts'

export default defineConfig({
extends: [
rootConfig,
tsTypeCheckedConfig,
testConfig
]
})
65 changes: 65 additions & 0 deletions packages/node-gha/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "@simple-release/node-gha",
"type": "module",
"version": "2.3.0",
"description": "A Node.js GitHub Actions addon for simple-release.",
"author": {
"name": "Dan Onoshko",
"email": "danon0404@gmail.com",
"url": "https://github.com/dangreen"
},
"license": "MIT",
"homepage": "https://github.com/TrigenSoftware/simple-release/tree/main/packages/node-gha#readme",
"funding": "https://ko-fi.com/dangreen",
"repository": {
"type": "git",
"url": "https://github.com/TrigenSoftware/simple-release.git",
"directory": "packages/node-gha"
},
"bugs": {
"url": "https://github.com/TrigenSoftware/simple-release/issues"
},
"keywords": [
"simple-release",
"github-actions",
"release",
"publish",
"changelog"
],
"engines": {
"node": ">=22"
},
"exports": "./src/index.ts",
"publishConfig": {
"exports": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"directory": "package",
"linkDirectory": false
},
"files": [
"dist"
],
"scripts": {
"clear:package": "del ./package",
"clear:dist": "del ./dist",
"clear": "del ./package ./dist ./coverage",
"prepublishOnly": "run build clear:package clean-publish",
"postpublish": "pnpm clear:package",
"build": "tsgo -p tsconfig.build.json",
"lint": "oxlint",
"test:unit": "vitest run --coverage",
"test:types": "tsgo --noEmit",
"test": "run -p lint test:unit test:types"
},
"dependencies": {
"@simple-libs/child-process-utils": "^2.0.0",
"@simple-release/core": "workspace:^",
"semver": "^7.5.2"
},
"devDependencies": {
"@types/semver": "^7.5.8",
"test": "workspace:^"
}
}
2 changes: 2 additions & 0 deletions packages/node-gha/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './project.js'
export * from './publish.js'
29 changes: 29 additions & 0 deletions packages/node-gha/src/project.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
type PackageJsonProjectOptions,
type ProjectBumpOptions,
PackageJsonProject
} from '@simple-release/core'
import {
type PublishOptions,
publish
} from './publish.js'

export type NodeGhaProjectOptions = PackageJsonProjectOptions

export type NodeGhaProjectBumpOptions = ProjectBumpOptions

export type NodeGhaProjectPublishOptions = PublishOptions

/**
* A Node.js GitHub Actions project that publishes version refs to git branches and tags.
*/
export class NodeGhaProject extends PackageJsonProject {
override async publish(options: NodeGhaProjectPublishOptions = {}): Promise<void> {
if (options.skip) {
options.logger?.info('Skipping publish')
return
}

await publish(this, options)
}
}
86 changes: 86 additions & 0 deletions packages/node-gha/src/publish.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { join } from 'path'
import {
describe,
expect,
it
} from 'vitest'
import {
createDirectory,
forkProject,
packageJsonProject
} from 'test'
import { NodeGhaProject } from './project.js'

function refHash(output: string) {
return output.split(/\s+/)[0]
}

describe('node-gha', () => {
describe('publish', () => {
it('should publish GitHub Action refs from the built latest branch', async () => {
const { cwd } = await forkProject('node-gha-publish', packageJsonProject({
version: '2.5.0',
files: [
'dist'
]
}))
const remote = await createDirectory('node-gha-publish-remote')
const project = new NodeGhaProject({
path: join(cwd, 'package.json')
})

await project.gitClient.exec('-C', remote, 'init', '--bare')
await project.gitClient.exec('remote', 'set-url', 'origin', remote)

await project.publish({
build: 'node -e "const fs=require(\'fs\');fs.mkdirSync(\'dist\',{recursive:true});fs.writeFileSync(\'dist/index.js\',\'built\\n\')"'
})

const latestRef = await project.gitClient.exec('ls-remote', '--heads', 'origin', 'latest')
const majorRef = await project.gitClient.exec('ls-remote', '--heads', 'origin', 'v2')
const tagRef = await project.gitClient.exec('ls-remote', '--tags', 'origin', 'v2.5.0')

expect(latestRef).toContain('refs/heads/latest')
expect(majorRef).toContain('refs/heads/v2')
expect(tagRef).toContain('refs/tags/v2.5.0')
expect(refHash(latestRef)).toBe(refHash(majorRef))
expect(refHash(latestRef)).toBe(refHash(tagRef))
expect(await project.gitClient.exec('show', 'v2.5.0:dist/index.js')).toBe('built')
expect(await project.gitClient.getCurrentBranch()).toBe('master')
})

it('should use custom ref names and explicit files', async () => {
const { cwd } = await forkProject('node-gha-publish-custom-refs', packageJsonProject({
version: '3.0.0'
}))
const remote = await createDirectory('node-gha-publish-custom-refs-remote')
const project = new NodeGhaProject({
path: join(cwd, 'package.json')
})

await project.gitClient.exec('-C', remote, 'init', '--bare')
await project.gitClient.exec('remote', 'set-url', 'origin', remote)

await project.publish({
latestBranch: 'stable',
majorBranchPrefix: 'release-',
tagPrefix: 'action-v',
build: 'node -e "const fs=require(\'fs\');fs.mkdirSync(\'lib\',{recursive:true});fs.writeFileSync(\'lib/action.js\',\'custom\\n\')"',
files: [
'lib/action.js'
]
})

const latestRef = await project.gitClient.exec('ls-remote', '--heads', 'origin', 'stable')
const majorRef = await project.gitClient.exec('ls-remote', '--heads', 'origin', 'release-3')
const tagRef = await project.gitClient.exec('ls-remote', '--tags', 'origin', 'action-v3.0.0')

expect(latestRef).toContain('refs/heads/stable')
expect(majorRef).toContain('refs/heads/release-3')
expect(tagRef).toContain('refs/tags/action-v3.0.0')
expect(refHash(latestRef)).toBe(refHash(majorRef))
expect(refHash(latestRef)).toBe(refHash(tagRef))
expect(await project.gitClient.exec('show', 'action-v3.0.0:lib/action.js')).toBe('custom')
})
})
})
Loading