mirror of
https://github.com/jimeh/update-tags-action.git
synced 2026-02-19 09:36:41 +00:00
Compare commits
4 Commits
v2.1.1
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb98d277e4 | ||
|
|
937c3e6f65 | ||
|
|
fed61b3f3c | ||
|
|
a77500883a |
32
README.md
32
README.md
@@ -40,6 +40,25 @@ to move its own major and minor tags.
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
|
||||
### Annotated Tags
|
||||
|
||||
Create annotated tags with a custom message:
|
||||
|
||||
```yaml
|
||||
- uses: jimeh/update-tags-action@v2
|
||||
with:
|
||||
tags: v1.0.0
|
||||
annotation: |
|
||||
Release version 1.0.0
|
||||
|
||||
This is a major release with new features and bug fixes.
|
||||
```
|
||||
|
||||
Annotated tags in Git include metadata such as the tagger's name, email, date,
|
||||
and a message. They are stored as full objects in the Git database and are
|
||||
recommended for releases. If the `annotation` input is not provided (or is
|
||||
empty), lightweight tags will be created instead.
|
||||
|
||||
### With Release Please
|
||||
|
||||
This example uses
|
||||
@@ -104,12 +123,13 @@ jobs:
|
||||
|
||||
## 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 }} |
|
||||
| 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 |
|
||||
| annotation | Optional annotation message for the tag. If provided, creates an annotated tag instead of a lightweight tag. | `false` | |
|
||||
| github_token | The GitHub token to use for authentication. | `false` | ${{ github.token }} |
|
||||
|
||||
<!-- action-docs-inputs -->
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@ export const mockOctokit = {
|
||||
git: {
|
||||
getRef: jest.fn<(args: unknown) => Promise<unknown>>(),
|
||||
createRef: jest.fn<(args: unknown) => Promise<unknown>>(),
|
||||
updateRef: 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>>()
|
||||
|
||||
@@ -654,4 +654,242 @@ describe('run', () => {
|
||||
'v4'
|
||||
])
|
||||
})
|
||||
|
||||
describe('annotated tags', () => {
|
||||
it('creates annotated tags when annotation is provided', async () => {
|
||||
setupInputs({
|
||||
tags: 'v1.0.0',
|
||||
ref: 'abc123',
|
||||
github_token: 'test-token',
|
||||
when_exists: 'update',
|
||||
annotation: 'Release version 1.0.0'
|
||||
})
|
||||
setupCommitResolver('sha-abc123')
|
||||
setupTagDoesNotExist()
|
||||
|
||||
github.mockOctokit.rest.git.createTag.mockResolvedValue({
|
||||
data: { sha: 'tag-object-sha' }
|
||||
})
|
||||
|
||||
await run()
|
||||
|
||||
// Should create tag object first
|
||||
expect(github.mockOctokit.rest.git.createTag).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
tag: 'v1.0.0',
|
||||
message: 'Release version 1.0.0',
|
||||
object: 'sha-abc123',
|
||||
type: 'commit'
|
||||
})
|
||||
|
||||
// Then create reference pointing to tag object
|
||||
expect(github.mockOctokit.rest.git.createRef).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
ref: 'refs/tags/v1.0.0',
|
||||
sha: 'tag-object-sha'
|
||||
})
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('created', ['v1.0.0'])
|
||||
})
|
||||
|
||||
it('creates lightweight tags when annotation is empty', async () => {
|
||||
setupInputs({
|
||||
tags: 'v1.0.0',
|
||||
ref: 'abc123',
|
||||
github_token: 'test-token',
|
||||
when_exists: 'update',
|
||||
annotation: ''
|
||||
})
|
||||
setupCommitResolver('sha-abc123')
|
||||
setupTagDoesNotExist()
|
||||
|
||||
await run()
|
||||
|
||||
// Should NOT create tag object
|
||||
expect(github.mockOctokit.rest.git.createTag).not.toHaveBeenCalled()
|
||||
|
||||
// Should create reference pointing directly to commit
|
||||
expect(github.mockOctokit.rest.git.createRef).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
ref: 'refs/tags/v1.0.0',
|
||||
sha: 'sha-abc123'
|
||||
})
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('created', ['v1.0.0'])
|
||||
})
|
||||
|
||||
it('creates lightweight tags when annotation is only whitespace', async () => {
|
||||
setupInputs({
|
||||
tags: 'v1.0.0',
|
||||
ref: 'abc123',
|
||||
github_token: 'test-token',
|
||||
when_exists: 'update',
|
||||
annotation: ' '
|
||||
})
|
||||
setupCommitResolver('sha-abc123')
|
||||
setupTagDoesNotExist()
|
||||
|
||||
await run()
|
||||
|
||||
// Should NOT create tag object for whitespace-only annotation
|
||||
expect(github.mockOctokit.rest.git.createTag).not.toHaveBeenCalled()
|
||||
|
||||
// Should create reference pointing directly to commit
|
||||
expect(github.mockOctokit.rest.git.createRef).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
ref: 'refs/tags/v1.0.0',
|
||||
sha: 'sha-abc123'
|
||||
})
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('created', ['v1.0.0'])
|
||||
})
|
||||
|
||||
it('updates tags with annotation', async () => {
|
||||
setupInputs({
|
||||
tags: 'v1',
|
||||
ref: 'def456',
|
||||
github_token: 'test-token',
|
||||
when_exists: 'update',
|
||||
annotation: 'Updated version'
|
||||
})
|
||||
setupCommitResolver('sha-def456')
|
||||
setupTagExistsForAll('sha-old123')
|
||||
|
||||
github.mockOctokit.rest.git.createTag.mockResolvedValue({
|
||||
data: { sha: 'new-tag-object-sha' }
|
||||
})
|
||||
|
||||
await run()
|
||||
|
||||
// Should create new tag object
|
||||
expect(github.mockOctokit.rest.git.createTag).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
tag: 'v1',
|
||||
message: 'Updated version',
|
||||
object: 'sha-def456',
|
||||
type: 'commit'
|
||||
})
|
||||
|
||||
// Should update reference to new tag object
|
||||
expect(github.mockOctokit.rest.git.updateRef).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
ref: 'tags/v1',
|
||||
sha: 'new-tag-object-sha',
|
||||
force: true
|
||||
})
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('updated', ['v1'])
|
||||
})
|
||||
|
||||
it('handles existing annotated tag and compares commit SHA', async () => {
|
||||
setupInputs({
|
||||
tags: 'v1',
|
||||
ref: 'abc123',
|
||||
github_token: 'test-token',
|
||||
when_exists: 'update',
|
||||
annotation: 'Test annotation'
|
||||
})
|
||||
setupCommitResolver('sha-abc123')
|
||||
|
||||
// Mock existing annotated tag
|
||||
github.mockOctokit.rest.git.getRef.mockResolvedValue({
|
||||
data: {
|
||||
ref: 'refs/tags/v1',
|
||||
object: { sha: 'existing-tag-object-sha', type: 'tag' }
|
||||
}
|
||||
})
|
||||
|
||||
// Mock getTag to return commit SHA
|
||||
github.mockOctokit.rest.git.getTag.mockResolvedValue({
|
||||
data: {
|
||||
sha: 'existing-tag-object-sha',
|
||||
object: { sha: 'sha-abc123', type: 'commit' }
|
||||
}
|
||||
})
|
||||
|
||||
await run()
|
||||
|
||||
// Should fetch tag object to get commit SHA
|
||||
expect(github.mockOctokit.rest.git.getTag).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
tag_sha: 'existing-tag-object-sha'
|
||||
})
|
||||
|
||||
// Should skip update since commit SHA matches
|
||||
expect(github.mockOctokit.rest.git.updateRef).not.toHaveBeenCalled()
|
||||
expect(github.mockOctokit.rest.git.createTag).not.toHaveBeenCalled()
|
||||
expect(core.info).toHaveBeenCalledWith(
|
||||
"Tag 'v1' already exists with desired SHA sha-abc123."
|
||||
)
|
||||
expect(core.setOutput).toHaveBeenCalledWith('created', [])
|
||||
expect(core.setOutput).toHaveBeenCalledWith('updated', [])
|
||||
})
|
||||
|
||||
it('updates existing annotated tag when commit SHA differs', async () => {
|
||||
setupInputs({
|
||||
tags: 'v1',
|
||||
ref: 'def456',
|
||||
github_token: 'test-token',
|
||||
when_exists: 'update',
|
||||
annotation: 'Updated annotation'
|
||||
})
|
||||
setupCommitResolver('sha-def456')
|
||||
|
||||
// Mock existing annotated tag
|
||||
github.mockOctokit.rest.git.getRef.mockResolvedValue({
|
||||
data: {
|
||||
ref: 'refs/tags/v1',
|
||||
object: { sha: 'existing-tag-object-sha', type: 'tag' }
|
||||
}
|
||||
})
|
||||
|
||||
// Mock getTag to return different commit SHA
|
||||
github.mockOctokit.rest.git.getTag.mockResolvedValue({
|
||||
data: {
|
||||
sha: 'existing-tag-object-sha',
|
||||
object: { sha: 'sha-old123', type: 'commit' }
|
||||
}
|
||||
})
|
||||
|
||||
github.mockOctokit.rest.git.createTag.mockResolvedValue({
|
||||
data: { sha: 'new-tag-object-sha' }
|
||||
})
|
||||
|
||||
await run()
|
||||
|
||||
// Should fetch tag object to get commit SHA
|
||||
expect(github.mockOctokit.rest.git.getTag).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
tag_sha: 'existing-tag-object-sha'
|
||||
})
|
||||
|
||||
// Should create new tag object and update reference
|
||||
expect(github.mockOctokit.rest.git.createTag).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
tag: 'v1',
|
||||
message: 'Updated annotation',
|
||||
object: 'sha-def456',
|
||||
type: 'commit'
|
||||
})
|
||||
|
||||
expect(github.mockOctokit.rest.git.updateRef).toHaveBeenCalledWith({
|
||||
owner: 'test-owner',
|
||||
repo: 'test-repo',
|
||||
ref: 'tags/v1',
|
||||
sha: 'new-tag-object-sha',
|
||||
force: true
|
||||
})
|
||||
|
||||
expect(core.setOutput).toHaveBeenCalledWith('updated', ['v1'])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -20,6 +20,12 @@ inputs:
|
||||
'fail'.
|
||||
required: false
|
||||
default: "update"
|
||||
annotation:
|
||||
description: >-
|
||||
Optional annotation message for the tag. If provided, creates an annotated
|
||||
tag instead of a lightweight tag.
|
||||
required: false
|
||||
default: ""
|
||||
github_token:
|
||||
description: "The GitHub token to use for authentication."
|
||||
required: false
|
||||
|
||||
6
dist/index.js
generated
vendored
6
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
18
package-lock.json
generated
18
package-lock.json
generated
@@ -125,7 +125,6 @@
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1567,7 +1566,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz",
|
||||
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
@@ -2375,7 +2373,6 @@
|
||||
"integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.46.2",
|
||||
@@ -2406,7 +2403,6 @@
|
||||
"integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.46.2",
|
||||
"@typescript-eslint/types": "8.46.2",
|
||||
@@ -2888,7 +2884,6 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -3356,7 +3351,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.19",
|
||||
"caniuse-lite": "^1.0.30001751",
|
||||
@@ -4156,7 +4150,6 @@
|
||||
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -4217,7 +4210,6 @@
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
@@ -4344,7 +4336,6 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -6065,7 +6056,6 @@
|
||||
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/core": "30.2.0",
|
||||
"@jest/types": "30.2.0",
|
||||
@@ -7899,7 +7889,6 @@
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -8178,7 +8167,6 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -8800,7 +8788,6 @@
|
||||
"integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
@@ -10088,8 +10075,7 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
@@ -10220,7 +10206,6 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -10294,7 +10279,6 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.3.0"
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@ export type WhenExistsMode = (typeof WHEN_EXISTS_MODES)[number]
|
||||
export interface Inputs {
|
||||
tags: Tag[]
|
||||
whenExists: WhenExistsMode
|
||||
annotation: string
|
||||
owner: string
|
||||
repo: string
|
||||
octokit: ReturnType<typeof github.getOctokit>
|
||||
@@ -40,6 +41,7 @@ export async function getInputs(): Promise<Inputs> {
|
||||
const defaultRef: string = core.getInput('ref')
|
||||
const whenExistsInput = core.getInput('when_exists') || 'update'
|
||||
const whenExists = validateWhenExists(whenExistsInput)
|
||||
const annotation: string = core.getInput('annotation') || ''
|
||||
const token: string = core.getInput('github_token', {
|
||||
required: true
|
||||
})
|
||||
@@ -52,6 +54,7 @@ export async function getInputs(): Promise<Inputs> {
|
||||
return {
|
||||
tags,
|
||||
whenExists,
|
||||
annotation,
|
||||
owner,
|
||||
repo,
|
||||
octokit
|
||||
|
||||
11
src/main.ts
11
src/main.ts
@@ -19,14 +19,21 @@ export async function run(): Promise<void> {
|
||||
return
|
||||
}
|
||||
|
||||
const { tags, whenExists, owner, repo, octokit } = inputs
|
||||
const { tags, whenExists, annotation, owner, repo, octokit } = inputs
|
||||
|
||||
const created: string[] = []
|
||||
const updated: string[] = []
|
||||
|
||||
// Create or update all tags.
|
||||
for (const tag of tags) {
|
||||
const result = await processTag(tag, whenExists, owner, repo, octokit)
|
||||
const result = await processTag(
|
||||
tag,
|
||||
whenExists,
|
||||
annotation,
|
||||
owner,
|
||||
repo,
|
||||
octokit
|
||||
)
|
||||
|
||||
if (result === 'failed') {
|
||||
return
|
||||
|
||||
146
src/tags.ts
146
src/tags.ts
@@ -99,6 +99,7 @@ export async function parseTagsInput(
|
||||
*
|
||||
* @param tag - The desired tag to process
|
||||
* @param whenExists - What to do if the tag already exists
|
||||
* @param annotation - Optional annotation message for the tag
|
||||
* @param owner - Repository owner
|
||||
* @param repo - Repository name
|
||||
* @param octokit - GitHub API client
|
||||
@@ -107,6 +108,7 @@ export async function parseTagsInput(
|
||||
export async function processTag(
|
||||
tag: Tag,
|
||||
whenExists: 'update' | 'skip' | 'fail',
|
||||
annotation: string,
|
||||
owner: string,
|
||||
repo: string,
|
||||
octokit: ReturnType<typeof github.getOctokit>
|
||||
@@ -124,22 +126,28 @@ export async function processTag(
|
||||
// If the tag exists, decide action based on 'when_exists'.
|
||||
if (whenExists === 'update') {
|
||||
const existingSHA = existing.data.object.sha
|
||||
if (existingSHA === sha) {
|
||||
|
||||
// For annotated tags, we need to get the commit SHA from the tag object
|
||||
let existingCommitSHA = existingSHA
|
||||
if (existing.data.object.type === 'tag') {
|
||||
const tagObject = await octokit.rest.git.getTag({
|
||||
owner,
|
||||
repo,
|
||||
tag_sha: existingSHA
|
||||
})
|
||||
existingCommitSHA = tagObject.data.object.sha
|
||||
}
|
||||
|
||||
if (existingCommitSHA === sha) {
|
||||
core.info(`Tag '${tagName}' already exists with desired SHA ${sha}.`)
|
||||
return 'skipped'
|
||||
}
|
||||
|
||||
core.info(
|
||||
`Tag '${tagName}' exists, updating to SHA ${sha} ` +
|
||||
`(was ${existingSHA}).`
|
||||
`(was ${existingCommitSHA}).`
|
||||
)
|
||||
await octokit.rest.git.updateRef({
|
||||
owner,
|
||||
repo,
|
||||
ref: `tags/${tagName}`,
|
||||
sha,
|
||||
force: true
|
||||
})
|
||||
await updateTag(tagName, sha, annotation, owner, repo, octokit)
|
||||
return 'updated'
|
||||
} else if (whenExists === 'skip') {
|
||||
core.info(`Tag '${tagName}' exists, skipping.`)
|
||||
@@ -157,16 +165,124 @@ export async function processTag(
|
||||
|
||||
// If the tag doesn't exist (404), 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
|
||||
})
|
||||
await createTag(tagName, sha, annotation, owner, repo, octokit)
|
||||
return 'created'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag object for an annotated tag.
|
||||
*
|
||||
* @param tagName - Name of the tag
|
||||
* @param sha - Commit SHA to tag
|
||||
* @param annotation - Annotation message
|
||||
* @param owner - Repository owner
|
||||
* @param repo - Repository name
|
||||
* @param octokit - GitHub API client
|
||||
* @returns SHA of the created tag object
|
||||
*/
|
||||
async function createTagObject(
|
||||
tagName: string,
|
||||
sha: string,
|
||||
annotation: string,
|
||||
owner: string,
|
||||
repo: string,
|
||||
octokit: ReturnType<typeof github.getOctokit>
|
||||
): Promise<string> {
|
||||
const tagObject = await octokit.rest.git.createTag({
|
||||
owner,
|
||||
repo,
|
||||
tag: tagName,
|
||||
message: annotation,
|
||||
object: sha,
|
||||
type: 'commit'
|
||||
})
|
||||
return tagObject.data.sha
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag (annotated or lightweight based on annotation parameter).
|
||||
*
|
||||
* @param tagName - Name of the tag
|
||||
* @param sha - Commit SHA to tag
|
||||
* @param annotation - Optional annotation message
|
||||
* @param owner - Repository owner
|
||||
* @param repo - Repository name
|
||||
* @param octokit - GitHub API client
|
||||
*/
|
||||
async function createTag(
|
||||
tagName: string,
|
||||
sha: string,
|
||||
annotation: string,
|
||||
owner: string,
|
||||
repo: string,
|
||||
octokit: ReturnType<typeof github.getOctokit>
|
||||
): Promise<void> {
|
||||
let refSha = sha
|
||||
|
||||
// If annotation is provided and non-empty, create an annotated tag object first
|
||||
if (annotation && annotation.trim()) {
|
||||
refSha = await createTagObject(
|
||||
tagName,
|
||||
sha,
|
||||
annotation,
|
||||
owner,
|
||||
repo,
|
||||
octokit
|
||||
)
|
||||
}
|
||||
|
||||
// Create the reference pointing to the tag object (or commit for lightweight)
|
||||
await octokit.rest.git.createRef({
|
||||
owner,
|
||||
repo,
|
||||
ref: `refs/tags/${tagName}`,
|
||||
sha: refSha
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a tag to point to a new SHA.
|
||||
*
|
||||
* @param tagName - Name of the tag
|
||||
* @param sha - New commit SHA
|
||||
* @param annotation - Optional annotation message
|
||||
* @param owner - Repository owner
|
||||
* @param repo - Repository name
|
||||
* @param octokit - GitHub API client
|
||||
*/
|
||||
async function updateTag(
|
||||
tagName: string,
|
||||
sha: string,
|
||||
annotation: string,
|
||||
owner: string,
|
||||
repo: string,
|
||||
octokit: ReturnType<typeof github.getOctokit>
|
||||
): Promise<void> {
|
||||
let refSha = sha
|
||||
|
||||
// If annotation is provided and non-empty, create an annotated tag object first
|
||||
if (annotation && annotation.trim()) {
|
||||
refSha = await createTagObject(
|
||||
tagName,
|
||||
sha,
|
||||
annotation,
|
||||
owner,
|
||||
repo,
|
||||
octokit
|
||||
)
|
||||
}
|
||||
|
||||
// Update the reference
|
||||
await octokit.rest.git.updateRef({
|
||||
owner,
|
||||
repo,
|
||||
ref: `tags/${tagName}`,
|
||||
sha: refSha,
|
||||
force: true
|
||||
})
|
||||
}
|
||||
|
||||
async function resolveRefToSha(
|
||||
octokit: ReturnType<typeof github.getOctokit>,
|
||||
owner: string,
|
||||
|
||||
Reference in New Issue
Block a user