76 Commits
v1.0.1 ... main

Author SHA1 Message Date
dependabot[bot]
f709bf4521 chore(deps-dev): bump the npm-development group with 6 updates (#92) 2026-01-19 00:05:11 +00:00
dependabot[bot]
713ef57d6a chore(deps): bump the npm-production group with 2 updates (#93) 2026-01-18 23:51:40 +00:00
dependabot[bot]
9faf3c9e39 chore(deps): bump the actions group with 2 updates (#94) 2026-01-18 23:50:34 +00:00
dependabot[bot]
2a6efacda6 chore(deps): bump ruby/setup-ruby from 1.278.0 to 1.280.0 in the actions group (#91) 2026-01-11 16:05:41 +00:00
dependabot[bot]
00f9f5b105 chore(deps-dev): bump the npm-development group with 4 updates (#90) 2026-01-11 16:05:18 +00:00
dependabot[bot]
b159afa635 chore(deps-dev): bump the npm-development group with 3 updates (#87)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 00:22:50 +00:00
dependabot[bot]
e9e6aa35a8 chore(deps): bump ruby/setup-ruby from 1.275.0 to 1.278.0 in the actions group (#88)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 00:22:15 +00:00
d92b2d6009 ci(release/tag): use new derive_from input (#89) 2026-01-02 00:21:59 +00:00
dependabot[bot]
9debb9deac chore(deps-dev): bump the npm-development group with 3 updates (#85) 2025-12-25 13:11:35 +00:00
dependabot[bot]
36243fb9d3 chore(deps): bump jimeh/update-tags-action from 2.2.0 to 2.3.0 in the actions group (#86) 2025-12-25 13:00:31 +00:00
jimehbot[bot]
98d6d448de chore(main): release 2.3.0 (#78)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-12-24 00:59:00 +00:00
fee5cc2ff2 chore(readme): strip out all release-please update tags (#84) 2025-12-24 00:54:17 +00:00
facf303096 chore(readme): fix version string bumps done by release-please (#83) 2025-12-24 00:33:14 +00:00
5dc277d712 chore(readme): tweak version numbering in examples (#82) 2025-12-24 00:23:39 +00:00
32e66b04be feat(tags): support per-tag annotation overrides (#81) 2025-12-24 00:12:13 +00:00
1d171e9f3c feat(tags/derive): add semver tag derivation functionality (#79) 2025-12-23 23:33:54 +00:00
6adab3a060 chore(AGENTS.md): add license compliance instructions for npm dependencies (#80) 2025-12-23 22:45:43 +00:00
ef41989077 feat(inputs): add dry run support (#76) 2025-12-23 21:31:53 +00:00
bb3e44be2f style(ci/dependabot-rebuild): apply prettier formatting to workflow YAML (#77) 2025-12-23 21:28:52 +00:00
jimehbot[bot]
46ebed28cc chore(main): release 2.2.1 (#72)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-12-22 15:45:13 +00:00
dependabot[bot]
04e502b026 chore(deps-dev): bump the npm-development group across 1 directory with 5 updates (#74)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 14:54:40 +00:00
dependabot[bot]
fa63dca88c chore(deps): bump @actions/core from 1.11.1 to 2.0.1 (#62)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-12-22 14:50:55 +00:00
dependabot[bot]
6593b10eb9 chore(deps): bump ruby/setup-ruby from 1.270.0 to 1.275.0 in the actions group (#73)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 14:42:42 +00:00
daa038fd7f ci(dependabot-rebuild): refactor workflow (#75) 2025-12-22 14:40:18 +00:00
5580fd8611 chore(deps): update dependabot configuration to include major updates (#69) 2025-12-22 13:11:20 +00:00
aa16a0ff75 chore(ci/workflow): improve license file update process (#70) 2025-12-22 13:09:26 +00:00
741ed40bb7 chore(deps): bump node and ruby versions to latest (#68) 2025-12-22 12:58:03 +00:00
a25f37f9e6 docs(AGENTS.md): update to align with current state of project (#71) 2025-12-22 12:55:52 +00:00
dependabot[bot]
82dc01ff9e chore(deps): bump the actions-minor group with 2 updates (#64)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:27:37 +00:00
dependabot[bot]
1d0890efd6 chore(deps-dev): bump the npm-development group with 2 updates (#61) 2025-12-15 18:24:14 +00:00
dependabot[bot]
fcb6d5925b chore(deps-dev): bump the npm-development group across 1 directory with 5 updates (#60) 2025-12-09 08:59:56 +00:00
dependabot[bot]
ecd1432d26 chore(deps): bump the actions-minor group with 4 updates (#59) 2025-12-09 08:55:42 +00:00
dependabot[bot]
73adb32d6a chore(deps-dev): bump prettier from 3.6.2 to 3.7.3 in the npm-development group (#57) 2025-12-01 13:36:47 +00:00
dependabot[bot]
0b1a9ea25d chore(deps-dev): bump the npm-development group across 1 directory with 3 updates (#56) 2025-11-24 21:16:08 +00:00
dependabot[bot]
88c489d592 chore(deps): bump the actions-minor group with 3 updates (#55) 2025-11-24 21:00:17 +00:00
dependabot[bot]
4e16af70e2 chore(deps-dev): bump js-yaml from 3.14.1 to 3.14.2 (#51) 2025-11-19 19:44:44 +00:00
dependabot[bot]
88edfaa38b chore(deps-dev): bump the npm-development group across 1 directory with 4 updates (#53) 2025-11-19 19:41:27 +00:00
dependabot[bot]
838b7bd8a1 chore(deps-dev): bump @eslint/compat from 1.4.1 to 2.0.0 (#50) 2025-11-19 19:36:23 +00:00
dependabot[bot]
2df44e1d6e chore(deps): bump glob from 10.4.5 to 10.5.0 (#52) 2025-11-19 19:29:53 +00:00
dependabot[bot]
e33b26678f chore(deps): bump jimeh/update-tags-action from 2.0.0 to 2.2.0 in the actions-minor group (#38)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-11 18:43:20 +00:00
ce60e958b3 ci(dependabot-rebuild): remove unnecessary ref from checkout action (#48) 2025-11-11 18:41:04 +00:00
dependabot[bot]
441aa939fd chore(deps-dev): bump the npm-development group across 1 directory with 5 updates (#47)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-11-11 18:37:15 +00:00
af088380e8 chore(deps): update dependabot configuration to include minor updates (#41) 2025-11-11 18:30:06 +00:00
dependabot[bot]
d2bac049db chore(deps-dev): bump @rollup/plugin-commonjs from 28.0.9 to 29.0.0 (#36)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-11-11 18:28:50 +00:00
b18dece8b1 ci(dependabot-rebuild): fix files path passed to commit signing action (#46) 2025-11-11 18:24:56 +00:00
5f14685d44 chore(build): disable minifaction of dist/index.js to make rebuilt debugging easier (#45) 2025-11-11 18:23:24 +00:00
605c1cfa34 ci(dependabot-rebuild): third attempt at signing commit with GitHub App (#44) 2025-11-11 18:05:07 +00:00
bd3bacec30 ci(dependabot-rebuild): second attempt at signing commits with GitHub App (#43) 2025-11-11 17:15:18 +00:00
389bd20c41 ci(dependabot-rebuild): configure git user dynamically for dependabot rebuild (#42) 2025-11-11 16:37:09 +00:00
38ccbb6879 ci(github/workflows): update bot secret names in dependabot rebuild workflow (#40) 2025-11-11 11:22:04 +00:00
9016fb217e ci(github/workflows): add dependabot rebuild workflow (#39) 2025-11-11 11:15:08 +00:00
dependabot[bot]
ca138ceed8 chore(deps-dev): bump the npm-development group with 3 updates (#35) 2025-11-04 09:04:09 +00:00
jimehbot[bot]
eecd8caae9 chore(main): release 2.2.0 (#34)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-10-29 13:08:22 +00:00
6723e4d4ac feat(action): add skipped tags output and tracking (#33) 2025-10-29 13:06:38 +00:00
92bdad7a4a refactor(tags): improve tag operation planning and execution (#32) 2025-10-29 12:51:33 +00:00
1576a544fe refactor(tags): simplify tag resolution and processing logic (#30) 2025-10-29 12:09:21 +00:00
2b1c01b3ed test: move tests and fixtures to top-level "tests" directory (#29) 2025-10-29 11:09:22 +00:00
73e6309596 chore(vscode): configure prettier as default formatter for multiple file types (#28) 2025-10-29 10:26:12 +00:00
jimehbot[bot]
08138ee77f chore(main): release 2.1.1 (#27)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-10-28 02:14:18 +00:00
c2d45bd3ef docs(readme): fix outdated action inputs/outputs (#26) 2025-10-28 02:12:53 +00:00
jimehbot[bot]
f44ca97378 chore(main): release 2.1.0 (#18)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-10-28 01:59:41 +00:00
1041193aa6 chore(readme): attempt 4 at example version bumps (#25) 2025-10-28 01:58:18 +00:00
4db4cf0ae7 ci: remove unnecessary dependency and add more checks for release-tags (#24) 2025-10-28 01:56:49 +00:00
78da350f05 chore(readme): attempt 3 at example version bumping (#23) 2025-10-28 01:54:45 +00:00
c0954ab20f chore(readme): another attempt at example version bumping (#22) 2025-10-28 01:51:46 +00:00
f690607ffe chore(readme): attempt to improve auto version bumping (#21) 2025-10-28 01:48:12 +00:00
20206210a0 chore(release-please): fix package naming config (#20) 2025-10-28 01:37:35 +00:00
c1b031da4b chore(package.json): bump version to 2.0.0 (#19) 2025-10-28 01:33:31 +00:00
40c0c24c34 feat(tag): add support for annotated tags and improved tag handling (#15) 2025-10-28 01:29:46 +00:00
2cb31b2a0a chore(release): update release-please configuration (#17) 2025-10-28 01:24:52 +00:00
5a403d344e chore(ci): bump jimeh/update-tags-action to v2.0.0 (#16) 2025-10-28 00:48:59 +00:00
99a7d3ae1f docs(changelog): update changelog formatting and whitespace (#14) 2025-10-27 22:31:26 +00:00
bdda9e7570 ci(github/workflows): add copilot setup steps workflow (#12) 2025-10-27 22:29:43 +00:00
ba01e004ad ci(licensed): fix typo in comment (#13) 2025-10-27 22:29:07 +00:00
jimehbot[bot]
bf34cb3d09 chore(main): release 2.0.0 (#10)
Co-authored-by: jimehbot[bot] <132453784+jimehbot[bot]@users.noreply.github.com>
2025-10-27 21:55:28 +00:00
733ded1f0b refactor(action): rebuild in TypeScript based on typescript-action template repo (#9) 2025-10-27 21:31:03 +00:00
87 changed files with 58919 additions and 6630 deletions

1
.cursor/rules/00-agents.mdc Symbolic link
View File

@@ -0,0 +1 @@
../../AGENTS.md

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
* text=auto eol=lf
dist/** -diff linguist-generated=true

View File

@@ -1,3 +1,3 @@
{
".": "1.0.1"
".": "2.3.0"
}

1
.github/copilot-instructions.md vendored Symbolic link
View File

@@ -0,0 +1 @@
../AGENTS.md

30
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
---
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
update-types:
- major
- minor
- patch
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
groups:
npm-development:
dependency-type: development
update-types:
- major
- minor
- patch
npm-production:
dependency-type: production
update-types:
- major
- minor
- patch

View File

@@ -1,17 +1,30 @@
{
"always-update": true,
"packages": {
".": {
"release-type": "simple",
"release-type": "node",
"changelog-path": "CHANGELOG.md",
"extra-files": [
"README.md"
],
"extra-files": ["README.md"],
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": true,
"draft": false,
"prerelease": false,
"initial-version": "0.0.1"
"include-component-in-tag": false
}
},
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "feature", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance Improvements" },
{ "type": "revert", "section": "Reverts" },
{ "type": "docs", "section": "Documentation", "hidden": false },
{ "type": "style", "section": "Styles", "hidden": true },
{ "type": "chore", "section": "Miscellaneous Chores", "hidden": true },
{ "type": "refactor", "section": "Code Refactoring", "hidden": true },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "build", "section": "Build System", "hidden": true },
{ "type": "ci", "section": "Continuous Integration", "hidden": true }
],
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
}

View File

@@ -1,36 +1,99 @@
---
name: CI
on: push
on:
pull_request:
branches:
- main
push:
branches:
- main
permissions:
contents: read
jobs:
build:
check-dist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 16
cache: "npm"
node-version-file: .node-version
cache: npm
- run: npm ci
- name: Run build script
run: npm run build
- name: Verify no changes after build
- name: build dist/*
run: npm run bundle
- name: Compare Directories
id: diff
run: |
git diff --exit-code
if [ ! -d dist/ ]; then
echo "Expected dist/ directory does not exist. See status below:"
ls -la ./
exit 1
fi
if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff --ignore-space-at-eol --text dist/
exit 1
fi
- name: Upload Artifact
if: ${{ failure() && steps.diff.outcome == 'failure' }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: dist
path: dist/
lint:
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
statuses: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: .node-version
cache: npm
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: .node-version
cache: npm
- run: npm ci
- run: npm run ci-test
release-please:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
if: ${{ github.ref == 'refs/heads/main' }}
outputs:
release_created: ${{ steps.release-please.outputs.release_created }}
tag_name: ${{ steps.release-please.outputs.tag_name }}
steps:
- uses: jimeh/release-please-manifest-action@v1
id: release
- uses: jimeh/release-please-manifest-action@84f33fd2828210488c36f3e0a7e3209252d2ae7d # v3.0.0
id: release-please
with:
app-id: ${{ secrets.RELEASE_BOT_APP_ID }}
private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}
- name: MAJOR and MAJOR.MINOR tags
if: ${{ steps.release.outputs.release_created }}
uses: jimeh/update-tags-action@v1
app-id: ${{ secrets.BOT_APP_ID }}
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
release-tags:
runs-on: ubuntu-latest
needs: [release-please, check-dist, lint, test]
if: ${{ needs.release-please.outputs.release_created }}
permissions:
contents: write
steps:
- uses: jimeh/update-tags-action@98d6d448de7488acb52bd8db115673541d019521 # v2.3.0
with:
tags: |
v${{ steps.release.outputs.major }}
v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}
derive_from: ${{ needs.release-please.outputs.tag_name }}

View File

@@ -0,0 +1,27 @@
name: "Copilot Setup Steps"
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: .node-version
cache: npm
- run: npm ci
- uses: ruby/setup-ruby@708024e6c902387ab41de36e1669e43b5ee7085e # v1.283.0
with:
ruby-version: ruby
bundler-cache: true

View File

@@ -0,0 +1,62 @@
---
name: Dependabot Rebuild
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: write
pull-requests: read
jobs:
rebuild:
runs-on: ubuntu-latest
if: |-
${{ github.actor == 'dependabot[bot]' && github.event.sender.login == 'dependabot[bot]' }}
steps:
- name: Generate app token
id: app-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.BOT_APP_ID }}
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ steps.app-token.outputs.token }}
# Update and push dist if changed.
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: .node-version
cache: npm
- run: npm ci
- name: Rebuild dist
run: npm run bundle
- name: Commit and push if changed
uses: ryancyq/github-signed-commit@e9f3b28c80da7be66d24b8f501a5abe82a6b855f # v1.2.0
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
with:
files: |
dist/
commit-message: |-
chore: rebuild dist
# Update and push .licenses if changed.
- uses: ruby/setup-ruby@708024e6c902387ab41de36e1669e43b5ee7085e # v1.283.0
with:
ruby-version: ruby
bundler-cache: true
- name: Update Licenses
id: update-licenses
run: bin/licensed cache
- name: Commit and push if changed
uses: ryancyq/github-signed-commit@e9f3b28c80da7be66d24b8f501a5abe82a6b855f # v1.2.0
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
with:
files: |
.licenses/
commit-message: |-
chore(licensed): update license files

64
.github/workflows/licensed.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
# This workflow checks the statuses of cached dependencies used in this action
# with the help of the Licensed tool. If any licenses are invalid or missing,
# this workflow will fail. See: https://github.com/licensee/licensed
name: Licensed
on:
pull_request:
branches:
- main
push:
branches:
- main
workflow_dispatch:
permissions:
contents: write
jobs:
check-licenses:
runs-on: ubuntu-latest
steps:
# Checkout code using app token.
- name: Generate app token
id: app-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.BOT_APP_ID }}
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ steps.app-token.outputs.token }}
# Setup Node and Ruby runtimes.
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: .node-version
cache: npm
- run: npm ci
- uses: ruby/setup-ruby@708024e6c902387ab41de36e1669e43b5ee7085e # v1.283.0
with:
ruby-version: ruby
bundler-cache: true
# If this is a workflow_dispatch event, update the cached licenses.
- if: ${{ github.event_name == 'workflow_dispatch' }}
name: Update Licenses
id: update-licenses
run: bin/licensed cache
- if: ${{ github.event_name == 'workflow_dispatch' }}
name: Commit and push if changed
uses: ryancyq/github-signed-commit@e9f3b28c80da7be66d24b8f501a5abe82a6b855f # v1.2.0
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
with:
files: |
.licenses/
commit-message: |-
chore(licensed): update license files
# Last, check the status of the cached licenses.
- name: Check Licenses
id: check-licenses
run: bin/licensed status

107
.gitignore vendored
View File

@@ -1,2 +1,105 @@
.tool-versions
node_modules/*
# Dependency directory
node_modules
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Avoid locking Licensed to exact version.
Gemfile.lock
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# OS metadata
.DS_Store
Thumbs.db
# Ignore built ts files
tests/runner/*
# IDE files
.idea
*.code-workspace

13
.licensed.yml Normal file
View File

@@ -0,0 +1,13 @@
# See: https://github.com/licensee/licensed/blob/main/docs/configuration.md
sources:
npm: true
allowed:
- apache-2.0
- bsd-2-clause
- bsd-3-clause
- isc
- mit
- cc0-1.0
- other

View File

@@ -0,0 +1,20 @@
---
name: "@actions/core"
version: 2.0.2
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@actions/exec"
version: 2.0.0
type: npm
summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@actions/github"
version: 7.0.0
type: npm
summary: Actions github lib
homepage: https://github.com/actions/toolkit/tree/main/packages/github
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,32 @@
---
name: "@actions/http-client"
version: 3.0.1
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
license: other
licenses:
- sources: LICENSE
text: |
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@actions/io"
version: 2.0.0
type: npm
summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,30 @@
---
name: "@fastify/busboy"
version: 2.1.1
type: npm
summary: A streaming parser for HTML form data for node.js
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright Brian White. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,34 @@
---
name: "@octokit/auth-token"
version: 4.0.0
type: npm
summary: GitHub API token authentication for browsers and Node.js
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,34 @@
---
name: "@octokit/core"
version: 5.2.2
type: npm
summary: Extendable client for GitHub's REST & GraphQL APIs
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,34 @@
---
name: "@octokit/endpoint"
version: 9.0.6
type: npm
summary: Turns REST API endpoints into generic request options
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,34 @@
---
name: "@octokit/graphql"
version: 7.1.1
type: npm
summary: GitHub GraphQL API client for browsers and Node
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@octokit/openapi-types"
version: 20.0.0
type: npm
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright 2020 Gregor Martynus
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@octokit/openapi-types"
version: 24.2.0
type: npm
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright 2020 Gregor Martynus
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@octokit/plugin-paginate-rest"
version: 9.2.2
type: npm
summary: Octokit plugin to paginate REST API endpoint responses
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@octokit/plugin-rest-endpoint-methods"
version: 10.4.1
type: npm
summary: Octokit plugin adding one method for all of api.github.com REST API endpoints
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,34 @@
---
name: "@octokit/request-error"
version: 5.1.1
type: npm
summary: Error class for Octokit request errors
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,35 @@
---
name: "@octokit/request"
version: 8.4.1
type: npm
summary: Send parameterized requests to GitHub's APIs with sensible defaults in browsers
and Node
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@octokit/types"
version: 12.6.0
type: npm
summary: Shared TypeScript definitions for Octokit projects
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,20 @@
---
name: "@octokit/types"
version: 13.10.0
type: npm
summary: Shared TypeScript definitions for Octokit projects
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@@ -0,0 +1,214 @@
---
name: before-after-hook
version: 2.2.3
type: npm
summary: asynchronous before/error/after hooks for internal functionality
homepage:
license: apache-2.0
licenses:
- sources: LICENSE
text: |2
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Gregor Martynus and other contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- sources: README.md
text: "[Apache 2.0](LICENSE)"
notices: []

View File

@@ -0,0 +1,32 @@
---
name: csv-parse
version: 6.1.0
type: npm
summary: CSV parsing implementing the Node.js `stream.Transform` API
homepage: https://csv.js.org/parse
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) 2010 Adaltas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices: []

View File

@@ -0,0 +1,28 @@
---
name: deprecation
version: 2.3.1
type: npm
summary: Log a deprecation message with stack
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Gregor Martynus and contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- sources: README.md
text: "[ISC](LICENSE)"
notices: []

View File

@@ -0,0 +1,36 @@
---
name: handlebars
version: 4.7.8
type: npm
summary: Handlebars provides the power necessary to let you build semantic templates
effectively with no frustration
homepage: https://www.handlebarsjs.com/
license: mit
licenses:
- sources: LICENSE
text: |
Copyright (C) 2011-2019 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.markdown
text: |-
Handlebars.js is released under the MIT license.
[pull-request]: https://github.com/handlebars-lang/handlebars.js/pull/new/master
notices: []

View File

@@ -0,0 +1,44 @@
---
name: minimist
version: 1.2.8
type: npm
summary: parse argument options
homepage: https://github.com/minimistjs/minimist
license: other
licenses:
- sources: LICENSE
text: |
This software is released under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: |-
MIT
[package-url]: https://npmjs.org/package/minimist
[npm-version-svg]: https://versionbadg.es/minimistjs/minimist.svg
[npm-badge-png]: https://nodei.co/npm/minimist.png?downloads=true&stars=true
[license-image]: https://img.shields.io/npm/l/minimist.svg
[license-url]: LICENSE
[downloads-image]: https://img.shields.io/npm/dm/minimist.svg
[downloads-url]: https://npm-stat.com/charts.html?package=minimist
[codecov-image]: https://codecov.io/gh/minimistjs/minimist/branch/main/graphs/badge.svg
[codecov-url]: https://app.codecov.io/gh/minimistjs/minimist/
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/minimistjs/minimist
[actions-url]: https://github.com/minimistjs/minimist/actions
notices: []

View File

@@ -0,0 +1,36 @@
---
name: neo-async
version: 2.6.2
type: npm
summary: 'Neo-Async is a drop-in replacement for Async, it almost fully covers its
functionality and runs faster '
homepage: https://github.com/suguru03/neo-async
license: other
licenses:
- sources: LICENSE
text: |
MIT License
Copyright (c) 2014-2018 Suguru Motegi
Based on Async.js, Copyright Caolan McMahon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: "[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsuguru03%2Fneo-async.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsuguru03%2Fneo-async?ref=badge_large)"
notices: []

View File

@@ -0,0 +1,26 @@
---
name: once
version: 1.4.0
type: npm
summary: Run a function exactly one time
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

View File

@@ -0,0 +1,26 @@
---
name: semver
version: 7.7.3
type: npm
summary: The semantic version parser used by npm.
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

View File

@@ -0,0 +1,39 @@
---
name: source-map
version: 0.6.1
type: npm
summary: Generates and consumes source maps
homepage: https://github.com/mozilla/source-map
license: other
licenses:
- sources: LICENSE
text: |2
Copyright (c) 2009-2011, Mozilla Foundation and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the names of the Mozilla Foundation nor the names of project
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
notices: []

View File

@@ -0,0 +1,35 @@
---
name: tunnel
version: 0.0.6
type: npm
summary: Node HTTP/HTTPS Agents for tunneling proxies
homepage: https://github.com/koichik/node-tunnel/
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) 2012 Koichi Kobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: Licensed under the [MIT](https://github.com/koichik/node-tunnel/blob/master/LICENSE)
license.
notices: []

View File

@@ -0,0 +1,40 @@
---
name: uglify-js
version: 3.19.3
type: npm
summary: JavaScript parser, mangler/compressor and beautifier toolkit
homepage:
license: other
licenses:
- sources: LICENSE
text: |
UglifyJS is released under the BSD license:
Copyright 2012-2024 (c) Mihai Bazon <mihai.bazon@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
notices: []

View File

@@ -0,0 +1,34 @@
---
name: undici
version: 5.29.0
type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
Copyright (c) Matteo Collina and Undici contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: MIT
notices: []

View File

@@ -0,0 +1,20 @@
---
name: universal-user-agent
version: 6.0.1
type: npm
summary: Get a user agent string in both browser and node
homepage:
license: isc
licenses:
- sources: LICENSE.md
text: |
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- sources: README.md
text: "[ISC](LICENSE.md)"
notices: []

View File

@@ -0,0 +1,29 @@
---
name: wordwrap
version: 1.0.0
type: npm
summary: Wrap those words. Show them at what columns to start and stop.
homepage:
license: other
licenses:
- sources: LICENSE
text: |
This software is released under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -0,0 +1,26 @@
---
name: wrappy
version: 1.0.2
type: npm
summary: Callback wrapping utility
homepage: https://github.com/npm/wrappy
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

2
.mise.toml Normal file
View File

@@ -0,0 +1,2 @@
[settings]
idiomatic_version_file_enable_tools = ["ruby", "node"]

1
.node-version Normal file
View File

@@ -0,0 +1 @@
24.12.0

6
.prettierignore Normal file
View File

@@ -0,0 +1,6 @@
.DS_Store
.licenses/
dist/
node_modules/
coverage/
CHANGELOG.md

21
.prettierrc.yml Normal file
View File

@@ -0,0 +1,21 @@
# See: https://prettier.io/docs/en/configuration
printWidth: 80
tabWidth: 2
useTabs: false
semi: false
singleQuote: true
quoteProps: as-needed
jsxSingleQuote: false
trailingComma: none
bracketSpacing: true
bracketSameLine: true
arrowParens: always
proseWrap: always
htmlWhitespaceSensitivity: css
endOfLine: lf
overrides:
- files: ["*.yml", "*.yaml"]
options:
singleQuote: false

1
.ruby-version Normal file
View File

@@ -0,0 +1 @@
3.4.8

10
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
// Allows for use of settings.shared.json and settings.local.json.
"swellaby.workspace-config-plus",
"esbenp.prettier-vscode"
]
}

14
.vscode/settings.shared.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}

292
AGENTS.md Normal file
View File

@@ -0,0 +1,292 @@
---
alwaysApply: true
---
# AGENTS.md
This file provides guidance to LLM agents when working with code in this
repository.
## Project Overview
GitHub Action that creates/updates Git tags in repositories. Commonly used to
maintain major (`v1`) and minor (`v1.2`) version tags pointing to the latest
patch release (`v1.2.3`). The action uses itself in CI to manage its own version
tags.
**Important**: TypeScript sources in `src/` are transpiled to JavaScript in
`dist/`. Both are checked into the repository. A CI workflow verifies `dist/` is
up-to-date. Always run `npm run package` (or `npm run bundle`) after modifying
`src/` files.
**License Compliance**: After modifying NPM dependencies, check license status
and re-cache if needed via `npm run licensed:status` and
`npm run licensed:cache`.
## Development Commands
Package manager: npm
```bash
# Install dependencies
npm install
# Development workflow
npm run format:write # Format code with Prettier (80 char lines)
npm run lint # ESLint check
npm run test # Run Jest tests
npm run package # Build src/index.ts -> dist/index.js via Rollup
npm run bundle # Alias: format + package
# Run a single test file
NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest tests/main.test.ts
# CI variants (suppress warnings)
npm run ci-test # Run tests in CI mode
# Full pre-commit check
npm run all # format → lint → test → coverage → update-readme → package
# Update README from action.yml
npm run update-readme
# Watch mode
npm run package:watch # Auto-rebuild on changes
# License compliance (after modifying dependencies)
npm run licensed:status # Check license status of dependencies
npm run licensed:cache # Re-cache licenses if needed
```
## Code Architecture
### Source Structure
- **[src/index.ts](src/index.ts)**: Entrypoint that imports and runs `main()`
- **[src/main.ts](src/main.ts)**: Core orchestration logic. Exports `run()`
function that coordinates input parsing, tag processing, and output setting
- **[src/inputs.ts](src/inputs.ts)**: Input parsing and validation. Exports
`getInputs()` that reads action inputs and `Inputs` interface
- **[src/derive.ts](src/derive.ts)**: Semver parsing and tag derivation:
- `parseSemver()`: Parses version strings into components (prefix, major,
minor, patch, prerelease, build)
- `renderTemplate()`: Renders Handlebars templates with semver context
- `deriveTags()`: Derives tags from a version string using a template
- **[src/tags.ts](src/tags.ts)**: Tag planning and execution logic:
- `planTagOperations()`: Parses tags, pre-resolves refs to SHAs in parallel,
plans create/update/skip operations
- `executeTagOperation()`: Executes a single planned operation (create,
update, or skip with logging)
- Private helpers for tag creation, updates, and annotation handling
- **[action.yml](action.yml)**: GitHub Action metadata (inputs/outputs)
- **[tests/fixtures/](tests/fixtures)**: Mock implementations of @actions/core,
@actions/github, and csv-parse for testing
### Tag Input Parsing
Uses `csv-parse/sync` to handle both CSV and newline-delimited formats. Supports
per-tag ref and annotation overrides using the format `tag:ref:annotation`:
- `tag` — Use default `ref` and `annotation` inputs
- `tag:ref` — Override ref for this tag (e.g., `v1:main` tags `v1` to `main`)
- `tag:ref:annotation` — Override both ref and annotation
- `tag::annotation` — Override annotation only (empty ref uses default)
Annotations can contain colons; everything after the second colon is treated as
the annotation text. Per-tag values override the global `ref` and `annotation`
inputs.
### Tag Derivation
The `derive_from` input allows automatic generation of tags from a semver
version string. Uses Handlebars templates with these placeholders:
- `{{prefix}}`: "v" or "V" if input had prefix, empty otherwise
- `{{major}}`, `{{minor}}`, `{{patch}}`: Version numbers
- `{{prerelease}}`, `{{build}}`: Optional semver components
- `{{version}}`: Full version without prefix
Default template `{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}` generates
major and minor tags (e.g., `v1.2.3``v1`, `v1.2`). Supports Handlebars
conditionals like `{{#if prerelease}}...{{/if}}`.
### Tag Update Logic
1. Parse and validate inputs ([inputs.ts](src/inputs.ts))
2. Plan all tag operations ([tags.ts](src/tags.ts):planTagOperations):
- Parse `tag:ref:annotation` syntax and extract per-tag refs/annotations
- Pre-resolve all unique refs to SHAs in parallel (optimization)
- For each tag, check existence and determine operation:
- If exists + fail mode: Fail action immediately
- If exists + skip mode: Plan skip
- If exists + update mode: Plan update if SHA or annotation differs
- If doesn't exist (404): Plan create
3. Execute each planned operation ([tags.ts](src/tags.ts):executeTagOperation)
4. Set outputs with created/updated/skipped tag lists ([main.ts](src/main.ts))
### Testing Patterns
Uses Jest with ESM support. Key pattern for mocking ESM modules:
```typescript
// Declare mocks BEFORE importing tested module
jest.unstable_mockModule('@actions/core', () => core)
// Dynamic import AFTER mocks
const { run } = await import('../src/main.ts')
```
Mock fixtures live in `tests/fixtures/` (e.g., `core.ts` mocks @actions/core).
### Testing Best Practices
- Consider edge cases as well as the main success path
- Tests live in `tests/` directory, fixtures in `tests/fixtures/`
- Run tests after any refactoring to ensure coverage requirements are met
- Use `@actions/core` package for logging (not `console`) for GitHub Actions
compatibility
## TypeScript Configuration
- Target: ES2022, NodeNext module resolution
- Strict mode enabled throughout
- Build outputs ESM to dist/index.js with external sourcemaps
- Line length: 80 chars (enforced by Prettier)
## CI/CD
`.github/workflows/ci.yml` runs:
1. **check-dist**: Verify bundled dist/ matches source
2. **lint**: ESLint check
3. **test**: Run Jest test suite
4. **release-please**: Semantic versioning releases
5. **release-tags**: Self-referential tag updates after release
## Release Process
This project uses [release-please](https://github.com/googleapis/release-please)
to automate versioning and releases based on
[Conventional Commits](https://www.conventionalcommits.org/).
### How It Works
1. **Commit with conventional format**: All commits must follow the Conventional
Commits specification (e.g., `feat:`, `fix:`, `chore:`, `docs:`)
2. **Release PR is created**: release-please automatically opens/updates a
"Release PR" that:
- Proposes the next version number based on commit types
- Updates `CHANGELOG.md` with all changes since last release
- Updates version numbers in `package.json` and other files
3. **Review the Release PR**: Check the proposed version bump and changelog
entries are correct
4. **Merge to release**: Merging the Release PR triggers:
- Creation of a GitHub Release with the changelog
- Publishing of a new Git tag
- Execution of the `release-tags` workflow to update major/minor version tags
### Conventional Commit Format
All commit messages must follow this format:
```text
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
**Common types:**
- `feat:` - New feature (triggers minor version bump)
- `fix:` - Bug fix (triggers patch version bump)
- `docs:` - Documentation changes only
- `chore:` - Maintenance tasks, dependency updates
- `refactor:` - Code refactoring without feature/behavior changes
- `test:` - Adding or updating tests
- `ci:` - CI/CD configuration changes
- `BREAKING CHANGE:` - In footer, triggers major version bump
**Examples:**
```text
feat: add support for multiple tag formats
fix: handle 404 errors when tag doesn't exist
docs: update README with new examples
chore(deps): bump @actions/core to v1.10.0
```
## Action Interface
**Inputs:**
- `tags`: CSV/newline list, supports `tag:ref:annotation` syntax for per-tag
overrides
- `derive_from`: Semver version string to derive tags from (e.g., "v1.2.3")
- `derive_from_template`: Handlebars template for tag derivation (default:
`{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}`)
- `ref`: Default SHA/ref to tag (default: current commit)
- `when_exists`: update|skip|fail (default: update)
- `annotation`: Default annotation message for tags (default: lightweight/none)
- `dry_run`: Log planned operations without executing (default: false)
- `github_token`: Auth token (default: github.token)
Either `tags` or `derive_from` (or both) must be provided.
**Outputs:**
- `tags`: All created/updated tags
- `created`: Newly created tags
- `updated`: Updated tags
- `skipped`: Skipped tags (already matching or when_exists=skip)
## Code Style and Guidelines
- 80 character line length (Prettier)
- No semicolons, single quotes, no trailing commas
- Explicit function return types
- Type imports: `import type * as core from '@actions/core'`
- Error handling via try-catch with `core.setFailed()`
- 404 errors specifically caught to distinguish "tag doesn't exist" from other
errors
- Use descriptive variable and function names
- Keep functions focused and manageable
- Document functions with JSDoc comments
- Follow DRY principles and avoid unnecessary complexity
- Maintain consistency with existing patterns and style
- Focus comments on explaining "why", not "what" (avoid basic unnecessary
comments)
- Use TypeScript's type system for safety and clarity
## Pull Request Guidelines
When creating a pull request (PR), please ensure that:
- Keep changes focused and minimal (avoid large changes, or consider breaking
them into separate, smaller PRs)
- Formatting checks pass
- Linting checks pass
- Unit tests pass and coverage requirements are met
- The action has been transpiled to JavaScript and the `dist` directory is
up-to-date with the latest changes in the `src` directory
- If necessary, the `README.md` file is updated to reflect any changes in
functionality or usage
The body of the PR should include:
- A summary of the changes
- A special note of any changes to dependencies
- A link to any relevant issues or discussions
- Any additional context that may be helpful for reviewers
## Code Review Guidelines
When performing a code review, please follow these guidelines:
- If there are changes that modify the functionality/usage of the action,
validate that there are changes in the `README.md` file that document the new
or modified functionality

View File

@@ -1,22 +1,75 @@
# Changelog
## [2.3.0](https://github.com/jimeh/update-tags-action/compare/v2.2.1...v2.3.0) (2025-12-24)
### Features
* **inputs/derive_from:** derive tags from provided semver string ([#79](https://github.com/jimeh/update-tags-action/issues/79)) ([1d171e9](https://github.com/jimeh/update-tags-action/commit/1d171e9f3c63639b8d0145a881a6df941200742d))
* **inputs/dry_run:** add dry run support ([#76](https://github.com/jimeh/update-tags-action/issues/76)) ([ef41989](https://github.com/jimeh/update-tags-action/commit/ef4198907727f6ff9e5813deb5ab5a4307ab4691))
* **inputs/tags:** support per-tag annotation overrides ([#81](https://github.com/jimeh/update-tags-action/issues/81)) ([32e66b0](https://github.com/jimeh/update-tags-action/commit/32e66b04be37383e2450d698007faa436c706ffd))
## [2.2.1](https://github.com/jimeh/update-tags-action/compare/v2.2.0...v2.2.1) (2025-12-22)
### Documentation
* **AGENTS.md:** update to align with current state of project ([#71](https://github.com/jimeh/update-tags-action/issues/71)) ([a25f37f](https://github.com/jimeh/update-tags-action/commit/a25f37f9e6300ff3fcdf28424cdec9d99944522f))
## [2.2.0](https://github.com/jimeh/update-tags-action/compare/v2.1.1...v2.2.0) (2025-10-29)
### Features
* **action:** add skipped tags output and tracking ([#33](https://github.com/jimeh/update-tags-action/issues/33)) ([6723e4d](https://github.com/jimeh/update-tags-action/commit/6723e4d4aceb3ba7314907830d8b1d5186f0a5d9))
## [2.1.1](https://github.com/jimeh/update-tags-action/compare/v2.1.0...v2.1.1) (2025-10-28)
### Documentation
* **readme:** fix outdated action inputs/outputs ([#26](https://github.com/jimeh/update-tags-action/issues/26)) ([c2d45bd](https://github.com/jimeh/update-tags-action/commit/c2d45bd3eff96a93679cc5dbac166c5a14400751))
## [2.1.0](https://github.com/jimeh/update-tags-action/compare/v2.0.0...v2.1.0) (2025-10-28)
### Features
* **tag:** add support for annotated tags and improved tag handling ([40c0c24](https://github.com/jimeh/update-tags-action/commit/40c0c24c3478fe96765282b3f82b7f72696f0e92)), closes [#7](https://github.com/jimeh/update-tags-action/issues/7)
### Bug Fixes
* **when_exists:** fail-fast if tags exist if `when_exists` is `fail` ([40c0c24](https://github.com/jimeh/update-tags-action/commit/40c0c24c3478fe96765282b3f82b7f72696f0e92))
## [2.0.0](https://github.com/jimeh/update-tags-action/compare/v1.0.1...v2.0.0) (2025-10-27)
### Features
* **action:** complete TypeScript rewrite with comprehensive test suite ([733ded1](https://github.com/jimeh/update-tags-action/commit/733ded1f0b9727d99d299cd42258479b4e64b27d))
## [1.0.1](https://github.com/jimeh/update-tags-action/compare/v1.0.0...v1.0.1) (2023-05-18)
### Bug Fixes
* **action:** tweak metadata for GitHub Marketplace ([#4](https://github.com/jimeh/update-tags-action/issues/4)) ([b74b3c7](https://github.com/jimeh/update-tags-action/commit/b74b3c77fc20bdfd61e29dbf680a9f84612e5fda))
* **action:** tweak metadata for GitHub Marketplace
([#4](https://github.com/jimeh/update-tags-action/issues/4))
([b74b3c7](https://github.com/jimeh/update-tags-action/commit/b74b3c77fc20bdfd61e29dbf680a9f84612e5fda))
## [1.0.0](https://github.com/jimeh/update-tags-action/compare/v0.0.1...v1.0.0) (2023-05-18)
### Miscellaneous Chores
* **release:** bump version to 1.0.0 ([d4f686e](https://github.com/jimeh/update-tags-action/commit/d4f686ef9ff51ff4426907f89983bd286903c23e))
* **release:** bump version to 1.0.0
([d4f686e](https://github.com/jimeh/update-tags-action/commit/d4f686ef9ff51ff4426907f89983bd286903c23e))
## 0.0.1 (2023-05-18)
### Features
* initial implementation ([0185b10](https://github.com/jimeh/update-tags-action/commit/0185b100ff1752ce06ade4b147b6befb8c37e525))
* initial implementation
([0185b10](https://github.com/jimeh/update-tags-action/commit/0185b100ff1752ce06ade4b147b6befb8c37e525))

1
CLAUDE.md Symbolic link
View File

@@ -0,0 +1 @@
AGENTS.md

5
Gemfile Normal file
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
gem "licensed", "~> 5"

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2023 Jim Myhrberg
Copyright (c) 2025 Jim Myhrberg
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

297
README.md
View File

@@ -1,27 +1,15 @@
<h1 align="center">
update-tags-action
</h1>
<div align="center">
<p align="center">
<strong>
Easily create/update one or more Git tags in a GitHub repository.
</strong>
</p>
# update-tags-action
<p align="center">
<a href="https://github.com/jimeh/update-tags-action/releases">
<img src="https://img.shields.io/github/v/tag/jimeh/update-tags-action?label=release" alt="GitHub tag (latest SemVer)">
</a>
<a href="https://github.com/jimeh/update-tags-action/issues">
<img src="https://img.shields.io/github/issues-raw/jimeh/update-tags-action.svg?style=flat&logo=github&logoColor=white" alt="GitHub issues">
</a>
<a href="https://github.com/jimeh/update-tags-action/pulls">
<img src="https://img.shields.io/github/issues-pr-raw/jimeh/update-tags-action.svg?style=flat&logo=github&logoColor=white" alt="GitHub pull requests">
</a>
<a href="https://github.com/jimeh/update-tags-action/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/jimeh/update-tags-action.svg?style=flat" alt="License Status">
</a>
</p>
**Easily create/update one or more Git tags in a GitHub repository.**
[![Latest Release](https://img.shields.io/github/release/jimeh/update-tags-action.svg)](https://github.com/jimeh/update-tags-action/releases)
[![GitHub Issues](https://img.shields.io/github/issues/jimeh/update-tags-action.svg?logo=github&logoColor=white)](https://github.com/jimeh/update-tags-action/issues)
[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/jimeh/update-tags-action.svg?logo=github&logoColor=white)](https://github.com/jimeh/update-tags-action/pulls)
[![License](https://img.shields.io/github/license/jimeh/update-tags-action.svg)](https://github.com/jimeh/update-tags-action/blob/main/LICENSE)
</div>
Generally useful for moving major (`v1`) and minor (`v1.2`) tags to same commit
as the latest `v1.x.x` tag.
@@ -35,19 +23,50 @@ to move its own major and minor tags.
### Basic
```yaml
- uses: jimeh/update-tags-action@v1
- uses: jimeh/update-tags-action@v2
with:
tags: v1,v1.2
```
```yaml
- uses: jimeh/update-tags-action@v1
- uses: jimeh/update-tags-action@v2
with:
tags: |
v1
v1.2
```
### Deriving Tags from Version
Automatically derive major and minor tags from a semver version string:
```yaml
- uses: jimeh/update-tags-action@v2
with:
derive_from: v1.2.3
# Creates tags: v1, v1.2
```
With a custom template (major tag only):
```yaml
- uses: jimeh/update-tags-action@v2
with:
derive_from: v1.2.3
derive_from_template: '{{prefix}}{{major}}'
# Creates tag: v1
```
Combine derived tags with explicit tags:
```yaml
- uses: jimeh/update-tags-action@v2
with:
derive_from: v1.2.3
tags: latest
# Creates tags: latest, v1, v1.2
```
### With Release Please
This example uses
@@ -56,45 +75,215 @@ but you can just as easily use the official
[google-github-actions/release-please-action](https://github.com/google-github-actions/release-please-action)
instead.
```yaml
name: Push
on: push
First you'll want the workflow setup to run on push:
jobs:
release-please:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- uses: jimeh/release-please-manifest-action@v1
id: release-please
- uses: jimeh/update-tags-action@v1
with:
tags: |
v${{ steps.release-please.outputs.major }}
v${{ steps.release-please.outputs.major }}.${{ steps.release-please.outputs.minor }}
```yaml
on: [push]
```
<!-- action-docs-inputs -->
Then you'll want a release-please job which only runs on pushes to your `main`
branch, and exposes relevant outputs from release please:
```yaml
jobs:
# [...]
release-please:
runs-on: ubuntu-latest
if: ${{ github.ref == 'refs/heads/main' }}
outputs:
release_created: ${{ steps.release-please.outputs.release_created }}
tag_name: ${{ steps.release-please.outputs.tag_name }}
permissions:
contents: write
issues: write
pull-requests: write
steps:
- uses: jimeh/release-please-manifest-action@v3
id: release-please
```
And finally a job to create MAJOR and MINOR release tags, which only runs when
release-please reports having created a release:
```yaml
jobs:
# [...]
release-tags:
runs-on: ubuntu-latest
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
permissions:
contents: write
steps:
- uses: jimeh/update-tags-action@v2
with:
derive_from: ${{ needs.release-please.outputs.tag_name }}
# Creates tags: v1, v1.2 (for tag_name v1.2.3)
```
<!-- action-docs-inputs source="action.yml" -->
## Inputs
| parameter | description | required | default |
| ------------ | --------------------------------------------------------------------------------- | -------- | ------------------- |
| tags | List/CSV of tags to create/update. | `true` | |
| ref | The SHA or ref to tag. Defaults to SHA of current commit. | `false` | ${{ github.sha }} |
| when_exists | What to do if the tag already exists. Must be one of 'update', 'skip', or 'fail'. | `false` | update |
| github_token | The GitHub token to use for authentication. | `false` | ${{ github.token }} |
| name | description | required | default |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | --------------------------------------------------- |
| `tags` | <p>List/CSV of tags to create/update. Supports per-tag ref and annotation overrides using the format 'tag:ref:annotation'. Use 'tag::annotation' to specify an annotation with the default ref.</p> | `false` | `""` |
| `derive_from` | <p>Semver version string to derive tags from (e.g., 'v1.2.3'). When provided, generates tags using <code>derive_from_template</code> input. Default template will produce major and minor tags. (e.g., 'v1', 'v1.2')</p> | `false` | `""` |
| `derive_from_template` | <p>Handlebars template for deriving tags from the <code>derive_from</code> input. Uses the same format as the <code>tags</code> input, and supports the following handlebars placeholders: <code>{{prefix}}</code>, <code>{{major}}</code>, <code>{{minor}}</code>, <code>{{patch}}</code>, <code>{{prerelease}}</code>, <code>{{build}}</code>, <code>{{version}}</code>.</p> | `false` | `{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}` |
| `ref` | <p>The SHA or ref to tag. Defaults to SHA of current commit.</p> | `false` | `${{ github.sha }}` |
| `when_exists` | <p>What to do if the tag already exists. Must be one of 'update', 'skip', or 'fail'.</p> | `false` | `update` |
| `annotation` | <p>Optional default annotation message for tags. If provided, creates annotated tags. If empty, creates lightweight tags. Can be overridden per-tag using the 'tag:ref:annotation' syntax in the tags input.</p> | `false` | `""` |
| `dry_run` | <p>If true, logs planned operations without executing them.</p> | `false` | `false` |
| `github_token` | <p>The GitHub token to use for authentication.</p> | `false` | `${{ github.token }}` |
<!-- action-docs-inputs -->
<!-- action-docs-inputs source="action.yml" -->
<!-- action-docs-outputs -->
### Tag Input Syntax
The `tags` input accepts a comma or newline-delimited list of tags. Each tag
specification supports optional per-tag ref and annotation overrides using the
format:
```
tag[:ref[:annotation]]
```
| Format | Description |
| -------------------- | ----------------------------------------------- |
| `tag` | Tag using default `ref` and `annotation` inputs |
| `tag:ref` | Tag using specified ref, default annotation |
| `tag:ref:annotation` | Tag using specified ref and annotation |
| `tag::annotation` | Tag using default ref with specified annotation |
**Per-tag refs** allow different tags to point to different commits:
```yaml
- uses: jimeh/update-tags-action@v2
with:
tags: |
v1:main
v2:develop
```
**Per-tag annotations** allow different annotation messages for each tag:
```yaml
- uses: jimeh/update-tags-action@v2
with:
tags: |
v1:main:Latest v1.x release
v1.2:main:Latest v1.2.x release
```
Use `tag::annotation` to specify an annotation while using the default ref:
```yaml
- uses: jimeh/update-tags-action@v2
with:
tags: |
v1::This is the v1 tag annotation
v1.2::This is the v1.2 tag annotation
```
Per-tag values override the global `ref` and `annotation` inputs:
```yaml
- uses: jimeh/update-tags-action@v2
with:
tags: |
v1:main:Custom annotation for v1
v2
ref: develop
annotation: Default annotation for tags without per-tag override
# v1 -> main with "Custom annotation for v1"
# v2 -> develop with "Default annotation..."
```
Annotations can contain colons (everything after the second colon is the
annotation):
```yaml
- uses: jimeh/update-tags-action@v2
with:
tags: |
v1:main:Release: version 1.0.0
# Annotation will be "Release: version 1.0.0"
```
### Derive Template Syntax
The `derive_from_template` input uses [Handlebars](https://handlebarsjs.com/)
for template rendering. Splitting the template into separate tags by comma or
newline is done after the template is rendered.
Available placeholders:
| Placeholder | Description |
| ---------------- | ----------------------------------------------------- |
| `{{prefix}}` | `v` or `V` if input had a prefix, empty otherwise |
| `{{major}}` | Major version number |
| `{{minor}}` | Minor version number |
| `{{patch}}` | Patch version number |
| `{{prerelease}}` | Prerelease identifier (e.g., `beta.1`), empty if none |
| `{{build}}` | Build metadata (e.g., `build.123`), empty if none |
| `{{version}}` | Full version string without prefix |
#### Conditional Sections
Use Handlebars `{{#if}}` blocks to include content only when a variable has a
value. This is useful for optional components like prerelease or build metadata:
```yaml
- uses: jimeh/update-tags-action@v2
with:
derive_from: v1.2.3-beta.1
derive_from_template: |
{{prefix}}{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}
# Creates tag: v1-beta.1
```
For a stable release without prerelease:
```yaml
- uses: jimeh/update-tags-action@v2
with:
derive_from: v1.2.3
derive_from_template: |
{{prefix}}{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}
# Creates tag: v1 (prerelease section omitted)
```
You can also use `{{#unless}}` for inverse logic:
```yaml
- uses: jimeh/update-tags-action@v2
with:
derive_from: v1.2.3
derive_from_template: |
{{prefix}}{{major}}{{#unless prerelease}}-stable{{/unless}}
# Creates tag: v1-stable (only for non-prerelease versions)
```
<!-- action-docs-outputs source="action.yml" -->
## Outputs
| parameter | description |
| --------- | --------------------------------------- |
| tags | List of tags that were created/updated. |
| created | List of tags that were created. |
| updated | List of tags that were updated. |
| name | description |
| --------- | ---------------------------------------------- |
| `tags` | <p>List of tags that were created/updated.</p> |
| `created` | <p>List of tags that were created.</p> |
| `updated` | <p>List of tags that were updated.</p> |
| `skipped` | <p>List of tags that were skipped.</p> |
<!-- action-docs-outputs -->
<!-- action-docs-outputs source="action.yml" -->
<!-- action-docs-runs source="action.yml" -->
## Runs
This action is a `node24` action.
<!-- action-docs-runs source="action.yml" -->
## License
[MIT](https://github.com/jimeh/update-tags-action/blob/main/LICENSE)

View File

@@ -8,8 +8,25 @@ branding:
inputs:
tags:
description: "List/CSV of tags to create/update."
required: true
description: >-
List/CSV of tags to create/update. Supports per-tag ref and annotation
overrides using the format 'tag:ref:annotation'. Use 'tag::annotation' to
specify an annotation with the default ref.
required: false
derive_from:
description: >-
Semver version string to derive tags from (e.g., 'v1.2.3'). When provided,
generates tags using `derive_from_template` input. Default template will
produce major and minor tags. (e.g., 'v1', 'v1.2')
required: false
derive_from_template:
description: >-
Handlebars template for deriving tags from the `derive_from` input. Uses
the same format as the `tags` input, and supports the following handlebars
placeholders: `{{prefix}}`, `{{major}}`, `{{minor}}`, `{{patch}}`,
`{{prerelease}}`, `{{build}}`, `{{version}}`.
required: false
default: "{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}"
ref:
description: "The SHA or ref to tag. Defaults to SHA of current commit."
required: false
@@ -20,6 +37,18 @@ inputs:
'fail'.
required: false
default: "update"
annotation:
description: >-
Optional default annotation message for tags. If provided, creates
annotated tags. If empty, creates lightweight tags. Can be overridden
per-tag using the 'tag:ref:annotation' syntax in the tags input.
required: false
default: ""
dry_run:
description: >-
If true, logs planned operations without executing them.
required: false
default: "false"
github_token:
description: "The GitHub token to use for authentication."
required: false
@@ -32,7 +61,9 @@ outputs:
description: "List of tags that were created."
updated:
description: "List of tags that were updated."
skipped:
description: "List of tags that were skipped."
runs:
using: "node16"
main: "dist/index.js"
using: node24
main: dist/index.js

1
badges/coverage.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="106" height="20" role="img" aria-label="Coverage: 100%"><title>Coverage: 100%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="106" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="43" height="20" fill="#4c1"/><rect width="106" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="835" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">100%</text><text x="835" y="140" transform="scale(.1)" fill="#fff" textLength="330">100%</text></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

16
bin/licensed Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'licensed' is installed as part of a gem, and
# this file is here to facilitate running it.
#
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
require "rubygems"
require "bundler/setup"
load Gem.bin_path("licensed", "licensed")

45026
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

660
dist/licenses.txt generated vendored
View File

@@ -1,660 +0,0 @@
@actions/core
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/github
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/http-client
MIT
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/auth-token
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/core
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/endpoint
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/graphql
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/plugin-paginate-rest
MIT
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/plugin-rest-endpoint-methods
MIT
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/request
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/request-error
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@vercel/ncc
MIT
Copyright 2018 ZEIT, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
before-after-hook
Apache-2.0
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Gregor Martynus and other contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
csv-parse
MIT
The MIT License (MIT)
Copyright (c) 2010 Adaltas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
deprecation
ISC
The ISC License
Copyright (c) Gregor Martynus and contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
is-plain-object
MIT
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
node-fetch
MIT
The MIT License (MIT)
Copyright (c) 2016 David Frank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
once
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
tr46
MIT
tunnel
MIT
The MIT License (MIT)
Copyright (c) 2012 Koichi Kobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
universal-user-agent
ISC
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
uuid
MIT
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
webidl-conversions
BSD-2-Clause
# The BSD 2-Clause License
Copyright (c) 2014, Domenic Denicola
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
whatwg-url
MIT
The MIT License (MIT)
Copyright (c) 20152016 Sebastian Mayr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
wrappy
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

1
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

81
eslint.config.mjs Normal file
View File

@@ -0,0 +1,81 @@
// See: https://eslint.org/docs/latest/use/configure/configuration-files
import { fixupPluginRules } from '@eslint/compat'
import { FlatCompat } from '@eslint/eslintrc'
import js from '@eslint/js'
import typescriptEslint from '@typescript-eslint/eslint-plugin'
import tsParser from '@typescript-eslint/parser'
import _import from 'eslint-plugin-import'
import jest from 'eslint-plugin-jest'
import prettier from 'eslint-plugin-prettier'
import globals from 'globals'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
})
export default [
{
ignores: ['**/coverage', '**/dist', '**/linter', '**/node_modules']
},
...compat.extends(
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:jest/recommended',
'plugin:prettier/recommended'
),
{
plugins: {
import: fixupPluginRules(_import),
jest,
prettier,
'@typescript-eslint': typescriptEslint
},
languageOptions: {
globals: {
...globals.node,
...globals.jest,
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parser: tsParser,
ecmaVersion: 2023,
sourceType: 'module',
parserOptions: {
project: ['tsconfig.eslint.json'],
tsconfigRootDir: __dirname
}
},
settings: {
'import/resolver': {
typescript: {
alwaysTryTypes: true,
project: 'tsconfig.eslint.json'
}
}
},
rules: {
camelcase: 'off',
'eslint-comments/no-use': 'off',
'eslint-comments/no-unused-disable': 'off',
'i18n-text/no-en': 'off',
'import/no-namespace': 'off',
'no-console': 'off',
'no-shadow': 'off',
'no-unused-vars': 'off',
'prettier/prettier': 'error'
}
}
]

134
index.js
View File

@@ -1,134 +0,0 @@
const core = require("@actions/core");
const github = require("@actions/github");
const { parse } = require("csv-parse/sync");
async function run() {
try {
const tagsInput = core.getInput("tags", { required: true });
const defaultRef = core.getInput("ref");
const token = core.getInput("github_token", { required: true });
const whenExists = core.getInput("when_exists") || "update";
const octokit = github.getOctokit(token);
const parsedTags = parse(tagsInput, {
delimiter: ",",
trim: true,
relax_column_count: true,
}).flat();
const { owner, repo } = github.context.repo;
const uniqueRefs = new Set();
const refToSha = {};
const tags = {};
for (const tag of parsedTags) {
const [t, tagRef] = tag.split(":").map((s) => s.trim());
const ref = tagRef || defaultRef;
tags[t] = ref;
uniqueRefs.add(ref);
}
// Pre-resolve all unique refs
for (const ref of uniqueRefs) {
refToSha[ref] = await resolveRefToSha(octokit, owner, repo, ref);
}
const created = [];
const updated = [];
// Create or update all tags by looping through tags
for (const tagName in tags) {
if (!tagName) {
core.setFailed(`Invalid tag: '${tagName}'`);
return;
}
const tagRef = tags[tagName];
const sha = refToSha[tagRef];
try {
// Check if the ref exists
const existing = await octokit.rest.git.getRef({
owner,
repo,
ref: `tags/${tagName}`,
});
// If the ref exists, decide action based on 'when_exists'
if (whenExists === "update") {
const existingSHA = existing.data.object.sha;
if (existingSHA === sha) {
core.info(
`Tag '${tagName}' already exists with desired SHA ${sha}.`
);
continue;
}
core.info(
`Tag '${tagName}' exists, updating to SHA ${sha} ` +
`(was ${existingSHA}).`
);
await octokit.rest.git.updateRef({
owner,
repo,
ref: `tags/${tagName}`,
sha,
force: true,
});
updated.push(tagName);
} else if (whenExists === "skip") {
core.info(`Tag '${tagName}' exists, skipping.`);
} else if (whenExists === "fail") {
core.setFailed(`Tag '${tagName}' already exists.`);
return;
} else {
core.setFailed(
`Invalid value for 'when_exists': '${whenExists}'. ` +
`Valid values are 'update', 'skip', and 'fail'.`
);
return;
}
} catch (error) {
if (error.status !== 404) {
throw error;
}
// If the ref doesn't exist, create it
core.info(`Tag '${tagName}' does not exist, creating with SHA ${sha}.`);
await octokit.rest.git.createRef({
owner,
repo,
ref: `refs/tags/${tagName}`,
sha,
});
created.push(tagName);
}
}
core.setOutput("created", created);
core.setOutput("updated", updated);
core.setOutput("tags", created.concat(updated));
} catch (error) {
core.setFailed(`Action failed with error: ${error}`);
}
}
async function resolveRefToSha(octokit, owner, repo, ref) {
try {
const {
data: { sha },
} = await octokit.rest.repos.getCommit({
owner,
repo,
ref,
});
return sha;
} catch (error) {
core.setFailed(`Failed to resolve ref '${ref}' to a SHA: ${error}`);
}
}
run();

40
jest.config.js Normal file
View File

@@ -0,0 +1,40 @@
// See: https://jestjs.io/docs/configuration
/** @type {import('ts-jest').JestConfigWithTsJest} **/
export default {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: ['./src/**', '!./src/index.ts'],
coverageDirectory: './coverage',
coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
coverageReporters: ['json-summary', 'text', 'lcov'],
// Uncomment the below lines if you would like to enforce a coverage threshold
// for your action. This will fail the build if the coverage is below the
// specified thresholds.
// coverageThreshold: {
// global: {
// branches: 100,
// functions: 100,
// lines: 100,
// statements: 100
// }
// },
extensionsToTreatAsEsm: ['.ts'],
moduleFileExtensions: ['ts', 'js'],
preset: 'ts-jest',
reporters: ['default'],
resolver: 'ts-jest-resolver',
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testPathIgnorePatterns: ['/dist/', '/node_modules/'],
transform: {
'^.+\\.ts$': [
'ts-jest',
{
tsconfig: 'tsconfig.eslint.json',
useESM: true
}
]
},
verbose: true
}

13457
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,78 @@
{
"name": "update-tags-action",
"version": "0.0.1",
"main": "dist/index.js",
"scripts": {
"build": "npm run dist && npm run update-readme",
"dist": "ncc build index.js --source-map --minify --license licenses.txt",
"lint": "eslint *.js",
"format": "eslint --fix *.js",
"update-readme": "action-docs --update-readme && prettier -w README.md"
"version": "2.3.0",
"author": "jimeh",
"type": "module",
"private": true,
"homepage": "https://github.com/jimeh/update-tags-action",
"repository": {
"type": "git",
"url": "git+https://github.com/jimeh/update-tags-action.git"
},
"devDependencies": {
"@vercel/ncc": "^0.36.1",
"action-docs": "^1.2.0",
"csv-parse": "^5.3.10",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.8",
"ts-jest": "^29.1.0",
"typescript": "^5.0.4"
"bugs": {
"url": "https://github.com/jimeh/update-tags-action/issues"
},
"keywords": [
"actions",
"github",
"git",
"tags",
"update"
],
"exports": {
".": "./dist/index.js"
},
"engines": {
"node": ">=24.0.0"
},
"scripts": {
"all": "npx npm-run-all -s format:write lint test coverage update-readme package",
"bundle": "npx npm-run-all -s format:write package",
"coverage": "npx make-coverage-badge --output-path ./badges/coverage.svg",
"format:check": "npx prettier --check .",
"format:write": "npx prettier --write .",
"licensed:cache": "bin/licensed cache",
"licensed:status": "bin/licensed status",
"lint": "npx eslint .",
"package": "npx rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
"package:watch": "npm run package -- --watch",
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest",
"ci-test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest",
"update-readme": "npx action-docs --update-readme && npx prettier --write README.md"
},
"dependencies": {
"@actions/core": "^1.10.0",
"@actions/github": "^5.1.1"
"@actions/core": "^2.0.2",
"@actions/github": "^7.0.0",
"csv-parse": "^6.1.0",
"handlebars": "^4.7.8",
"semver": "^7.7.3"
},
"eslintConfig": {
"env": {
"node": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
],
"plugins": [
"prettier"
]
"devDependencies": {
"@eslint/compat": "^2.0.1",
"@jest/globals": "^30.2.0",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-node-resolve": "^16.0.3",
"@rollup/plugin-typescript": "^12.3.0",
"@types/jest": "^30.0.0",
"@types/node": "^25.0.9",
"@types/semver": "^7.7.1",
"@typescript-eslint/eslint-plugin": "^8.53.0",
"@typescript-eslint/parser": "^8.46.2",
"action-docs": "^2.5.1",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^29.12.1",
"eslint-plugin-prettier": "^5.5.5",
"jest": "^30.2.0",
"make-coverage-badge": "^1.2.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.8.0",
"prettier-eslint": "^16.4.2",
"rollup": "^4.55.1",
"ts-jest": "^29.4.6",
"ts-jest-resolver": "^2.0.1",
"typescript": "^5.9.3"
}
}

18
rollup.config.ts Normal file
View File

@@ -0,0 +1,18 @@
// See: https://rollupjs.org/introduction/
import commonjs from '@rollup/plugin-commonjs'
import nodeResolve from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript'
const config = {
input: 'src/index.ts',
output: {
esModule: true,
file: 'dist/index.js',
format: 'es',
sourcemap: true
},
plugins: [typescript(), nodeResolve({ preferBuiltins: true }), commonjs()]
}
export default config

105
src/derive.ts Normal file
View File

@@ -0,0 +1,105 @@
import { parse } from 'csv-parse/sync'
import Handlebars from 'handlebars'
import * as semver from 'semver'
/**
* Context containing parsed semver components for template rendering.
*/
export interface SemverContext {
/** "v" or "V" if input had a prefix, empty string otherwise */
prefix: string
/** Major version number */
major: number
/** Minor version number */
minor: number
/** Patch version number */
patch: number
/** Prerelease identifier (e.g., "beta.1"), empty if none */
prerelease: string
/** Build metadata (e.g., "build.123"), empty if none */
build: string
/** Full version string without prefix */
version: string
}
/**
* Parse a version string into semver components.
*
* @param input - Version string (e.g., "v1.2.3", "1.2.3-beta.1+build.456")
* @returns Parsed semver context
* @throws Error if the version string is not valid semver
*/
export function parseSemver(input: string): SemverContext {
const trimmed = input.trim()
if (!trimmed) {
throw new Error('Invalid semver: empty string')
}
// Check for v/V prefix and preserve original case
const firstChar = trimmed[0]
const hasPrefix = firstChar === 'v' || firstChar === 'V'
const prefix = hasPrefix ? firstChar : ''
const versionStr = hasPrefix ? trimmed.slice(1) : trimmed
// Parse with semver library
const parsed = semver.parse(versionStr)
if (!parsed) {
throw new Error(`Invalid semver: '${input}'`)
}
return {
prefix,
major: parsed.major,
minor: parsed.minor,
patch: parsed.patch,
prerelease: parsed.prerelease.join('.'),
build: parsed.build.join('.'),
version: parsed.version
}
}
/**
* Render a single template string with semver context using Handlebars.
* Supports {{#if variable}}...{{/if}} conditionals for optional sections.
*
* @param template - Handlebars template string
* @param ctx - Semver context for substitution
* @returns Rendered string
*/
export function renderTemplate(template: string, ctx: SemverContext): string {
const compiled = Handlebars.compile(template, { noEscape: true })
// Convert numbers to strings so 0 is truthy in conditionals
const stringCtx = {
...ctx,
major: String(ctx.major),
minor: String(ctx.minor),
patch: String(ctx.patch)
}
return compiled(stringCtx)
}
/**
* Derive tags from a semver version string using a template.
*
* @param deriveFrom - Semver version string (e.g., "v1.2.3")
* @param template - CSV/newline-delimited Handlebars template string
* @returns Array of derived tag strings
*/
export function deriveTags(deriveFrom: string, template: string): string[] {
const ctx = parseSemver(deriveFrom)
// Render template with Handlebars first, enabling conditional tag inclusion
const rendered = renderTemplate(template, ctx)
// Parse rendered result as CSV/newline delimited
const tags = (
parse(rendered, {
delimiter: ',',
trim: true,
relax_column_count: true
}) as string[][]
).flat()
// Exclude empty tags and tags that are just the prefix with no version data
return tags.filter((tag) => tag.length > 0 && tag !== ctx.prefix)
}

8
src/index.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* The entrypoint for the action. This file simply imports and runs the action's
* main logic.
*/
import { run } from './main.js'
/* istanbul ignore next */
void run()

97
src/inputs.ts Normal file
View File

@@ -0,0 +1,97 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import { parse } from 'csv-parse/sync'
import { deriveTags } from './derive.js'
const WHEN_EXISTS_MODES = ['update', 'skip', 'fail'] as const
export type WhenExistsMode = (typeof WHEN_EXISTS_MODES)[number]
export interface Inputs {
tags: string[]
defaultRef: string
whenExists: WhenExistsMode
annotation: string
dryRun: boolean
owner: string
repo: string
token: string
}
/**
* Validate when_exists input value.
*
* @param input - The when_exists input value to validate
* @returns The validated when_exists mode
*/
function validateWhenExists(input: string): WhenExistsMode {
if (!WHEN_EXISTS_MODES.includes(input as WhenExistsMode)) {
const validList = WHEN_EXISTS_MODES.map((m) => `'${m}'`).join(', ')
throw new Error(
`Invalid value for 'when_exists': '${input}'. ` +
`Valid values are ${validList}.`
)
}
return input as WhenExistsMode
}
const DEFAULT_DERIVE_FROM_TEMPLATE =
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}'
/**
* Get and validate action inputs.
*
* @returns Parsed and validated inputs
*/
export function getInputs(): Inputs {
const tagsInput: string = core.getInput('tags')
const deriveFrom: string = core.getInput('derive_from')
const deriveFromTemplate: string =
core.getInput('derive_from_template') || DEFAULT_DERIVE_FROM_TEMPLATE
const defaultRef: string = core.getInput('ref')
const whenExistsInput = core.getInput('when_exists') || 'update'
const whenExists = validateWhenExists(whenExistsInput)
const annotation: string = core.getInput('annotation')
const dryRun: boolean = core.getBooleanInput('dry_run')
const token: string = core.getInput('github_token', {
required: true
})
const { owner, repo } = github.context.repo
// Parse explicit tags as CSV/newline delimited strings
const explicitTags: string[] = tagsInput
? (
parse(tagsInput, {
delimiter: ',',
trim: true,
relax_column_count: true
}) as string[][]
).flat()
: []
// Derive tags from semver version string if provided
const derivedTags: string[] = deriveFrom
? deriveTags(deriveFrom, deriveFromTemplate)
: []
// Combine explicit and derived tags
const tags = [...explicitTags, ...derivedTags]
// Validate that at least one tag source is provided
if (tags.length === 0) {
throw new Error(
"No tags specified. Provide 'tags' input, 'derive_from' input, or both."
)
}
return {
tags,
defaultRef,
whenExists,
annotation,
dryRun,
owner,
repo,
token
}
}

47
src/logger.ts Normal file
View File

@@ -0,0 +1,47 @@
import * as core from '@actions/core'
import type { AnnotationProperties } from '@actions/core'
/**
* Logger interface that mirrors @actions/core logging functions.
*/
export interface Logger {
debug: (message: string) => void
info: (message: string) => void
notice: (message: string | Error, properties?: AnnotationProperties) => void
warning: (message: string | Error, properties?: AnnotationProperties) => void
error: (message: string | Error, properties?: AnnotationProperties) => void
}
/**
* Create a logger that optionally prefixes all messages.
*
* @param prefix - Optional prefix to prepend to all log messages
* @returns Logger instance with prefixed messages
*/
export function createLogger(prefix: string = ''): Logger {
const prefixMessage = (msg: string | Error): string | Error => {
if (!prefix) {
return msg
}
if (typeof msg === 'string') {
return `${prefix}${msg}`
}
// Wrap Error with prefixed message, preserving the original as cause
const wrapped = new Error(`${prefix}${msg.message}`, { cause: msg })
if (msg.stack) {
wrapped.stack = msg.stack
}
return wrapped
}
return {
debug: (message: string) => core.debug(`${prefix}${message}`),
info: (message: string) => core.info(`${prefix}${message}`),
notice: (message: string | Error, properties?: AnnotationProperties) =>
core.notice(prefixMessage(message), properties),
warning: (message: string | Error, properties?: AnnotationProperties) =>
core.warning(prefixMessage(message), properties),
error: (message: string | Error, properties?: AnnotationProperties) =>
core.error(prefixMessage(message), properties)
}
}

49
src/main.ts Normal file
View File

@@ -0,0 +1,49 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import { getInputs } from './inputs.js'
import { planTagOperations, executeTagOperation } from './tags.js'
/**
* The main function for the action.
*
* @returns Resolves when the action is complete.
*/
export async function run(): Promise<void> {
try {
const inputs = getInputs()
const octokit = github.getOctokit(inputs.token)
const operations = await planTagOperations(inputs, octokit)
if (inputs.dryRun) {
core.info('[dry-run] Dry-run mode enabled, no changes will be made.')
}
const created: string[] = []
const updated: string[] = []
const skipped: string[] = []
// Execute all planned operations.
for (const operation of operations) {
await executeTagOperation(operation, octokit, { dryRun: inputs.dryRun })
// Only track actual changes when not in dry-run mode
if (!inputs.dryRun) {
if (operation.operation === 'create') {
created.push(operation.name)
} else if (operation.operation === 'update') {
updated.push(operation.name)
} else if (operation.operation === 'skip') {
skipped.push(operation.name)
}
}
}
core.setOutput('created', created)
core.setOutput('updated', updated)
core.setOutput('skipped', skipped)
core.setOutput('tags', created.concat(updated))
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
core.setFailed(message)
}
}

497
src/tags.ts Normal file
View File

@@ -0,0 +1,497 @@
import * as github from '@actions/github'
import type { Inputs } from './inputs.js'
import { createLogger, type Logger } from './logger.js'
export interface ExistingTagInfo {
commitSHA: string
isAnnotated: boolean
annotation?: string
}
interface BaseOperation {
name: string
ref: string
sha: string
owner: string
repo: string
}
export interface CreateOperation extends BaseOperation {
operation: 'create'
annotation: string
}
export interface UpdateOperation extends BaseOperation {
operation: 'update'
annotation: string
existingSHA: string
existingIsAnnotated: boolean
reasons: string[]
}
export interface SkipOperation extends BaseOperation {
operation: 'skip'
existingIsAnnotated: boolean
reason: 'when_exists_skip' | 'already_matches'
}
export type TagOperation = CreateOperation | UpdateOperation | SkipOperation
export interface ExecuteOptions {
dryRun?: boolean
}
interface ReadContext {
owner: string
repo: string
octokit: ReturnType<typeof github.getOctokit>
}
interface Context extends ReadContext {
dryRun: boolean
log: Logger
}
/**
* Plan tag operations based on inputs.
*
* @param inputs - The validated inputs containing tags, refs, and configuration
* @param octokit - The GitHub API client
* @returns Array of planned tag operations (create, update, or skip)
*/
export async function planTagOperations(
inputs: Inputs,
octokit: ReturnType<typeof github.getOctokit>
): Promise<TagOperation[]> {
const uniqueRefs = new Set<string>()
const tagRefs: Record<string, string> = {}
const tagAnnotations: Record<string, string> = {}
for (const tag of inputs.tags) {
const parts = tag.split(':')
const tagName = (parts[0] || '').trim()
const tagRef = (parts[1] || '').trim()
// Join remaining parts back with colons to preserve annotation content
const tagAnnotation = parts.slice(2).join(':').trim()
if (!tagName) {
// Skip completely empty tags, but fail on invalid ones like ":main"
if (tagRef || tagAnnotation) {
throw new Error(`Invalid tag: '${tag}'`)
}
continue
}
const ref = tagRef || inputs.defaultRef
if (!ref) {
throw new Error("Missing ref: provide 'ref' input or specify per-tag ref")
}
// Check for duplicate tag with different ref
if (tagRefs[tagName] && tagRefs[tagName] !== ref) {
throw new Error(
`Duplicate tag '${tagName}' with different refs: ` +
`'${tagRefs[tagName]}' and '${ref}'`
)
}
tagRefs[tagName] = ref
if (tagAnnotation) {
tagAnnotations[tagName] = tagAnnotation
}
uniqueRefs.add(ref)
}
// Pre-resolve all unique refs in parallel.
const ctx: ReadContext = { owner: inputs.owner, repo: inputs.repo, octokit }
const refSHAs: Record<string, string> = {}
await Promise.all(
Array.from(uniqueRefs).map(async (ref) => {
refSHAs[ref] = await resolveRefToSha(ctx, ref)
})
)
// Build result array with planned operations
const tagNames = Object.keys(tagRefs)
const result: TagOperation[] = await Promise.all(
tagNames.map(async (tagName) => {
const tagRef = tagRefs[tagName]
const sha = refSHAs[tagRef]
const annotation = tagAnnotations[tagName] || inputs.annotation
// Check if tag already exists
let existing: ExistingTagInfo | undefined
try {
existing = await fetchTagInfo(ctx, tagName)
// Fail early if when_exists is 'fail'
if (inputs.whenExists === 'fail') {
throw new Error(`Tag '${tagName}' already exists.`)
}
} catch (error: unknown) {
// Check if it's a GitHub API error with a status property
if (typeof error === 'object' && error !== null && 'status' in error) {
const apiError = error as { status: number; message?: string }
if (apiError.status === 404) {
// Tag doesn't exist, existing remains undefined
} else {
// Some other API error
throw new Error(
`Failed to check if tag '${tagName}' exists: ${apiError.message || String(error)}`
)
}
} else {
throw error
}
}
const baseOp = {
name: tagName,
ref: tagRef,
sha,
owner: inputs.owner,
repo: inputs.repo
}
// Tag doesn't exist - plan creation
if (!existing) {
return {
...baseOp,
operation: 'create',
annotation
} as CreateOperation
}
// Tag exists - determine operation based on mode and state
if (inputs.whenExists === 'skip') {
return {
...baseOp,
operation: 'skip',
existingIsAnnotated: existing.isAnnotated,
reason: 'when_exists_skip'
} as SkipOperation
}
// whenExists === 'update' - check if update is needed
const { commitMatches, annotationMatches } = compareTagState(
sha,
annotation,
existing
)
if (commitMatches && annotationMatches) {
return {
...baseOp,
operation: 'skip',
existingIsAnnotated: existing.isAnnotated,
reason: 'already_matches'
} as SkipOperation
}
// Plan update with reasons
const reasons = getUpdateReasons(sha, annotation, existing)
return {
...baseOp,
operation: 'update',
annotation,
existingSHA: existing.commitSHA,
existingIsAnnotated: existing.isAnnotated,
reasons
} as UpdateOperation
})
)
return result
}
/**
* Execute a planned tag operation.
*
* @param operation - The planned tag operation to execute
* @param octokit - GitHub API client
* @param options - Execution options (e.g., dryRun)
*/
export async function executeTagOperation(
operation: TagOperation,
octokit: ReturnType<typeof github.getOctokit>,
options: ExecuteOptions = {}
): Promise<void> {
const dryRun = options.dryRun ?? false
const ctx: Context = {
owner: operation.owner,
repo: operation.repo,
octokit,
dryRun,
log: createLogger(dryRun ? '[dry-run] ' : '')
}
if (operation.operation === 'skip') {
logSkipOperation(ctx, operation)
return
}
if (operation.operation === 'create') {
await createTag(ctx, operation)
return
}
if (operation.operation === 'update') {
await updateExistingTag(ctx, operation)
return
}
throw new Error(
`Unknown operation type: ${(operation as TagOperation).operation}`
)
}
/**
* Log a skip operation.
*/
function logSkipOperation(ctx: Context, operation: SkipOperation): void {
if (operation.reason === 'when_exists_skip') {
ctx.log.info(`Tag '${operation.name}' exists, skipping.`)
} else {
ctx.log.info(
`Tag '${operation.name}' already exists with desired ` +
`commit SHA ${operation.sha}` +
(operation.existingIsAnnotated ? ' (annotated).' : '.')
)
}
}
/**
* Fetch information about an existing tag, dereferencing if annotated.
*
* @param ctx - Read-only operation context
* @param tagName - The name of the tag to fetch
* @returns Information about the existing tag
*/
async function fetchTagInfo(
ctx: ReadContext,
tagName: string
): Promise<ExistingTagInfo> {
const ref = await ctx.octokit.rest.git.getRef({
owner: ctx.owner,
repo: ctx.repo,
ref: `tags/${tagName}`
})
const object = ref.data.object
const isAnnotated = object.type === 'tag'
if (!isAnnotated) {
return {
commitSHA: object.sha,
isAnnotated: false
}
}
// Dereference annotated tag to get underlying commit
const tagRef = await ctx.octokit.rest.git.getTag({
owner: ctx.owner,
repo: ctx.repo,
tag_sha: object.sha
})
return {
commitSHA: tagRef.data.object.sha,
isAnnotated: true,
annotation: tagRef.data.message
}
}
/**
* Resolve a ref to a SHA.
*
* @param ctx - Read-only operation context
* @param ref - The ref to resolve
* @returns The SHA
*/
async function resolveRefToSha(ctx: ReadContext, ref: string): Promise<string> {
try {
const {
data: { sha }
} = await ctx.octokit.rest.repos.getCommit({
owner: ctx.owner,
repo: ctx.repo,
ref
})
return sha
} catch (error) {
throw new Error(`Failed to resolve ref '${ref}' to a SHA: ${String(error)}`)
}
}
/**
* Update an existing tag to point to a new commit and/or annotation.
*/
async function updateExistingTag(
ctx: Context,
operation: UpdateOperation
): Promise<void> {
const commitMatches = operation.existingSHA === operation.sha
const verb = ctx.dryRun ? 'Would update' : 'Updating'
if (commitMatches) {
ctx.log.info(
`${verb} tag '${operation.name}', ${operation.reasons.join(', ')}.`
)
} else {
ctx.log.info(
`${verb} tag '${operation.name}'` +
`${operation.existingIsAnnotated ? ' (annotated)' : ''} ` +
`to ${operation.reasons.join(', ')}.`
)
}
if (ctx.dryRun) {
return
}
const targetSha = await resolveTargetSHA(
ctx,
operation.name,
operation.sha,
operation.annotation
)
await ctx.octokit.rest.git.updateRef({
owner: ctx.owner,
repo: ctx.repo,
ref: `tags/${operation.name}`,
sha: targetSha,
force: true
})
}
/**
* Create a tag (doesn't exist yet).
*/
async function createTag(
ctx: Context,
operation: CreateOperation
): Promise<void> {
const verb = ctx.dryRun ? 'Would create' : 'Creating'
ctx.log.info(
`${verb} tag '${operation.name}' at commit SHA ${operation.sha}` +
(operation.annotation ? ' (annotated).' : '.')
)
if (ctx.dryRun) {
return
}
const targetSha = await resolveTargetSHA(
ctx,
operation.name,
operation.sha,
operation.annotation
)
await ctx.octokit.rest.git.createRef({
owner: ctx.owner,
repo: ctx.repo,
ref: `refs/tags/${operation.name}`,
sha: targetSha
})
}
/**
* Resolve the target SHA for a tag (creates annotated tag object if needed).
*
* @param ctx - Read-only operation context
* @param tagName - The tag name
* @param commitSha - The commit SHA
* @param annotation - The annotation message (if any)
* @returns The SHA to use (tag object SHA if annotated, commit SHA otherwise)
*/
async function resolveTargetSHA(
ctx: ReadContext,
tagName: string,
commitSha: string,
annotation: string
): Promise<string> {
if (!annotation) {
return commitSha
}
const tagObject = await ctx.octokit.rest.git.createTag({
owner: ctx.owner,
repo: ctx.repo,
tag: tagName,
message: annotation,
object: commitSha,
type: 'commit'
})
return tagObject.data.sha
}
/**
* Compare existing tag state with desired target state.
*
* @param sha - The desired commit SHA
* @param annotation - The desired annotation
* @param existing - Information about the existing tag
* @returns Object indicating whether commit and annotation match
*/
function compareTagState(
sha: string,
annotation: string,
existing: ExistingTagInfo
): {
commitMatches: boolean
annotationMatches: boolean
} {
const isAnnotated = existing.isAnnotated === true
const commitMatches = existing.commitSHA === sha
const annotationMatches =
(isAnnotated && !!annotation && existing.annotation === annotation) ||
(!isAnnotated && !annotation) ||
false
return { commitMatches, annotationMatches }
}
/**
* Get update reason messages based on what changed.
*
* @param sha - The desired commit SHA
* @param annotation - The desired annotation
* @param existing - Information about the existing tag
* @returns Array of reason strings
*/
function getUpdateReasons(
sha: string,
annotation: string,
existing: ExistingTagInfo
): string[] {
const { commitMatches, annotationMatches } = compareTagState(
sha,
annotation,
existing
)
const reasons: string[] = []
if (!commitMatches) {
reasons.push(`commit SHA ${sha} (was ${existing.commitSHA})`)
}
if (!annotationMatches && annotation) {
if (existing.isAnnotated === true) {
reasons.push('annotation message changed')
} else {
reasons.push('adding annotation')
}
} else if (
!annotationMatches &&
!annotation &&
existing.isAnnotated === true
) {
reasons.push('removing annotation')
}
return reasons
}

420
tests/derive.test.ts Normal file
View File

@@ -0,0 +1,420 @@
/**
* Unit tests for the derive module, src/derive.ts
*/
import { parseSemver, renderTemplate, deriveTags } from '../src/derive.js'
describe('parseSemver', () => {
it('parses simple version without prefix', () => {
const result = parseSemver('1.2.3')
expect(result).toEqual({
prefix: '',
major: 1,
minor: 2,
patch: 3,
prerelease: '',
build: '',
version: '1.2.3'
})
})
it('parses version with v prefix', () => {
const result = parseSemver('v1.2.3')
expect(result).toEqual({
prefix: 'v',
major: 1,
minor: 2,
patch: 3,
prerelease: '',
build: '',
version: '1.2.3'
})
})
it('parses version with uppercase V prefix', () => {
const result = parseSemver('V1.2.3')
expect(result).toEqual({
prefix: 'V',
major: 1,
minor: 2,
patch: 3,
prerelease: '',
build: '',
version: '1.2.3'
})
})
it('parses version with prerelease', () => {
const result = parseSemver('v1.0.0-beta.1')
expect(result).toEqual({
prefix: 'v',
major: 1,
minor: 0,
patch: 0,
prerelease: 'beta.1',
build: '',
version: '1.0.0-beta.1'
})
})
it('parses version with build metadata', () => {
const result = parseSemver('v1.0.0+build.456')
expect(result).toEqual({
prefix: 'v',
major: 1,
minor: 0,
patch: 0,
prerelease: '',
build: 'build.456',
version: '1.0.0'
})
})
it('parses version with both prerelease and build metadata', () => {
const result = parseSemver('v1.2.3-alpha.1+build.789')
expect(result).toEqual({
prefix: 'v',
major: 1,
minor: 2,
patch: 3,
prerelease: 'alpha.1',
build: 'build.789',
version: '1.2.3-alpha.1'
})
})
it('handles whitespace around version string', () => {
const result = parseSemver(' v1.2.3 ')
expect(result).toEqual({
prefix: 'v',
major: 1,
minor: 2,
patch: 3,
prerelease: '',
build: '',
version: '1.2.3'
})
})
it('throws on empty string', () => {
expect(() => parseSemver('')).toThrow('Invalid semver: empty string')
})
it('throws on whitespace only', () => {
expect(() => parseSemver(' ')).toThrow('Invalid semver: empty string')
})
it('throws on invalid semver', () => {
expect(() => parseSemver('not-a-version')).toThrow(
"Invalid semver: 'not-a-version'"
)
})
it('throws on incomplete version', () => {
expect(() => parseSemver('v1.2')).toThrow("Invalid semver: 'v1.2'")
})
})
describe('renderTemplate', () => {
const ctx = {
prefix: 'v',
major: 1,
minor: 2,
patch: 3,
prerelease: 'beta.1',
build: 'build.456',
version: '1.2.3-beta.1'
}
it('renders prefix placeholder', () => {
expect(renderTemplate('{{prefix}}', ctx)).toBe('v')
})
it('renders major placeholder', () => {
expect(renderTemplate('{{major}}', ctx)).toBe('1')
})
it('renders minor placeholder', () => {
expect(renderTemplate('{{minor}}', ctx)).toBe('2')
})
it('renders patch placeholder', () => {
expect(renderTemplate('{{patch}}', ctx)).toBe('3')
})
it('renders prerelease placeholder', () => {
expect(renderTemplate('{{prerelease}}', ctx)).toBe('beta.1')
})
it('renders build placeholder', () => {
expect(renderTemplate('{{build}}', ctx)).toBe('build.456')
})
it('renders version placeholder', () => {
expect(renderTemplate('{{version}}', ctx)).toBe('1.2.3-beta.1')
})
it('renders multiple placeholders', () => {
expect(renderTemplate('{{prefix}}{{major}}.{{minor}}', ctx)).toBe('v1.2')
})
it('renders same placeholder multiple times', () => {
expect(renderTemplate('{{major}}-{{major}}', ctx)).toBe('1-1')
})
it('preserves text without placeholders', () => {
expect(renderTemplate('latest', ctx)).toBe('latest')
})
it('handles empty prefix', () => {
const noPrefix = { ...ctx, prefix: '' }
expect(renderTemplate('{{prefix}}{{major}}', noPrefix)).toBe('1')
})
it('handles empty prerelease', () => {
const noPrerelease = { ...ctx, prerelease: '' }
expect(renderTemplate('{{major}}-{{prerelease}}', noPrerelease)).toBe('1-')
})
describe('Handlebars conditionals', () => {
it('renders {{#if}} section when variable has value', () => {
expect(
renderTemplate('{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}', ctx)
).toBe('1-beta.1')
})
it('omits {{#if}} section when variable is empty', () => {
const noPrerelease = { ...ctx, prerelease: '' }
expect(
renderTemplate(
'{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}',
noPrerelease
)
).toBe('1')
})
it('handles {{#if}} with zero-valued numbers (converted to strings)', () => {
const zeroMinor = { ...ctx, minor: 0 }
expect(
renderTemplate('{{major}}{{#if minor}}.{{minor}}{{/if}}', zeroMinor)
).toBe('1.0')
})
it('handles nested conditionals', () => {
expect(
renderTemplate(
'{{major}}{{#if prerelease}}-{{prerelease}}{{#if build}}+{{build}}{{/if}}{{/if}}',
ctx
)
).toBe('1-beta.1+build.456')
})
it('handles nested conditionals with inner empty', () => {
const noBuild = { ...ctx, build: '' }
expect(
renderTemplate(
'{{major}}{{#if prerelease}}-{{prerelease}}{{#if build}}+{{build}}{{/if}}{{/if}}',
noBuild
)
).toBe('1-beta.1')
})
it('handles {{#unless}} for inverse logic', () => {
const noPrerelease = { ...ctx, prerelease: '' }
expect(
renderTemplate('{{major}}{{#unless prerelease}}-stable{{/unless}}', ctx)
).toBe('1')
expect(
renderTemplate(
'{{major}}{{#unless prerelease}}-stable{{/unless}}',
noPrerelease
)
).toBe('1-stable')
})
it('handles multiple {{#if}} sections', () => {
const noBuild = { ...ctx, build: '' }
expect(
renderTemplate(
'{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}{{#if build}}+{{build}}{{/if}}',
noBuild
)
).toBe('1-beta.1')
})
})
})
describe('deriveTags', () => {
it('generates tags with default-style template', () => {
const result = deriveTags(
'v1.2.3',
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}'
)
expect(result).toEqual(['v1', 'v1.2'])
})
it('generates single tag from simple template', () => {
const result = deriveTags('v1.2.3', '{{prefix}}{{major}}')
expect(result).toEqual(['v1'])
})
it('handles version without prefix', () => {
const result = deriveTags(
'1.2.3',
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}'
)
expect(result).toEqual(['1', '1.2'])
})
it('handles prerelease in template', () => {
const result = deriveTags(
'v1.0.0-rc.1',
'{{prefix}}{{major}}-{{prerelease}}'
)
expect(result).toEqual(['v1-rc.1'])
})
it('filters empty tags and prefix-only tags from result', () => {
const result = deriveTags('v1.2.3', '{{prefix}}{{major}},,{{prefix}}')
expect(result).toEqual(['v1'])
})
it('trims whitespace around template parts', () => {
const result = deriveTags('v1.2.3', ' {{prefix}}{{major}} , latest ')
expect(result).toEqual(['v1', 'latest'])
})
it('generates full version tag', () => {
const result = deriveTags('v1.2.3', '{{prefix}}{{version}}')
expect(result).toEqual(['v1.2.3'])
})
it('throws on invalid semver', () => {
expect(() => deriveTags('invalid', '{{major}}')).toThrow(
"Invalid semver: 'invalid'"
)
})
it('handles newline-delimited template', () => {
const result = deriveTags(
'v1.2.3',
'{{prefix}}{{major}}\n{{prefix}}{{major}}.{{minor}}'
)
expect(result).toEqual(['v1', 'v1.2'])
})
it('handles mixed newlines and commas in template', () => {
const result = deriveTags(
'v1.2.3',
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}\nlatest'
)
expect(result).toEqual(['v1', 'v1.2', 'latest'])
})
describe('with Handlebars conditionals', () => {
it('generates tag with optional prerelease when present', () => {
const result = deriveTags(
'v1.0.0-beta.1',
'{{prefix}}{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}'
)
expect(result).toEqual(['v1-beta.1'])
})
it('generates tag without prerelease section when absent', () => {
const result = deriveTags(
'v1.0.0',
'{{prefix}}{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}'
)
expect(result).toEqual(['v1'])
})
it('generates multiple tags with conditionals', () => {
const result = deriveTags(
'v1.2.3-rc.1',
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}{{#if prerelease}}-{{prerelease}}{{/if}}'
)
expect(result).toEqual(['v1', 'v1.2-rc.1'])
})
it('handles build metadata conditional', () => {
const result = deriveTags(
'v1.0.0+build.123',
'{{prefix}}{{major}}{{#if build}}+{{build}}{{/if}}'
)
expect(result).toEqual(['v1+build.123'])
})
it('handles both prerelease and build conditionals', () => {
const result = deriveTags(
'v1.0.0-alpha.1+build.789',
'{{prefix}}{{major}}{{#if prerelease}}-{{prerelease}}{{/if}}{{#if build}}+{{build}}{{/if}}'
)
expect(result).toEqual(['v1-alpha.1+build.789'])
})
})
describe('conditional tag inclusion', () => {
it('includes latest tag only for stable releases', () => {
// Stable release gets latest tag
const stable = deriveTags(
'v1.2.3',
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}{{#unless prerelease}},latest{{/unless}}'
)
expect(stable).toEqual(['v1', 'v1.2', 'latest'])
// Prerelease does not get latest tag
const prerelease = deriveTags(
'v1.2.3-beta.1',
'{{prefix}}{{major}},{{prefix}}{{major}}.{{minor}}{{#unless prerelease}},latest{{/unless}}'
)
expect(prerelease).toEqual(['v1', 'v1.2'])
})
it('conditionally includes entire tag group with {{#if}}', () => {
// With prerelease: include prerelease-specific tags
const withPre = deriveTags(
'v2.0.0-rc.1',
'{{prefix}}{{major}}{{#if prerelease}},{{prefix}}{{major}}-{{prerelease}}{{/if}}'
)
expect(withPre).toEqual(['v2', 'v2-rc.1'])
// Without prerelease: only major tag
const withoutPre = deriveTags(
'v2.0.0',
'{{prefix}}{{major}}{{#if prerelease}},{{prefix}}{{major}}-{{prerelease}}{{/if}}'
)
expect(withoutPre).toEqual(['v2'])
})
it('conditionally includes newline-separated tags', () => {
// Stable release includes all tags
const stable = deriveTags(
'v1.0.0',
'{{prefix}}{{major}}\n{{prefix}}{{major}}.{{minor}}{{#unless prerelease}}\nstable{{/unless}}'
)
expect(stable).toEqual(['v1', 'v1.0', 'stable'])
// Prerelease excludes stable tag
const prerelease = deriveTags(
'v1.0.0-alpha.1',
'{{prefix}}{{major}}\n{{prefix}}{{major}}.{{minor}}{{#unless prerelease}}\nstable{{/unless}}'
)
expect(prerelease).toEqual(['v1', 'v1.0'])
})
it('excludes multiple tags conditionally', () => {
const result = deriveTags(
'v1.0.0-beta.1',
'{{prefix}}{{major}}{{#unless prerelease}},latest,stable,production{{/unless}}'
)
expect(result).toEqual(['v1'])
})
it('includes multiple tags conditionally for stable', () => {
const result = deriveTags(
'v1.0.0',
'{{prefix}}{{major}}{{#unless prerelease}},latest,stable,production{{/unless}}'
)
expect(result).toEqual(['v1', 'latest', 'stable', 'production'])
})
})
})

12
tests/fixtures/core.ts vendored Normal file
View File

@@ -0,0 +1,12 @@
import type * as core from '@actions/core'
import { jest } from '@jest/globals'
export const debug = jest.fn<typeof core.debug>()
export const error = jest.fn<typeof core.error>()
export const info = jest.fn<typeof core.info>()
export const notice = jest.fn<typeof core.notice>()
export const getInput = jest.fn<typeof core.getInput>()
export const getBooleanInput = jest.fn<typeof core.getBooleanInput>()
export const setOutput = jest.fn<typeof core.setOutput>()
export const setFailed = jest.fn<typeof core.setFailed>()
export const warning = jest.fn<typeof core.warning>()

13
tests/fixtures/csv-parse.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import { jest } from '@jest/globals'
import { parse as realParse } from 'csv-parse/sync'
export const parse = jest.fn()
// Helper to reset to real implementation after jest.resetAllMocks()
export const resetToRealImplementation = (): void => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
parse.mockImplementation(realParse as any)
}
// Initialize with real implementation
resetToRealImplementation()

27
tests/fixtures/github.ts vendored Normal file
View File

@@ -0,0 +1,27 @@
import { jest } from '@jest/globals'
export const mockOctokit = {
rest: {
git: {
getRef: jest.fn<(args: unknown) => Promise<unknown>>(),
createRef: jest.fn<(args: unknown) => Promise<unknown>>(),
updateRef: jest.fn<(args: unknown) => Promise<unknown>>(),
createTag: jest.fn<(args: unknown) => Promise<unknown>>(),
getTag: jest.fn<(args: unknown) => Promise<unknown>>()
},
repos: {
getCommit: jest.fn<(args: unknown) => Promise<unknown>>()
}
}
}
export const getOctokit = jest
.fn<(token: string) => typeof mockOctokit>()
.mockReturnValue(mockOctokit)
export const context = {
repo: {
owner: 'test-owner',
repo: 'test-repo'
}
}

193
tests/logger.test.ts Normal file
View File

@@ -0,0 +1,193 @@
/**
* Unit tests for the logger module, src/logger.ts
*/
import { jest } from '@jest/globals'
import * as core from './fixtures/core.js'
jest.unstable_mockModule('@actions/core', () => core)
const { createLogger } = await import('../src/logger.js')
describe('createLogger', () => {
beforeEach(() => {
jest.resetAllMocks()
})
describe('without prefix', () => {
it('calls core.debug with the message', () => {
const log = createLogger()
log.debug('test debug message')
expect(core.debug).toHaveBeenCalledWith('test debug message')
})
it('calls core.info with the message', () => {
const log = createLogger()
log.info('test info message')
expect(core.info).toHaveBeenCalledWith('test info message')
})
it('calls core.notice with string message', () => {
const log = createLogger()
log.notice('test notice message')
expect(core.notice).toHaveBeenCalledWith('test notice message', undefined)
})
it('calls core.notice with Error unchanged', () => {
const log = createLogger()
const error = new Error('test error')
log.notice(error)
expect(core.notice).toHaveBeenCalledWith(error, undefined)
})
it('calls core.notice with properties', () => {
const log = createLogger()
const props = { title: 'Notice Title' }
log.notice('test notice', props)
expect(core.notice).toHaveBeenCalledWith('test notice', props)
})
it('calls core.warning with string message', () => {
const log = createLogger()
log.warning('test warning message')
expect(core.warning).toHaveBeenCalledWith(
'test warning message',
undefined
)
})
it('calls core.warning with Error unchanged', () => {
const log = createLogger()
const error = new Error('warning error')
log.warning(error)
expect(core.warning).toHaveBeenCalledWith(error, undefined)
})
it('calls core.warning with properties', () => {
const log = createLogger()
const props = { title: 'Warning Title' }
log.warning('test warning', props)
expect(core.warning).toHaveBeenCalledWith('test warning', props)
})
it('calls core.error with string message', () => {
const log = createLogger()
log.error('test error message')
expect(core.error).toHaveBeenCalledWith('test error message', undefined)
})
it('calls core.error with Error unchanged', () => {
const log = createLogger()
const error = new Error('error error')
log.error(error)
expect(core.error).toHaveBeenCalledWith(error, undefined)
})
it('calls core.error with properties', () => {
const log = createLogger()
const props = { title: 'Error Title' }
log.error('test error', props)
expect(core.error).toHaveBeenCalledWith('test error', props)
})
})
describe('with prefix', () => {
it('prefixes debug messages', () => {
const log = createLogger('[dry-run] ')
log.debug('test debug message')
expect(core.debug).toHaveBeenCalledWith('[dry-run] test debug message')
})
it('prefixes info messages', () => {
const log = createLogger('[dry-run] ')
log.info('test info message')
expect(core.info).toHaveBeenCalledWith('[dry-run] test info message')
})
it('prefixes notice string messages', () => {
const log = createLogger('[dry-run] ')
log.notice('test notice message')
expect(core.notice).toHaveBeenCalledWith(
'[dry-run] test notice message',
undefined
)
})
it('wraps notice Error with prefixed message and cause', () => {
const log = createLogger('[dry-run] ')
const original = new Error('notice error')
log.notice(original)
expect(core.notice).toHaveBeenCalledTimes(1)
const [wrapped, props] = core.notice.mock.calls[0]
expect(wrapped).toBeInstanceOf(Error)
expect((wrapped as Error).message).toBe('[dry-run] notice error')
expect((wrapped as Error).cause).toBe(original)
expect((wrapped as Error).stack).toBe(original.stack)
expect(props).toBeUndefined()
})
it('prefixes warning string messages', () => {
const log = createLogger('[dry-run] ')
log.warning('test warning message')
expect(core.warning).toHaveBeenCalledWith(
'[dry-run] test warning message',
undefined
)
})
it('wraps warning Error with prefixed message and cause', () => {
const log = createLogger('[dry-run] ')
const original = new Error('warning error')
log.warning(original)
expect(core.warning).toHaveBeenCalledTimes(1)
const [wrapped, props] = core.warning.mock.calls[0]
expect(wrapped).toBeInstanceOf(Error)
expect((wrapped as Error).message).toBe('[dry-run] warning error')
expect((wrapped as Error).cause).toBe(original)
expect((wrapped as Error).stack).toBe(original.stack)
expect(props).toBeUndefined()
})
it('prefixes error string messages', () => {
const log = createLogger('[dry-run] ')
log.error('test error message')
expect(core.error).toHaveBeenCalledWith(
'[dry-run] test error message',
undefined
)
})
it('wraps error Error with prefixed message and cause', () => {
const log = createLogger('[dry-run] ')
const original = new Error('error error')
log.error(original)
expect(core.error).toHaveBeenCalledTimes(1)
const [wrapped, props] = core.error.mock.calls[0]
expect(wrapped).toBeInstanceOf(Error)
expect((wrapped as Error).message).toBe('[dry-run] error error')
expect((wrapped as Error).cause).toBe(original)
expect((wrapped as Error).stack).toBe(original.stack)
expect(props).toBeUndefined()
})
it('preserves properties when prefixing', () => {
const log = createLogger('[test] ')
const props = { title: 'Test Title', file: 'test.ts', startLine: 10 }
log.warning('message with props', props)
expect(core.warning).toHaveBeenCalledWith(
'[test] message with props',
props
)
})
})
describe('with empty prefix', () => {
it('behaves the same as no prefix', () => {
const log = createLogger('')
log.info('test message')
expect(core.info).toHaveBeenCalledWith('test message')
})
})
})

1888
tests/main.test.ts Normal file

File diff suppressed because it is too large Load Diff

285
tests/tags.test.ts Normal file
View File

@@ -0,0 +1,285 @@
/**
* Unit tests for tag operation execution, src/tags.ts
*/
import { jest } from '@jest/globals'
import * as core from './fixtures/core.js'
import * as github from './fixtures/github.js'
import type { Inputs } from '../src/inputs.js'
// Mocks should be declared before the module being tested is imported.
jest.unstable_mockModule('@actions/core', () => core)
jest.unstable_mockModule('@actions/github', () => github)
// The module being tested should be imported dynamically.
const { executeTagOperation, planTagOperations } =
await import('../src/tags.js')
import type {
TagOperation,
CreateOperation,
UpdateOperation
} from '../src/tags.js'
// Helper to create a minimal Inputs object for testing
const createInputs = (overrides: Partial<Inputs> = {}): Inputs => ({
tags: [],
defaultRef: 'main',
whenExists: 'update',
annotation: '',
dryRun: false,
owner: 'test-owner',
repo: 'test-repo',
token: 'test-token',
...overrides
})
describe('planTagOperations', () => {
beforeEach(() => {
jest.resetAllMocks()
github.getOctokit.mockReturnValue(github.mockOctokit)
})
const setupCommitResolver = (
refToSha: Record<string, string> | string
): void => {
if (typeof refToSha === 'string') {
github.mockOctokit.rest.repos.getCommit.mockResolvedValue({
data: { sha: refToSha }
})
} else {
github.mockOctokit.rest.repos.getCommit.mockImplementation(
async (args: unknown) => {
const { ref } = args as { ref: string }
const sha = refToSha[ref]
if (sha) return { data: { sha } }
throw new Error(`Unknown ref: ${ref}`)
}
)
}
}
const setupTagDoesNotExist = (): void => {
github.mockOctokit.rest.git.getRef.mockRejectedValue({
status: 404
})
}
describe('per-tag annotations', () => {
it('parses per-tag annotation with explicit ref', async () => {
const inputs = createInputs({
tags: ['v1:main:Custom annotation'],
annotation: 'Global annotation'
})
setupCommitResolver('sha-main')
setupTagDoesNotExist()
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(1)
expect(operations[0].operation).toBe('create')
expect((operations[0] as CreateOperation).annotation).toBe(
'Custom annotation'
)
})
it('parses per-tag annotation with empty ref (fallback to default)', async () => {
const inputs = createInputs({
tags: ['v1::Custom annotation'],
defaultRef: 'develop',
annotation: 'Global annotation'
})
setupCommitResolver('sha-develop')
setupTagDoesNotExist()
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(1)
expect(operations[0].operation).toBe('create')
expect(operations[0].ref).toBe('develop')
expect((operations[0] as CreateOperation).annotation).toBe(
'Custom annotation'
)
})
it('handles annotation containing colons', async () => {
const inputs = createInputs({
tags: ['v1:main:Release: v1.0.0'],
annotation: ''
})
setupCommitResolver('sha-main')
setupTagDoesNotExist()
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(1)
expect((operations[0] as CreateOperation).annotation).toBe(
'Release: v1.0.0'
)
})
it('falls back to global annotation when per-tag not specified', async () => {
const inputs = createInputs({
tags: ['v1', 'v2:main'],
annotation: 'Global annotation'
})
setupCommitResolver('sha-main')
setupTagDoesNotExist()
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(2)
expect((operations[0] as CreateOperation).annotation).toBe(
'Global annotation'
)
expect((operations[1] as CreateOperation).annotation).toBe(
'Global annotation'
)
})
it('mixes per-tag and global annotations', async () => {
const inputs = createInputs({
tags: ['v1:main:Per-tag message', 'v2'],
annotation: 'Global annotation'
})
setupCommitResolver('sha-main')
setupTagDoesNotExist()
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(2)
expect((operations[0] as CreateOperation).annotation).toBe(
'Per-tag message'
)
expect((operations[1] as CreateOperation).annotation).toBe(
'Global annotation'
)
})
it('uses per-tag annotation for update comparison', async () => {
const inputs = createInputs({
tags: ['v1:main:New annotation'],
annotation: 'Global annotation',
whenExists: 'update'
})
setupCommitResolver('sha-main')
// Tag exists with same commit but different annotation
github.mockOctokit.rest.git.getRef.mockResolvedValue({
data: {
ref: 'refs/tags/v1',
object: { sha: 'sha-tag-object', type: 'tag' }
}
})
github.mockOctokit.rest.git.getTag.mockResolvedValue({
data: {
sha: 'sha-tag-object',
message: 'Old annotation',
object: { sha: 'sha-main', type: 'commit' }
}
})
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(1)
expect(operations[0].operation).toBe('update')
expect((operations[0] as UpdateOperation).annotation).toBe(
'New annotation'
)
expect((operations[0] as UpdateOperation).reasons).toContain(
'annotation message changed'
)
})
it('skips tag when per-tag annotation matches existing', async () => {
const inputs = createInputs({
tags: ['v1:main:Same annotation'],
annotation: 'Global annotation',
whenExists: 'update'
})
setupCommitResolver('sha-main')
github.mockOctokit.rest.git.getRef.mockResolvedValue({
data: {
ref: 'refs/tags/v1',
object: { sha: 'sha-tag-object', type: 'tag' }
}
})
github.mockOctokit.rest.git.getTag.mockResolvedValue({
data: {
sha: 'sha-tag-object',
message: 'Same annotation',
object: { sha: 'sha-main', type: 'commit' }
}
})
const operations = await planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
expect(operations).toHaveLength(1)
expect(operations[0].operation).toBe('skip')
})
it('rejects empty tag name with annotation', async () => {
const inputs = createInputs({
tags: ['::Some annotation']
})
await expect(
planTagOperations(
inputs,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
github.mockOctokit as any
)
).rejects.toThrow("Invalid tag: '::Some annotation'")
})
})
})
describe('executeTagOperation', () => {
beforeEach(() => {
jest.resetAllMocks()
github.getOctokit.mockReturnValue(github.mockOctokit)
})
it('throws error for unknown operation type', async () => {
const invalidOperation = {
operation: 'invalid',
name: 'v1',
ref: 'main',
sha: 'abc123',
owner: 'test-owner',
repo: 'test-repo'
} as unknown as TagOperation
await expect(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
executeTagOperation(invalidOperation, github.mockOctokit as any)
).rejects.toThrow('Unknown operation type: invalid')
})
})

23
tsconfig.base.json Normal file
View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": false,
"declarationMap": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"newLine": "lf",
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"pretty": true,
"resolveJsonModule": true,
"strict": true,
"strictNullChecks": true,
"target": "ES2022"
}
}

16
tsconfig.eslint.json Normal file
View File

@@ -0,0 +1,16 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"noEmit": true
},
"exclude": ["dist", "node_modules"],
"include": [
"tests",
"src",
"eslint.config.mjs",
"jest.config.js",
"rollup.config.ts"
]
}

11
tsconfig.json Normal file
View File

@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.base.json",
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist"
},
"exclude": ["tests", "coverage", "dist", "node_modules"],
"include": ["src"]
}