@siranjeevan/releaseflow 1.0.0 โ 1.0.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/MANUAL.md +55 -0
- package/README.md +45 -0
- package/index.js +51 -17
- package/package.json +1 -1
package/MANUAL.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# ๐ ReleaseFlow Official User Manual
|
|
2
|
+
|
|
3
|
+
Welcome to **ReleaseFlow**, the ultimate automation tool for Flutter developers. This guide will help you master the system.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐ ๏ธ 1. Setup Phase
|
|
8
|
+
Before pushing your first update, you must link your project to Firebase.
|
|
9
|
+
- **Run**: `releaseflow configure`
|
|
10
|
+
- **What you need**:
|
|
11
|
+
1. Your Firebase Service Account JSON file.
|
|
12
|
+
2. Your Storage Bucket Name (found in Firebase Storage Console).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ๐ 2. Releasing an Update
|
|
17
|
+
This is the most common task. It builds the app and puts it in the cloud.
|
|
18
|
+
- **Run**: `releaseflow release`
|
|
19
|
+
- **What happens**:
|
|
20
|
+
- The CLI checks if your version is new (e.g., moves you from 1.0.4 to 1.0.5).
|
|
21
|
+
- It builds a small, optimized APK (< 15MB).
|
|
22
|
+
- It uploads the file and updates your users instantly.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## โช 3. Rolling Back
|
|
27
|
+
If you find a mistake in your latest version, you can go back.
|
|
28
|
+
- **Run**: `releaseflow rollback`
|
|
29
|
+
- **What happens**:
|
|
30
|
+
- You see a list of your last 3 versions.
|
|
31
|
+
- Pick one, and the database instantly points users back to that stable APK.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ๐งน 4. Storage Management
|
|
36
|
+
**You don't need to do anything!** The CLI automatically keeps only the 3 latest versions in your Firebase Storage to save you space and money.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ๐ฑ 5. Phone Behavior
|
|
41
|
+
- If a phone version is **different** from the live version, it will show the **Update Required** screen.
|
|
42
|
+
- If they are the same, the user sees your **Home Screen**.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## ๐ 6. Help Center
|
|
49
|
+
If you are stuck or encounter an error, join the official support group:
|
|
50
|
+
- **GitHub Issues**: https://github.com/siranjeevan/releaseflow-cli/issues
|
|
51
|
+
- **Community Support**: Check the Readme on NPM for latest updates.
|
|
52
|
+
- **Direct Help**: `releaseflow --help`
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
ยฉ 2026 ReleaseFlow | Designed for Flutter Developers ๐
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ๐ ReleaseFlow CLI
|
|
2
|
+
|
|
3
|
+
Automated Flutter Release Manager. Effortlessly build, version, and deploy Flutter APKs to Firebase with a single command.
|
|
4
|
+
|
|
5
|
+
## ๐ฆ Installation
|
|
6
|
+
|
|
7
|
+
Install globally via NPM:
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g @siranjeevan/releaseflow
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## ๐ ๏ธ First-Time Setup
|
|
13
|
+
|
|
14
|
+
1. **Configure Firebase**:
|
|
15
|
+
Run the configuration command to link your service account and storage bucket.
|
|
16
|
+
- **Bucket Name**: Enter your storage bucket (e.g., `your-project-id.firebasestorage.app`).
|
|
17
|
+
```bash
|
|
18
|
+
releaseflow configure
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
2. **Integrate Flutter**:
|
|
22
|
+
Ensure your Flutter app uses the `version_service` to check for updates against your Firestore `app_config/version` document.
|
|
23
|
+
|
|
24
|
+
## ๐ Usage
|
|
25
|
+
|
|
26
|
+
### Full Release (Build + Upload + Clean)
|
|
27
|
+
The most powerful command. It automatically detects your version, builds the optimized APK, and pushes it to Firebase.
|
|
28
|
+
```bash
|
|
29
|
+
releaseflow release
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Rollback
|
|
33
|
+
Instantly move the live version back to a previous stable build.
|
|
34
|
+
```bash
|
|
35
|
+
releaseflow rollback
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## โจ Key Features
|
|
39
|
+
- **Smart Versioning**: Automatically reads/increments `pubspec.yaml`.
|
|
40
|
+
- **Storage Cleanup**: Only keeps the 3 most recent APKs to save cloud space.
|
|
41
|
+
- **Optimized Builds**: Automatically builds for `arm64` to reduce APK size (< 15MB).
|
|
42
|
+
- **History Aware**: Never allows duplicate version releases.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
Created by [Jeevith](https://github.com/siranjeevan)
|
package/index.js
CHANGED
|
@@ -38,35 +38,69 @@ async function main() {
|
|
|
38
38
|
console.log('\x1b[36m%s\x1b[0m', '\n--- Configure Firebase Credentials ---');
|
|
39
39
|
await runConfigureFlow();
|
|
40
40
|
})
|
|
41
|
-
.
|
|
41
|
+
.command('manual', 'Open the detailed user manual', {}, async () => {
|
|
42
|
+
const manualPath = path.resolve(__dirname, 'MANUAL.md');
|
|
43
|
+
if (fs.existsSync(manualPath)) {
|
|
44
|
+
console.log('\n' + fs.readFileSync(manualPath, 'utf8'));
|
|
45
|
+
} else {
|
|
46
|
+
console.log('\x1b[31mManual file not found. Please check GitHub.\x1b[0m');
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
.demandCommand(1, 'โ Please specify a valid command.')
|
|
50
|
+
.recommendCommands()
|
|
51
|
+
.strict()
|
|
52
|
+
.showHelpOnFail(true, 'Type --help for the user manual.')
|
|
53
|
+
.epilogue(`
|
|
54
|
+
๐ USER MANUAL:
|
|
55
|
+
--------------------------------------------------
|
|
56
|
+
1. CONFIGURE: Run 'releaseflow configure' first to set up your Firebase keys.
|
|
57
|
+
2. RELEASE: Run 'releaseflow release' to build and push your app.
|
|
58
|
+
3. ROLLBACK: Run 'releaseflow rollback' to move back to an older version.
|
|
59
|
+
|
|
60
|
+
Support: https://github.com/siranjeevan/releaseflow-cli
|
|
61
|
+
--------------------------------------------------
|
|
62
|
+
`)
|
|
42
63
|
.help()
|
|
43
64
|
.argv;
|
|
44
65
|
}
|
|
45
66
|
|
|
46
|
-
|
|
67
|
+
// Global path detection for pubspec.yaml
|
|
68
|
+
function getProjectPaths() {
|
|
69
|
+
const cwd = process.cwd();
|
|
70
|
+
|
|
71
|
+
// Option 1: Current directory (user is inside flutter_app)
|
|
72
|
+
const p1 = path.join(cwd, 'pubspec.yaml');
|
|
73
|
+
// Option 2: flutter_app subfolder (user is in project root)
|
|
74
|
+
const p2 = path.join(cwd, 'flutter_app', 'pubspec.yaml');
|
|
75
|
+
|
|
76
|
+
if (fs.existsSync(p1)) return { root: cwd, pubspec: p1 };
|
|
77
|
+
if (fs.existsSync(p2)) return { root: path.join(cwd, 'flutter_app'), pubspec: p2 };
|
|
78
|
+
|
|
79
|
+
throw new Error('โ Could not find pubspec.yaml. Please run this command inside your Flutter project folder.');
|
|
80
|
+
}
|
|
47
81
|
|
|
48
82
|
function getPubspecVersion() {
|
|
49
83
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
84
|
+
const { pubspec } = getProjectPaths();
|
|
85
|
+
const doc = yaml.load(fs.readFileSync(pubspec, 'utf8'));
|
|
86
|
+
return doc.version.split('+')[0];
|
|
54
87
|
} catch (e) {
|
|
55
|
-
console.error('
|
|
88
|
+
console.error('\x1b[31mError: ' + e.message + '\x1b[0m');
|
|
89
|
+
process.exit(1);
|
|
56
90
|
}
|
|
57
|
-
return null;
|
|
58
91
|
}
|
|
59
92
|
|
|
60
93
|
function updatePubspecVersion(newVersion) {
|
|
61
94
|
try {
|
|
62
|
-
const
|
|
95
|
+
const { pubspec } = getProjectPaths();
|
|
96
|
+
const rawPubspec = fs.readFileSync(pubspec, 'utf8');
|
|
63
97
|
const updatedPubspec = rawPubspec.replace(/^version: ([\d\.]+)(.*)$/m, (match, v, build) => {
|
|
64
98
|
return `version: ${newVersion}${build || '+1'}`;
|
|
65
99
|
});
|
|
66
|
-
fs.writeFileSync(
|
|
100
|
+
fs.writeFileSync(pubspec, updatedPubspec);
|
|
67
101
|
return true;
|
|
68
102
|
} catch (e) {
|
|
69
|
-
console.error('
|
|
103
|
+
console.error('\x1b[31mError updating pubspec.yaml: ' + e.message + '\x1b[0m');
|
|
70
104
|
return false;
|
|
71
105
|
}
|
|
72
106
|
}
|
|
@@ -89,7 +123,7 @@ async function runConfigureFlow() {
|
|
|
89
123
|
type: 'input',
|
|
90
124
|
name: 'storageBucket',
|
|
91
125
|
message: 'Enter your Firebase Storage Bucket name:',
|
|
92
|
-
default: '
|
|
126
|
+
default: 'your-project-id.firebasestorage.app'
|
|
93
127
|
}
|
|
94
128
|
]);
|
|
95
129
|
|
|
@@ -140,10 +174,11 @@ async function runFullReleaseFlow() {
|
|
|
140
174
|
}
|
|
141
175
|
|
|
142
176
|
// Automated Build
|
|
143
|
-
|
|
177
|
+
const { root } = getProjectPaths();
|
|
178
|
+
console.log('\x1b[35m๐ ๏ธ Building Optimized APK (arm64)... Please wait...\x1b[0m');
|
|
144
179
|
|
|
145
180
|
const build = spawn('flutter', ['build', 'apk', '--release', '--split-per-abi', '--target-platform', 'android-arm64'], {
|
|
146
|
-
cwd:
|
|
181
|
+
cwd: root,
|
|
147
182
|
stdio: 'inherit'
|
|
148
183
|
});
|
|
149
184
|
|
|
@@ -154,8 +189,7 @@ async function runFullReleaseFlow() {
|
|
|
154
189
|
}
|
|
155
190
|
|
|
156
191
|
console.log('\x1b[32mโ Build Successful!\x1b[0m');
|
|
157
|
-
const apkPath = '
|
|
158
|
-
const fullApkPath = path.resolve(__dirname, apkPath);
|
|
192
|
+
const apkPath = path.join(root, 'build/app/outputs/flutter-apk/app-arm64-v8a-release.apk');
|
|
159
193
|
|
|
160
194
|
const answers = await inquirer.prompt([{
|
|
161
195
|
type: 'confirm',
|
|
@@ -166,7 +200,7 @@ async function runFullReleaseFlow() {
|
|
|
166
200
|
|
|
167
201
|
try {
|
|
168
202
|
console.log('\n\x1b[33m๐ Starting Cloud Release Flow...\x1b[0m');
|
|
169
|
-
const downloadUrl = await uploadApk(
|
|
203
|
+
const downloadUrl = await uploadApk(apkPath, localVersion);
|
|
170
204
|
await updateFirestore(localVersion, downloadUrl, answers.forceUpdate);
|
|
171
205
|
|
|
172
206
|
console.log('\n\x1b[35mSummary:\x1b[0m');
|