@logickernel/agileflow 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/README.md +0 -1
- package/docs/cli-reference.md +231 -60
- package/docs/getting-started.md +144 -160
- package/package.json +1 -1
- package/src/git-push.js +40 -0
- package/src/github-push.js +156 -0
- package/src/gitlab-push.js +136 -0
- package/src/index.js +93 -29
- package/src/utils.js +121 -106
- package/docs/gitlab-ci-template.md +0 -324
- package/src/git-utils.js +0 -57
- package/src/local.js +0 -17
- package/templates/agileflow-tagged.gitlab-ci.yml +0 -66
- package/templates/agileflow.gitlab-ci.yml +0 -64
package/docs/getting-started.md
CHANGED
|
@@ -5,205 +5,189 @@ Welcome to AgileFlow! This guide will help you get up and running with AgileFlow
|
|
|
5
5
|
## What You'll Learn
|
|
6
6
|
|
|
7
7
|
By the end of this guide, you'll have:
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- ✅ Confidence to customize the pipeline for your needs
|
|
8
|
+
- AgileFlow running in your project
|
|
9
|
+
- Automatic semantic versioning based on conventional commits
|
|
10
|
+
- Understanding of how the version-centric approach works
|
|
12
11
|
|
|
13
12
|
## Prerequisites
|
|
14
13
|
|
|
15
14
|
Before you begin, ensure you have:
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- Basic understanding of Git and
|
|
15
|
+
- Node.js 14+ installed (for local usage)
|
|
16
|
+
- A Git repository with commit history
|
|
17
|
+
- Basic understanding of Git and conventional commits
|
|
19
18
|
|
|
20
|
-
## Quick Start
|
|
19
|
+
## Quick Start
|
|
21
20
|
|
|
22
|
-
###
|
|
21
|
+
### Local Usage
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
Run AgileFlow directly with npx to see your current and next version:
|
|
25
24
|
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
- remote: https://code.logickernel.com/kernel/agileflow/-/raw/main/templates/AgileFlow.gitlab-ci.yml
|
|
25
|
+
```bash
|
|
26
|
+
npx @logickernel/agileflow
|
|
29
27
|
```
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
AgileFlow needs a GitLab access token to create version tags via the API. Set this in your GitLab project:
|
|
34
|
-
|
|
35
|
-
1. Go to **Settings > CI/CD > Variables**
|
|
36
|
-
2. Add the `AGILEFLOW_TOKEN` variable:
|
|
37
|
-
|
|
38
|
-
| Variable | Value | Type | Protect | Mask |
|
|
39
|
-
|----------|-------|------|---------|------|
|
|
40
|
-
| `AGILEFLOW_TOKEN` | Your GitLab API token | Variable | Yes | No |
|
|
41
|
-
|
|
42
|
-
**Creating the AGILEFLOW_TOKEN:**
|
|
43
|
-
- **Project Access Token (Recommended)**: Go to **Settings > Access Tokens** in your project
|
|
44
|
-
- **Personal Access Token**: Go to your user **Settings > Access Tokens**
|
|
45
|
-
- Set **Name**: `AgileFlow Bot`, **Scopes**: `api`, **Role**: `maintainer` or higher
|
|
46
|
-
|
|
47
|
-
### Step 3: Add Your First Job
|
|
48
|
-
|
|
49
|
-
Below the include statement, add a simple build job:
|
|
50
|
-
|
|
51
|
-
```yaml
|
|
52
|
-
build:
|
|
53
|
-
stage: build
|
|
54
|
-
script:
|
|
55
|
-
- echo "Building version ${VERSION}"
|
|
56
|
-
- docker build -t myapp:${VERSION} .
|
|
57
|
-
- docker push myapp:${VERSION}
|
|
58
|
-
needs:
|
|
59
|
-
- agileflow
|
|
29
|
+
Example output:
|
|
60
30
|
```
|
|
31
|
+
Current version: v1.2.3
|
|
32
|
+
Next version: v1.2.4
|
|
33
|
+
Commits since current version: 3
|
|
61
34
|
|
|
62
|
-
|
|
35
|
+
Changelog:
|
|
36
|
+
### fix
|
|
37
|
+
- resolve authentication issue
|
|
38
|
+
- correct null handling in user lookup
|
|
63
39
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
git commit -m "feat: add AgileFlow CI/CD pipeline"
|
|
67
|
-
git push
|
|
40
|
+
### docs
|
|
41
|
+
- update README with usage examples
|
|
68
42
|
```
|
|
69
43
|
|
|
70
|
-
|
|
44
|
+
### Quiet Mode
|
|
71
45
|
|
|
72
|
-
|
|
46
|
+
Use `--quiet` to only output the next version (useful for scripts):
|
|
73
47
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## Understanding the Pipeline
|
|
48
|
+
```bash
|
|
49
|
+
VERSION=$(npx @logickernel/agileflow --quiet)
|
|
50
|
+
echo "Next version will be: $VERSION"
|
|
51
|
+
```
|
|
80
52
|
|
|
81
|
-
|
|
53
|
+
## CI/CD Integration
|
|
54
|
+
|
|
55
|
+
### GitLab CI
|
|
56
|
+
|
|
57
|
+
1. **Configure the AGILEFLOW_TOKEN**
|
|
58
|
+
|
|
59
|
+
Go to **Settings > CI/CD > Variables** and add:
|
|
60
|
+
|
|
61
|
+
| Variable | Value | Protect | Mask |
|
|
62
|
+
|----------|-------|---------|------|
|
|
63
|
+
| `AGILEFLOW_TOKEN` | Your GitLab API token | Yes | Yes |
|
|
64
|
+
|
|
65
|
+
Create the token at **Settings > Access Tokens** with:
|
|
66
|
+
- **Name**: AgileFlow Bot
|
|
67
|
+
- **Role**: Maintainer
|
|
68
|
+
- **Scopes**: api
|
|
69
|
+
|
|
70
|
+
2. **Add AgileFlow to your pipeline**
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
stages:
|
|
74
|
+
- version
|
|
75
|
+
- build
|
|
76
|
+
|
|
77
|
+
agileflow:
|
|
78
|
+
stage: version
|
|
79
|
+
image: node:20-alpine
|
|
80
|
+
script:
|
|
81
|
+
- npx @logickernel/agileflow gitlab
|
|
82
|
+
only:
|
|
83
|
+
- main
|
|
84
|
+
|
|
85
|
+
build:
|
|
86
|
+
stage: build
|
|
87
|
+
script:
|
|
88
|
+
- echo "Building..."
|
|
89
|
+
needs:
|
|
90
|
+
- agileflow
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### GitHub Actions
|
|
94
|
+
|
|
95
|
+
1. **Configure the AGILEFLOW_TOKEN**
|
|
96
|
+
|
|
97
|
+
Go to **Settings > Secrets and variables > Actions** and add a secret:
|
|
98
|
+
- **Name**: `AGILEFLOW_TOKEN`
|
|
99
|
+
- **Value**: A Personal Access Token with `contents: write` permission
|
|
100
|
+
|
|
101
|
+
2. **Add AgileFlow to your workflow**
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
name: Release
|
|
105
|
+
on:
|
|
106
|
+
push:
|
|
107
|
+
branches: [main]
|
|
108
|
+
|
|
109
|
+
jobs:
|
|
110
|
+
version:
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
steps:
|
|
113
|
+
- uses: actions/checkout@v4
|
|
114
|
+
with:
|
|
115
|
+
fetch-depth: 0 # Required for version history
|
|
116
|
+
|
|
117
|
+
- uses: actions/setup-node@v4
|
|
118
|
+
with:
|
|
119
|
+
node-version: '20'
|
|
120
|
+
|
|
121
|
+
- name: Create version tag
|
|
122
|
+
env:
|
|
123
|
+
AGILEFLOW_TOKEN: ${{ secrets.AGILEFLOW_TOKEN }}
|
|
124
|
+
run: npx @logickernel/agileflow github
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Native Git Push
|
|
128
|
+
|
|
129
|
+
If you prefer using native git commands (requires git credentials):
|
|
82
130
|
|
|
83
|
-
```
|
|
84
|
-
|
|
131
|
+
```bash
|
|
132
|
+
npx @logickernel/agileflow push
|
|
85
133
|
```
|
|
86
134
|
|
|
87
|
-
|
|
88
|
-
- **test**: Run tests against source code before building (add your test jobs here)
|
|
89
|
-
- **build**: Your application builds with the generated version
|
|
90
|
-
- **deploy**: Deploy the versioned artifacts (add your deployment jobs here)
|
|
91
|
-
- **e2e**: Run end-to-end tests against deployed versions (add your e2e test jobs here)
|
|
92
|
-
- **clean**: Cleanup temporary resources (optional)
|
|
135
|
+
This creates an annotated tag and pushes it to the origin remote.
|
|
93
136
|
|
|
94
137
|
## How AgileFlow Works
|
|
95
138
|
|
|
96
|
-
###
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
- **Works with protected branches** without special permissions
|
|
101
|
-
|
|
102
|
-
### Version Generation
|
|
103
|
-
- **Analyzes commit messages** since the last version
|
|
104
|
-
- **Uses conventional commits** to determine version bump type
|
|
105
|
-
- **Creates semantic versions** automatically (v1.0.0, v1.0.1, etc.)
|
|
106
|
-
- **Generates release notes** from commit history
|
|
139
|
+
### Version Calculation
|
|
140
|
+
- Analyzes commit messages since the last version tag
|
|
141
|
+
- Uses conventional commits to determine version bump type
|
|
142
|
+
- Generates semantic versions automatically (v1.0.0, v1.0.1, etc.)
|
|
107
143
|
|
|
108
|
-
|
|
144
|
+
### Version Bump Rules
|
|
109
145
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
name: staging
|
|
120
|
-
needs:
|
|
121
|
-
- build
|
|
122
|
-
```
|
|
146
|
+
| Commit Type | Example | Version Bump |
|
|
147
|
+
|-------------|---------|--------------|
|
|
148
|
+
| Breaking change | `feat!: redesign API` | Major (1.0.0 → 2.0.0) |
|
|
149
|
+
| Feature | `feat: add login` | Minor (1.0.0 → 1.1.0) |
|
|
150
|
+
| Fix | `fix: resolve crash` | Patch (1.0.0 → 1.0.1) |
|
|
151
|
+
| Performance | `perf: optimize query` | Patch |
|
|
152
|
+
| Refactor | `refactor: simplify logic` | Patch |
|
|
153
|
+
| Docs only | `docs: update README` | No bump |
|
|
154
|
+
| Chore | `chore: update deps` | No bump |
|
|
123
155
|
|
|
124
|
-
###
|
|
125
|
-
```yaml
|
|
126
|
-
# Unit tests run before building
|
|
127
|
-
unit-tests:
|
|
128
|
-
stage: test
|
|
129
|
-
script:
|
|
130
|
-
- npm test
|
|
131
|
-
- npm run lint
|
|
132
|
-
needs:
|
|
133
|
-
- agileflow
|
|
134
|
-
|
|
135
|
-
# Integration tests run after deployment
|
|
136
|
-
integration-tests:
|
|
137
|
-
stage: e2e
|
|
138
|
-
script:
|
|
139
|
-
- ./run-tests.sh --version ${VERSION}
|
|
140
|
-
needs:
|
|
141
|
-
- deploy-staging
|
|
142
|
-
```
|
|
156
|
+
### No Bump Needed
|
|
143
157
|
|
|
144
|
-
|
|
145
|
-
```yaml
|
|
146
|
-
build-backend:
|
|
147
|
-
stage: build
|
|
148
|
-
script:
|
|
149
|
-
- docker build -t backend:${VERSION} ./backend
|
|
150
|
-
- docker push backend:${VERSION}
|
|
151
|
-
needs:
|
|
152
|
-
- agileflow
|
|
153
|
-
|
|
154
|
-
build-frontend:
|
|
155
|
-
stage: build
|
|
156
|
-
script:
|
|
157
|
-
- docker build -t frontend:${VERSION} ./frontend
|
|
158
|
-
- docker push frontend:${VERSION}
|
|
159
|
-
needs:
|
|
160
|
-
- agileflow
|
|
161
|
-
```
|
|
158
|
+
If all commits since the last version are docs/chore/style types, AgileFlow will report "no bump needed" and skip tag creation in push commands.
|
|
162
159
|
|
|
163
160
|
## Common Questions
|
|
164
161
|
|
|
165
162
|
### Q: How does AgileFlow determine the next version?
|
|
166
|
-
A: AgileFlow analyzes your commit messages using conventional commits.
|
|
167
|
-
|
|
168
|
-
### Q: Can I use this with existing CI/CD pipelines?
|
|
169
|
-
A: Yes! AgileFlow is designed to work alongside existing pipelines. Just include the template and gradually migrate your jobs to use the `${VERSION}` variable.
|
|
163
|
+
A: AgileFlow analyzes your commit messages using conventional commits. Features bump the minor version, fixes bump the patch version, and breaking changes bump the major version.
|
|
170
164
|
|
|
171
|
-
### Q: What if
|
|
172
|
-
A: AgileFlow
|
|
165
|
+
### Q: What if there's no version tag yet?
|
|
166
|
+
A: AgileFlow starts from v0.0.0 and calculates the first version based on your commits.
|
|
173
167
|
|
|
174
|
-
### Q:
|
|
175
|
-
A:
|
|
168
|
+
### Q: Can I use this locally before pushing?
|
|
169
|
+
A: Yes! Run `npx @logickernel/agileflow` to preview the next version without creating any tags.
|
|
176
170
|
|
|
177
|
-
### Q:
|
|
178
|
-
A:
|
|
171
|
+
### Q: What happens if no version bump is needed?
|
|
172
|
+
A: The push commands (`push`, `gitlab`, `github`) will skip tag creation and exit successfully.
|
|
179
173
|
|
|
180
174
|
## Troubleshooting
|
|
181
175
|
|
|
182
|
-
###
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
- Verify your GitLab CI/CD settings
|
|
186
|
-
- Check the `agileflow` job logs for specific errors
|
|
187
|
-
|
|
188
|
-
### VERSION Variable Not Available
|
|
189
|
-
- Ensure the `agileflow` job completed successfully
|
|
190
|
-
- Check that your jobs have `needs: - agileflow` dependency
|
|
191
|
-
- Verify the dotenv artifact is properly configured
|
|
176
|
+
### "Not a git repository" Error
|
|
177
|
+
- Ensure you're running AgileFlow from within a git repository
|
|
178
|
+
- Check that the `.git` directory exists
|
|
192
179
|
|
|
193
|
-
###
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
- Verify your build scripts work with the version variable
|
|
180
|
+
### "AGILEFLOW_TOKEN not set" Error
|
|
181
|
+
- Ensure the environment variable is configured in your CI/CD settings
|
|
182
|
+
- Verify the token has the required permissions
|
|
197
183
|
|
|
198
|
-
|
|
184
|
+
### No Version Bump Detected
|
|
185
|
+
- Ensure you're using conventional commit format
|
|
186
|
+
- Check that there are commits since the last version tag
|
|
187
|
+
- Verify commits include bump-triggering types (feat, fix, perf, etc.)
|
|
199
188
|
|
|
200
|
-
|
|
201
|
-
- 🔧 [GitLab CI Template Reference](./gitlab-ci-template.md) - Detailed template documentation
|
|
202
|
-
- 💡 [Version-Centric CI/CD Approach](./version-centric-cicd.md) - Deep dive into the methodology
|
|
203
|
-
- 🐛 [Troubleshooting](./troubleshooting.md) - Common issues and solutions
|
|
204
|
-
|
|
205
|
-
## Congratulations! 🎉
|
|
206
|
-
|
|
207
|
-
You've successfully set up AgileFlow and are now using a modern, version-centric CI/CD approach. Your deployments will be more predictable, your rollbacks will be simpler, and your team will have better visibility into what's running where.
|
|
189
|
+
## Next Steps
|
|
208
190
|
|
|
209
|
-
|
|
191
|
+
- Read the [CLI Reference](./cli-reference.md) for all available commands
|
|
192
|
+
- Learn about [Conventional Commits](./conventional-commits.md)
|
|
193
|
+
- Explore [Version-Centric CI/CD](./version-centric-cicd.md) methodology
|
package/package.json
CHANGED
package/src/git-push.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates an annotated tag and pushes it to the remote repository.
|
|
10
|
+
* Uses native git commands - requires git credentials to be configured.
|
|
11
|
+
* @param {string} tagName - The tag name (e.g., "v1.2.3")
|
|
12
|
+
* @param {string} message - The tag message (changelog)
|
|
13
|
+
* @returns {Promise<void>}
|
|
14
|
+
*/
|
|
15
|
+
async function pushTag(tagName, message) {
|
|
16
|
+
const safeTag = String(tagName).replace(/"/g, '\\"');
|
|
17
|
+
|
|
18
|
+
// Write message to a temp file to avoid shell escaping issues with special characters
|
|
19
|
+
const tempFile = path.join(os.tmpdir(), `agileflow-tag-${Date.now()}.txt`);
|
|
20
|
+
try {
|
|
21
|
+
fs.writeFileSync(tempFile, message, 'utf8');
|
|
22
|
+
|
|
23
|
+
// Create annotated tag using -F to read message from file
|
|
24
|
+
execSync(`git tag -a "${safeTag}" -F "${tempFile}"`, { stdio: 'pipe' });
|
|
25
|
+
|
|
26
|
+
// Push to origin
|
|
27
|
+
execSync(`git push origin "${safeTag}"`, { stdio: 'pipe' });
|
|
28
|
+
} finally {
|
|
29
|
+
// Clean up temp file
|
|
30
|
+
try {
|
|
31
|
+
fs.unlinkSync(tempFile);
|
|
32
|
+
} catch {
|
|
33
|
+
// Ignore cleanup errors
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
pushTag,
|
|
40
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const https = require('https');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a tag via the GitHub API.
|
|
7
|
+
* GitHub requires creating a tag object first, then a reference.
|
|
8
|
+
* @param {string} tagName - The tag name
|
|
9
|
+
* @param {string} message - The tag message
|
|
10
|
+
* @param {string} repository - GitHub repository (e.g., "owner/repo")
|
|
11
|
+
* @param {string} accessToken - GitHub access token
|
|
12
|
+
* @param {string} commitSha - The commit SHA to tag
|
|
13
|
+
* @returns {Promise<Object>} API response
|
|
14
|
+
*/
|
|
15
|
+
async function createTagViaAPI(tagName, message, repository, accessToken, commitSha) {
|
|
16
|
+
// Step 1: Create an annotated tag object
|
|
17
|
+
const tagObject = await makeRequest({
|
|
18
|
+
method: 'POST',
|
|
19
|
+
path: `/repos/${repository}/git/tags`,
|
|
20
|
+
accessToken,
|
|
21
|
+
body: {
|
|
22
|
+
tag: tagName,
|
|
23
|
+
message: message,
|
|
24
|
+
object: commitSha,
|
|
25
|
+
type: 'commit',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Step 2: Create a reference pointing to the tag object
|
|
30
|
+
await makeRequest({
|
|
31
|
+
method: 'POST',
|
|
32
|
+
path: `/repos/${repository}/git/refs`,
|
|
33
|
+
accessToken,
|
|
34
|
+
body: {
|
|
35
|
+
ref: `refs/tags/${tagName}`,
|
|
36
|
+
sha: tagObject.sha,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return tagObject;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Makes an HTTPS request to the GitHub API.
|
|
45
|
+
* @param {{method: string, path: string, accessToken: string, body?: Object}} options
|
|
46
|
+
* @returns {Promise<Object>}
|
|
47
|
+
*/
|
|
48
|
+
function makeRequest({ method, path, accessToken, body }) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const postData = body ? JSON.stringify(body) : '';
|
|
51
|
+
|
|
52
|
+
const options = {
|
|
53
|
+
hostname: 'api.github.com',
|
|
54
|
+
port: 443,
|
|
55
|
+
path: path,
|
|
56
|
+
method: method,
|
|
57
|
+
headers: {
|
|
58
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
59
|
+
'Accept': 'application/vnd.github+json',
|
|
60
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
61
|
+
'User-Agent': 'AgileFlow',
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
...(body && { 'Content-Length': Buffer.byteLength(postData) }),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const req = https.request(options, (res) => {
|
|
68
|
+
let data = '';
|
|
69
|
+
|
|
70
|
+
res.on('data', (chunk) => {
|
|
71
|
+
data += chunk;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
res.on('end', () => {
|
|
75
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
76
|
+
resolve(data ? JSON.parse(data) : {});
|
|
77
|
+
} else {
|
|
78
|
+
let errorMessage = `GitHub API request failed with status ${res.statusCode}`;
|
|
79
|
+
try {
|
|
80
|
+
const errorData = JSON.parse(data);
|
|
81
|
+
if (errorData.message) {
|
|
82
|
+
errorMessage += `: ${errorData.message}`;
|
|
83
|
+
}
|
|
84
|
+
if (res.statusCode === 401) {
|
|
85
|
+
errorMessage += '\n\nAuthentication failed. The AGILEFLOW_TOKEN is invalid or expired.';
|
|
86
|
+
errorMessage += '\nTo fix this:';
|
|
87
|
+
errorMessage += '\n1. Go to your repository Settings > Secrets and variables > Actions';
|
|
88
|
+
errorMessage += '\n2. Create a secret named AGILEFLOW_TOKEN with a Personal Access Token';
|
|
89
|
+
errorMessage += '\n3. The token needs "contents: write" permission';
|
|
90
|
+
} else if (res.statusCode === 403) {
|
|
91
|
+
errorMessage += '\n\nPermission denied. The AGILEFLOW_TOKEN needs "contents: write" permission.';
|
|
92
|
+
errorMessage += '\nTo fix this:';
|
|
93
|
+
errorMessage += '\n1. Ensure your token has "contents: write" scope';
|
|
94
|
+
errorMessage += '\n2. If using GITHUB_TOKEN, add permissions to your workflow';
|
|
95
|
+
} else if (res.statusCode === 422) {
|
|
96
|
+
errorMessage += '\n\nThe tag may already exist or the reference is invalid.';
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
if (data) {
|
|
100
|
+
errorMessage += `\nResponse: ${data}`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
reject(new Error(errorMessage));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
req.on('error', (error) => {
|
|
109
|
+
reject(new Error(`Network error: ${error.message}`));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (postData) {
|
|
113
|
+
req.write(postData);
|
|
114
|
+
}
|
|
115
|
+
req.end();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Pushes a tag to GitHub via the API.
|
|
121
|
+
* Requires AGILEFLOW_TOKEN environment variable.
|
|
122
|
+
* Uses GITHUB_REPOSITORY and GITHUB_SHA from GitHub Actions environment.
|
|
123
|
+
* @param {string} tagName - The tag name
|
|
124
|
+
* @param {string} message - The tag message
|
|
125
|
+
* @returns {Promise<void>}
|
|
126
|
+
*/
|
|
127
|
+
async function pushTag(tagName, message) {
|
|
128
|
+
const accessToken = process.env.AGILEFLOW_TOKEN;
|
|
129
|
+
const repository = process.env.GITHUB_REPOSITORY;
|
|
130
|
+
const commitSha = process.env.GITHUB_SHA;
|
|
131
|
+
|
|
132
|
+
if (!accessToken) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`AGILEFLOW_TOKEN environment variable is required but not set.\n\n` +
|
|
135
|
+
`To fix this:\n` +
|
|
136
|
+
`1. Create a Personal Access Token with "contents: write" permission\n` +
|
|
137
|
+
`2. Add it as a repository secret named AGILEFLOW_TOKEN\n` +
|
|
138
|
+
`3. In your workflow, add: env: AGILEFLOW_TOKEN: \${{ secrets.AGILEFLOW_TOKEN }}`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!repository) {
|
|
143
|
+
throw new Error('GITHUB_REPOSITORY environment variable is not set. Are you running inside GitHub Actions?');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!commitSha) {
|
|
147
|
+
throw new Error('GITHUB_SHA environment variable is not set. Are you running inside GitHub Actions?');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await createTagViaAPI(tagName, message || tagName, repository, accessToken, commitSha);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
pushTag,
|
|
155
|
+
};
|
|
156
|
+
|