forked from qt-creator/qt-creator
Axivion: Check for local dashboard results
Enable the local dashboard button depending on the existence of available results. Start local dashboards on request and shut them down at end. Task-number: QTCREATORBUG-32385 Change-Id: I31083669f0c042195570da51d24fd6c95449e1ea Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
add_qtc_plugin(Axivion
|
add_qtc_plugin(Axivion
|
||||||
PLUGIN_DEPENDS
|
PLUGIN_DEPENDS
|
||||||
Core Debugger ProjectExplorer TextEditor
|
Core Debugger ProjectExplorer TextEditor
|
||||||
DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils
|
DEPENDS Qt::Network Qt::Sql Qt::Widgets ExtensionSystem Utils
|
||||||
LONG_DESCRIPTION_MD AxivionDescription.md
|
LONG_DESCRIPTION_MD AxivionDescription.md
|
||||||
SOURCES
|
SOURCES
|
||||||
axivionperspective.cpp axivionperspective.h
|
axivionperspective.cpp axivionperspective.h
|
||||||
@@ -14,6 +14,7 @@ add_qtc_plugin(Axivion
|
|||||||
dashboard/error.cpp dashboard/error.h
|
dashboard/error.cpp dashboard/error.h
|
||||||
dynamiclistmodel.cpp dynamiclistmodel.h
|
dynamiclistmodel.cpp dynamiclistmodel.h
|
||||||
issueheaderview.cpp issueheaderview.h
|
issueheaderview.cpp issueheaderview.h
|
||||||
|
localbuild.cpp localbuild.h
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB_RECURSE images RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} images/*)
|
file(GLOB_RECURSE images RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} images/*)
|
||||||
|
@@ -9,8 +9,7 @@ QtcPlugin {
|
|||||||
Depends { name: "ProjectExplorer" }
|
Depends { name: "ProjectExplorer" }
|
||||||
Depends { name: "TextEditor" }
|
Depends { name: "TextEditor" }
|
||||||
Depends { name: "Utils" }
|
Depends { name: "Utils" }
|
||||||
Depends { name: "Qt.widgets" }
|
Depends { name: "Qt"; submodules: ["network", "sql", "widgets"] }
|
||||||
Depends { name: "Qt.network" }
|
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
"axivionperspective.cpp",
|
"axivionperspective.cpp",
|
||||||
@@ -24,6 +23,8 @@ QtcPlugin {
|
|||||||
"dynamiclistmodel.h",
|
"dynamiclistmodel.h",
|
||||||
"issueheaderview.cpp",
|
"issueheaderview.cpp",
|
||||||
"issueheaderview.h",
|
"issueheaderview.h",
|
||||||
|
"localbuild.cpp",
|
||||||
|
"localbuild.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
cpp.includePaths: base.concat(["."]) // needed for the generated stuff below
|
cpp.includePaths: base.concat(["."]) // needed for the generated stuff below
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include "dashboard/dto.h"
|
#include "dashboard/dto.h"
|
||||||
#include "issueheaderview.h"
|
#include "issueheaderview.h"
|
||||||
#include "dynamiclistmodel.h"
|
#include "dynamiclistmodel.h"
|
||||||
|
#include "localbuild.h"
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -212,6 +213,7 @@ private:
|
|||||||
void fetchTable();
|
void fetchTable();
|
||||||
void fetchIssues(const IssueListSearch &search);
|
void fetchIssues(const IssueListSearch &search);
|
||||||
void onFetchRequested(int startRow, int limit);
|
void onFetchRequested(int startRow, int limit);
|
||||||
|
void switchDashboard(bool local);
|
||||||
void hideOverlays();
|
void hideOverlays();
|
||||||
void openFilterHelp();
|
void openFilterHelp();
|
||||||
|
|
||||||
@@ -308,11 +310,11 @@ IssuesWidget::IssuesWidget(QWidget *parent)
|
|||||||
localLayout->addWidget(m_localDashBoard);
|
localLayout->addWidget(m_localDashBoard);
|
||||||
connect(&settings(), &AxivionSettings::suitePathValidated, this, [this] {
|
connect(&settings(), &AxivionSettings::suitePathValidated, this, [this] {
|
||||||
const auto info = settings().versionInfo();
|
const auto info = settings().versionInfo();
|
||||||
const bool enable = info && !info->versionNumber.isEmpty(); // for now
|
const bool enable = info && !info->versionNumber.isEmpty();
|
||||||
m_localBuild->setEnabled(enable);
|
m_localBuild->setEnabled(enable);
|
||||||
m_localDashBoard->setEnabled(enable);
|
checkForLocalBuildResults(m_currentProject, [this] { m_localDashBoard->setEnabled(true); });
|
||||||
});
|
});
|
||||||
|
connect(m_localDashBoard, &QToolButton::clicked, this, &IssuesWidget::switchDashboard);
|
||||||
m_typesButtonGroup = new QButtonGroup(this);
|
m_typesButtonGroup = new QButtonGroup(this);
|
||||||
m_typesButtonGroup->setExclusive(true);
|
m_typesButtonGroup->setExclusive(true);
|
||||||
m_typesLayout = new QHBoxLayout;
|
m_typesLayout = new QHBoxLayout;
|
||||||
@@ -855,7 +857,7 @@ void IssuesWidget::updateBasicProjectInfo(const std::optional<Dto::ProjectInfoDt
|
|||||||
std::optional<AxivionVersionInfo> suiteVersionInfo = settings().versionInfo();
|
std::optional<AxivionVersionInfo> suiteVersionInfo = settings().versionInfo();
|
||||||
m_localBuild->setEnabled(!m_currentProject.isEmpty()
|
m_localBuild->setEnabled(!m_currentProject.isEmpty()
|
||||||
&& suiteVersionInfo && !suiteVersionInfo->versionNumber.isEmpty());
|
&& suiteVersionInfo && !suiteVersionInfo->versionNumber.isEmpty());
|
||||||
m_localDashBoard->setEnabled(true);
|
checkForLocalBuildResults(m_currentProject, [this] { m_localDashBoard->setEnabled(true); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void IssuesWidget::updateAllFilters(const QVariant &namedFilter)
|
void IssuesWidget::updateAllFilters(const QVariant &namedFilter)
|
||||||
@@ -1010,6 +1012,16 @@ void IssuesWidget::showErrorMessage(const QString &message)
|
|||||||
m_stack->setCurrentIndex(1);
|
m_stack->setCurrentIndex(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IssuesWidget::switchDashboard(bool local)
|
||||||
|
{
|
||||||
|
if (local) {
|
||||||
|
QTC_ASSERT(!m_currentProject.isEmpty(), return);
|
||||||
|
startLocalDashboard(m_currentProject, {});
|
||||||
|
} else {
|
||||||
|
// TODO switch back
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IssuesWidget::hideOverlays()
|
void IssuesWidget::hideOverlays()
|
||||||
{
|
{
|
||||||
if (m_overlay)
|
if (m_overlay)
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "axiviontr.h"
|
#include "axiviontr.h"
|
||||||
#include "dashboard/dto.h"
|
#include "dashboard/dto.h"
|
||||||
#include "dashboard/error.h"
|
#include "dashboard/error.h"
|
||||||
|
#include "localbuild.h"
|
||||||
|
|
||||||
#include <coreplugin/credentialquery.h>
|
#include <coreplugin/credentialquery.h>
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
@@ -1227,6 +1228,14 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin
|
|||||||
connect(EditorManager::instance(), &EditorManager::documentClosed,
|
connect(EditorManager::instance(), &EditorManager::documentClosed,
|
||||||
dd, &AxivionPluginPrivate::onDocumentClosed);
|
dd, &AxivionPluginPrivate::onDocumentClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShutdownFlag aboutToShutdown() final
|
||||||
|
{
|
||||||
|
if (shutdownAllLocalDashboards([this] { emit asynchronousShutdownFinished(); }))
|
||||||
|
return AsynchronousShutdown;
|
||||||
|
else
|
||||||
|
return SynchronousShutdown;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void fetchIssueInfo(const QString &id)
|
void fetchIssueInfo(const QString &id)
|
||||||
|
296
src/plugins/axivion/localbuild.cpp
Normal file
296
src/plugins/axivion/localbuild.cpp
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "localbuild.h"
|
||||||
|
|
||||||
|
#include "axivionperspective.h"
|
||||||
|
#include "axivionsettings.h"
|
||||||
|
#include "axiviontr.h"
|
||||||
|
|
||||||
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
|
#include <solutions/tasking/tasktree.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/commandline.h>
|
||||||
|
#include <utils/environment.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QSqlDriver>
|
||||||
|
#include <QSqlError>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlResult>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using namespace Tasking;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace Axivion::Internal {
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(sqlLog, "qtc.axivion.sql", QtWarningMsg)
|
||||||
|
Q_LOGGING_CATEGORY(localDashLog, "qtc.axivion.localdashboard", QtWarningMsg)
|
||||||
|
|
||||||
|
struct LocalDashboard
|
||||||
|
{
|
||||||
|
QString id;
|
||||||
|
CommandLine startCommandLine;
|
||||||
|
CommandLine stopCommandLine;
|
||||||
|
Environment environment;
|
||||||
|
|
||||||
|
// access data will be updated after successful start
|
||||||
|
QUrl localUrl;
|
||||||
|
QString localUser;
|
||||||
|
QString localProject;
|
||||||
|
QByteArray pass;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LocalBuild
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LocalBuild() {}
|
||||||
|
~LocalBuild()
|
||||||
|
{
|
||||||
|
QTC_CHECK(m_startedDashboards.isEmpty()); // shutdownAll() must be done already
|
||||||
|
QTC_CHECK(m_startedDashboardTrees.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void startDashboard(const QString &projectName, const LocalDashboard &dashboard,
|
||||||
|
const std::function<void()> &callback);
|
||||||
|
bool shutdownAll(const std::function<void()> &callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, LocalDashboard> m_startedDashboards;
|
||||||
|
std::unordered_map<QString, std::unique_ptr<TaskTree>> m_startedDashboardTrees;
|
||||||
|
};
|
||||||
|
|
||||||
|
void LocalBuild::startDashboard(const QString &projectName, const LocalDashboard &dashboard,
|
||||||
|
const std::function<void()> &callback)
|
||||||
|
{
|
||||||
|
if (ExtensionSystem::PluginManager::isShuttingDown())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Storage<LocalDashboard> storage;
|
||||||
|
const auto onSetup = [dash = dashboard](Process &process) {
|
||||||
|
process.setCommand(dash.startCommandLine);
|
||||||
|
process.setEnvironment(dash.environment);
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskTree *taskTree = new TaskTree;
|
||||||
|
m_startedDashboardTrees.insert_or_assign(projectName, std::unique_ptr<TaskTree>(taskTree));
|
||||||
|
const auto onDone = [this, callback, dash = dashboard, projectName] (const Process &process) {
|
||||||
|
const auto onFinish = qScopeGuard([this, projectName] {
|
||||||
|
auto it = m_startedDashboardTrees.find(projectName);
|
||||||
|
QTC_ASSERT(it != m_startedDashboardTrees.end(), return);
|
||||||
|
it->second.release()->deleteLater();
|
||||||
|
m_startedDashboardTrees.erase(it);
|
||||||
|
});
|
||||||
|
if (process.result() != ProcessResult::FinishedWithSuccess) {
|
||||||
|
qCDebug(localDashLog) << "Process failed...." << int(process.result());
|
||||||
|
const QString errOutput = process.cleanedStdErr();
|
||||||
|
if (errOutput.isEmpty())
|
||||||
|
showErrorMessage(Tr::tr("Failed to start local dashboard."));
|
||||||
|
else
|
||||||
|
showErrorMessage(errOutput);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QString output = process.cleanedStdOut();
|
||||||
|
QJsonParseError error;
|
||||||
|
const QJsonDocument json = QJsonDocument::fromJson(output.toUtf8(), &error);
|
||||||
|
if (error.error != QJsonParseError::NoError)
|
||||||
|
return;
|
||||||
|
if (!json.isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
LocalDashboard updated = dash;
|
||||||
|
const QJsonObject data = json.object();
|
||||||
|
updated.localUrl = QUrl::fromUserInput(data.value("url").toString());
|
||||||
|
updated.localProject = data.value("project").toString();
|
||||||
|
updated.localUser = data.value("user").toString();
|
||||||
|
updated.pass = data.value("password").toString().toUtf8();
|
||||||
|
|
||||||
|
m_startedDashboards.insert(updated.id, updated);
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
m_startedDashboards.insert(dashboard.id, dashboard);
|
||||||
|
qCDebug(localDashLog) << "Dashboard [start]" << dashboard.startCommandLine.toUserOutput();
|
||||||
|
taskTree->setRecipe({ProcessTask(onSetup, onDone)});
|
||||||
|
taskTree->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalBuild::shutdownAll(const std::function<void()> &callback)
|
||||||
|
{
|
||||||
|
for (auto it = m_startedDashboardTrees.begin(), end = m_startedDashboardTrees.end();
|
||||||
|
it != end; ++it) {
|
||||||
|
if (it->second)
|
||||||
|
it->second->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_startedDashboards.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const LoopList iterator(m_startedDashboards.values());
|
||||||
|
|
||||||
|
const auto onSetup = [iterator](Process &process) {
|
||||||
|
process.setCommand(iterator->stopCommandLine);
|
||||||
|
process.setEnvironment(iterator->environment);
|
||||||
|
qCDebug(localDashLog) << "Dashboard [stop]" << iterator->stopCommandLine.toUserOutput();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto onDone = [this, iterator](const Process &) {
|
||||||
|
m_startedDashboards.remove(iterator->id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Group recipe = Group {
|
||||||
|
For (iterator) >> Do {
|
||||||
|
parallel,
|
||||||
|
continueOnError,
|
||||||
|
ProcessTask(onSetup, onDone)
|
||||||
|
}
|
||||||
|
}.withTimeout(std::chrono::seconds(5));
|
||||||
|
|
||||||
|
TaskTree *taskTree = new TaskTree(recipe);
|
||||||
|
QObject::connect(taskTree, &TaskTree::done, taskTree, [taskTree, callback] {
|
||||||
|
taskTree->deleteLater();
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
taskTree->start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalBuild s_localBuildInstance;
|
||||||
|
|
||||||
|
static QSqlDatabase localDashboardDB()
|
||||||
|
{
|
||||||
|
static QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "localDashboardDB");
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkForLocalBuildResults(const QString &projectName, const std::function<void()> &callback)
|
||||||
|
{
|
||||||
|
const FilePath configDbl = FileUtils::homePath().pathAppended(".bauhaus/localbuild/config.dbl");
|
||||||
|
if (!configDbl.exists())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!QSqlDatabase::isDriverAvailable("QSQLITE"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSqlDatabase db = localDashboardDB();
|
||||||
|
if (!db.isValid())
|
||||||
|
return;
|
||||||
|
db.setDatabaseName(configDbl.path());
|
||||||
|
if (!db.open()) {
|
||||||
|
qCDebug(sqlLog) << "open db failed" << db.lastError().text();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cleanup = qScopeGuard([&db] { db.close(); });
|
||||||
|
|
||||||
|
QSqlQuery query(db);
|
||||||
|
query.prepare("SELECT Data FROM axMetaData WHERE Name=\"version\"");
|
||||||
|
if (!query.exec() || !query.next())
|
||||||
|
return;
|
||||||
|
if (!query.value("Data").toString().startsWith("1."))
|
||||||
|
return;
|
||||||
|
|
||||||
|
query.prepare("SELECT COUNT(*) FROM axLocalProjects WHERE Remote_Project_Name=(:projectName)");
|
||||||
|
query.bindValue(":projectName", projectName);
|
||||||
|
|
||||||
|
if (!query.exec() || !query.next())
|
||||||
|
return;
|
||||||
|
bool ok = true;
|
||||||
|
const int count = query.value(0).toUInt(&ok);
|
||||||
|
if (!ok || count < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandLine parseCommandLine(const QString &jsonArrayCmd)
|
||||||
|
{
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(jsonArrayCmd.toUtf8(), &error);
|
||||||
|
if (error.error != QJsonParseError::NoError)
|
||||||
|
return {};
|
||||||
|
if (!doc.isArray())
|
||||||
|
return {};
|
||||||
|
const QJsonArray array = doc.array();
|
||||||
|
QStringList fullCommand;
|
||||||
|
for (const auto &val : array)
|
||||||
|
fullCommand.append(val.toString());
|
||||||
|
if (fullCommand.isEmpty())
|
||||||
|
return {};
|
||||||
|
const QString first = fullCommand.takeFirst();
|
||||||
|
return CommandLine{FilePath::fromUserInput(first).withExecutableSuffix(), fullCommand};
|
||||||
|
}
|
||||||
|
|
||||||
|
void startLocalDashboard(const QString &projectName, const std::function<void ()> &callback)
|
||||||
|
{
|
||||||
|
QSqlDatabase db = localDashboardDB();
|
||||||
|
QTC_ASSERT(db.isValid(), return); // we should be here only if we had some valid db before
|
||||||
|
if (!db.open()) {
|
||||||
|
qCDebug(sqlLog) << "open db failed" << db.lastError().text();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cleanup = qScopeGuard([&db]{ db.close(); });
|
||||||
|
|
||||||
|
QSqlQuery query(db);
|
||||||
|
query.prepare("SELECT ID, Dashboard_Start_Command_Line, Dashboard_Stop_Command_Line "
|
||||||
|
"FROM axLocalProjects WHERE Remote_Project_Name=(:projectName)");
|
||||||
|
query.bindValue(":projectName", projectName);
|
||||||
|
if (!query.exec() || !query.next())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString id = query.value("ID").toString();
|
||||||
|
const QString startCmdLine = query.value("Dashboard_Start_Command_Line").toString();
|
||||||
|
const QString stopCmdLine = query.value("Dashboard_Stop_Command_Line").toString();
|
||||||
|
|
||||||
|
query.prepare("SELECT Name, Value FROM axDashboardEnvironments WHERE LocalProject_ID=(:id)");
|
||||||
|
query.bindValue(":id", id);
|
||||||
|
|
||||||
|
if (!query.exec())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString userAgent("Axivion" + QCoreApplication::applicationName() +
|
||||||
|
"Plugin/" + QCoreApplication::applicationVersion());
|
||||||
|
EnvironmentItems envItems;
|
||||||
|
if (!settings().bauhausPython().isEmpty())
|
||||||
|
envItems.append(EnvironmentItem("BAUHAUS_PYTHON", settings().bauhausPython().path()));
|
||||||
|
if (!settings().javaHome().isEmpty())
|
||||||
|
envItems.append(EnvironmentItem("JAVA_HOME", settings().javaHome().path()));
|
||||||
|
envItems.append(EnvironmentItem("AXIVION_USER_AGENT", userAgent));
|
||||||
|
while (query.next()) {
|
||||||
|
const QString name = query.value("Name").toString();
|
||||||
|
const QString value = query.value("Value").toString();
|
||||||
|
QTC_ASSERT(!name.isEmpty(), continue);
|
||||||
|
envItems.append(EnvironmentItem(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment env = Environment::systemEnvironment();
|
||||||
|
env.modify(envItems);
|
||||||
|
const CommandLine start = parseCommandLine(startCmdLine);
|
||||||
|
const CommandLine stop = parseCommandLine(stopCmdLine);
|
||||||
|
|
||||||
|
LocalDashboard localDashboard{id, start, stop, env, {}, {}, {}, {}};
|
||||||
|
s_localBuildInstance.startDashboard(projectName, localDashboard, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shutdownAllLocalDashboards(const std::function<void()> &callback)
|
||||||
|
{
|
||||||
|
return s_localBuildInstance.shutdownAll(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Axivion::Internal
|
14
src/plugins/axivion/localbuild.h
Normal file
14
src/plugins/axivion/localbuild.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace Axivion::Internal {
|
||||||
|
|
||||||
|
void checkForLocalBuildResults(const QString &projectName, const std::function<void()> &callback);
|
||||||
|
void startLocalDashboard(const QString &projectName, const std::function<void()> &callback);
|
||||||
|
bool shutdownAllLocalDashboards(const std::function<void()> &callback);
|
||||||
|
|
||||||
|
} // namespace Axivion::Internal
|
Reference in New Issue
Block a user