Merge branch 'master' of github.com:mattermost/mattermost-server into MM-50966-in-product-expansion-backend

Этот коммит содержится в:
Conor Macpherson
2023-03-27 13:29:20 -04:00
родитель 336176f8cb 1cf0cff9c6
Коммит 1b9d97209d
107 изменённых файлов: 2137 добавлений и 929 удалений

Просмотреть файл

@@ -140,6 +140,7 @@ func TestAddMemberToBoard(t *testing.T) {
}
func TestPatchBoard(t *testing.T) {
t.Skip("MM-51699")
th, tearDown := SetupTestHelper(t)
defer tearDown()

Просмотреть файл

@@ -231,6 +231,9 @@ func (bm *BoardsMigrator) MigrateToStep(step int) error {
func (bm *BoardsMigrator) Interceptors() map[int]foundation.Interceptor {
return map[int]foundation.Interceptor{
18: bm.store.RunDeletedMembershipBoardsMigration,
35: func() error {
return bm.store.RunDeDuplicateCategoryBoardsMigration(35)
},
}
}

Просмотреть файл

@@ -863,10 +863,8 @@ func (s *SQLStore) doesDuplicateCategoryBoardsExist() (bool, error) {
}
func (s *SQLStore) runMySQLDeDuplicateCategoryBoardsMigration() error {
query := "WITH duplicates AS (SELECT id, ROW_NUMBER() OVER(PARTITION BY user_id, board_id) AS rownum " +
"FROM " + s.tablePrefix + "category_boards) " +
"DELETE " + s.tablePrefix + "category_boards FROM " + s.tablePrefix + "category_boards " +
"JOIN duplicates USING(id) WHERE duplicates.rownum > 1;"
query := "DELETE FROM " + s.tablePrefix + "category_boards WHERE id NOT IN " +
"(SELECT * FROM ( SELECT min(id) FROM " + s.tablePrefix + "category_boards GROUP BY user_id, board_id ) as data)"
if _, err := s.db.Exec(query); err != nil {
s.logger.Error("Failed to de-duplicate data in category_boards table", mlog.Err(err))
}

Просмотреть файл

@@ -7,6 +7,9 @@ import (
"testing"
"time"
"github.com/mattermost/mattermost-server/v6/server/boards/services/store/sqlstore/migrationstests"
"github.com/mgdelacroix/foundation"
"github.com/mattermost/mattermost-server/v6/server/boards/model"
"github.com/stretchr/testify/assert"
@@ -263,3 +266,23 @@ func TestCheckForMismatchedCollation(t *testing.T) {
}
})
}
func TestRunDeDuplicateCategoryBoardsMigration(t *testing.T) {
RunStoreTestsWithFoundation(t, func(t *testing.T, f *foundation.Foundation) {
th, tearDown := migrationstests.SetupTestHelper(t, f)
defer tearDown()
th.F().MigrateToStepSkippingLastInterceptor(35).
ExecFile("./fixtures/testDeDuplicateCategoryBoardsMigration.sql")
th.F().RunInterceptor(35)
// verifying count of rows
var count int
countQuery := "SELECT COUNT(*) FROM focalboard_category_boards"
row := th.F().DB().QueryRow(countQuery)
err := row.Scan(&count)
assert.NoError(t, err)
assert.Equal(t, 4, count)
})
}

Просмотреть файл

@@ -0,0 +1,9 @@
INSERT INTO focalboard_category_boards(id, user_id, category_id, board_id, create_at, update_at, sort_order)
VALUES
('id_1', 'user_id_1', 'category_id_1', 'board_id_1', 0, 0, 0),
('id_2', 'user_id_1', 'category_id_2', 'board_id_1', 0, 0, 0),
('id_3', 'user_id_1', 'category_id_3', 'board_id_1', 0, 0, 0),
('id_4', 'user_id_2', 'category_id_4', 'board_id_2', 0, 0, 0),
('id_5', 'user_id_2', 'category_id_5', 'board_id_2', 0, 0, 0),
('id_6', 'user_id_3', 'category_id_6', 'board_id_3', 0, 0, 0),
('id_7', 'user_id_4', 'category_id_6', 'board_id_4', 0, 0, 0);

Просмотреть файл

@@ -22,6 +22,10 @@ func (th *TestHelper) IsMySQL() bool {
return th.f.DB().DriverName() == "mysql"
}
func (th *TestHelper) F() *foundation.Foundation {
return th.f
}
func SetupTestHelper(t *testing.T, f *foundation.Foundation) (*TestHelper, func()) {
th := &TestHelper{t, f}

Просмотреть файл

@@ -50,6 +50,7 @@ func NewStoreType(name string, driver string, skipMigrations bool) *storeType {
DB: sqlDB,
IsPlugin: false, // ToDo: to be removed
}
store, err := New(storeParams)
if err != nil {
panic(fmt.Sprintf("cannot create store: %s", err))

Просмотреть файл

@@ -17,7 +17,7 @@ import (
)
const (
rudderKey = "placeholder_rudder_key"
rudderKey = "placeholder_boards_rudder_key"
rudderDataplaneURL = "placeholder_rudder_dataplane_url"
timeBetweenTelemetryChecks = 10 * time.Minute
)

Просмотреть файл

@@ -71,10 +71,8 @@ type TestHelper struct {
IncludeCacheLayer bool
LogBuffer *mlog.Buffer
TestLogger *mlog.Logger
boardsProductEnvValue string
playbooksDisableEnvValue string
LogBuffer *mlog.Buffer
TestLogger *mlog.Logger
}
var mainHelper *testlib.MainHelper
@@ -104,17 +102,6 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent
*memoryConfig.AnnouncementSettings.AdminNoticesEnabled = false
*memoryConfig.AnnouncementSettings.UserNoticesEnabled = false
*memoryConfig.PluginSettings.AutomaticPrepackagedPlugins = false
// disable Boards through the feature flag
boardsProductEnvValue := os.Getenv("MM_FEATUREFLAGS_BoardsProduct")
os.Unsetenv("MM_FEATUREFLAGS_BoardsProduct")
memoryConfig.FeatureFlags.BoardsProduct = false
// disable Playbooks (temporarily) as it causes many more mocked methods to get
// called, and cannot receieve a mocked database.
playbooksDisableEnvValue := os.Getenv("MM_DISABLE_PLAYBOOKS")
os.Setenv("MM_DISABLE_PLAYBOOKS", "true")
if updateConfig != nil {
updateConfig(memoryConfig)
}
@@ -153,15 +140,13 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent
}
th := &TestHelper{
App: app.New(app.ServerConnector(s.Channels())),
Server: s,
ConfigStore: configStore,
IncludeCacheLayer: includeCache,
Context: request.EmptyContext(testLogger),
TestLogger: testLogger,
LogBuffer: buffer,
boardsProductEnvValue: boardsProductEnvValue,
playbooksDisableEnvValue: playbooksDisableEnvValue,
App: app.New(app.ServerConnector(s.Channels())),
Server: s,
ConfigStore: configStore,
IncludeCacheLayer: includeCache,
Context: request.EmptyContext(testLogger),
TestLogger: testLogger,
LogBuffer: buffer,
}
th.Context.SetLogger(testLogger)
@@ -386,17 +371,6 @@ func (th *TestHelper) ShutdownApp() {
}
func (th *TestHelper) TearDown() {
// reset board and playbooks product setting to original
if th.boardsProductEnvValue != "" {
os.Setenv("MM_FEATUREFLAGS_BoardsProduct", th.boardsProductEnvValue)
}
if th.playbooksDisableEnvValue != "" {
os.Setenv("MM_DISABLE_PLAYBOOKS", th.playbooksDisableEnvValue)
} else {
os.Unsetenv("MM_DISABLE_PLAYBOOKS")
}
if th.IncludeCacheLayer {
// Clean all the caches
th.App.Srv().InvalidateAllCaches()

Просмотреть файл

@@ -13,6 +13,8 @@ import (
"reflect"
"time"
"github.com/pkg/errors"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/server/channels/utils"
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
@@ -274,6 +276,10 @@ func selfHostedInvoices(c *Context, w http.ResponseWriter, r *http.Request) {
invoices, err := c.App.Cloud().GetSelfHostedInvoices()
if err != nil {
if err.Error() == "404" {
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusNotFound).Wrap(errors.New("invoices for license not found"))
return
}
c.Err = model.NewAppError(where, "api.cloud.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
return
}

Просмотреть файл

@@ -11,8 +11,10 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/server/channels/store/storetest/mocks"
)
/* Temporarily comment out until MM-11108
@@ -37,9 +39,26 @@ func init() {
}
func TestUnitUpdateConfig(t *testing.T) {
th := Setup(t)
th := SetupWithStoreMock(t)
defer th.TearDown()
mockStore := th.App.Srv().Store().(*mocks.Store)
mockUserStore := mocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
mockPostStore := mocks.PostStore{}
mockPostStore.On("GetMaxPostSize").Return(65535, nil)
mockSystemStore := mocks.SystemStore{}
mockSystemStore.On("GetByName", "UpgradedFromTE").Return(&model.System{Name: "UpgradedFromTE", Value: "false"}, nil)
mockSystemStore.On("GetByName", "InstallationDate").Return(&model.System{Name: "InstallationDate", Value: "10"}, nil)
mockSystemStore.On("GetByName", "FirstServerRunTimestamp").Return(&model.System{Name: "FirstServerRunTimestamp", Value: "10"}, nil)
mockLicenseStore := mocks.LicenseStore{}
mockLicenseStore.On("Get", "").Return(&model.LicenseRecord{}, nil)
mockStore.On("User").Return(&mockUserStore)
mockStore.On("Post").Return(&mockPostStore)
mockStore.On("System").Return(&mockSystemStore)
mockStore.On("License").Return(&mockLicenseStore)
mockStore.On("GetDBSchemaVersion").Return(1, nil)
prev := *th.App.Config().ServiceSettings.SiteURL
var called int32

Просмотреть файл

@@ -42,9 +42,7 @@ type TestHelper struct {
TestLogger *mlog.Logger
IncludeCacheLayer bool
tempWorkspace string
boardsProductEnvValue string
playbooksDisableEnvValue string
tempWorkspace string
}
func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer bool, options []Option, tb testing.TB) *TestHelper {
@@ -62,17 +60,6 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
*memoryConfig.LogSettings.EnableSentry = false // disable error reporting during tests
*memoryConfig.AnnouncementSettings.AdminNoticesEnabled = false
*memoryConfig.AnnouncementSettings.UserNoticesEnabled = false
// disable Boards through the feature flag
boardsProductEnvValue := os.Getenv("MM_FEATUREFLAGS_BoardsProduct")
os.Unsetenv("MM_FEATUREFLAGS_BoardsProduct")
memoryConfig.FeatureFlags.BoardsProduct = false
// disable Playbooks (temporarily) as it causes many more mocked methods to get
// called, and cannot receieve a mocked database.
playbooksDisableEnvValue := os.Getenv("MM_DISABLE_PLAYBOOKS")
os.Setenv("MM_DISABLE_PLAYBOOKS", "true")
configStore.Set(memoryConfig)
buffer := &mlog.Buffer{}
@@ -103,14 +90,12 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
}
th := &TestHelper{
App: New(ServerConnector(s.Channels())),
Context: request.EmptyContext(testLogger),
Server: s,
LogBuffer: buffer,
TestLogger: testLogger,
IncludeCacheLayer: includeCacheLayer,
boardsProductEnvValue: boardsProductEnvValue,
playbooksDisableEnvValue: playbooksDisableEnvValue,
App: New(ServerConnector(s.Channels())),
Context: request.EmptyContext(testLogger),
Server: s,
LogBuffer: buffer,
TestLogger: testLogger,
IncludeCacheLayer: includeCacheLayer,
}
th.Context.SetLogger(testLogger)
@@ -184,10 +169,16 @@ func SetupWithStoreMock(tb testing.TB) *TestHelper {
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
statusMock.On("UpdateLastActivityAt", "user1", mock.Anything).Return(nil)
statusMock.On("SaveOrUpdate", mock.AnythingOfType("*model.Status")).Return(nil)
pluginMock := mocks.PluginStore{}
pluginMock.On("Get", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(&model.PluginKeyValue{}, nil)
emptyMockStore := mocks.Store{}
emptyMockStore.On("Close").Return(nil)
emptyMockStore.On("Status").Return(&statusMock)
emptyMockStore.On("Plugin").Return(&pluginMock).Maybe()
th.App.Srv().SetStore(&emptyMockStore)
return th
}
@@ -553,17 +544,6 @@ func (th *TestHelper) ShutdownApp() {
}
func (th *TestHelper) TearDown() {
// reset board and playbooks product setting to original
if th.boardsProductEnvValue != "" {
os.Setenv("MM_FEATUREFLAGS_BoardsProduct", th.boardsProductEnvValue)
}
if th.playbooksDisableEnvValue != "" {
os.Setenv("MM_DISABLE_PLAYBOOKS", th.playbooksDisableEnvValue)
} else {
os.Unsetenv("MM_DISABLE_PLAYBOOKS")
}
if th.IncludeCacheLayer {
// Clean all the caches
th.App.Srv().InvalidateAllCaches()

Просмотреть файл

@@ -1445,13 +1445,9 @@ func TestPushNotificationRace(t *testing.T) {
Router: mux.NewRouter(),
}
var err error
s.platform, err = platform.New(
platform.ServiceConfig{
ConfigStore: memoryStore,
},
platform.SetFileStore(&fmocks.FileBackend{}),
platform.StoreOverride(th.GetSqlStore()),
)
s.platform, err = platform.New(platform.ServiceConfig{
ConfigStore: memoryStore,
}, platform.SetFileStore(&fmocks.FileBackend{}))
s.SetStore(mockStore)
require.NoError(t, err)
serviceMap := map[product.ServiceKey]any{

Просмотреть файл

@@ -48,12 +48,12 @@ func (a *App) SaveAdminNotification(userId string, notifyData *model.NotifyAdmin
func (a *App) DoCheckForAdminNotifications(trial bool) *model.AppError {
ctx := request.EmptyContext(a.Srv().Log())
currentSKU := "starter"
license := a.Srv().License()
if license == nil {
return model.NewAppError("DoCheckForAdminNotifications", "app.notify_admin.send_notification_post.app_error", nil, "No license found", http.StatusInternalServerError)
if license != nil {
currentSKU = license.SkuShortName
}
currentSKU := license.SkuShortName
workspaceName := ""
return a.SendNotifyAdminPosts(ctx, workspaceName, currentSKU, trial)

Просмотреть файл

@@ -73,17 +73,15 @@ func (s *Server) initializeProducts(
func (s *Server) shouldStart(product string) bool {
if product == "boards" {
if !s.Config().FeatureFlags.BoardsProduct {
s.Log().Info("Skipping Boards init; disabled via feature flag")
s.Log().Warn("Skipping boards start: not enabled via feature flag")
return false
}
s.Log().Info("Allowing Boards init; enabled via feature flag")
}
if product == "playbooks" {
if os.Getenv("MM_DISABLE_PLAYBOOKS") == "true" {
s.Log().Info("Skipping Playbooks init; disabled via env var")
s.Log().Warn("Skipping playbooks start: disabled via env var")
return false
}
s.Log().Info("Allowing Playbooks init; enabled via env var")
}
return true

Просмотреть файл

@@ -36,9 +36,7 @@ type TestHelper struct {
TestLogger *mlog.Logger
IncludeCacheLayer bool
tempWorkspace string
boardsProductEnvValue string
playbooksDisableEnvValue string
tempWorkspace string
}
func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer bool, tb testing.TB, configSet func(*model.Config)) *TestHelper {
@@ -53,17 +51,6 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
if configSet != nil {
configSet(memoryConfig)
}
// disable Boards through the feature flag
boardsProductEnvValue := os.Getenv("MM_FEATUREFLAGS_BoardsProduct")
os.Unsetenv("MM_FEATUREFLAGS_BoardsProduct")
memoryConfig.FeatureFlags.BoardsProduct = false
// disable Playbooks (temporarily) as it causes many more mocked methods to get
// called, and cannot receieve a mocked database.
playbooksDisableEnvValue := os.Getenv("MM_DISABLE_PLAYBOOKS")
os.Setenv("MM_DISABLE_PLAYBOOKS", "true")
*memoryConfig.PluginSettings.Directory = filepath.Join(tempWorkspace, "plugins")
*memoryConfig.PluginSettings.ClientDirectory = filepath.Join(tempWorkspace, "webapp")
*memoryConfig.PluginSettings.AutomaticPrepackagedPlugins = false
@@ -95,14 +82,12 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
}
th := &TestHelper{
App: app.New(app.ServerConnector(s.Channels())),
Context: request.EmptyContext(testLogger),
Server: s,
LogBuffer: buffer,
TestLogger: testLogger,
IncludeCacheLayer: includeCacheLayer,
boardsProductEnvValue: boardsProductEnvValue,
playbooksDisableEnvValue: playbooksDisableEnvValue,
App: app.New(app.ServerConnector(s.Channels())),
Context: request.EmptyContext(testLogger),
Server: s,
LogBuffer: buffer,
TestLogger: testLogger,
IncludeCacheLayer: includeCacheLayer,
}
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxUsersPerTeam = 50 })
@@ -389,17 +374,6 @@ func (th *TestHelper) shutdownApp() {
}
func (th *TestHelper) tearDown() {
// reset board and playbooks product setting to original
if th.boardsProductEnvValue != "" {
os.Setenv("MM_FEATUREFLAGS_BoardsProduct", th.boardsProductEnvValue)
}
if th.playbooksDisableEnvValue != "" {
os.Setenv("MM_DISABLE_PLAYBOOKS", th.playbooksDisableEnvValue)
} else {
os.Unsetenv("MM_DISABLE_PLAYBOOKS")
}
if th.IncludeCacheLayer {
// Clean all the caches
th.App.Srv().InvalidateAllCaches()

Просмотреть файл

@@ -12,7 +12,7 @@ import (
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
)
const installPluginSchedFreq = 1 * time.Minute
const installPluginSchedFreq = 24 * time.Hour
func MakeInstallPluginScheduler(jobServer *jobs.JobServer, license *model.License, jobType string) model.Scheduler {
isEnabled := func(cfg *model.Config) bool {

Просмотреть файл

@@ -48,9 +48,6 @@ type TestHelper struct {
IncludeCacheLayer bool
TestLogger *mlog.Logger
boardsProductEnvValue string
playbooksDisableEnvValue string
}
func SetupWithStoreMock(tb testing.TB) *TestHelper {
@@ -80,17 +77,6 @@ func setupTestHelper(tb testing.TB, includeCacheLayer bool) *TestHelper {
*newConfig.AnnouncementSettings.AdminNoticesEnabled = false
*newConfig.AnnouncementSettings.UserNoticesEnabled = false
*newConfig.PluginSettings.AutomaticPrepackagedPlugins = false
// disable Boards through the feature flag
boardsProductEnvValue := os.Getenv("MM_FEATUREFLAGS_BoardsProduct")
os.Unsetenv("MM_FEATUREFLAGS_BoardsProduct")
newConfig.FeatureFlags.BoardsProduct = false
// disable Playbooks (temporarily) as it causes many more mocked methods to get
// called, and cannot receieve a mocked database.
playbooksDisableEnvValue := os.Getenv("MM_DISABLE_PLAYBOOKS")
os.Setenv("MM_DISABLE_PLAYBOOKS", "true")
memoryStore.Set(newConfig)
var options []app.Option
options = append(options, app.ConfigStore(memoryStore))
@@ -148,14 +134,12 @@ func setupTestHelper(tb testing.TB, includeCacheLayer bool) *TestHelper {
})
th := &TestHelper{
App: a,
Context: request.EmptyContext(testLogger),
Server: s,
Web: web,
IncludeCacheLayer: includeCacheLayer,
TestLogger: testLogger,
boardsProductEnvValue: boardsProductEnvValue,
playbooksDisableEnvValue: playbooksDisableEnvValue,
App: a,
Context: request.EmptyContext(testLogger),
Server: s,
Web: web,
IncludeCacheLayer: includeCacheLayer,
TestLogger: testLogger,
}
th.Context.SetLogger(testLogger)
@@ -194,17 +178,6 @@ func (th *TestHelper) InitBasic() *TestHelper {
}
func (th *TestHelper) TearDown() {
// reset board and playbooks product setting to original
if th.boardsProductEnvValue != "" {
os.Setenv("MM_FEATUREFLAGS_BoardsProduct", th.boardsProductEnvValue)
}
if th.playbooksDisableEnvValue != "" {
os.Setenv("MM_DISABLE_PLAYBOOKS", th.playbooksDisableEnvValue)
} else {
os.Unsetenv("MM_DISABLE_PLAYBOOKS")
}
if th.IncludeCacheLayer {
// Clean all the caches
th.App.Srv().InvalidateAllCaches()

Просмотреть файл

@@ -10013,5 +10013,213 @@
{
"id": "app.oauth.remove_auth_data_by_client_id.app_error",
"translation": "Oauth-Daten können nicht entfernt werden."
},
{
"id": "app.user.run.update_status.title",
"translation": "Aktueller Stand"
},
{
"id": "app.user.run.update_status.submit_label",
"translation": "Status aktualisieren"
},
{
"id": "app.user.run.update_status.reminder_for_next_update",
"translation": "Erinnerung an das nächste Update"
},
{
"id": "app.user.run.update_status.num_channel",
"translation": {
"one": "Bringe die Beteiligten auf den neuesten Stand. Dieser Beitrag wird in einem Kanal veröffentlicht.",
"other": "Bringe die Beteiligten auf den neuesten Stand. Dieser Beitrag wird in {{.Count}} Kanälen veröffentlicht."
}
},
{
"id": "app.user.run.update_status.finish_run.placeholder",
"translation": "Markiere den Durchlauf auch als beendet"
},
{
"id": "app.user.run.update_status.finish_run",
"translation": "Durchlauf beenden"
},
{
"id": "app.user.run.update_status.change_since_last_update",
"translation": "Änderung seit der letzten Aktualisierung"
},
{
"id": "app.user.run.status_enable",
"translation": "@{{.Username}} hat die Statusaktualisierungen für [{{.RunName}}]({{.RunURL}}) aktiviert"
},
{
"id": "app.user.run.status_disable",
"translation": "@{{.Username}} hat die Statusaktualisierungen für [{{.RunName}}]({{.RunURL}}) deaktiviert"
},
{
"id": "app.user.run.request_update",
"translation": "@here — @{{.Name}} hat eine Statusaktualisierung für [{{.RunName}}]({{.RunURL}}) angefordert. \n"
},
{
"id": "app.user.run.request_join_channel",
"translation": "@{{.Name}} ist ein Teilnehmer und möchte diesem Kanal beitreten. Jedes Mitglied des Kanals kann ihn einladen.\n"
},
{
"id": "app.user.run.confirm_finish.title",
"translation": "Beenden des Durchlaufs bestätigen"
},
{
"id": "app.user.run.confirm_finish.submit_label",
"translation": "Durchlauf beenden"
},
{
"id": "app.user.run.confirm_finish.num_outstanding",
"translation": {
"one": "Es gibt **eine offene Aufgabe**. Bist du sicher, dass du den Durchlauf *{{.RunName}}* für alle Teilnehmer beenden willst?",
"other": "Es gibt **{{.Count}} offene Aufgaben**. Bist du sicher, dass du den Durchlauf *{{.RunName}}* für alle Teilnehmer beenden willst?"
}
},
{
"id": "app.user.run.add_to_timeline.title",
"translation": "Zur Zeitleiste hinzufügen"
},
{
"id": "app.user.run.add_to_timeline.summary.placeholder",
"translation": "Kurze Zusammenfassung auf der Zeitachse"
},
{
"id": "app.user.run.add_to_timeline.summary.help",
"translation": "Max. 64 Zeichen"
},
{
"id": "app.user.run.add_to_timeline.summary",
"translation": "Zusammenfassung"
},
{
"id": "app.user.run.add_to_timeline.submit_label",
"translation": "Zur Zeitleiste hinzufügen"
},
{
"id": "app.user.run.add_to_timeline.playbook_run",
"translation": "Playbook-Durchlauf"
},
{
"id": "app.user.run.add_checklist_item.title",
"translation": "Neue Aufgabe hinzufügen"
},
{
"id": "app.user.run.add_checklist_item.submit_label",
"translation": "Aufgabe hinzufügen"
},
{
"id": "app.user.run.add_checklist_item.name",
"translation": "Name"
},
{
"id": "app.user.run.add_checklist_item.description",
"translation": "Beschreibung"
},
{
"id": "app.user.new_run.title",
"translation": "Playbook starten"
},
{
"id": "app.user.new_run.submit_label",
"translation": "Starte Durchlauf"
},
{
"id": "app.user.new_run.run_name",
"translation": "Name des Durchlaufs"
},
{
"id": "app.user.new_run.playbook",
"translation": "Playbook"
},
{
"id": "app.user.new_run.intro",
"translation": "**Eigentümer** {{.Username}}"
},
{
"id": "app.user.digest.tasks.zero_assigned",
"translation": "Du hast keine zugewiesene Aufgabe."
},
{
"id": "app.user.digest.tasks.num_assigned_due_until_today",
"translation": {
"one": "Du hast eine zugewiesene Aufgabe, die jetzt fällig ist:",
"other": "Du hast {{.Count}} zugewiesene Aufgaben, die jetzt fällig sind:"
}
},
{
"id": "app.user.digest.tasks.num_assigned",
"translation": {
"one": "Du hast eine zugewiesene Aufgabe:",
"other": "Du hast {{.Count}} zugewiesene Aufgaben:"
}
},
{
"id": "app.user.digest.tasks.heading",
"translation": "Deine zugewiesenen Aufgaben"
},
{
"id": "app.user.digest.tasks.due_yesterday",
"translation": "Gestern fällig"
},
{
"id": "app.user.digest.tasks.due_x_days_ago",
"translation": "Fällig vor {{.Count}} Tagen"
},
{
"id": "app.user.digest.tasks.due_today",
"translation": "Heute fällig"
},
{
"id": "app.user.digest.tasks.due_in_x_days",
"translation": {
"one": "Fällig in einem Tag",
"other": "Fällig in {{.Count}} Tagen"
}
},
{
"id": "app.user.digest.tasks.due_after_today",
"translation": {
"one": "Du hast **eine zugewiesene Aufgabe, die nach dem heutige Tag fällig ist**.",
"other": "Du hast **{{.Count}} zugewiesene Aufgaben, die nach dem heutige Tag fällig sind**."
}
},
{
"id": "app.user.digest.tasks.all_tasks_command",
"translation": "Bitte benutze `/playbook todo` um alle deine Aufgaben anzuzeigen."
},
{
"id": "app.user.digest.runs_in_progress.zero_in_progress",
"translation": "Du hast keinen aktiven Durchlauf."
},
{
"id": "app.user.digest.runs_in_progress.num_in_progress",
"translation": {
"one": "Du hast einen aktiven Durchlauf:",
"other": "Du hast {{.Count}} aktive Durchläufe:"
}
},
{
"id": "app.user.digest.runs_in_progress.heading",
"translation": "Aktive Durchläufe"
},
{
"id": "app.user.digest.overdue_status_updates.zero_overdue",
"translation": "Du hast keine überfälligen Durchläufe."
},
{
"id": "app.user.digest.overdue_status_updates.num_overdue",
"translation": {
"one": "Du hast einen überfälligen Durchlauf für ein Statusupdate:",
"other": "Du hast {{.Count}} überfällige Durchläufe für ein Statusupdate:"
}
},
{
"id": "app.user.digest.overdue_status_updates.heading",
"translation": "Überfällige Statusaktualisierungen"
},
{
"id": "app.command.execute.error",
"translation": "Kann Befehl nicht ausführen."
}
]

Просмотреть файл

@@ -9546,5 +9546,9 @@
{
"id": "api.admin.syncables_error",
"translation": "Error al agregar usuario a grupo-equipos y grupo-canales"
},
{
"id": "api.command_templates.name",
"translation": "plantillas"
}
]

Просмотреть файл

@@ -9998,5 +9998,213 @@
{
"id": "api.command_templates.unsupported.app_error",
"translation": "あなたのデバイスではテンプレートコマンドはサポートされていません。"
},
{
"id": "app.user.run.update_status.title",
"translation": "ステータスの更新"
},
{
"id": "app.user.run.update_status.submit_label",
"translation": "ステータスを更新"
},
{
"id": "app.user.run.update_status.reminder_for_next_update",
"translation": "次回更新のリマインド"
},
{
"id": "app.user.run.update_status.num_channel",
"translation": {
"other": "関係者に更新内容を提供します。この投稿は {{.Count}} チャンネルに配信されます。"
}
},
{
"id": "app.user.run.update_status.finish_run.placeholder",
"translation": "また、実行を終了としてマークする"
},
{
"id": "app.user.run.update_status.finish_run",
"translation": "実行を終了する"
},
{
"id": "app.user.run.update_status.change_since_last_update",
"translation": "前回更新時からの変更点"
},
{
"id": "app.user.run.status_enable",
"translation": "@{{.Username}} は [{{.RunName}}]({{.RunURL}}) のステータス更新を有効化しました"
},
{
"id": "app.user.run.status_disable",
"translation": "@{{.Username}} は [{{.RunName}}]({{.RunURL}}) のステータス更新を無効化しました"
},
{
"id": "app.user.run.request_update",
"translation": "@here — @{{.Name}} は [{{.RunName}}]({{.RunURL}}) のステータスの更新を要求しました。 \n"
},
{
"id": "app.user.run.request_join_channel",
"translation": "@{{.Name}} は実行の参加者で、このチャンネルへの参加を希望しています。チャンネルのメンバーなら誰でも招待できます。\n"
},
{
"id": "app.user.run.confirm_finish.title",
"translation": "実行終了の確認"
},
{
"id": "app.user.run.confirm_finish.submit_label",
"translation": "実行を終了する"
},
{
"id": "app.user.run.confirm_finish.num_outstanding",
"translation": {
"other": "**{{.Count}} 個の未解決タスク**があります。 本当に実行 *{{.RunName}}* を終了してもよろしいですか?"
}
},
{
"id": "app.user.run.add_to_timeline.title",
"translation": "実行のタイムラインに追加する"
},
{
"id": "app.user.run.add_to_timeline.summary.placeholder",
"translation": "タイムラインに表示される短い要約"
},
{
"id": "app.user.run.add_to_timeline.summary.help",
"translation": "最大 64 文字"
},
{
"id": "app.user.run.add_to_timeline.summary",
"translation": "概要"
},
{
"id": "app.user.run.add_to_timeline.submit_label",
"translation": "実行のタイムラインに追加する"
},
{
"id": "app.user.run.add_to_timeline.playbook_run",
"translation": "Playbookを実行"
},
{
"id": "app.user.run.add_checklist_item.title",
"translation": "新しいタスクを追加"
},
{
"id": "app.user.run.add_checklist_item.submit_label",
"translation": "タスクを追加"
},
{
"id": "app.user.run.add_checklist_item.name",
"translation": "名前"
},
{
"id": "app.user.run.add_checklist_item.description",
"translation": "説明"
},
{
"id": "app.user.new_run.title",
"translation": "Playbookを実行する"
},
{
"id": "app.user.new_run.submit_label",
"translation": "実行開始"
},
{
"id": "app.user.new_run.run_name",
"translation": "実行名"
},
{
"id": "app.user.new_run.playbook",
"translation": "Playbook"
},
{
"id": "app.user.new_run.intro",
"translation": "**オーナー** {{.Username}}"
},
{
"id": "app.user.digest.tasks.zero_assigned",
"translation": "割り当てられたタスクがありません。"
},
{
"id": "app.user.digest.tasks.num_assigned_due_until_today",
"translation": {
"other": "対応期限を迎えている{{.Count}}タスクが割り当てられています:"
}
},
{
"id": "app.user.digest.tasks.num_assigned",
"translation": {
"other": "{{.Count}}タスクが割り当てられています:"
}
},
{
"id": "app.user.digest.tasks.heading",
"translation": "あなたに割り当てられたタスク"
},
{
"id": "app.user.digest.tasks.due_yesterday",
"translation": "昨日で期限切れ"
},
{
"id": "app.user.digest.tasks.due_x_days_ago",
"translation": "{{.Count}}日前に期限切れ"
},
{
"id": "app.user.digest.tasks.due_today",
"translation": "今日が期限です"
},
{
"id": "app.user.digest.tasks.due_in_x_days",
"translation": {
"other": "期限は{{.Count}}日後です"
}
},
{
"id": "app.user.digest.tasks.due_after_today",
"translation": {
"other": "**今日で期限切れとなるタスクが {{.Count}} 件**割り当てられています。"
}
},
{
"id": "app.user.digest.tasks.all_tasks_command",
"translation": "`/playbook todo`を使用すると、あなたのすべてのタスクを確認することができます。"
},
{
"id": "app.user.digest.runs_in_progress.zero_in_progress",
"translation": "進行中の実行はありません。"
},
{
"id": "app.user.digest.runs_in_progress.num_in_progress",
"translation": {
"other": "現在、 {{.Count}} の実行が進行中です:"
}
},
{
"id": "app.user.digest.runs_in_progress.heading",
"translation": "進行中の実行"
},
{
"id": "app.user.digest.overdue_status_updates.zero_overdue",
"translation": "期限切れの実行は 0 です。"
},
{
"id": "app.user.digest.overdue_status_updates.num_overdue",
"translation": {
"other": "ステータス更新の期日が過ぎた実行が {{.Count}} あります:"
}
},
{
"id": "app.user.digest.overdue_status_updates.heading",
"translation": "期限切れステータスの更新"
},
{
"id": "app.oauth.remove_auth_data_by_client_id.app_error",
"translation": "oauth データを削除することができませんでした。"
},
{
"id": "app.command.execute.error",
"translation": "コマンドを実行できませんでした。"
},
{
"id": "api.templates.license_up_for_renewal_contact_sales",
"translation": "営業に問い合わせる"
}
]

Просмотреть файл

@@ -10014,5 +10014,29 @@
{
"id": "app.oauth.remove_auth_data_by_client_id.app_error",
"translation": "Nie można usunąć danych oauth."
},
{
"id": "app.user.digest.runs_in_progress.heading",
"translation": "Uruchomienia w Trakcie"
},
{
"id": "app.user.digest.overdue_status_updates.zero_overdue",
"translation": "Masz 0 zaległych uruchomień."
},
{
"id": "app.user.digest.overdue_status_updates.num_overdue",
"translation": {
"few": "Masz {{.Count}} zaległości w aktualizacji statusu:",
"many": "Masz {{.Count}} zaległości w aktualizacji statusu:",
"one": "Masz {{.Count}} zaległość w aktualizacji statusu:"
}
},
{
"id": "app.user.digest.overdue_status_updates.heading",
"translation": "Zaległe aktualizacje statusu"
},
{
"id": "app.command.execute.error",
"translation": "Nie można wykonać polecenia."
}
]

Просмотреть файл

@@ -9858,5 +9858,353 @@
{
"id": "api.command_templates.unsupported.app_error",
"translation": "您的设备不支持模板命令。"
},
{
"id": "worktemplate.product_teams.sprint_planning.integration",
"translation": "项目面板可以使迭代计划前所未来的容易。频道可以用来对话和保证问题的被关注。迭代计划面板可以使所以有本周对任务的关注,回顾面板让团队作为一个整体不断改进。"
},
{
"id": "worktemplate.product_teams.sprint_planning.channel",
"translation": "项目面板可以使迭代计划前所未来的容易。频道可以用来对话和保证问题的被关注。迭代计划面板可以使所以有本周对任务的关注,回顾面板让团队作为一个整体不断改进。"
},
{
"id": "worktemplate.product_teams.sprint_planning.board",
"translation": "项目面板可以使迭代计划前所未来的容易。频道可以用来对话和保证问题的被关注。迭代计划面板可以使所以有本周对任务的关注,回顾面板让团队作为一个整体不断改进。"
},
{
"id": "worktemplate.product_teams.product_roadmap.channel",
"translation": "这里描述了为什么需要面板"
},
{
"id": "worktemplate.product_teams.product_roadmap.board",
"translation": "这里描述了为什么需要面板"
},
{
"id": "worktemplate.product_teams.goals_and_okrs.integration",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.product_teams.goals_and_okrs.channel",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.product_teams.goals_and_okrs.board",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.product_teams.feature_release.description.playbook",
"translation": "通过建立透明的跨越整个研发团队的工作流程确保你的功能开发过程完美流畅。"
},
{
"id": "worktemplate.product_teams.feature_release.description.integration",
"translation": "在你的频道通过集成Jira和Gtihub机器人提高效率。这些会自动下载安装。"
},
{
"id": "worktemplate.product_teams.feature_release.description.channel",
"translation": "Boards,Playbooks和应用Bot可以很容易地接入功能发布频道并且和你的团队进行相关互动和讨论。"
},
{
"id": "worktemplate.product_teams.feature_release.description.board",
"translation": "使用我们的会议日程模板安排像站立会议这样的定期会议,使用我们的项目任务面板在一路上管理任务的进度。"
},
{
"id": "worktemplate.product_teams.bug_bash.playbook",
"translation": "把事情安排好并且干掉此项目里的所有bug用包含的Playbook, Board, and Channel推动项目并评估进度。"
},
{
"id": "worktemplate.product_teams.bug_bash.integration",
"translation": "把事情安排好并且干掉此项目里的所有bug用包含的Playbook, Board, and Channel推动项目并评估进度。"
},
{
"id": "worktemplate.product_teams.bug_bash.channel",
"translation": "把事情安排好并且干掉此项目里的所有bug用包含的Playbook, Board, and Channel推动项目并评估进度。"
},
{
"id": "worktemplate.product_teams.bug_bash.board",
"translation": "把事情安排好并且干掉此项目里的所有bug用包含的Playbook, Board, and Channel推动项目并评估进度。"
},
{
"id": "worktemplate.leadership.goals_and_okrs.integration",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.leadership.goals_and_okrs.channel",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.leadership.goals_and_okrs.board",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.devops.product_release.playbook",
"translation": "不要丢失此项目的任何一个步骤。从Playbook的检验清单分离成任务部署并达到项目面板的里程碑。用频道来保持所有人对事情的理解一致。"
},
{
"id": "worktemplate.devops.product_release.channel",
"translation": "不要丢失此项目的任何一个步骤。从Playbook的检验清单分离成任务部署并达到项目面板的里程碑。用频道来保持所有人对事情的理解一致。"
},
{
"id": "worktemplate.devops.product_release.board",
"translation": "不要丢失此项目的任何一个步骤。从Playbook的检验清单分离成任务部署并达到项目面板的里程碑。用频道来保持所有人对事情的理解一致。"
},
{
"id": "worktemplate.devops.incident_resolution.description.playbook",
"translation": "当到处都是问题的时候有一个能够确保一切都尽快回归正确的可重复流程是关键。此项目使用Mattermost提供的一切功能保证火被一步步扑灭以及利益相关者被告知。"
},
{
"id": "worktemplate.devops.incident_resolution.description.channel",
"translation": "当到处都是问题的时候有一个能够确保一切都尽快回归正确的可重复流程是关键。此项目使用Mattermost提供的一切功能保证火被一步步扑灭以及利益相关者被告知。"
},
{
"id": "worktemplate.devops.incident_resolution.description.board",
"translation": "当到处都是问题的时候有一个能够确保一切都尽快回归正确的可重复流程是关键。此项目使用Mattermost提供的一切功能保证火被一步步扑灭以及利益相关者被告知。"
},
{
"id": "worktemplate.companywide.goals_and_okrs.integration",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.companywide.goals_and_okrs.channel",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.companywide.goals_and_okrs.board",
"translation": "清晰的目标对团队的成功至关重要在此项目里你可以在文档里写下团队的目标和OKR并在相关的频道里会有消息提醒。"
},
{
"id": "worktemplate.companywide.create_project.integration",
"translation": "使用此项目面板设计一个路线图,并在产生的频道里就相应话题进行探讨合作。"
},
{
"id": "worktemplate.companywide.create_project.channel",
"translation": "使用此项目面板设计一个路线图,并在产生的频道里就相应话题进行探讨合作。"
},
{
"id": "worktemplate.companywide.create_project.board",
"translation": "使用此项目面板设计一个路线图,并在产生的频道里就相应话题进行探讨合作。"
},
{
"id": "app.user.run.update_status.title",
"translation": "状态更新"
},
{
"id": "app.user.run.update_status.submit_label",
"translation": "更新状态"
},
{
"id": "app.user.run.update_status.reminder_for_next_update",
"translation": "下次更新的提醒"
},
{
"id": "app.user.run.update_status.num_channel",
"translation": {
"other": "为利益相关者提供一次更新提醒。这条提醒将被广播到{{.Count}} 个频道。"
}
},
{
"id": "app.user.run.update_status.finish_run.placeholder",
"translation": "并且标记此运行为已结束"
},
{
"id": "app.user.run.update_status.finish_run",
"translation": "结束运行"
},
{
"id": "app.user.run.update_status.change_since_last_update",
"translation": "对比上次存在更改"
},
{
"id": "app.user.run.status_enable",
"translation": "@{{.Username}} 启用了对 [{{.RunName}}]({{.RunURL}})的状态更新"
},
{
"id": "app.user.run.status_disable",
"translation": "@{{.Username}} 停止用了 [{{.RunName}}]({{.RunURL}})的状态更新。"
},
{
"id": "app.user.run.request_update",
"translation": "@here — @{{.Name}} 请求对 [{{.RunName}}]({{.RunURL}}) 进行状态更新。 \n"
},
{
"id": "app.user.run.request_join_channel",
"translation": "@{{.Name}} 是一个运行的参与者,并且希望要参加这个频道。任何的频道成员都可以邀请他们。\n"
},
{
"id": "app.user.run.confirm_finish.title",
"translation": "确认完成运行"
},
{
"id": "app.user.run.confirm_finish.submit_label",
"translation": "完成运行"
},
{
"id": "app.user.run.confirm_finish.num_outstanding",
"translation": {
"other": "一共有 **{{.Count}} 未完成的任务**. 您确定想为所有的参与者结束*{{.RunName}}*吗?"
}
},
{
"id": "app.user.run.add_to_timeline.title",
"translation": "添加到运行队列"
},
{
"id": "app.user.run.add_to_timeline.summary.placeholder",
"translation": "时间表里显示的简单概要"
},
{
"id": "app.user.run.add_to_timeline.summary.help",
"translation": "最大64个字符"
},
{
"id": "app.user.run.add_to_timeline.summary",
"translation": "概要"
},
{
"id": "app.user.run.add_to_timeline.submit_label",
"translation": "添加到运行队列"
},
{
"id": "app.user.run.add_to_timeline.playbook_run",
"translation": "Playbook运行"
},
{
"id": "app.user.run.add_checklist_item.title",
"translation": "添加新任务"
},
{
"id": "app.user.run.add_checklist_item.submit_label",
"translation": "添加任务"
},
{
"id": "app.user.run.add_checklist_item.name",
"translation": "名字"
},
{
"id": "app.user.run.add_checklist_item.description",
"translation": "描述"
},
{
"id": "app.user.new_run.title",
"translation": "运行playbook"
},
{
"id": "app.user.new_run.submit_label",
"translation": "开始运行"
},
{
"id": "app.user.new_run.run_name",
"translation": "运行名"
},
{
"id": "app.user.new_run.playbook",
"translation": "Playbook"
},
{
"id": "app.user.new_run.intro",
"translation": "**所有者** {{.Username}}"
},
{
"id": "app.user.digest.tasks.zero_assigned",
"translation": "您没有任务。"
},
{
"id": "app.user.digest.tasks.num_assigned_due_until_today",
"translation": {
"other": "您有 {{.Count}} 个任务现在已经逾期:"
}
},
{
"id": "app.user.digest.tasks.num_assigned",
"translation": {
"other": "您一共有{{.Count}}个任务:"
}
},
{
"id": "app.user.digest.tasks.heading",
"translation": "您的任务"
},
{
"id": "app.user.digest.tasks.due_yesterday",
"translation": "于昨天过期"
},
{
"id": "app.user.digest.tasks.due_x_days_ago",
"translation": "{{.Count}}天已过期"
},
{
"id": "app.user.digest.tasks.due_today",
"translation": "将于今天过期"
},
{
"id": "app.user.digest.tasks.due_in_x_days",
"translation": {
"other": "{{.Count}}天后过期"
}
},
{
"id": "app.user.digest.tasks.due_after_today",
"translation": {
"other": "您有 **{{.Count}} 项目任务今天之后将要过期**."
}
},
{
"id": "app.user.digest.tasks.all_tasks_command",
"translation": "请使用`/playbook todo`来查看您所有的任务。"
},
{
"id": "app.user.digest.runs_in_progress.zero_in_progress",
"translation": "您有0项正在运行。"
},
{
"id": "app.user.digest.runs_in_progress.num_in_progress",
"translation": {
"other": "您有{{.Count}}正在运行:"
}
},
{
"id": "app.user.digest.runs_in_progress.heading",
"translation": "正在运行"
},
{
"id": "app.user.digest.overdue_status_updates.zero_overdue",
"translation": "您没有逾期。"
},
{
"id": "app.user.digest.overdue_status_updates.num_overdue",
"translation": {
"other": "您有 {{.Count}} 过期需要状态更新:"
}
},
{
"id": "app.user.digest.overdue_status_updates.heading",
"translation": "过期状态更新"
},
{
"id": "app.oauth.remove_auth_data_by_client_id.app_error",
"translation": "不能删除oauth认证信息。"
},
{
"id": "app.command.execute.error",
"translation": "无法执行命令。"
},
{
"id": "api.templates.license_up_for_renewal_contact_sales",
"translation": "联系销售"
},
{
"id": "api.license.true_up_review.not_allowed_for_cloud",
"translation": "云实例不允许真实性评估"
},
{
"id": "api.license.true_up_review.license_required",
"translation": "真实性评估需要许可证"
},
{
"id": "api.license.true_up_review.get_status_error",
"translation": "无法获取真实的状态记录"
},
{
"id": "api.license.true_up_review.create_error",
"translation": "无法创建真实的状态记录"
}
]

Просмотреть файл

@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/mattermost/mattermost-server/v6/model"
@@ -53,12 +54,10 @@ const (
const ServerKey product.ServiceKey = "server"
// These credentials for Rudder need to be populated at build-time,
// passing the following flags to the go build command:
// -ldflags "-X main.rudderDataplaneURL=<url> -X main.rudderWriteKey=<write_key>"
var (
rudderDataplaneURL string
rudderWriteKey string
// These credentials for Rudder need to be replaced at build-time.
const (
rudderDataplaneURL = "placeholder_rudder_dataplane_url"
rudderWriteKey = "placeholder_playbooks_rudder_key"
)
var errServiceTypeAssert = errors.New("type assertion failed")
@@ -157,229 +156,9 @@ func newPlaybooksProduct(services map[product.ServiceKey]interface{}) (product.P
return nil, err
}
logger := logrus.StandardLogger()
ConfigureLogrus(logger, playbooks.logger)
playbooks.server = services[ServerKey].(*mmapp.Server)
playbooks.serviceAdapter = newServiceAPIAdapter(playbooks)
botID, err := playbooks.serviceAdapter.EnsureBot(&model.Bot{
Username: "playbooks",
DisplayName: "Playbooks",
Description: "Playbooks bot.",
OwnerId: "playbooks",
})
if err != nil {
return nil, errors.Wrapf(err, "failed to ensure bot")
}
playbooks.config = config.NewConfigService(playbooks.serviceAdapter)
err = playbooks.config.UpdateConfiguration(func(c *config.Configuration) {
c.BotUserID = botID
c.AdminLogLevel = "debug"
})
if err != nil {
return nil, errors.Wrapf(err, "failed save bot to config")
}
playbooks.handler = api.NewHandler(playbooks.config)
if rudderDataplaneURL == "" || rudderWriteKey == "" {
logrus.Warn("Rudder credentials are not set. Disabling analytics.")
playbooks.telemetryClient = &telemetry.NoopTelemetry{}
} else {
diagnosticID := playbooks.serviceAdapter.GetDiagnosticID()
serverVersion := playbooks.serviceAdapter.GetServerVersion()
playbooks.telemetryClient, err = telemetry.NewRudder(rudderDataplaneURL, rudderWriteKey, diagnosticID, model.BuildHashPlaybooks, serverVersion)
if err != nil {
return nil, errors.Wrapf(err, "failed init telemetry client")
}
}
toggleTelemetry := func() {
diagnosticsFlag := playbooks.serviceAdapter.GetConfig().LogSettings.EnableDiagnostics
telemetryEnabled := diagnosticsFlag != nil && *diagnosticsFlag
if telemetryEnabled {
if err = playbooks.telemetryClient.Enable(); err != nil {
logrus.WithError(err).Error("Telemetry could not be enabled")
}
return
}
if err = playbooks.telemetryClient.Disable(); err != nil {
logrus.WithError(err).Error("Telemetry could not be disabled")
}
}
toggleTelemetry()
playbooks.config.RegisterConfigChangeListener(toggleTelemetry)
apiClient := sqlstore.NewClient(playbooks.serviceAdapter)
playbooks.bot = bot.New(playbooks.serviceAdapter, playbooks.config.GetConfiguration().BotUserID, playbooks.config, playbooks.telemetryClient)
scheduler := cluster.GetJobOnceScheduler(playbooks.serviceAdapter)
sqlStore, err := sqlstore.New(apiClient, scheduler)
if err != nil {
return nil, errors.Wrapf(err, "failed creating the SQL store")
}
playbooks.playbookRunStore = sqlstore.NewPlaybookRunStore(apiClient, sqlStore)
playbooks.playbookStore = sqlstore.NewPlaybookStore(apiClient, sqlStore)
statsStore := sqlstore.NewStatsStore(apiClient, sqlStore)
playbooks.userInfoStore = sqlstore.NewUserInfoStore(sqlStore)
channelActionStore := sqlstore.NewChannelActionStore(apiClient, sqlStore)
categoryStore := sqlstore.NewCategoryStore(apiClient, sqlStore)
playbooks.handler = api.NewHandler(playbooks.config)
playbooks.playbookService = app.NewPlaybookService(playbooks.playbookStore, playbooks.bot, playbooks.telemetryClient, playbooks.serviceAdapter, playbooks.metricsService)
keywordsThreadIgnorer := app.NewKeywordsThreadIgnorer()
playbooks.channelActionService = app.NewChannelActionsService(playbooks.serviceAdapter, playbooks.bot, playbooks.config, channelActionStore, playbooks.playbookService, keywordsThreadIgnorer, playbooks.telemetryClient)
playbooks.categoryService = app.NewCategoryService(categoryStore, playbooks.serviceAdapter, playbooks.telemetryClient)
playbooks.licenseChecker = enterprise.NewLicenseChecker(playbooks.serviceAdapter)
playbooks.playbookRunService = app.NewPlaybookRunService(
playbooks.playbookRunStore,
playbooks.bot,
playbooks.config,
scheduler,
playbooks.telemetryClient,
playbooks.telemetryClient,
playbooks.serviceAdapter,
playbooks.playbookService,
playbooks.channelActionService,
playbooks.licenseChecker,
playbooks.metricsService,
)
if err = scheduler.SetCallback(playbooks.playbookRunService.HandleReminder); err != nil {
logrus.WithError(err).Error("JobOnceScheduler could not add the playbookRunService's HandleReminder")
}
if err = scheduler.Start(); err != nil {
logrus.WithError(err).Error("JobOnceScheduler could not start")
}
// Migrations use the scheduler, so they have to be run after playbookRunService and scheduler have started
mutex, err := cluster.NewMutex(playbooks.serviceAdapter, "IR_dbMutex")
if err != nil {
return nil, errors.Wrapf(err, "failed creating cluster mutex")
}
mutex.Lock()
if err = sqlStore.RunMigrations(); err != nil {
mutex.Unlock()
return nil, errors.Wrapf(err, "failed to run migrations")
}
mutex.Unlock()
playbooks.permissions = app.NewPermissionsService(
playbooks.playbookService,
playbooks.playbookRunService,
playbooks.serviceAdapter,
playbooks.config,
playbooks.licenseChecker,
)
// register collections and topics.
// TODO bump the minimum server version
if err = playbooks.serviceAdapter.RegisterCollectionAndTopic(CollectionTypeRun, TopicTypeStatus); err != nil {
logrus.WithError(err).WithField("collection_type", CollectionTypeRun).WithField("topic_type", TopicTypeStatus).Warnf("failed to register collection and topic")
}
if err = playbooks.serviceAdapter.RegisterCollectionAndTopic(CollectionTypeRun, TopicTypeTask); err != nil {
logrus.WithError(err).WithField("collection_type", CollectionTypeRun).WithField("topic_type", TopicTypeTask).Warnf("failed to register collection and topic")
}
api.NewGraphQLHandler(
playbooks.handler.APIRouter,
playbooks.playbookService,
playbooks.playbookRunService,
playbooks.categoryService,
playbooks.serviceAdapter,
playbooks.config,
playbooks.permissions,
playbooks.playbookStore,
playbooks.licenseChecker,
)
api.NewPlaybookHandler(
playbooks.handler.APIRouter,
playbooks.playbookService,
playbooks.serviceAdapter,
playbooks.config,
playbooks.permissions,
)
api.NewPlaybookRunHandler(
playbooks.handler.APIRouter,
playbooks.playbookRunService,
playbooks.playbookService,
playbooks.permissions,
playbooks.licenseChecker,
playbooks.serviceAdapter,
playbooks.bot,
playbooks.config,
)
api.NewStatsHandler(
playbooks.handler.APIRouter,
playbooks.serviceAdapter,
statsStore,
playbooks.playbookService,
playbooks.permissions,
playbooks.licenseChecker,
)
api.NewBotHandler(
playbooks.handler.APIRouter,
playbooks.serviceAdapter, playbooks.bot,
playbooks.config,
playbooks.playbookRunService,
playbooks.userInfoStore,
)
api.NewTelemetryHandler(
playbooks.handler.APIRouter,
playbooks.playbookRunService,
playbooks.serviceAdapter,
playbooks.telemetryClient,
playbooks.playbookService,
playbooks.telemetryClient,
playbooks.telemetryClient,
playbooks.telemetryClient,
playbooks.permissions,
)
api.NewSignalHandler(
playbooks.handler.APIRouter,
playbooks.serviceAdapter,
playbooks.playbookRunService,
playbooks.playbookService,
keywordsThreadIgnorer,
)
api.NewSettingsHandler(
playbooks.handler.APIRouter,
playbooks.serviceAdapter,
playbooks.config,
)
api.NewActionsHandler(
playbooks.handler.APIRouter,
playbooks.channelActionService,
playbooks.serviceAdapter,
playbooks.permissions,
)
api.NewCategoryHandler(
playbooks.handler.APIRouter,
playbooks.serviceAdapter,
playbooks.categoryService,
playbooks.playbookService,
playbooks.playbookRunService,
)
isTestingEnabled := false
flag := playbooks.serviceAdapter.GetConfig().ServiceSettings.EnableTesting
if flag != nil {
isTestingEnabled = *flag
}
if err = command.RegisterCommands(playbooks.serviceAdapter.RegisterCommand, isTestingEnabled); err != nil {
return nil, errors.Wrapf(err, "failed register commands")
}
return playbooks, nil
}
@@ -531,6 +310,228 @@ func (pp *playbooksProduct) setProductServices(services map[product.ServiceKey]i
}
func (pp *playbooksProduct) Start() error {
logger := logrus.StandardLogger()
ConfigureLogrus(logger, pp.logger)
botID, err := pp.serviceAdapter.EnsureBot(&model.Bot{
Username: "playbooks",
DisplayName: "Playbooks",
Description: "Playbooks bot.",
OwnerId: "playbooks",
})
if err != nil {
return errors.Wrapf(err, "failed to ensure bot")
}
pp.config = config.NewConfigService(pp.serviceAdapter)
err = pp.config.UpdateConfiguration(func(c *config.Configuration) {
c.BotUserID = botID
c.AdminLogLevel = "debug"
})
if err != nil {
return errors.Wrapf(err, "failed save bot to config")
}
pp.handler = api.NewHandler(pp.config)
if strings.HasPrefix(rudderWriteKey, "placeholder_") {
logrus.Warn("Rudder credentials are not set. Disabling analytics.")
pp.telemetryClient = &telemetry.NoopTelemetry{}
} else {
logrus.Info("Rudder credentials are set. Enabling analytics.")
diagnosticID := pp.serviceAdapter.GetDiagnosticID()
serverVersion := pp.serviceAdapter.GetServerVersion()
pp.telemetryClient, err = telemetry.NewRudder(rudderDataplaneURL, rudderWriteKey, diagnosticID, model.BuildHashPlaybooks, serverVersion)
if err != nil {
return errors.Wrapf(err, "failed init telemetry client")
}
}
toggleTelemetry := func() {
diagnosticsFlag := pp.serviceAdapter.GetConfig().LogSettings.EnableDiagnostics
telemetryEnabled := diagnosticsFlag != nil && *diagnosticsFlag
if telemetryEnabled {
if err = pp.telemetryClient.Enable(); err != nil {
logrus.WithError(err).Error("Telemetry could not be enabled")
}
return
}
if err = pp.telemetryClient.Disable(); err != nil {
logrus.WithError(err).Error("Telemetry could not be disabled")
}
}
toggleTelemetry()
pp.config.RegisterConfigChangeListener(toggleTelemetry)
apiClient := sqlstore.NewClient(pp.serviceAdapter)
pp.bot = bot.New(pp.serviceAdapter, pp.config.GetConfiguration().BotUserID, pp.config, pp.telemetryClient)
scheduler := cluster.GetJobOnceScheduler(pp.serviceAdapter)
sqlStore, err := sqlstore.New(apiClient, scheduler)
if err != nil {
return errors.Wrapf(err, "failed creating the SQL store")
}
pp.playbookRunStore = sqlstore.NewPlaybookRunStore(apiClient, sqlStore)
pp.playbookStore = sqlstore.NewPlaybookStore(apiClient, sqlStore)
statsStore := sqlstore.NewStatsStore(apiClient, sqlStore)
pp.userInfoStore = sqlstore.NewUserInfoStore(sqlStore)
channelActionStore := sqlstore.NewChannelActionStore(apiClient, sqlStore)
categoryStore := sqlstore.NewCategoryStore(apiClient, sqlStore)
pp.handler = api.NewHandler(pp.config)
pp.playbookService = app.NewPlaybookService(pp.playbookStore, pp.bot, pp.telemetryClient, pp.serviceAdapter, pp.metricsService)
keywordsThreadIgnorer := app.NewKeywordsThreadIgnorer()
pp.channelActionService = app.NewChannelActionsService(pp.serviceAdapter, pp.bot, pp.config, channelActionStore, pp.playbookService, keywordsThreadIgnorer, pp.telemetryClient)
pp.categoryService = app.NewCategoryService(categoryStore, pp.serviceAdapter, pp.telemetryClient)
pp.licenseChecker = enterprise.NewLicenseChecker(pp.serviceAdapter)
pp.playbookRunService = app.NewPlaybookRunService(
pp.playbookRunStore,
pp.bot,
pp.config,
scheduler,
pp.telemetryClient,
pp.telemetryClient,
pp.serviceAdapter,
pp.playbookService,
pp.channelActionService,
pp.licenseChecker,
pp.metricsService,
)
if err = scheduler.SetCallback(pp.playbookRunService.HandleReminder); err != nil {
logrus.WithError(err).Error("JobOnceScheduler could not add the playbookRunService's HandleReminder")
}
if err = scheduler.Start(); err != nil {
logrus.WithError(err).Error("JobOnceScheduler could not start")
}
// Migrations use the scheduler, so they have to be run after playbookRunService and scheduler have started
mutex, err := cluster.NewMutex(pp.serviceAdapter, "IR_dbMutex")
if err != nil {
return errors.Wrapf(err, "failed creating cluster mutex")
}
mutex.Lock()
if err = sqlStore.RunMigrations(); err != nil {
mutex.Unlock()
return errors.Wrapf(err, "failed to run migrations")
}
mutex.Unlock()
pp.permissions = app.NewPermissionsService(
pp.playbookService,
pp.playbookRunService,
pp.serviceAdapter,
pp.config,
pp.licenseChecker,
)
// register collections and topics.
// TODO bump the minimum server version
if err = pp.serviceAdapter.RegisterCollectionAndTopic(CollectionTypeRun, TopicTypeStatus); err != nil {
logrus.WithError(err).WithField("collection_type", CollectionTypeRun).WithField("topic_type", TopicTypeStatus).Warnf("failed to register collection and topic")
}
if err = pp.serviceAdapter.RegisterCollectionAndTopic(CollectionTypeRun, TopicTypeTask); err != nil {
logrus.WithError(err).WithField("collection_type", CollectionTypeRun).WithField("topic_type", TopicTypeTask).Warnf("failed to register collection and topic")
}
api.NewGraphQLHandler(
pp.handler.APIRouter,
pp.playbookService,
pp.playbookRunService,
pp.categoryService,
pp.serviceAdapter,
pp.config,
pp.permissions,
pp.playbookStore,
pp.licenseChecker,
)
api.NewPlaybookHandler(
pp.handler.APIRouter,
pp.playbookService,
pp.serviceAdapter,
pp.config,
pp.permissions,
)
api.NewPlaybookRunHandler(
pp.handler.APIRouter,
pp.playbookRunService,
pp.playbookService,
pp.permissions,
pp.licenseChecker,
pp.serviceAdapter,
pp.bot,
pp.config,
)
api.NewStatsHandler(
pp.handler.APIRouter,
pp.serviceAdapter,
statsStore,
pp.playbookService,
pp.permissions,
pp.licenseChecker,
)
api.NewBotHandler(
pp.handler.APIRouter,
pp.serviceAdapter, pp.bot,
pp.config,
pp.playbookRunService,
pp.userInfoStore,
)
api.NewTelemetryHandler(
pp.handler.APIRouter,
pp.playbookRunService,
pp.serviceAdapter,
pp.telemetryClient,
pp.playbookService,
pp.telemetryClient,
pp.telemetryClient,
pp.telemetryClient,
pp.permissions,
)
api.NewSignalHandler(
pp.handler.APIRouter,
pp.serviceAdapter,
pp.playbookRunService,
pp.playbookService,
keywordsThreadIgnorer,
)
api.NewSettingsHandler(
pp.handler.APIRouter,
pp.serviceAdapter,
pp.config,
)
api.NewActionsHandler(
pp.handler.APIRouter,
pp.channelActionService,
pp.serviceAdapter,
pp.permissions,
)
api.NewCategoryHandler(
pp.handler.APIRouter,
pp.serviceAdapter,
pp.categoryService,
pp.playbookService,
pp.playbookRunService,
)
isTestingEnabled := false
flag := pp.serviceAdapter.GetConfig().ServiceSettings.EnableTesting
if flag != nil {
isTestingEnabled = *flag
}
if err = command.RegisterCommands(pp.serviceAdapter.RegisterCommand, isTestingEnabled); err != nil {
return errors.Wrapf(err, "failed register commands")
}
if err := pp.hooksService.RegisterHooks(playbooksProductName, pp); err != nil {
return fmt.Errorf("failed to register hooks: %w", err)
}

Просмотреть файл

@@ -15,8 +15,7 @@ import (
)
func TestActionCreation(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
createNewChannel := func(t *testing.T, name string) *model.Channel {
@@ -201,8 +200,7 @@ func TestActionCreation(t *testing.T) {
}
func TestActionList(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
// Create three valid actions
@@ -294,8 +292,7 @@ func TestActionList(t *testing.T) {
}
func TestActionUpdate(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
// Create a valid action

Просмотреть файл

@@ -16,8 +16,7 @@ func TestTrialLicences(t *testing.T) {
// This test is flaky due to upstream connectivity issues.
t.Skip()
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("request trial license without permissions", func(t *testing.T) {

Просмотреть файл

@@ -11,8 +11,7 @@ import (
)
func TestAPI(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
t.Run("404", func(t *testing.T) {

Просмотреть файл

@@ -21,8 +21,7 @@ import (
)
func TestGraphQLPlaybooks(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("basic get", func(t *testing.T) {
@@ -206,8 +205,7 @@ func TestGraphQLPlaybooks(t *testing.T) {
}
func TestGraphQLUpdatePlaybookFails(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("update playbook fails because size constraints.", func(t *testing.T) {
@@ -370,8 +368,7 @@ func TestGraphQLUpdatePlaybookFails(t *testing.T) {
}
func TestUpdatePlaybookFavorite(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("favorite", func(t *testing.T) {
@@ -493,8 +490,7 @@ func gqlTestPlaybookUpdate(e *TestEnvironment, t *testing.T, playbookID string,
}
func TestGraphQLPlaybooksMetrics(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("metrics get", func(t *testing.T) {

Просмотреть файл

@@ -20,8 +20,7 @@ import (
)
func TestGraphQLRunList(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("list by participantOrFollower", func(t *testing.T) {
@@ -206,8 +205,7 @@ func TestGraphQLRunList(t *testing.T) {
}
func TestGraphQLChangeRunParticipants(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
user3, _, err := e.ServerAdminClient.CreateUser(&model.User{
@@ -669,8 +667,7 @@ func TestGraphQLChangeRunParticipants(t *testing.T) {
}
func TestGraphQLChangeRunOwner(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
// create a third user to test change owner
@@ -713,8 +710,7 @@ func TestGraphQLChangeRunOwner(t *testing.T) {
}
func TestSetRunFavorite(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
createRun := func() *client.PlaybookRun {
@@ -800,8 +796,7 @@ func TestSetRunFavorite(t *testing.T) {
}
func TestResolverFavorites(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
createRun := func() *client.PlaybookRun {
@@ -833,8 +828,7 @@ func TestResolverFavorites(t *testing.T) {
}
func TestResolverPlaybooks(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
createRun := func() *client.PlaybookRun {
@@ -860,8 +854,7 @@ func TestResolverPlaybooks(t *testing.T) {
}
func TestUpdateRun(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
createRun := func() *client.PlaybookRun {
@@ -977,8 +970,7 @@ func TestUpdateRun(t *testing.T) {
}
func TestUpdateRunTaskActions(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("task actions mutation create and update", func(t *testing.T) {
@@ -1071,8 +1063,7 @@ func TestUpdateRunTaskActions(t *testing.T) {
}
func TestBadGraphQLRequest(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
testRunsQuery := `

Просмотреть файл

@@ -22,8 +22,7 @@ import (
)
func TestPlaybooks(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
@@ -267,8 +266,7 @@ func TestPlaybooks(t *testing.T) {
}
func TestCreateInvalidPlaybook(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
@@ -369,8 +367,7 @@ func TestCreateInvalidPlaybook(t *testing.T) {
}
func TestPlaybooksRetrieval(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("get playbook", func(t *testing.T) {
@@ -387,8 +384,7 @@ func TestPlaybooksRetrieval(t *testing.T) {
}
func TestPlaybookUpdate(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("update playbook properties", func(t *testing.T) {
@@ -521,8 +517,7 @@ func TestPlaybookUpdate(t *testing.T) {
}
func TestPlaybookUpdateCrossTeam(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("update playbook properties not in team public playbook", func(t *testing.T) {
@@ -552,8 +547,7 @@ func TestPlaybookUpdateCrossTeam(t *testing.T) {
}
func TestPlaybooksSort(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
e.SetE20Licence()
@@ -795,8 +789,7 @@ func TestPlaybooksSort(t *testing.T) {
}
func TestPlaybooksPaging(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
e.SetE20Licence()
@@ -935,8 +928,7 @@ func getPlaybookIDsList(playbooks []client.Playbook) []string {
}
func TestPlaybooksPermissions(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("test no permissions to create", func(t *testing.T) {
@@ -1148,8 +1140,7 @@ func TestPlaybooksPermissions(t *testing.T) {
}
func TestPlaybooksConversions(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("public to private conversion", func(t *testing.T) {
@@ -1208,8 +1199,7 @@ func TestPlaybooksConversions(t *testing.T) {
}
func TestPlaybooksImportExport(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
e.CreateBasicPublicPlaybook()
@@ -1237,8 +1227,7 @@ func TestPlaybooksImportExport(t *testing.T) {
}
func TestPlaybooksDuplicate(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
e.SetE20Licence()
@@ -1259,8 +1248,7 @@ func TestPlaybooksDuplicate(t *testing.T) {
}
func TestAddPostToTimeline(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
dialogRequest := model.SubmitDialogRequest{
@@ -1307,8 +1295,7 @@ func TestAddPostToTimeline(t *testing.T) {
}
func TestPlaybookStats(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateClients()
e.CreateBasicServer()
e.SetE20Licence()
@@ -1343,8 +1330,7 @@ func TestPlaybookStats(t *testing.T) {
}
func TestPlaybookGetAutoFollows(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
p1ID, err := e.PlaybooksAdminClient.Playbooks.Create(context.Background(), client.PlaybookCreateOptions{
@@ -1450,8 +1436,7 @@ func TestPlaybookGetAutoFollows(t *testing.T) {
}
func TestPlaybookChecklistCleanup(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("update playbook", func(t *testing.T) {

Просмотреть файл

@@ -19,8 +19,7 @@ import (
)
func TestRunCreation(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
incompletePlaybookID, err := e.PlaybooksAdminClient.Playbooks.Create(context.Background(), client.PlaybookCreateOptions{
@@ -314,8 +313,7 @@ func TestRunCreation(t *testing.T) {
}
func TestCreateRunInExistingChannel(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
// create playbook
@@ -410,8 +408,7 @@ func TestCreateRunInExistingChannel(t *testing.T) {
}
func TestCreateInvalidRuns(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("fails if description is longer than 4096", func(t *testing.T) {
@@ -428,8 +425,7 @@ func TestCreateInvalidRuns(t *testing.T) {
}
func TestRunRetrieval(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("by channel id", func(t *testing.T) {
@@ -510,8 +506,7 @@ func TestRunRetrieval(t *testing.T) {
}
func TestRunPostStatusUpdate(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("post an update", func(t *testing.T) {
@@ -571,8 +566,7 @@ func TestRunPostStatusUpdate(t *testing.T) {
}
func TestChecklistManagement(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
createNewRunWithNoChecklists := func(t *testing.T) *client.PlaybookRun {
@@ -1188,8 +1182,7 @@ func TestChecklistManagement(t *testing.T) {
}
func TestChecklisFailTooLarge(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("checklist creation - failure: too large checklist", func(t *testing.T) {
@@ -1213,8 +1206,7 @@ func TestChecklisFailTooLarge(t *testing.T) {
}
func TestRunGetStatusUpdates(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("public - get no updates", func(t *testing.T) {
@@ -1343,8 +1335,7 @@ func TestRunGetStatusUpdates(t *testing.T) {
}
func TestRequestUpdate(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("private - no viewer access ", func(t *testing.T) {
@@ -1437,8 +1428,7 @@ func TestRequestUpdate(t *testing.T) {
}
func TestReminderReset(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("reminder reset - timeline event created", func(t *testing.T) {
@@ -1485,8 +1475,7 @@ func TestReminderReset(t *testing.T) {
}
func TestChecklisItem_SetAssignee(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
addSimpleChecklistToTun := func(t *testing.T, runID string) *client.PlaybookRun {
@@ -1597,8 +1586,7 @@ func TestChecklisItem_SetAssignee(t *testing.T) {
}
func TestChecklisItem_SetCommand(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
run, err := e.PlaybooksClient.PlaybookRuns.Create(context.Background(), client.PlaybookRunCreateOptions{
@@ -1699,8 +1687,7 @@ func TestChecklisItem_SetCommand(t *testing.T) {
}
func TestGetOwners(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
ownerFromUser := func(u *model.User) client.OwnerInfo {

Просмотреть файл

@@ -14,8 +14,7 @@ import (
)
func TestSettings(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("get settings", func(t *testing.T) {

Просмотреть файл

@@ -16,8 +16,7 @@ import (
)
func TestGetSiteStats(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("get sites stats", func(t *testing.T) {
@@ -50,8 +49,7 @@ func TestGetSiteStats(t *testing.T) {
}
func TestPlaybookKeyMetricsStats(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("3 runs with published metrics, 2 runs without publishing", func(t *testing.T) {

Просмотреть файл

@@ -11,8 +11,7 @@ import (
)
func TestCreateEvent(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
t.Run("create an event with bad type fails", func(t *testing.T) {

Просмотреть файл

@@ -97,7 +97,7 @@ func getEnvWithDefault(name, defaultValue string) string {
return defaultValue
}
func Setup(t *testing.T) (*TestEnvironment, func()) {
func Setup(t *testing.T) *TestEnvironment {
// Ignore any locally defined SiteURL as we intend to host our own.
os.Unsetenv("MM_SERVICESETTINGS_SITEURL")
os.Unsetenv("MM_SERVICESETTINGS_LISTENADDRESS")
@@ -126,11 +126,6 @@ func Setup(t *testing.T) (*TestEnvironment, func()) {
config.LogSettings.EnableFile = model.NewBool(false)
config.LogSettings.ConsoleLevel = model.NewString("INFO")
// disable Boards through the feature flag
boardsProductEnvValue := os.Getenv("MM_FEATUREFLAGS_BoardsProduct")
os.Unsetenv("MM_FEATUREFLAGS_BoardsProduct")
config.FeatureFlags.BoardsProduct = false
// override config with e2etest.config.json if it exists
textConfig, err := os.ReadFile("./e2etest.config.json")
if err == nil {
@@ -169,10 +164,6 @@ func Setup(t *testing.T) (*TestEnvironment, func()) {
ap := sapp.New(sapp.ServerConnector(server.Channels()))
teardown := func() {
os.Setenv("MM_FEATUREFLAGS_BoardsProduct", boardsProductEnvValue)
}
return &TestEnvironment{
T: t,
Srv: server,
@@ -184,7 +175,7 @@ func Setup(t *testing.T) (*TestEnvironment, func()) {
},
},
logger: testLogger,
}, teardown
}
}
func (e *TestEnvironment) CreateClients() {
@@ -478,8 +469,7 @@ func (e *TestEnvironment) CreateBasic() {
// TestTestFramework If this is failing you know the break is not exclusively in your test.
func TestTestFramework(t *testing.T) {
e, teardown := Setup(t)
defer teardown()
e := Setup(t)
e.CreateBasic()
}