feat: add auto-update functionality and release scripts
This commit is contained in:
@@ -2,4 +2,96 @@ Introducing Notetaker, an open source Granola alternative for on-device AI meeti
|
|||||||
|
|
||||||
- 100% free (bring your own Deepgram & OpenAI API keys)
|
- 100% free (bring your own Deepgram & OpenAI API keys)
|
||||||
- 100% data privacy (data stored on device)
|
- 100% data privacy (data stored on device)
|
||||||
- 100% open source (please contribute)
|
- 100% open source (please contribute)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Implemented:
|
||||||
|
|
||||||
|
- Recording mic & system audio
|
||||||
|
- Live transcript using Deepgram
|
||||||
|
- Ability to also write down additional notes
|
||||||
|
- AI generated enhanced notes
|
||||||
|
- Copy functionality
|
||||||
|
- Meeting deletion functionality
|
||||||
|
- Meeting search functionality
|
||||||
|
- Abilty to edit system prompt
|
||||||
|
- Use your own API key
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
|
||||||
|
- Add license
|
||||||
|
- Auto updates
|
||||||
|
- Auto migration of meeting files (incase of format changes)
|
||||||
|
|
||||||
|
Later:
|
||||||
|
|
||||||
|
- Cool recording indicator (dancing bars)
|
||||||
|
- Connecting to your Google calendar
|
||||||
|
- Different note templates
|
||||||
|
- AI chat for asking questions about a meeting
|
||||||
|
- Ability to use different models
|
||||||
|
- Ability to use different STT providers
|
||||||
|
- Integrations for email, Slack, Notion, etc.
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
Open the project in Xcode
|
||||||
|
|
||||||
|
## Releasing a New Version
|
||||||
|
|
||||||
|
Follow these steps to create a new release with auto-updates:
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
<!-- - Apple Developer Account with valid certificates -->
|
||||||
|
|
||||||
|
- Homebrew packages: `brew install create-dmg sparkle`
|
||||||
|
- Make scripts executable: `chmod +x scripts/update_version.sh scripts/build_release.sh`
|
||||||
|
|
||||||
|
### Release Process
|
||||||
|
|
||||||
|
1. **Update the version number:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For bug fixes (1.0 → 1.0.1):
|
||||||
|
./scripts/update_version.sh patch
|
||||||
|
|
||||||
|
# For new features (1.0 → 1.1):
|
||||||
|
./scripts/update_version.sh minor
|
||||||
|
|
||||||
|
# For major changes (1.0 → 2.0):
|
||||||
|
./scripts/update_version.sh major
|
||||||
|
|
||||||
|
# For custom version:
|
||||||
|
./scripts/update_version.sh custom 1.2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Build the release:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/build_release.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
|
||||||
|
- Clean build the app in Release mode
|
||||||
|
- Create a signed DMG file
|
||||||
|
- Generate the appcast.xml for auto-updates
|
||||||
|
|
||||||
|
3. **Create GitHub Release:**
|
||||||
|
|
||||||
|
- Go to [GitHub Releases](https://github.com/owengretzinger/notetaker/releases)
|
||||||
|
- Click "Create a new release"
|
||||||
|
- Tag: `v1.0.1` (match the version number)
|
||||||
|
- Title: `Notetaker v1.0.1`
|
||||||
|
- Upload the DMG from `releases/` folder
|
||||||
|
- Write release notes describing changes
|
||||||
|
|
||||||
|
4. **Update appcast:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add appcast.xml
|
||||||
|
git commit -m "Update appcast for v1.0.1"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" standalone="yes"?>
|
||||||
|
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title>Notetaker</title>
|
||||||
|
<item>
|
||||||
|
<title>1.0</title>
|
||||||
|
<pubDate>Fri, 11 Jul 2025 08:36:54 -0400</pubDate>
|
||||||
|
<sparkle:version>1</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>1.0</sparkle:shortVersionString>
|
||||||
|
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
|
||||||
|
<enclosure url="https://github.com/owengretzinger/notetaker/releases/download/v1.0/Notetaker-1.0.dmg" length="4108528" type="application/octet-stream"/>
|
||||||
|
</item>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
CC5718382E2020490042BA88 /* OpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = CC5718372E2020490042BA88 /* OpenAI */; };
|
CC5718382E2020490042BA88 /* OpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = CC5718372E2020490042BA88 /* OpenAI */; };
|
||||||
|
CCBA53E72E212F1C00469D84 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = CCBA53E62E212F1C00469D84 /* Sparkle */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
CC5718382E2020490042BA88 /* OpenAI in Frameworks */,
|
CC5718382E2020490042BA88 /* OpenAI in Frameworks */,
|
||||||
|
CCBA53E72E212F1C00469D84 /* Sparkle in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -84,6 +86,7 @@
|
|||||||
name = notetaker;
|
name = notetaker;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
CC5718372E2020490042BA88 /* OpenAI */,
|
CC5718372E2020490042BA88 /* OpenAI */,
|
||||||
|
CCBA53E62E212F1C00469D84 /* Sparkle */,
|
||||||
);
|
);
|
||||||
productName = notetaker;
|
productName = notetaker;
|
||||||
productReference = CC5718182E201D8D0042BA88 /* notetaker.app */;
|
productReference = CC5718182E201D8D0042BA88 /* notetaker.app */;
|
||||||
@@ -115,6 +118,7 @@
|
|||||||
minimizedProjectReferenceProxies = 1;
|
minimizedProjectReferenceProxies = 1;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
CC5718362E2020490042BA88 /* XCRemoteSwiftPackageReference "OpenAI" */,
|
CC5718362E2020490042BA88 /* XCRemoteSwiftPackageReference "OpenAI" */,
|
||||||
|
CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||||
);
|
);
|
||||||
preferredProjectObjectVersion = 77;
|
preferredProjectObjectVersion = 77;
|
||||||
productRefGroup = CC5718192E201D8D0042BA88 /* Products */;
|
productRefGroup = CC5718192E201D8D0042BA88 /* Products */;
|
||||||
@@ -359,6 +363,14 @@
|
|||||||
minimumVersion = 0.4.4;
|
minimumVersion = 0.4.4;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/sparkle-project/Sparkle.git";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 2.7.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
@@ -367,6 +379,11 @@
|
|||||||
package = CC5718362E2020490042BA88 /* XCRemoteSwiftPackageReference "OpenAI" */;
|
package = CC5718362E2020490042BA88 /* XCRemoteSwiftPackageReference "OpenAI" */;
|
||||||
productName = OpenAI;
|
productName = OpenAI;
|
||||||
};
|
};
|
||||||
|
CCBA53E62E212F1C00469D84 /* Sparkle */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */;
|
||||||
|
productName = Sparkle;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = CC5718102E201D8D0042BA88 /* Project object */;
|
rootObject = CC5718102E201D8D0042BA88 /* Project object */;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "c351aabe13067917247f7926404d096603b95663248b51124280feb61a2edf30",
|
"originHash" : "e8774f1c4a54f0b9bb959e13d276fae95c54472a479606f1fd28800bfbcb6da5",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "openai",
|
"identity" : "openai",
|
||||||
@@ -10,6 +10,15 @@
|
|||||||
"version" : "0.4.4"
|
"version" : "0.4.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sparkle",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/sparkle-project/Sparkle.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "df074165274afaa39539c05d57b0832620775b11",
|
||||||
|
"version" : "2.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swift-http-types",
|
"identity" : "swift-http-types",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
@@ -6,5 +6,7 @@
|
|||||||
<string>Notetaker needs access to capture system audio for transcription.</string>
|
<string>Notetaker needs access to capture system audio for transcription.</string>
|
||||||
<key>NSScreenCaptureUsageDescription</key>
|
<key>NSScreenCaptureUsageDescription</key>
|
||||||
<string>Notetaker needs screen recording permission to capture system audio for transcription.</string>
|
<string>Notetaker needs screen recording permission to capture system audio for transcription.</string>
|
||||||
|
<key>SUFeedURL</key>
|
||||||
|
<string>https://raw.githubusercontent.com/owengretzinger/notetaker/main/appcast.xml</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -6,14 +6,37 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Sparkle
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct notetakerApp: App {
|
struct notetakerApp: App {
|
||||||
|
private let updaterController: SPUStandardUpdaterController
|
||||||
|
|
||||||
|
init() {
|
||||||
|
updaterController = SPUStandardUpdaterController(updaterDelegate: nil, userDriverDelegate: nil)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ContentView()
|
||||||
.frame(minWidth: 800, minHeight: 600)
|
.frame(minWidth: 800, minHeight: 600)
|
||||||
}
|
}
|
||||||
.windowResizability(.contentSize)
|
.windowResizability(.contentSize)
|
||||||
|
.commands {
|
||||||
|
CommandGroup(after: .appInfo) {
|
||||||
|
CheckForUpdatesView(updater: updaterController.updater)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckForUpdatesView: View {
|
||||||
|
let updater: SPUUpdater
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button("Check for Updates...") {
|
||||||
|
updater.checkForUpdates()
|
||||||
|
}
|
||||||
|
.keyboardShortcut("u", modifiers: .command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Executable
+81
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Build and Release Script for Notetaker
|
||||||
|
# This script builds the app, creates a DMG, and generates the appcast
|
||||||
|
|
||||||
|
set -e # Exit on any error
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
APP_NAME="Notetaker"
|
||||||
|
BUNDLE_ID="owen.notetaker"
|
||||||
|
VERSION=$(grep -m1 "MARKETING_VERSION" notetaker.xcodeproj/project.pbxproj | sed 's/.*= \(.*\);/\1/')
|
||||||
|
|
||||||
|
if [ -z "$VERSION" ]; then
|
||||||
|
echo "❌ Could not determine version from project file"
|
||||||
|
echo " Make sure notetaker.xcodeproj/project.pbxproj exists and contains MARKETING_VERSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
BUILD_DIR="$(pwd)/build"
|
||||||
|
RELEASES_DIR="$(pwd)/releases"
|
||||||
|
DMG_NAME="${APP_NAME}-${VERSION}.dmg"
|
||||||
|
|
||||||
|
echo "🚀 Building ${APP_NAME} v${VERSION}..."
|
||||||
|
|
||||||
|
# Clean and build
|
||||||
|
echo "📦 Building app..."
|
||||||
|
xcodebuild -project notetaker.xcodeproj -scheme notetaker -configuration Release -derivedDataPath "${BUILD_DIR}" clean build
|
||||||
|
|
||||||
|
# Find the built app
|
||||||
|
APP_PATH="${BUILD_DIR}/Build/Products/Release/${APP_NAME}.app"
|
||||||
|
|
||||||
|
if [ ! -d "$APP_PATH" ]; then
|
||||||
|
echo "❌ App not found at $APP_PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ App built successfully at $APP_PATH"
|
||||||
|
|
||||||
|
# Create DMG
|
||||||
|
echo "📀 Creating DMG..."
|
||||||
|
mkdir -p "$RELEASES_DIR"
|
||||||
|
|
||||||
|
# Remove old DMG if it exists
|
||||||
|
if [ -f "$RELEASES_DIR/$DMG_NAME" ]; then
|
||||||
|
rm "$RELEASES_DIR/$DMG_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create DMG using create-dmg
|
||||||
|
create-dmg \
|
||||||
|
--volname "$APP_NAME" \
|
||||||
|
--window-pos 200 120 \
|
||||||
|
--window-size 800 400 \
|
||||||
|
--icon-size 100 \
|
||||||
|
--icon "$APP_NAME.app" 200 190 \
|
||||||
|
--hide-extension "$APP_NAME.app" \
|
||||||
|
--app-drop-link 600 185 \
|
||||||
|
"$RELEASES_DIR/$DMG_NAME" \
|
||||||
|
"$APP_PATH"
|
||||||
|
|
||||||
|
echo "✅ DMG created: $RELEASES_DIR/$DMG_NAME"
|
||||||
|
|
||||||
|
# Generate appcast
|
||||||
|
echo "📡 Generating appcast..."
|
||||||
|
/opt/homebrew/Caskroom/sparkle/2.7.1/bin/generate_appcast "$RELEASES_DIR" \
|
||||||
|
--download-url-prefix "https://github.com/owengretzinger/notetaker/releases/download/v${VERSION}/" \
|
||||||
|
-o "appcast.xml"
|
||||||
|
|
||||||
|
echo "✅ Appcast generated: appcast.xml"
|
||||||
|
|
||||||
|
# Show file sizes
|
||||||
|
echo ""
|
||||||
|
echo "📊 Release Summary:"
|
||||||
|
echo " Version: $VERSION"
|
||||||
|
echo " DMG: $DMG_NAME ($(du -h "$RELEASES_DIR/$DMG_NAME" | cut -f1))"
|
||||||
|
echo " Location: $RELEASES_DIR/$DMG_NAME"
|
||||||
|
echo ""
|
||||||
|
echo "🎉 Release ready! Next steps:"
|
||||||
|
echo " 1. Test the DMG on another Mac"
|
||||||
|
echo " 2. Create a GitHub release with tag v${VERSION}"
|
||||||
|
echo " 3. Upload the DMG to the GitHub release"
|
||||||
|
echo " 4. Commit and push the appcast.xml file"
|
||||||
|
echo " 5. Your users will get auto-update notifications!"
|
||||||
Executable
+110
@@ -0,0 +1,110 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Version Update Script for Notetaker
|
||||||
|
# Usage: ./update_version.sh [major|minor|patch|build] [custom_version]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PROJECT_FILE="notetaker.xcodeproj/project.pbxproj"
|
||||||
|
CURRENT_MARKETING_VERSION=$(grep -m1 "MARKETING_VERSION" "$PROJECT_FILE" | sed 's/.*= \(.*\);/\1/')
|
||||||
|
CURRENT_BUILD_VERSION=$(grep -m1 "CURRENT_PROJECT_VERSION" "$PROJECT_FILE" | sed 's/.*= \(.*\);/\1/')
|
||||||
|
|
||||||
|
if [ -z "$CURRENT_MARKETING_VERSION" ] || [ -z "$CURRENT_BUILD_VERSION" ]; then
|
||||||
|
echo "❌ Could not determine current version from project file"
|
||||||
|
echo " Make sure $PROJECT_FILE exists and contains MARKETING_VERSION and CURRENT_PROJECT_VERSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📋 Current Version Info:"
|
||||||
|
echo " Marketing Version: $CURRENT_MARKETING_VERSION"
|
||||||
|
echo " Build Version: $CURRENT_BUILD_VERSION"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to increment version
|
||||||
|
increment_version() {
|
||||||
|
local version=$1
|
||||||
|
local type=$2
|
||||||
|
|
||||||
|
IFS='.' read -ra VERSION_PARTS <<< "$version"
|
||||||
|
local major=${VERSION_PARTS[0]:-0}
|
||||||
|
local minor=${VERSION_PARTS[1]:-0}
|
||||||
|
local patch=${VERSION_PARTS[2]:-0}
|
||||||
|
|
||||||
|
case $type in
|
||||||
|
"major")
|
||||||
|
major=$((major + 1))
|
||||||
|
minor=0
|
||||||
|
patch=0
|
||||||
|
;;
|
||||||
|
"minor")
|
||||||
|
minor=$((minor + 1))
|
||||||
|
patch=0
|
||||||
|
;;
|
||||||
|
"patch")
|
||||||
|
patch=$((patch + 1))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "❌ Invalid increment type: $type"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "${major}.${minor}.${patch}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to update version in project file
|
||||||
|
update_project_version() {
|
||||||
|
local new_marketing_version=$1
|
||||||
|
local new_build_version=$2
|
||||||
|
|
||||||
|
# Update marketing version
|
||||||
|
sed -i '' "s/MARKETING_VERSION = .*;/MARKETING_VERSION = $new_marketing_version;/g" "$PROJECT_FILE"
|
||||||
|
|
||||||
|
# Update build version
|
||||||
|
sed -i '' "s/CURRENT_PROJECT_VERSION = .*;/CURRENT_PROJECT_VERSION = $new_build_version;/g" "$PROJECT_FILE"
|
||||||
|
|
||||||
|
echo "✅ Updated project file:"
|
||||||
|
echo " Marketing Version: $CURRENT_MARKETING_VERSION → $new_marketing_version"
|
||||||
|
echo " Build Version: $CURRENT_BUILD_VERSION → $new_build_version"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main logic
|
||||||
|
case $1 in
|
||||||
|
"major"|"minor"|"patch")
|
||||||
|
NEW_MARKETING_VERSION=$(increment_version "$CURRENT_MARKETING_VERSION" "$1")
|
||||||
|
NEW_BUILD_VERSION=$((CURRENT_BUILD_VERSION + 1))
|
||||||
|
update_project_version "$NEW_MARKETING_VERSION" "$NEW_BUILD_VERSION"
|
||||||
|
;;
|
||||||
|
"build")
|
||||||
|
NEW_BUILD_VERSION=$((CURRENT_BUILD_VERSION + 1))
|
||||||
|
update_project_version "$CURRENT_MARKETING_VERSION" "$NEW_BUILD_VERSION"
|
||||||
|
;;
|
||||||
|
"custom")
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "❌ Please provide a custom version number"
|
||||||
|
echo "Usage: ./update_version.sh custom 1.2.0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
NEW_BUILD_VERSION=$((CURRENT_BUILD_VERSION + 1))
|
||||||
|
update_project_version "$2" "$NEW_BUILD_VERSION"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "🔢 Version Update Script"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " ./update_version.sh major # 1.0 → 2.0"
|
||||||
|
echo " ./update_version.sh minor # 1.0 → 1.1"
|
||||||
|
echo " ./update_version.sh patch # 1.0 → 1.0.1"
|
||||||
|
echo " ./update_version.sh build # Keep version, increment build"
|
||||||
|
echo " ./update_version.sh custom 1.2.0 # Set specific version"
|
||||||
|
echo ""
|
||||||
|
echo "Current version: $CURRENT_MARKETING_VERSION (build $CURRENT_BUILD_VERSION)"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🎯 Next steps:"
|
||||||
|
echo " 1. Test the app to make sure everything works"
|
||||||
|
echo " 2. Run ./build_release.sh to create a release"
|
||||||
|
echo " 3. The new version will be: $(grep -m1 "MARKETING_VERSION" "$PROJECT_FILE" | sed 's/.*= \(.*\);/\1/')"
|
||||||
Reference in New Issue
Block a user