Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## 10.2.2

* Fix `logout` command showing duplicate sessions
* Fix `logout` command showing a blank email even when logged out
* Add syncing of `tablesDB` resource during `push tables` command

## 10.2.1

* Add transaction support for Databases and TablesDB
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Once the installation is complete, you can verify the install using

```sh
$ appwrite -v
10.2.1
10.2.2
```

### Install using prebuilt binaries
Expand Down Expand Up @@ -60,7 +60,7 @@ $ scoop install https://raw.githubusercontent.com/appwrite/sdk-for-cli/master/sc
Once the installation completes, you can verify your install using
```
$ appwrite -v
10.2.1
10.2.2
```

## Getting Started
Expand Down
4 changes: 2 additions & 2 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
# You can use "View source" of this page to see the full script.

# REPO
$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.1/appwrite-cli-win-x64.exe"
$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.1/appwrite-cli-win-arm64.exe"
$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-x64.exe"
$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-arm64.exe"

$APPWRITE_BINARY_NAME = "appwrite.exe"

Expand Down
2 changes: 1 addition & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ printSuccess() {
downloadBinary() {
echo "[2/4] Downloading executable for $OS ($ARCH) ..."

GITHUB_LATEST_VERSION="10.2.1"
GITHUB_LATEST_VERSION="10.2.2"
GITHUB_FILE="appwrite-cli-${OS}-${ARCH}"
GITHUB_URL="https://github.com/$GITHUB_REPOSITORY_NAME/releases/download/$GITHUB_LATEST_VERSION/$GITHUB_FILE"

Expand Down
4 changes: 2 additions & 2 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class Client {
'x-sdk-name': 'Command Line',
'x-sdk-platform': 'console',
'x-sdk-language': 'cli',
'x-sdk-version': '10.2.1',
'user-agent' : `AppwriteCLI/10.2.1 (${os.type()} ${os.version()}; ${os.arch()})`,
'x-sdk-version': '10.2.2',
'user-agent' : `AppwriteCLI/10.2.2 (${os.type()} ${os.version()}; ${os.arch()})`,
'X-Appwrite-Response-Format' : '1.8.0',
};
}
Expand Down
8 changes: 5 additions & 3 deletions lib/commands/generic.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,11 @@ const deleteSession = async (accountId) => {
parseOutput: false,
sdk: client
})

globalConfig.removeSession(accountId);
} catch (e) {
error('Unable to log out, removing locally saved session information')
} finally {
globalConfig.removeSession(accountId);
}
globalConfig.removeSession(accountId);
}

const logout = new Command("logout")
Expand All @@ -194,6 +193,7 @@ const logout = new Command("logout")
}
if (sessions.length === 1) {
await deleteSession(current);
globalConfig.setCurrentSession('');
success("Logging out");

return;
Expand All @@ -215,6 +215,8 @@ const logout = new Command("logout")
globalConfig.setCurrentSession(accountId);

success(`Current account is ${accountId}`);
} else if (remainingSessions.length === 0) {
globalConfig.setCurrentSession('');
}

success("Logging out");
Expand Down
198 changes: 164 additions & 34 deletions lib/commands/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ const {
tablesDBUpdate,
tablesDBCreateTable,
tablesDBGetTable,
tablesDBUpdateTable
tablesDBUpdateTable,
tablesDBList,
tablesDBDelete,
tablesDBListTables
} = require("./tables-db");
const {
storageGetBucket, storageUpdateBucket, storageCreateBucket
Expand Down Expand Up @@ -1700,13 +1703,173 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur
}
}

const checkAndApplyTablesDBChanges = async () => {
log('Checking for tablesDB changes ...');

const localTablesDBs = localConfig.getTablesDBs();
const { databases: remoteTablesDBs } = await paginate(tablesDBList, { parseOutput: false }, 100, 'databases');

if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) {
return { applied: false, resyncNeeded: false };
}

const changes = [];
const toCreate = [];
const toUpdate = [];
const toDelete = [];

// Check for deletions - remote DBs that aren't in local config
for (const remoteDB of remoteTablesDBs) {
const localDB = localTablesDBs.find(db => db.$id === remoteDB.$id);
if (!localDB) {
toDelete.push(remoteDB);
changes.push({
id: remoteDB.$id,
key: 'Database',
remote: chalk.red(`${remoteDB.name} (${remoteDB.$id})`),
local: chalk.green('(deleted locally)')
});
}
}

// Check for additions and updates
for (const localDB of localTablesDBs) {
const remoteDB = remoteTablesDBs.find(db => db.$id === localDB.$id);

if (!remoteDB) {
toCreate.push(localDB);
changes.push({
id: localDB.$id,
key: 'Database',
remote: chalk.red('(does not exist)'),
local: chalk.green(`${localDB.name} (${localDB.$id})`)
});
} else {
let hasChanges = false;

if (remoteDB.name !== localDB.name) {
hasChanges = true;
changes.push({
id: localDB.$id,
key: 'Name',
remote: chalk.red(remoteDB.name),
local: chalk.green(localDB.name)
});
}

if (remoteDB.enabled !== localDB.enabled) {
hasChanges = true;
changes.push({
id: localDB.$id,
key: 'Enabled?',
remote: chalk.red(remoteDB.enabled),
local: chalk.green(localDB.enabled)
});
}

if (hasChanges) {
toUpdate.push(localDB);
}
}
}

if (changes.length === 0) {
return { applied: false, resyncNeeded: false };
}

log('Found changes in tablesDB resources:');
drawTable(changes);

if (toDelete.length > 0) {
console.log(`${chalk.red('-------------------------------------------------------------------')}`);
console.log(`${chalk.red('| WARNING: Database deletion will also delete all related tables |')}`);
console.log(`${chalk.red('-------------------------------------------------------------------')}`);
}

if ((await getConfirmation()) !== true) {
return { applied: false, resyncNeeded: false };
}

// Apply deletions first
let needsResync = false;
for (const db of toDelete) {
try {
log(`Deleting database ${db.name} ( ${db.$id} ) ...`);
await tablesDBDelete({
databaseId: db.$id,
parseOutput: false
});
success(`Deleted ${db.name} ( ${db.$id} )`);
needsResync = true;
} catch (e) {
error(`Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`);
throw new Error(`Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`);
}
}

// Apply creations
for (const db of toCreate) {
try {
log(`Creating database ${db.name} ( ${db.$id} ) ...`);
await tablesDBCreate({
databaseId: db.$id,
name: db.name,
enabled: db.enabled,
parseOutput: false
});
success(`Created ${db.name} ( ${db.$id} )`);
} catch (e) {
error(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`);
throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`);
}
}

// Apply updates
for (const db of toUpdate) {
try {
log(`Updating database ${db.name} ( ${db.$id} ) ...`);
await tablesDBUpdate({
databaseId: db.$id,
name: db.name,
enabled: db.enabled,
parseOutput: false
});
success(`Updated ${db.name} ( ${db.$id} )`);
} catch (e) {
error(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`);
throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`);
}
}

return { applied: true, resyncNeeded: needsResync };
};

const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => {
const tables = [];

if (attempts) {
pollMaxDebounces = attempts;
}

const { applied: tablesDBApplied, resyncNeeded } = await checkAndApplyTablesDBChanges();
if (resyncNeeded) {
log('Resyncing configuration due to tablesDB deletions ...');

const remoteTablesDBs = (await paginate(tablesDBList, { parseOutput: false }, 100, 'databases')).databases;
const localTablesDBs = localConfig.getTablesDBs();

const remoteDatabaseIds = new Set(remoteTablesDBs.map(db => db.$id));
const localTables = localConfig.getTables();
const validTables = localTables.filter(table => remoteDatabaseIds.has(table.databaseId));

localConfig.set('tables', validTables);

const validTablesDBs = localTablesDBs.filter(db => remoteDatabaseIds.has(db.$id));
localConfig.set('tablesDB', validTablesDBs);

success('Configuration resynced successfully.');
}

if (cliConfig.all) {
checkDeployConditions(localConfig);
tables.push(...localConfig.getTables());
Expand All @@ -1730,39 +1893,6 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) =
return;
}

const databases = Array.from(new Set(tables.map(table => table['databaseId'])));

// Parallel tablesDB actions
await Promise.all(databases.map(async (databaseId) => {
const localDatabase = localConfig.getTablesDB(databaseId);

try {
const database = await tablesDBGet({
databaseId: databaseId,
parseOutput: false,
});

if (database.name !== (localDatabase.name ?? databaseId)) {
await tablesDBUpdate({
databaseId: databaseId,
name: localDatabase.name ?? databaseId,
parseOutput: false
})

success(`Updated ${localDatabase.name} ( ${databaseId} ) name`);
}
} catch (err) {
log(`Database ${databaseId} not found. Creating it now ...`);

await tablesDBCreate({
databaseId: databaseId,
name: localDatabase.name ?? databaseId,
parseOutput: false,
});
}
}));


if (!(await approveChanges(tables, tablesDBGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) {
return;
}
Expand Down
24 changes: 17 additions & 7 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -681,15 +681,25 @@ class Global extends Config {

getSessions() {
const sessions = Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key))
const current = this.getCurrentSession();

return sessions.map((session) => {

return {
id: session,
endpoint: this.data[session][Global.PREFERENCE_ENDPOINT],
email: this.data[session][Global.PREFERENCE_EMAIL]
const sessionMap = new Map();

sessions.forEach((sessionId) => {
const email = this.data[sessionId][Global.PREFERENCE_EMAIL];
const endpoint = this.data[sessionId][Global.PREFERENCE_ENDPOINT];
const key = `${email}|${endpoint}`;

if (sessionId === current || !sessionMap.has(key)) {
sessionMap.set(key, {
id: sessionId,
endpoint: this.data[sessionId][Global.PREFERENCE_ENDPOINT],
email: this.data[sessionId][Global.PREFERENCE_EMAIL]
});
}
})
});

return Array.from(sessionMap.values());
}

addSession(session, data) {
Expand Down
2 changes: 1 addition & 1 deletion lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const parseError = (err) => {
} catch {
}

const version = '10.2.1';
const version = '10.2.2';
const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``;
const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`;

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "appwrite-cli",
"homepage": "https://appwrite.io/support",
"description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
"version": "10.2.1",
"version": "10.2.2",
"license": "BSD-3-Clause",
"main": "index.js",
"bin": {
Expand Down
6 changes: 3 additions & 3 deletions scoop/appwrite.config.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json",
"version": "10.2.1",
"version": "10.2.2",
"description": "The Appwrite CLI is a command-line application that allows you to interact with Appwrite and perform server-side tasks using your terminal.",
"homepage": "https://github.com/appwrite/sdk-for-cli",
"license": "BSD-3-Clause",
"architecture": {
"64bit": {
"url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.1/appwrite-cli-win-x64.exe",
"url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-x64.exe",
"bin": [
[
"appwrite-cli-win-x64.exe",
Expand All @@ -15,7 +15,7 @@
]
},
"arm64": {
"url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.1/appwrite-cli-win-arm64.exe",
"url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-arm64.exe",
"bin": [
[
"appwrite-cli-win-arm64.exe",
Expand Down