├── .fleet └── settings.json ├── .gitattributes ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── PULL_REQUEST_TEMPLATE.md ├── maintainers_guide.md └── workflows │ ├── ci.yml │ ├── code-review.yml │ ├── mkdocs-requirements.txt │ ├── publish-docs.yml │ └── renovate.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── RELEASING.md ├── build.gradle.kts ├── config ├── bin │ ├── gjf │ ├── ktfmt │ └── sort-dependencies ├── git │ └── hooks │ │ ├── post-checkout │ │ ├── post-commit │ │ ├── post-merge │ │ ├── pre-commit │ │ ├── pre-push │ │ └── pre-receive.sh └── lint │ └── lint.xml ├── deploy_website.sh ├── docs ├── images │ ├── slack_logo.png │ └── slack_logo_small.png ├── index.md ├── platforms │ └── gradle │ │ ├── architecture.md │ │ ├── bootstrap.md │ │ ├── configuration.md │ │ ├── dependency-rake.md │ │ ├── dsl.md │ │ ├── formatters-and-analysis.md │ │ ├── lint.md │ │ ├── mod-score.md │ │ ├── properties.md │ │ ├── testing.md │ │ ├── thermals-logging.md │ │ └── utilities.md └── tools │ ├── cli.md │ └── skippy.md ├── foundry-migration ├── mapping.txt └── property_migration.sh ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mkdocs.yml ├── platforms ├── gradle │ ├── agp-handlers │ │ └── agp-handler-api │ │ │ ├── build.gradle.kts │ │ │ ├── gradle.properties │ │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── foundry │ │ │ │ └── gradle │ │ │ │ └── agp │ │ │ │ ├── AgpHandler.kt │ │ │ │ ├── AgpHandlers.kt │ │ │ │ ├── PermissionAllowlistConfigurer.kt │ │ │ │ ├── VariantConfiguration.kt │ │ │ │ └── internal │ │ │ │ └── NoOpIssueReporter.kt │ │ │ └── test │ │ │ └── kotlin │ │ │ └── foundry │ │ │ └── gradle │ │ │ └── agp │ │ │ └── AgpHandlersTest.kt │ ├── better-gradle-properties │ │ ├── api │ │ │ └── better-gradle-properties.api │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── foundry │ │ │ └── gradle │ │ │ └── properties │ │ │ ├── GitExecProviders.kt │ │ │ ├── HasConfigurableValues.kt │ │ │ ├── PropertyResolver.kt │ │ │ └── PropertyUtil.kt │ └── foundry-gradle-plugin │ │ ├── best-practices-baseline.json │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ ├── lint-baseline.xml │ │ ├── src │ │ ├── main │ │ │ ├── kotlin │ │ │ │ ├── Aliases.kt │ │ │ │ └── foundry │ │ │ │ │ └── gradle │ │ │ │ │ ├── AndroidSourcesConfigurer.kt │ │ │ │ │ ├── AnnotationProcessing.kt │ │ │ │ │ ├── ApkVersioningPlugin.kt │ │ │ │ │ ├── Configurations.kt │ │ │ │ │ ├── DelicateFoundryGradlePluginApi.kt │ │ │ │ │ ├── ErrorProneChecks.kt │ │ │ │ │ ├── FoundryBasePlugin.kt │ │ │ │ │ ├── FoundryExtension.kt │ │ │ │ │ ├── FoundryGradleUtil.kt │ │ │ │ │ ├── FoundryProperties.kt │ │ │ │ │ ├── FoundryRootPlugin.kt │ │ │ │ │ ├── FoundryShared.kt │ │ │ │ │ ├── FoundryTools.kt │ │ │ │ │ ├── FoundryVersions.kt │ │ │ │ │ ├── GlobalConfig.kt │ │ │ │ │ ├── GradleExt.kt │ │ │ │ │ ├── Platforms.kt │ │ │ │ │ ├── StandardProjectConfigurations.kt │ │ │ │ │ ├── android │ │ │ │ │ └── AndroidArchitecture.kt │ │ │ │ │ ├── anvil │ │ │ │ │ └── AnvilMode.kt │ │ │ │ │ ├── artifacts │ │ │ │ │ ├── ArtifactUtil.kt │ │ │ │ │ ├── FoundryArtifact.kt │ │ │ │ │ ├── Publisher.kt │ │ │ │ │ ├── Resolver.kt │ │ │ │ │ └── ShareableArtifact.kt │ │ │ │ │ ├── avoidance │ │ │ │ │ ├── ComputeAffectedProjectsTask.kt │ │ │ │ │ ├── GenerateAndroidTestProjectPathsTask.kt │ │ │ │ │ ├── GenerateDependencyGraphTask.kt │ │ │ │ │ ├── ProjectDependenciesDumpTask.kt │ │ │ │ │ ├── SkippyArtifacts.kt │ │ │ │ │ └── SkippyExtension.kt │ │ │ │ │ ├── compose │ │ │ │ │ └── ComposeUtil.kt │ │ │ │ │ ├── configureBuildTags.kt │ │ │ │ │ ├── dependencies │ │ │ │ │ ├── DependencyCollection.kt │ │ │ │ │ ├── DependencyDef.kt │ │ │ │ │ ├── DependencyDelegate.kt │ │ │ │ │ ├── DependencyGroup.kt │ │ │ │ │ ├── DependencySet.kt │ │ │ │ │ └── FoundryDependencies.kt │ │ │ │ │ ├── dependencyrake │ │ │ │ │ └── DependencyRake.kt │ │ │ │ │ ├── develocity │ │ │ │ │ └── DevelocityFinderApi.kt │ │ │ │ │ ├── kgp │ │ │ │ │ └── KgpTasks.kt │ │ │ │ │ ├── lint │ │ │ │ │ ├── DetektTasks.kt │ │ │ │ │ └── LintTasks.kt │ │ │ │ │ ├── permissionchecks │ │ │ │ │ └── PermissionChecks.kt │ │ │ │ │ ├── stats │ │ │ │ │ ├── LanguageStats.kt │ │ │ │ │ ├── LocTask.kt │ │ │ │ │ └── ModuleStats.kt │ │ │ │ │ ├── tasks │ │ │ │ │ ├── AndroidTestApksTask.kt │ │ │ │ │ ├── BaseDependencyCheckTask.kt │ │ │ │ │ ├── BaseDownloadTask.kt │ │ │ │ │ ├── BootstrapTask.kt │ │ │ │ │ ├── CheckDependencyVersionsTask.kt │ │ │ │ │ ├── CheckManifestPermissionsTask.kt │ │ │ │ │ ├── DetektDownloadTask.kt │ │ │ │ │ ├── FileTasks.kt │ │ │ │ │ ├── FoundryValidationTask.kt │ │ │ │ │ ├── GjfDownloadTask.kt │ │ │ │ │ ├── InstallCommitHooksTask.kt │ │ │ │ │ ├── KtLintDownloadTask.kt │ │ │ │ │ ├── KtfmtDownloadTask.kt │ │ │ │ │ ├── LifecycleTask.kt │ │ │ │ │ ├── PrintFossaDependencies.kt │ │ │ │ │ ├── ProgressResponseBody.kt │ │ │ │ │ ├── SortDependenciesDownloadTask.kt │ │ │ │ │ ├── TaskExtensions.kt │ │ │ │ │ ├── ValidateVersionsMatch.kt │ │ │ │ │ └── robolectric │ │ │ │ │ │ └── UpdateRobolectricJarsTask.kt │ │ │ │ │ ├── testing │ │ │ │ │ ├── EmulatorWtfTests.kt │ │ │ │ │ ├── RoborazziTests.kt │ │ │ │ │ └── UnitTests.kt │ │ │ │ │ ├── topography │ │ │ │ │ ├── DefaultFeatures.kt │ │ │ │ │ ├── ModuleFeature.kt │ │ │ │ │ ├── ModuleFeaturesConfig.kt │ │ │ │ │ ├── ModuleTopography.kt │ │ │ │ │ └── ModuleTopographyTask.kt │ │ │ │ │ └── util │ │ │ │ │ ├── GradleFoundryLogger.kt │ │ │ │ │ ├── GradleJsonTools.kt │ │ │ │ │ ├── JavaAgentArgumentProvider.kt │ │ │ │ │ ├── JavaAgentDependenciesExtension.kt │ │ │ │ │ ├── KspUtil.kt │ │ │ │ │ ├── OkHttpExt.kt │ │ │ │ │ ├── ThermalsWatcher.kt │ │ │ │ │ ├── charting │ │ │ │ │ ├── AxisRange.kt │ │ │ │ │ ├── AxisStyle.kt │ │ │ │ │ ├── ChartCreator.kt │ │ │ │ │ ├── ChartData.kt │ │ │ │ │ ├── ChartFill.kt │ │ │ │ │ ├── ChartProperty.kt │ │ │ │ │ ├── ChartSize.kt │ │ │ │ │ ├── ChartType.kt │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── ColorRange.kt │ │ │ │ │ ├── SeriesColors.kt │ │ │ │ │ ├── ValuesEncoder.kt │ │ │ │ │ └── VisibleAxis.kt │ │ │ │ │ └── kgpUtil.kt │ │ │ └── resources │ │ │ │ └── libthermal_state.dylib │ │ └── test │ │ │ └── kotlin │ │ │ └── foundry │ │ │ └── gradle │ │ │ ├── AndroidSourcesConfigurerTest.kt │ │ │ ├── StandardProjectConfigurationsTest.kt │ │ │ ├── agp │ │ │ └── AgpHandlerTest.kt │ │ │ ├── dependencies │ │ │ └── DependencyCollectionTest.kt │ │ │ ├── fakes │ │ │ └── NoOpLogger.kt │ │ │ ├── stats │ │ │ ├── LanguageStatsTest.kt │ │ │ └── ModuleStatsTest.kt │ │ │ ├── tasks │ │ │ └── ManifestParsingTest.kt │ │ │ ├── topography │ │ │ ├── ModuleFeatureTest.kt │ │ │ └── ModuleTopographyTest.kt │ │ │ └── util │ │ │ └── ThermlogParserTest.kt │ │ └── thermal_state.swift └── intellij │ ├── artifactory-authenticator │ ├── README.md │ ├── build.gradle.kts │ ├── gradle.properties │ └── src │ │ └── main │ │ ├── kotlin │ │ └── foundry │ │ │ └── intellij │ │ │ └── artifactory │ │ │ ├── ArtifactoryPluginRepositoryAuthProvider.kt │ │ │ ├── AuthBundle.kt │ │ │ ├── AuthConfig.kt │ │ │ ├── AuthPluginSettings.kt │ │ │ └── RepoAuthHotfix.kt │ │ └── resources │ │ ├── META-INF │ │ ├── plugin.xml │ │ └── pluginIcon.svg │ │ └── messages │ │ └── artifactoryAuthenticator.properties │ ├── compose │ ├── build.gradle.kts │ ├── gradle.properties │ ├── lint-baseline.xml │ ├── playground │ │ ├── build.gradle.kts │ │ └── src │ │ │ ├── jvmMain │ │ │ └── kotlin │ │ │ │ └── foundry │ │ │ │ └── intellij │ │ │ │ └── compose │ │ │ │ └── playground │ │ │ │ ├── MarkdownPlayground.kt │ │ │ │ └── ProjectGenPlayground.kt │ │ │ └── jvmTest │ │ │ └── kotlin │ │ │ └── foundry │ │ │ └── intellij │ │ │ └── compose │ │ │ └── playground │ │ │ ├── MarkdownPlaygroundTest.kt │ │ │ └── snapshots │ │ │ └── images │ │ │ ├── foundry.intellij.compose.playground.MarkdownPlaygroundTest.snapshot.png │ │ │ ├── foundry.intellij.compose.playground.MarkdownPlaygroundTest.snapshot_2.png │ │ │ ├── foundry.intellij.compose.playground.MarkdownPlaygroundTest.test.png │ │ │ └── foundry.intellij.compose.playground.MarkdownPlaygroundTest.test_2.png │ └── src │ │ ├── jvmMain │ │ ├── kotlin │ │ │ └── foundry │ │ │ │ └── intellij │ │ │ │ └── compose │ │ │ │ ├── aibot │ │ │ │ ├── ChatColors.kt │ │ │ │ ├── ChatPanel.kt │ │ │ │ ├── ChatPresenter.kt │ │ │ │ ├── ChatScreen.kt │ │ │ │ ├── ChatWindowUi.kt │ │ │ │ ├── LoadingAnimation.kt │ │ │ │ ├── Message.kt │ │ │ │ └── PainterResource.kt │ │ │ │ ├── markdown │ │ │ │ └── ui │ │ │ │ │ └── MarkdownPanel.kt │ │ │ │ └── projectgen │ │ │ │ ├── FoundryDesktopTheme.kt │ │ │ │ ├── PrefixTransformation.kt │ │ │ │ ├── ProjectGenPresenter.kt │ │ │ │ ├── ProjectGenScreen.kt │ │ │ │ ├── ProjectGenUi.kt │ │ │ │ ├── UiElement.kt │ │ │ │ └── models.kt │ │ └── resources │ │ │ └── drawable │ │ │ └── send.svg │ │ └── jvmTest │ │ └── kotlin │ │ └── foundry │ │ └── intellij │ │ └── compose │ │ └── projectgen │ │ └── TextElementTest.kt │ └── skate │ ├── README.md │ ├── build.gradle.kts │ ├── change-notes.html │ ├── gradle.properties │ ├── lint-baseline.xml │ └── src │ ├── main │ ├── kotlin │ │ └── foundry │ │ │ └── intellij │ │ │ └── skate │ │ │ ├── ChangelogJournal.kt │ │ │ ├── ChangelogParser.kt │ │ │ ├── LocalDateConverter.kt │ │ │ ├── PostStartupActivityExtension.kt │ │ │ ├── SkateBundle.kt │ │ │ ├── SkateConfig.kt │ │ │ ├── SkateErrorHandler.kt │ │ │ ├── SkatePluginSettings.kt │ │ │ ├── SkateService.kt │ │ │ ├── WhatsNewToolWindowListener.kt │ │ │ ├── aibot │ │ │ └── ChatBotToolWindow.kt │ │ │ ├── codeowners │ │ │ ├── CodeOwnerFileFetcher.kt │ │ │ ├── CodeOwnerInfo.kt │ │ │ ├── CodeOwnerRepository.kt │ │ │ └── model │ │ │ │ ├── CodeOwner.kt │ │ │ │ ├── CodeOwnersFile.kt │ │ │ │ ├── Path.kt │ │ │ │ └── PathObjectSerializer.kt │ │ │ ├── featureflags │ │ │ ├── FeatureFlagAnnotator.kt │ │ │ ├── FeatureFlagExtractor.kt │ │ │ └── UastExtensions.kt │ │ │ ├── gradle │ │ │ ├── CopyGradleProjectAccessorPathProvider.kt │ │ │ ├── CopyGradleProjectPathProvider.kt │ │ │ └── GradleProjectUtils.kt │ │ │ ├── ideinstall │ │ │ ├── InstallationLocationService.kt │ │ │ └── InstallationLocationStartupActivity.kt │ │ │ ├── idemetrics │ │ │ ├── GradleSyncSubscriber.kt │ │ │ └── IndexingListener.kt │ │ │ ├── modeltranslator │ │ │ ├── GenerateTranslatorBodyAction.kt │ │ │ ├── TranslatorAnnotator.kt │ │ │ ├── helper │ │ │ │ └── TranslatorHelper.kt │ │ │ └── model │ │ │ │ └── TranslatorBundle.kt │ │ │ ├── projectgen │ │ │ ├── ProjectGenMenuAction.kt │ │ │ └── ProjectGenWindow.kt │ │ │ ├── tracing │ │ │ ├── SkateSpanBuilder.kt │ │ │ ├── SkateTraceReporter.kt │ │ │ └── SkateTracingEvent.kt │ │ │ ├── ui │ │ │ ├── CodeOwnerWidget.kt │ │ │ ├── CodeOwnerWidgetFactory.kt │ │ │ ├── FileChoosing.kt │ │ │ ├── ShowWhatsNewAction.kt │ │ │ ├── SkateConfigUI.kt │ │ │ └── WhatsNewPanelFactory.kt │ │ │ └── util │ │ │ ├── MemoizedSequence.kt │ │ │ ├── ProjectUtils.kt │ │ │ └── StringExtensions.kt │ └── resources │ │ ├── META-INF │ │ ├── plugin.xml │ │ └── pluginIcon.svg │ │ └── messages │ │ └── skateBundle.properties │ └── test │ ├── kotlin │ └── foundry │ │ └── intellij │ │ └── skate │ │ ├── ChangeLogParserTest.kt │ │ ├── SkateTraceReporterTest.kt │ │ ├── WhatsNewToolWindowListenerTest.kt │ │ ├── codeowners │ │ ├── CodeOwnerFileFetcherImplTest.kt │ │ └── CodeOwnerRepositoryTest.kt │ │ ├── featureflags │ │ ├── BaseFeatureFlagTest.kt │ │ ├── FeatureFlagAnnotatorTest.kt │ │ └── FeatureFlagExtractorTest.kt │ │ ├── gradle │ │ └── GradleProjectUtilsTest.kt │ │ ├── ideinstall │ │ └── InstallationLocationServiceTest.kt │ │ ├── modeltranslator │ │ ├── TranslatorAnnotatorTest.kt │ │ └── TranslatorHelperTest.kt │ │ └── projectgen │ │ └── ProjectGenWindowTest.kt │ ├── resources │ └── test-code-ownership.yaml │ └── testData │ ├── ActionTranslator.kt │ ├── Call.kt │ ├── CallExtensions.kt │ ├── CallObjectTranslator.kt │ ├── CallObjectsTranslator.kt │ ├── CallTranslator.kt │ ├── FullyQualifiedActionTranslator.kt │ ├── FullyQualifiedCallTranslator.kt │ ├── ImportAliasCallTranslator.kt │ ├── NullableCallTranslator.kt │ ├── SingleLineCallTranslator.kt │ ├── StatusStringTranslator.kt │ └── TranscriptionStringTranslator.kt ├── publish_skate.sh ├── regenerate_thermals_lib.sh ├── release.sh ├── renovate.json ├── settings.gradle.kts ├── spotless └── spotless.kt └── tools ├── cli ├── api │ └── cli.api ├── build.gradle.kts ├── gradle.properties ├── lint-baseline.xml └── src │ ├── main │ └── kotlin │ │ └── foundry │ │ └── cli │ │ ├── AppleSiliconCompat.kt │ │ ├── CliUtil.kt │ │ ├── CliktExtensions.kt │ │ ├── CommandFactory.kt │ │ ├── Toml.kt │ │ ├── buildkite │ │ ├── BuildkiteDataBindings.kt │ │ ├── BuildkitePipelineDsl.kt │ │ ├── Extensions.kt │ │ ├── JsonElementKamlSerializers.kt │ │ └── Keyable.kt │ │ ├── gradle │ │ ├── GradleProjectFlattenerCli.kt │ │ ├── GradleSettingsVerifierCli.kt │ │ └── GradleTestFixturesMigratorCli.kt │ │ ├── lint │ │ └── LintBaselineMergerCli.kt │ │ ├── playground.kt │ │ ├── sarif │ │ ├── ApplyBaselinesToSarifs.kt │ │ ├── MergeSarifReports.kt │ │ └── SarifUtil.kt │ │ ├── shellsentry │ │ ├── Issue.kt │ │ ├── KnownIssues.kt │ │ ├── OkHttpSyncHttpDelivery.kt │ │ ├── ProcessingUtil.kt │ │ ├── ResultProcessor.kt │ │ ├── RetrySignal.kt │ │ ├── ShellSentry.kt │ │ ├── ShellSentryCli.kt │ │ ├── ShellSentryConfig.kt │ │ └── ShellSentryExtension.kt │ │ └── util │ │ ├── DurationJsonAdapter.kt │ │ ├── RegexJsonAdapter.kt │ │ └── SingleItemListJsonAdapterFactory.kt │ └── test │ └── kotlin │ └── foundry │ └── cli │ ├── TomlTest.kt │ ├── buildkite │ └── BuildkitePipelineDslKtTest.kt │ ├── shellsentry │ ├── ResultProcessorTest.kt │ ├── ShellSentryCliTest.kt │ └── ShellSentryConfigTest.kt │ └── util │ ├── RegexJsonAdapterFactoryTest.kt │ └── SingleItemListAdapterTest.kt ├── foundry-common ├── build.gradle.kts ├── gradle.properties ├── lint-baseline.xml └── src │ ├── main │ └── kotlin │ │ └── foundry │ │ └── common │ │ ├── Collections.kt │ │ ├── FoundryKeys.kt │ │ ├── FoundryLogger.kt │ │ ├── GradlePathUtils.kt │ │ ├── ParallelIterables.kt │ │ ├── Paths.kt │ │ ├── RegexMap.kt │ │ └── json │ │ └── JsonTools.kt │ └── test │ └── kotlin │ └── foundry │ └── common │ └── GradlePathUtilsTest.kt ├── robolectric-sdk-management ├── README.md ├── api │ └── robolectric-sdk-management.api ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ └── kotlin │ └── foundry │ └── tools │ └── robolectric │ └── sdk │ └── management │ └── RobolectricSdkAccess.kt ├── scripts └── scriptUtil.sh ├── skippy ├── build.gradle.kts ├── gradle.properties ├── lint-baseline.xml └── src │ ├── main │ └── kotlin │ │ └── foundry │ │ └── skippy │ │ ├── AffectedProjectsComputer.kt │ │ ├── AffectedProjectsDefaults.kt │ │ ├── AffectedProjectsResult.kt │ │ ├── CliktFoundryLogger.kt │ │ ├── ComputeAffectedProjectsCli.kt │ │ ├── DependencyMetadata.kt │ │ ├── DiagnosticWriter.kt │ │ ├── GlobUtil.kt │ │ ├── SkippyConfig.kt │ │ ├── SkippyOutput.kt │ │ └── SkippyRunner.kt │ └── test │ └── kotlin │ └── foundry │ └── skippy │ ├── AffectedProjectsComputerTest.kt │ ├── PathMatcherTest.kt │ ├── SkippyConfigTest.kt │ ├── SkippyRunnerTest.kt │ └── TestProject.kt ├── tracing ├── build.gradle.kts ├── gradle.properties ├── lint-baseline.xml └── src │ └── main │ ├── kotlin │ └── foundry │ │ └── tracing │ │ ├── api │ │ └── TracingService.kt │ │ ├── model │ │ ├── SpanIds.kt │ │ ├── Spans.kt │ │ └── TagBuilder.kt │ │ └── reporter │ │ ├── SimpleTraceReporter.kt │ │ └── TraceReporter.kt │ └── proto │ └── trace.proto └── version-number ├── api └── version-number.api ├── build.gradle.kts ├── gradle.properties └── src ├── main └── kotlin │ └── foundry │ └── common │ └── versioning │ └── VersionNumber.kt └── test └── kotlin └── foundry └── common └── versioning └── VersionNumberTest.kt /.fleet/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "backend.maxHeapSizeMb": 1487, 3 | "gradle.autoImportOnSave": false 4 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | gradlew linguist-generated=true 2 | gradlew.bat linguist-generated=true 3 | config/bin/* filter=lfs diff=lfs merge=lfs -text 4 | **/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Introduction 4 | 5 | Diversity and inclusion make our community strong. We encourage participation from the most varied and diverse backgrounds possible and want to be very clear about where we stand. 6 | 7 | Our goal is to maintain a safe, helpful and friendly community for everyone, regardless of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other defining characteristic. 8 | 9 | This code and related procedures also apply to unacceptable behavior occurring outside the scope of community activities, in all community venues (online and in-person) as well as in all one-on-one communications, and anywhere such behavior has the potential to adversely affect the safety and well-being of community members. 10 | 11 | For more information on our code of conduct, please visit [https://slackhq.github.io/code-of-conduct](https://slackhq.github.io/code-of-conduct) 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributors Guide 2 | 3 | Note that this project is considered READ-ONLY. You are welcome to discuss or ask questions in the 4 | discussions section of the repo, but we do not normally accept external contributions without prior 5 | discussion. 6 | 7 | ## Development 8 | 9 | Check out this repo with Android Studio or IntelliJ. It's a standard gradle project and 10 | conventional to check out. 11 | 12 | The primary project is `slack-plugin`. 13 | 14 | Kotlin should be used for more idiomatic use with Gradle/AGP APIs 15 | 16 | Code formatting is checked via [Spotless](https://github.com/diffplug/spotless). To run the formatter, 17 | use the `spotlessApply` command. 18 | 19 | ```bash 20 | ./gradlew spotlessApply 21 | ``` 22 | 23 | Optionally, there are commit hooks in the repo you can enable by running the below 24 | ```bash 25 | git config core.hooksPath config/git/hooks 26 | ``` -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/code-review.yml: -------------------------------------------------------------------------------- 1 | # This workflow triggers a code review using the OpenAI GPT-3.5 Turbo model with a 16k context window 2 | name: Code Review 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - opened 8 | 9 | jobs: 10 | code-review: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: read 14 | pull-requests: write 15 | if: ${{ github.actor != 'slack-oss-bot' }} 16 | steps: 17 | - name: Trigger code review 18 | uses: fxchen/code-review@v0.2.9-alpha 19 | with: 20 | model: 'gpt-3.5-turbo-16k' 21 | openai-key: ${{ secrets.OPENAI_API_KEY }} 22 | -------------------------------------------------------------------------------- /.github/workflows/mkdocs-requirements.txt: -------------------------------------------------------------------------------- 1 | click==8.1.8 2 | future==1.0.0 3 | Jinja2==3.1.6 4 | livereload==2.7.1 5 | lunr==0.8.0 6 | Markdown==3.8 7 | MarkupSafe==3.0.2 8 | mkdocs==1.6.1 9 | mkdocs-macros-plugin==1.3.7 10 | mkdocs-material==9.6.12 11 | mkdocs-material-extensions==1.3.1 12 | Pygments==2.19.1 13 | pymdown-extensions==10.14.3 14 | python-dateutil==2.9.0.post0 15 | PyYAML==6.0.2 16 | repackage==0.7.3 17 | six==1.17.0 18 | termcolor==3.0.1 19 | tornado==6.5 -------------------------------------------------------------------------------- /.github/workflows/publish-docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs 2 | 3 | on: 4 | # Run on new version tags... 5 | push: 6 | tags: 7 | - v* 8 | # or manually from workflow dispatch (from GitHub UI) 9 | workflow_dispatch: 10 | 11 | jobs: 12 | deploy_docs: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Export JDK version 19 | shell: bash 20 | run: | 21 | JDK_VERSION=$(grep "jdk =" gradle/libs.versions.toml | head -n 1 | cut -d'=' -f2 | tr -d '"' | xargs) 22 | echo "JDK_VERSION=${JDK_VERSION}" >> $GITHUB_ENV 23 | 24 | - name: Install JDK 25 | uses: actions/setup-java@v4 26 | with: 27 | distribution: 'zulu' 28 | java-version: '${{ env.JDK_VERSION }}' 29 | 30 | - name: Setup Gradle 31 | uses: gradle/actions/setup-gradle@v4 32 | 33 | - name: Build Dokka API docs 34 | run: :dokkaGenerate 35 | 36 | - name: Setup Python 37 | uses: actions/setup-python@v5 38 | with: 39 | python-version: '3.x' 40 | 41 | - name: Install python dependencies 42 | run: | 43 | python3 -m pip install --upgrade pip 44 | python3 -m pip install -r .github/workflows/mkdocs-requirements.txt 45 | 46 | - name: Build site 47 | run: ./deploy_website.sh --ci 48 | 49 | - name: Deploy site 50 | uses: peaceiris/actions-gh-pages@v4 51 | with: 52 | github_token: ${{ secrets.GITHUB_TOKEN }} 53 | publish_dir: ./site 54 | -------------------------------------------------------------------------------- /.github/workflows/renovate.yml: -------------------------------------------------------------------------------- 1 | name: Renovate 2 | 3 | on: 4 | schedule: 5 | - cron: "0 8 * * *" # 8am daily 6 | workflow_dispatch: 7 | 8 | jobs: 9 | renovate: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | 15 | - name: Self-hosted Renovate 16 | uses: renovatebot/github-action@v41.0.21 17 | with: 18 | configurationFile: renovate.json 19 | token: ${{ secrets.SLACKHQ_MBR_GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .kotlin/ 3 | local.properties 4 | .idea 5 | !/.idea/codeStyles 6 | !/.idea/inspectionProfiles 7 | !/.idea/icon.png 8 | *.iml 9 | *.so 10 | .DS_Store 11 | build 12 | captures 13 | version.properties 14 | env 15 | node_modules 16 | reports 17 | .cxx 18 | .intellijPlatform 19 | 20 | # IDE-generated dir 21 | out/ 22 | 23 | # We have one gitignore but project generation often generates extra ones. Ignore those 24 | */**/.gitignore 25 | 26 | .run/ 27 | 28 | # Docs-related hings 29 | docs/code-of-conduct.md 30 | docs/contributing.md 31 | docs/changelog.md 32 | docs/api/ 33 | site/ 34 | temp-clone/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | foundry 2 | =================== 3 | 4 | ### [slackhq.github.io/foundry](https://slackhq.github.io/foundry) 5 | 6 | License 7 | -------- 8 | 9 | Copyright 2022 Slack Technologies, LLC 10 | 11 | Licensed under the Apache License, Version 2.0 (the "License"); 12 | you may not use this file except in compliance with the License. 13 | You may obtain a copy of the License at 14 | 15 | http://www.apache.org/licenses/LICENSE-2.0 16 | 17 | Unless required by applicable law or agreed to in writing, software 18 | distributed under the License is distributed on an "AS IS" BASIS, 19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | See the License for the specific language governing permissions and 21 | limitations under the License. 22 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | Releasing 2 | ========= 3 | 4 | 1. Update the `CHANGELOG.md` for the impending release. 5 | 2. Run `./release.sh `. 6 | 3. Publish the release on the repo's releases tab. 7 | -------------------------------------------------------------------------------- /config/bin/gjf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:d2bfd15a18808d146081044a3421a0d265f23c1d29bf32a77d0c13cf91a18377 3 | size 3611081 4 | -------------------------------------------------------------------------------- /config/bin/ktfmt: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:45739e1c6844c6e9232b4341e822df35a2617ffa0239dbbf8cc603a1a508492c 3 | size 67919097 4 | -------------------------------------------------------------------------------- /config/bin/sort-dependencies: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:34b814d4395bae01551294232e357bc8cf03855e1b86c02d3c301f3258084541 3 | size 29280610 4 | -------------------------------------------------------------------------------- /config/git/hooks/post-checkout: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\n[post-checkout] This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook.\n"; exit 2; } 3 | git lfs post-checkout "$@" 4 | -------------------------------------------------------------------------------- /config/git/hooks/post-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\n[post-commit] This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook.\n"; exit 2; } 3 | git lfs post-commit "$@" 4 | -------------------------------------------------------------------------------- /config/git/hooks/post-merge: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\n[post-merge] This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook.\n"; exit 2; } 3 | git lfs post-merge "$@" 4 | -------------------------------------------------------------------------------- /config/git/hooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\n[pre-push] This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook.\n"; exit 2; } 3 | git lfs pre-push "$@" 4 | -------------------------------------------------------------------------------- /config/git/hooks/pre-receive.sh: -------------------------------------------------------------------------------- 1 | # compares files that match .gitattributes filter to those actually tracked by git-lfs 2 | diff <(git ls-files ':(attr:filter=lfs)' | sort) <(git lfs ls-files -n | sort) >/dev/null 3 | 4 | ret=$? 5 | if [[ $ret -ne 0 ]]; then 6 | echo >&2 "This remote has detected files committed without using Git LFS. Run 'brew install git-lfs && git lfs install' to install it and re-commit your files."; 7 | exit 1; 8 | fi -------------------------------------------------------------------------------- /config/lint/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /deploy_website.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The website is built using MkDocs with the Material theme. 4 | # https://squidfunk.github.io/mkdocs-material/ 5 | # It requires Python to run. 6 | # Install the packages with the following command: 7 | # python3 -m pip install -r .github/workflows/mkdocs-requirements.txt 8 | 9 | if [[ "$1" = "--local" ]]; then 10 | local=true 11 | elif [[ "$1" = "--ci" ]]; then 12 | ci=true 13 | fi 14 | 15 | if ! [[ ${local} || ${ci} ]]; then 16 | set -ex 17 | REPO="git@github.com:slackhq/foundry.git" 18 | DIR=temp-clone 19 | # Delete any existing temporary website clone 20 | rm -rf ${DIR} 21 | # Clone the current repo into temp folder 22 | git clone ${REPO} ${DIR} 23 | # Move working directory into temp folder 24 | cd ${DIR} 25 | # Generate the API docs 26 | ./gradlew :dokkaGenerate 27 | fi 28 | 29 | # Copy in special files that GitHub wants in the project root. 30 | cp CHANGELOG.md docs/changelog.md 31 | cp .github/CONTRIBUTING.md docs/contributing.md 32 | cp .github/CODE_OF_CONDUCT.md docs/code-of-conduct.md 33 | 34 | # Build the site and push the new files up to GitHub 35 | if [[ ${local} ]]; then 36 | # For local dev, just serve to localhost 37 | mkdocs serve 38 | elif [[ ${ci} ]]; then 39 | # For CI we just build the site. It deploys using a GitHub Action 40 | mkdocs build -d site 41 | else 42 | # Otherwise we deploy using mkdocs 43 | mkdocs gh-deploy 44 | fi 45 | 46 | # Delete our temp folder 47 | if ! [[ ${local} || ${ci} ]]; then 48 | cd .. 49 | rm -rf ${DIR} 50 | fi -------------------------------------------------------------------------------- /docs/images/slack_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slackhq/foundry/3eadab765ef7b74a7d2d28b4a95edbfa6f68a915/docs/images/slack_logo.png -------------------------------------------------------------------------------- /docs/images/slack_logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slackhq/foundry/3eadab765ef7b74a7d2d28b4a95edbfa6f68a915/docs/images/slack_logo_small.png -------------------------------------------------------------------------------- /docs/platforms/gradle/bootstrap.md: -------------------------------------------------------------------------------- 1 | Bootstrap 2 | ========= 3 | 4 | Bootstrap is a tool for bootstrapping local dev environments. This is usually used in tandem with a bootstrap bash 5 | script that runs the `./gradlew bootstrap` task and any other repo-specific setups. 6 | 7 | The core implementation lives in `BootstrapTask.kt`. 8 | 9 | At a high level, bootstrap is mostly focused on configuring the JDK and daemon environments. Gradle has extremely 10 | limited configurability for the Gradle daemon, and we want to optimize the JDK for available space on different 11 | developer machines. To support this, we compute optimal daemon jvm arguments in bootstrap and write them to the user's 12 | home `~/.gradle/gradle.properties` to override repo-specific settings with client-side properties. 13 | 14 | For the JDK, it requests the JDK toolchain from Gradle's first-party APIs. This includes allowing Gradle to download the 15 | JDK if it's missing, which is useful for getting developers set up and running faster. 16 | 17 | Bootstrap is also useful on CI for its ability to scale available memory to the machine it's running on, so we generally 18 | run it as a preflight step for all of our CI jobs too. 19 | 20 | Finally, there are some other specific things it does to optimize things: 21 | 22 | - Disable Gradle file watching on CI as it's not necessary there. 23 | - Configure specific GC and heap args for optimized use in Gradle builds (favoring larger young generation spaces). 24 | - Configure a fixed-size heap for CI to avoid time spent growing the heap. 25 | -------------------------------------------------------------------------------- /docs/platforms/gradle/configuration.md: -------------------------------------------------------------------------------- 1 | Configuration 2 | ============= 3 | 4 | TODO -------------------------------------------------------------------------------- /docs/platforms/gradle/formatters-and-analysis.md: -------------------------------------------------------------------------------- 1 | Formatters and Static Analysis 2 | ============================== 3 | 4 | Foundry supports running a number of formatters and static analysis tools. 5 | 6 | Individual tools are usually gated on whether they have a version specified in `libs.versions.toml`. If they do not have a version specified, they are deemed not enabled. 7 | 8 | ## Formatting 9 | 10 | The core set of formatters are: 11 | 12 | - ktfmt (Kotlin) 13 | - google-java-format (Java) 14 | - gson (JSON) 15 | - gradle-dependency-sorter (Gradle build file dependencies) 16 | - Spotless (general purpose Gradle plugin that runs most of the above) 17 | 18 | ## Static Analysis 19 | 20 | The core set of analysis tools supported in Foundry are: 21 | 22 | - Android Lint (Kotlin, Java, XML resources, build files, etc.) 23 | - Detekt (Kotlin) 24 | - Error Prone (Java) 25 | 26 | ## Git Hooks 27 | 28 | Foundry ships with a standard set of git hooks (pre-commit, etc) that it can bootstrap in projects by running `./gradlew installCommitHooks`. These hooks rely on checking in relevant binaries for each formatter/checker, it's strongly recommended to use git-lfs for these. These files should be edited as needed to best serve the project they're running in. 29 | 30 | Foundry can configure these hooks in the project automatically during bootstrap if you add the `foundry.git.hooksPath` gradle property and point it at the hooks directory that the above command output to, or wherever the host project opts to store them. 31 | 32 | Note that Detekt is not yet supported in git hooks as these require extra parameters for baselines. 33 | 34 | ### Downloading binaries 35 | 36 | Each tool (ktfmt, gjf, etc) has corresponding `./gradlew update` tasks that you can run to download and install them, by default to `config/bin/`. You should re-run these any time you update a tool to re-run them. -------------------------------------------------------------------------------- /docs/platforms/gradle/lint.md: -------------------------------------------------------------------------------- 1 | Lint 2 | ==== 3 | 4 | TODO -------------------------------------------------------------------------------- /docs/platforms/gradle/mod-score.md: -------------------------------------------------------------------------------- 1 | Mod Score 2 | ========= 3 | 4 | TODO -------------------------------------------------------------------------------- /docs/platforms/gradle/properties.md: -------------------------------------------------------------------------------- 1 | Properties 2 | ========== 3 | 4 | TODO -------------------------------------------------------------------------------- /docs/platforms/gradle/testing.md: -------------------------------------------------------------------------------- 1 | Testing 2 | ======= 3 | 4 | TODO -------------------------------------------------------------------------------- /docs/platforms/gradle/thermals-logging.md: -------------------------------------------------------------------------------- 1 | Thermals Logging 2 | ================ 3 | 4 | TODO -------------------------------------------------------------------------------- /docs/tools/cli.md: -------------------------------------------------------------------------------- 1 | # Foundry CLIs 2 | 3 | An artifact containing basic CLI utilities for Kotlin. 4 | 5 | ## Installation 6 | 7 | [![Maven Central](https://img.shields.io/maven-central/v/com.slack.foundry/cli.svg)](https://mvnrepository.com/artifact/com.slack.foundry/cli) 8 | ```kotlin 9 | // In Gradle 10 | dependencies { 11 | implementation("com.slack.foundry:cli:") 12 | } 13 | 14 | // In kotlin script 15 | @file:DependsOn("com.slack.foundry:cli:{version}") 16 | ``` 17 | 18 | ## Local testing 19 | 20 | If consuming these utilities from a kotlin script file, you can test changes like so: 21 | 22 | 1. Set the version in `gradle.properties`, such as `2.5.0-LOCAL1`. 23 | 2. Run `./gradlew publishToMavenLocal` to publish the current version to your local maven repository. 24 | 3. In your script file, add the local repository and update the version: 25 | ```kotlin 26 | @file:Repository("file:///Users/{username}/.m2/repository") 27 | @file:DependsOn("com.slack.foundry:cli:{version you set in gradle.properties}") 28 | ``` 29 | 4. Repeat as needed while testing, incrementing the version number each time to avoid caching issues. 30 | -------------------------------------------------------------------------------- /docs/tools/skippy.md: -------------------------------------------------------------------------------- 1 | Skippy 2 | ====== 3 | 4 | TODO -------------------------------------------------------------------------------- /foundry-migration/property_migration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires two parameters 4 | # 1. A mapping file of old properties to nw properties. This is available in the foundry repo at foundry-migration/mapping.txt 5 | # 2. Project directory to search for .properties and .kts files in. 6 | if [ "$#" -lt 2 ]; then 7 | echo "Usage: $0 " 8 | exit 1 9 | fi 10 | 11 | # Input parameters 12 | MAPPING_FILE="$1" 13 | SEARCH_DIR="$2" 14 | 15 | # Check if the mapping file exists 16 | if [ ! -f "$MAPPING_FILE" ]; then 17 | echo "Mapping file '$MAPPING_FILE' not found!" 18 | exit 1 19 | fi 20 | 21 | # Find all .properties and .kts files in the directory and its subdirectories 22 | find "$SEARCH_DIR" -type f \( -name "*.properties" -o -name "*.kts" \) | while read -r file; do 23 | echo "Processing file: $file" 24 | 25 | # Loop through each line in the mapping file 26 | while IFS="=" read -r old_string new_string; do 27 | # Skip empty lines or lines that don't contain '=' 28 | [[ -z "$old_string" || -z "$new_string" ]] && continue 29 | # Use sed to perform the in-place replacement 30 | sed -i '' "s/$old_string/$new_string/g" "$file" 31 | done < "$MAPPING_FILE" 32 | done 33 | 34 | 35 | echo "Replacement completed." -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slackhq/foundry/3eadab765ef7b74a7d2d28b4a95edbfa6f68a915/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /platforms/gradle/agp-handlers/agp-handler-api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.mavenPublish) 19 | alias(libs.plugins.lint) 20 | } 21 | 22 | dependencies { 23 | implementation(projects.tools.versionNumber) 24 | 25 | compileOnly(gradleApi()) 26 | compileOnly(libs.agp) 27 | 28 | testImplementation(gradleApi()) 29 | testImplementation(libs.agp) 30 | testImplementation(libs.junit) 31 | testImplementation(libs.truth) 32 | 33 | lintChecks(libs.gradleLints) 34 | } 35 | -------------------------------------------------------------------------------- /platforms/gradle/agp-handlers/agp-handler-api/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=agp-handler-api 2 | POM_NAME=AGP Handler API 3 | POM_DESCRIPTION=AGP Handler API 4 | -------------------------------------------------------------------------------- /platforms/gradle/agp-handlers/agp-handler-api/src/main/kotlin/foundry/gradle/agp/PermissionAllowlistConfigurer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.agp 17 | 18 | import org.gradle.api.file.RegularFileProperty 19 | 20 | public interface PermissionAllowlistConfigurer : VariantConfiguration { 21 | /** 22 | * Represents a configurable file containing a newline-delimited allowlist of permissions. If set, 23 | * merged manifest permissions for this variant will have their permissions checked against the 24 | * allowlist defined in [allowListFile]. 25 | */ 26 | public val allowListFile: RegularFileProperty 27 | } 28 | -------------------------------------------------------------------------------- /platforms/gradle/agp-handlers/agp-handler-api/src/main/kotlin/foundry/gradle/agp/VariantConfiguration.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.agp 17 | 18 | /** 19 | * Base interface for interfaces that configure on a per-variant basis and need to expose variant 20 | * info. 21 | */ 22 | public interface VariantConfiguration { 23 | /** Returns the Build Type. */ 24 | public val buildType: String? 25 | 26 | /** Returns the list of flavors, or an empty list. */ 27 | public val flavors: List> 28 | 29 | /** Returns the unique variant name. */ 30 | public val name: String 31 | } 32 | -------------------------------------------------------------------------------- /platforms/gradle/agp-handlers/agp-handler-api/src/main/kotlin/foundry/gradle/agp/internal/NoOpIssueReporter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.agp.internal 17 | 18 | import com.android.builder.errors.EvalIssueException 19 | import com.android.builder.errors.IssueReporter 20 | 21 | public object NoOpIssueReporter : IssueReporter() { 22 | override fun hasIssue(type: Type): Boolean = false 23 | 24 | override fun reportIssue(type: Type, severity: Severity, exception: EvalIssueException) { 25 | // No-op 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /platforms/gradle/agp-handlers/agp-handler-api/src/test/kotlin/foundry/gradle/agp/AgpHandlersTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.agp 17 | 18 | import com.google.common.truth.Truth.assertThat 19 | import org.junit.Test 20 | 21 | class AgpHandlersTest { 22 | @Test 23 | fun parseTest() { 24 | assertVersion("8.0.0-alpha01") 25 | assertVersion("8.0.0-beta01") 26 | assertVersion("8.0.0-beta11") 27 | assertVersion("8.0.0-rc11") 28 | assertVersion("8.0.0-dev") 29 | } 30 | 31 | private fun assertVersion(version: String) { 32 | assertThat(computeAndroidPluginVersion(version).toString()) 33 | .isEqualTo("Android Gradle Plugin version $version") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/gradle/better-gradle-properties/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.mavenPublish) 19 | alias(libs.plugins.lint) 20 | } 21 | 22 | dependencies { 23 | implementation(libs.okio) 24 | 25 | compileOnly(gradleApi()) 26 | } 27 | -------------------------------------------------------------------------------- /platforms/gradle/better-gradle-properties/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=better-gradle-properties 2 | POM_NAME=Better Gradle Properties 3 | POM_DESCRIPTION=Better Gradle Properties 4 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=gradle-plugin 2 | POM_NAME=Foundry Gradle Plugin 3 | POM_DESCRIPTION=Foundry Gradle Plugin 4 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/DelicateFoundryGradlePluginApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle 17 | 18 | /** 19 | * Marks declarations in the Foundry Gradle Plugin API that are **delicate** — they have 20 | * limited use-case and shall be used with care in general code. Any use of a delicate declaration 21 | * has to be carefully reviewed to make sure it is properly used and does not create problems like 22 | * lossy Java -> Kotlin type parsing. Carefully read documentation and [message] of any declaration 23 | * marked as `DelicateFoundryGradlePluginApi`. 24 | */ 25 | @MustBeDocumented 26 | @Retention(value = AnnotationRetention.BINARY) 27 | @RequiresOptIn( 28 | level = RequiresOptIn.Level.WARNING, 29 | message = 30 | "This is a delicate API and its use requires care." + 31 | " Make sure you fully read and understand documentation of the declaration that is marked as a delicate API.", 32 | ) 33 | public annotation class DelicateFoundryGradlePluginApi(val message: String = "See kdoc.") 34 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/FoundryShared.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle 17 | 18 | import org.gradle.api.problems.ProblemGroup 19 | 20 | internal object FoundryShared { 21 | val PROBLEM_GROUP = ProblemGroup.create("foundry-group", "Foundry Problems") 22 | const val FOUNDRY_TASK_GROUP = "foundry" 23 | } 24 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/android/AndroidArchitecture.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.android 17 | 18 | /** Represents possible Android architectures. */ 19 | public enum class AndroidArchitecture(public val jniLibsPath: String) { 20 | ARM64_V8A("arm64-v8a"), 21 | ARMEABI_V7A("armeabi-v7a"), 22 | X86("x86"), 23 | X86_64("x86_64"), 24 | } 25 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/artifacts/ArtifactUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.artifacts 17 | 18 | import org.gradle.api.Project 19 | import org.gradle.api.attributes.AttributeContainer 20 | import org.gradle.api.attributes.Category 21 | import org.gradle.api.attributes.Usage 22 | 23 | internal fun AttributeContainer.addCommonAttributes(project: Project, category: String) { 24 | attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category::class.java, category)) 25 | attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, "sgp")) 26 | } 27 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/artifacts/ShareableArtifact.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.artifacts 17 | 18 | import java.io.Serializable 19 | import org.gradle.api.attributes.Attribute 20 | 21 | internal interface ShareableArtifact> : Serializable { 22 | val attribute: Attribute 23 | val declarableName: String 24 | } 25 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/avoidance/SkippyArtifacts.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.avoidance 17 | 18 | import foundry.gradle.artifacts.FoundryArtifact 19 | import foundry.gradle.artifacts.Publisher 20 | import foundry.gradle.capitalizeUS 21 | import foundry.gradle.tasks.SimpleFileProducerTask 22 | import foundry.gradle.tasks.publishWith 23 | import org.gradle.api.Project 24 | 25 | internal object SkippyArtifacts { 26 | fun publishSkippedTask(project: Project, name: String) { 27 | SimpleFileProducerTask.registerOrConfigure( 28 | project, 29 | name = "skipped${name.capitalizeUS()}", 30 | description = "Lifecycle task to run unit tests for ${project.path} (skipped).", 31 | ) 32 | .publishWith(Publisher.interProjectPublisher(project, FoundryArtifact.SkippyAvoidedTasks)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/compose/ComposeUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.compose 17 | 18 | internal const val COMPOSE_COMPILER_OPTION_PREFIX = 19 | "plugin:androidx.compose.compiler.plugins.kotlin" 20 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/configureBuildTags.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle 17 | 18 | import com.gradle.develocity.agent.gradle.adapters.BuildScanAdapter 19 | import org.gradle.api.Project 20 | import org.gradle.api.configuration.BuildFeatures 21 | import org.gradle.api.tasks.testing.Test 22 | 23 | internal fun BuildFeatures.reportTo(scanApi: BuildScanAdapter) { 24 | scanApi.value( 25 | "bf-configuration-cache-requested", 26 | configurationCache.requested.getOrElse(false).toString(), 27 | ) 28 | scanApi.value( 29 | "bf-configuration-cache-active", 30 | configurationCache.active.getOrElse(false).toString(), 31 | ) 32 | scanApi.value( 33 | "bf-isolated-projects-requested", 34 | isolatedProjects.requested.getOrElse(false).toString(), 35 | ) 36 | scanApi.value("bf-isolated-projects-active", isolatedProjects.active.getOrElse(false).toString()) 37 | } 38 | 39 | internal fun BuildScanAdapter.addTestParallelization(project: Project) { 40 | project.tasks.withType(Test::class.java).configureEach { 41 | doFirst { value("$identityPath#maxParallelForks", maxParallelForks.toString()) } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/dependencies/DependencyDef.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.dependencies 17 | 18 | public typealias Notation = Map 19 | 20 | public data class DependencyDef( 21 | val group: String, 22 | val artifact: String, 23 | val comments: String? = null, 24 | val ext: String? = null, 25 | val gradleProperty: String, 26 | val isBomManaged: Boolean = false, 27 | ) { 28 | val coordinates: Map = 29 | mutableMapOf().apply { 30 | put("group", group) 31 | put("name", artifact) 32 | ext?.let { put("ext", it) } 33 | } 34 | val identifier: String = "$group:$artifact" 35 | val extSuffix: String 36 | get() = ext?.let { "@$it" }.orEmpty() 37 | } 38 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/dependencies/DependencySet.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.dependencies 17 | 18 | public abstract class DependencySet : DependencyCollection { 19 | internal fun artifact( 20 | group: String, 21 | artifact: String? = null, 22 | gradleProperty: String? = null, 23 | ): DependencyDelegate { 24 | return DependencyDelegate( 25 | group = group, 26 | artifact = artifact, 27 | gradleProperty = gradleProperty?.let { "${DependencyCollection.GRADLE_PROPERTY_PREFIX}$it" }, 28 | ) 29 | } 30 | 31 | internal fun artifactWithExtension( 32 | group: String, 33 | artifact: String, 34 | ext: String, 35 | gradleProperty: String? = null, 36 | ): DependencyDelegate { 37 | return DependencyDelegate( 38 | group = group, 39 | artifact = artifact, 40 | ext = ext, 41 | gradleProperty = gradleProperty?.let { "${DependencyCollection.GRADLE_PROPERTY_PREFIX}$it" }, 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/stats/LanguageStats.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.stats 17 | 18 | import com.squareup.moshi.Json 19 | import com.squareup.moshi.JsonClass 20 | 21 | // Example 22 | // "HTML" :{ 23 | // "nFiles": 1000, 24 | // "blank": 3575, 25 | // "comment": 0, 26 | // "code": 116111}, 27 | @JsonClass(generateAdapter = true) 28 | internal data class LanguageStats( 29 | @Json(name = "nFiles") val files: Int, 30 | val code: Int, 31 | val comment: Int, 32 | val blank: Int, 33 | ) { 34 | 35 | val total: Int 36 | get() = code + comment + blank 37 | 38 | companion object { 39 | val EMPTY = LanguageStats(0, 0, 0, 0) 40 | } 41 | 42 | operator fun plus(other: LanguageStats): LanguageStats { 43 | return LanguageStats( 44 | files + other.files, 45 | code + other.code, 46 | comment + other.comment, 47 | blank + other.blank, 48 | ) 49 | } 50 | } 51 | 52 | /** Merges this map with [other]. Keys present in both will have their values merged together. */ 53 | internal fun Map.mergeWith( 54 | other: Map 55 | ): Map { 56 | return (keys + other.keys) 57 | .associateWith { key -> listOfNotNull(get(key), other[key]) } 58 | .mapValues { (_, values) -> values.reduce(LanguageStats::plus) } 59 | } 60 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/DetektDownloadTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import org.gradle.api.tasks.UntrackedTask 19 | 20 | /** 21 | * Downloads the Detekt binary from its GitHub releases. 22 | * 23 | * Usage: 24 | * ``` 25 | * ./gradlew updateDetekt 26 | * ``` 27 | */ 28 | @UntrackedTask(because = "These are one-off, on-demand download tasks") 29 | internal abstract class DetektDownloadTask : 30 | BaseDownloadTask( 31 | targetName = "Detekt", 32 | // https://github.com/detekt/detekt/issues/3895 33 | addExecPrefix = true, 34 | urlTemplate = { version -> 35 | "https://github.com/detekt/detekt/releases/download/v$version/detekt-cli-$version-all.jar" 36 | }, 37 | ) 38 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/FoundryValidationTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import org.gradle.api.Project 19 | import org.gradle.api.Task 20 | import org.gradle.api.tasks.TaskProvider 21 | 22 | /** Marker interface for Foundry validation tasks that can be depended on by type. */ 23 | public interface FoundryValidationTask : Task { 24 | public companion object { 25 | internal fun registerLifecycleTask(project: Project): TaskProvider { 26 | return LifecycleTask.register(project, "validateFoundryProject") { 27 | dependsOn(project.tasks.withType(FoundryValidationTask::class.java)) 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/GjfDownloadTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import org.gradle.api.tasks.UntrackedTask 19 | 20 | /** 21 | * Downloads the GJF binary from its GitHub releases. 22 | * 23 | * Usage: 24 | * ``` 25 | * ./gradlew updateGjf 26 | * ``` 27 | */ 28 | @UntrackedTask(because = "These are one-off, on-demand download tasks") 29 | internal abstract class GjfDownloadTask : 30 | BaseDownloadTask( 31 | targetName = "GoogleJavaFormat", 32 | // https://github.com/google/google-java-format#jdk-16 33 | addExecPrefix = true, 34 | urlTemplate = { version -> 35 | "https://github.com/google/google-java-format/releases/download/v$version/google-java-format-$version-all-deps.jar" 36 | }, 37 | ) 38 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/KtLintDownloadTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import org.gradle.api.tasks.UntrackedTask 19 | 20 | /** 21 | * Downloads the KtLint binary from its GitHub releases. 22 | * 23 | * Usage: 24 | * ``` 25 | * ./gradlew updateKtLint 26 | * ``` 27 | */ 28 | @UntrackedTask(because = "These are one-off, on-demand download tasks") 29 | internal abstract class KtLintDownloadTask : 30 | BaseDownloadTask( 31 | targetName = "KtLint", 32 | addExecPrefix = false, 33 | urlTemplate = { version -> 34 | "https://github.com/pinterest/ktlint/releases/download/$version/ktlint" 35 | }, 36 | ) 37 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/KtfmtDownloadTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import org.gradle.api.tasks.UntrackedTask 19 | 20 | /** 21 | * Downloads the ktfmt binary from maven central. 22 | * 23 | * Usage: 24 | * ``` 25 | * ./gradlew updateKtfmt 26 | * ``` 27 | */ 28 | @UntrackedTask(because = "These are one-off, on-demand download tasks") 29 | internal abstract class KtfmtDownloadTask : 30 | BaseDownloadTask( 31 | targetName = "ktfmt", 32 | addExecPrefix = true, 33 | urlTemplate = { version -> 34 | "https://repo1.maven.org/maven2/com/facebook/ktfmt/$version/ktfmt-$version-jar-with-dependencies.jar" 35 | }, 36 | ) 37 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/LifecycleTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import foundry.gradle.register 19 | import org.gradle.api.Action 20 | import org.gradle.api.DefaultTask 21 | import org.gradle.api.Project 22 | import org.gradle.api.tasks.TaskProvider 23 | import org.gradle.api.tasks.UntrackedTask 24 | 25 | @UntrackedTask(because = "Just a lifecycle task") 26 | internal abstract class LifecycleTask : DefaultTask() { 27 | companion object { 28 | internal fun register( 29 | project: Project, 30 | name: String, 31 | group: String = "foundry", 32 | action: Action = Action {}, 33 | ): TaskProvider { 34 | return project.tasks.register(name) { 35 | this.group = group 36 | action.execute(this) 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/tasks/SortDependenciesDownloadTask.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.tasks 17 | 18 | import org.gradle.api.tasks.UntrackedTask 19 | 20 | /** 21 | * Downloads the Sort Dependencies binary from maven central. 22 | * 23 | * Usage: 24 | * ``` 25 | * ./gradlew updateSortDependencies 26 | * ``` 27 | */ 28 | @UntrackedTask(because = "These are one-off, on-demand download tasks") 29 | internal abstract class SortDependenciesDownloadTask : 30 | BaseDownloadTask( 31 | targetName = "Sort Dependencies", 32 | addExecPrefix = true, 33 | urlTemplate = { version -> 34 | "https://repo1.maven.org/maven2/com/squareup/sort-gradle-dependencies-app/$version/sort-gradle-dependencies-app-$version-all.jar" 35 | }, 36 | ) { 37 | init { 38 | description = "Downloads the Sort Dependencies binary from maven central." 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/topography/ModuleFeature.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.topography 17 | 18 | import com.squareup.moshi.JsonClass 19 | import foundry.common.RegexMap 20 | 21 | @JsonClass(generateAdapter = true) 22 | public data class ModuleFeature( 23 | val name: String, 24 | val explanation: String, 25 | val advice: String, 26 | val replacementPatterns: RegexMap = RegexMap(), 27 | /** 28 | * Generated sources root dir relative to the project dir, if any. Files are checked recursively. 29 | */ 30 | val generatedSourcesDir: String? = null, 31 | val generatedSourcesExtensions: Set = emptySet(), 32 | val matchingText: Set = emptySet(), 33 | val matchingTextFileExtensions: Set = emptySet(), 34 | /** 35 | * If specified, looks for any sources in this dir relative to the project dir. Files are checked 36 | * recursively. 37 | */ 38 | val matchingSourcesDir: String? = null, 39 | val matchingPlugin: String? = null, 40 | ) 41 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/topography/ModuleTopography.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.topography 17 | 18 | import com.squareup.moshi.JsonClass 19 | import foundry.common.json.JsonTools 20 | import java.nio.file.Path 21 | import org.gradle.api.file.FileSystemLocation 22 | import org.gradle.api.provider.Provider 23 | 24 | @JsonClass(generateAdapter = true) 25 | public data class ModuleTopography( 26 | val name: String, 27 | val gradlePath: String, 28 | val features: Set, 29 | val plugins: Set, 30 | ) { 31 | public fun writeJsonTo(property: Provider, prettyPrint: Boolean = false) { 32 | writeJsonTo(property.get().asFile.toPath(), prettyPrint) 33 | } 34 | 35 | public fun writeJsonTo(path: Path, prettyPrint: Boolean = false) { 36 | JsonTools.toJson(path, this, prettyPrint) 37 | } 38 | 39 | public companion object { 40 | public fun from(provider: Provider): ModuleTopography = 41 | from(provider.get().asFile.toPath()) 42 | 43 | public fun from(path: Path): ModuleTopography = JsonTools.fromJson(path) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/GradleFoundryLogger.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util 17 | 18 | import foundry.common.FoundryLogger 19 | import org.gradle.api.logging.Logger 20 | 21 | /** A Gradle [Logger]-based [FoundryLogger]. */ 22 | private class GradleFoundryLogger(private val delegate: Logger) : FoundryLogger { 23 | override fun debug(message: String) { 24 | delegate.debug(message) 25 | } 26 | 27 | override fun info(message: String) { 28 | delegate.info(message) 29 | } 30 | 31 | override fun lifecycle(message: String) { 32 | delegate.lifecycle(message) 33 | } 34 | 35 | override fun warn(message: String) { 36 | delegate.warn(message) 37 | } 38 | 39 | override fun warn(message: String, error: Throwable) { 40 | delegate.warn(message, error) 41 | } 42 | 43 | override fun error(message: String) { 44 | delegate.error(message) 45 | } 46 | 47 | override fun error(message: String, error: Throwable) { 48 | delegate.error(message, error) 49 | } 50 | } 51 | 52 | internal fun FoundryLogger.Companion.gradle(logger: Logger): FoundryLogger = 53 | GradleFoundryLogger(logger) 54 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/GradleJsonTools.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util 17 | 18 | import foundry.common.json.JsonTools 19 | import org.gradle.api.file.FileSystemLocation 20 | import org.gradle.api.provider.Provider 21 | 22 | internal inline fun JsonTools.toJson( 23 | provider: Provider, 24 | value: T?, 25 | prettyPrint: Boolean = false, 26 | ) { 27 | return toJson(provider.get().asFile, value, prettyPrint) 28 | } 29 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/JavaAgentArgumentProvider.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util 17 | 18 | import org.gradle.api.file.ConfigurableFileCollection 19 | import org.gradle.api.tasks.Classpath 20 | import org.gradle.process.CommandLineArgumentProvider 21 | 22 | internal abstract class JavaAgentArgumentProvider : CommandLineArgumentProvider { 23 | @get:Classpath abstract val classpath: ConfigurableFileCollection 24 | 25 | override fun asArguments() = listOf("-javaagent:${classpath.singleFile.absolutePath}") 26 | } 27 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/KspUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util 17 | 18 | import com.google.devtools.ksp.gradle.KspAATask 19 | import com.google.devtools.ksp.gradle.KspTaskJvm 20 | import org.gradle.api.Project 21 | import org.gradle.api.provider.Provider 22 | import org.gradle.api.tasks.TaskProvider 23 | 24 | internal fun Project.addKspSource( 25 | kspTaskName: String, 26 | task: TaskProvider<*>, 27 | provider: Provider, 28 | ) { 29 | tasks 30 | .named { it == kspTaskName } 31 | .configureEach { 32 | when (this) { 33 | is KspTaskJvm -> { 34 | source(provider) 35 | dependsOn(task) 36 | } 37 | is KspAATask -> { 38 | kspConfig.javaSourceRoots.from(provider) 39 | dependsOn(task) 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/OkHttpExt.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util 17 | 18 | import okhttp3.OkHttpClient 19 | 20 | /** Shuts down this [OkHttpClient] and all of its resources. */ 21 | internal fun OkHttpClient.shutdown() { 22 | dispatcher.executorService.shutdown() 23 | connectionPool.evictAll() 24 | cache?.close() 25 | } 26 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/AxisRange.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class AxisRange(val index: Int, val startValue: Int, val endValue: Int) : 19 | ChartProperty { 20 | override val key: String = "chxr" 21 | 22 | override val value: String 23 | get() = "$index,$startValue,$endValue" 24 | } 25 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/AxisStyle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class AxisStyle(val index: Int, val color: Color) : ChartProperty { 19 | override val key: String = "chxs" 20 | 21 | override val value: String 22 | get() = "$index,${color.hex}" 23 | } 24 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/ChartData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | import foundry.gradle.util.charting.ValuesEncoder.encodeExtendedSeries 19 | import foundry.gradle.util.charting.ValuesEncoder.encodePositionSeries 20 | 21 | internal sealed class ChartData : ChartProperty { 22 | override val key: String = "chd" 23 | 24 | data class SimpleData(val data: List, val maxValue: Int = data.maxOrNull() ?: 0) : 25 | ChartData() { 26 | override val value: String 27 | get() = encodeExtendedSeries(data, maxValue) 28 | } 29 | 30 | data class TimeSeriesData(val data: Map) : ChartData() { 31 | override val value: String 32 | get() = encodePositionSeries(data) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/ChartFill.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class ChartFill(val type: FillType, val color: Color) : ChartProperty { 19 | override val key: String = "chf" 20 | 21 | override val value: String 22 | get() = "${type.type},s,${color.hex}" 23 | 24 | enum class FillType(val type: String) { 25 | TRANSPARENT("a"), 26 | BACKGROUND("bg"), 27 | CHART("c"), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/ChartSize.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class ChartSize(val width: Int, val height: Int) : ChartProperty { 19 | override val key: String = "chs" 20 | 21 | override val value: String 22 | get() = "${width}x$height" 23 | } 24 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/ChartType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal sealed class ChartType : ChartProperty { 19 | override val key: String = "cht" 20 | 21 | object LineChart : ChartType() { 22 | override val value: String = "lc" 23 | } 24 | 25 | object SparklineChart : ChartType() { 26 | override val value: String = "ls" 27 | } 28 | 29 | object TimeSeriesChart : ChartType() { 30 | override val value: String = "lxy" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/Color.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class Color(val hex: String) { 19 | constructor(value: Int) : this(String.format("%06X", 0xFFFFFF and value)) 20 | 21 | companion object { 22 | val BLACK = Color(0x000000) 23 | val WHITE = Color(0xFFFFFF) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/ColorRange.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class ColorRange(val color: Color, val startIndex: Int, val endIndex: Int) : 19 | ChartProperty { 20 | override val key: String = "chm" 21 | 22 | override val value: String 23 | get() = "B,${color.hex},0,$startIndex:$endIndex,0" 24 | } 25 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/SeriesColors.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal data class SeriesColors(val colors: List) : ChartProperty { 19 | override val key: String = "chco" 20 | 21 | override val value: String 22 | get() = colors.joinToString(separator = ",") { it.hex } 23 | 24 | constructor(color: Color) : this(listOf(color)) 25 | 26 | constructor(vararg colors: Color) : this(colors.toList()) 27 | } 28 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/kotlin/foundry/gradle/util/charting/VisibleAxis.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.util.charting 17 | 18 | internal sealed class VisibleAxis : ChartProperty { 19 | override val key: String = "chxt" 20 | 21 | object XAxis : VisibleAxis() { 22 | override val value: String = "x" 23 | } 24 | 25 | object TAxis : VisibleAxis() { 26 | override val value: String = "t" 27 | } 28 | 29 | object YAxis : VisibleAxis() { 30 | override val value: String = "y" 31 | } 32 | 33 | object RAxis : VisibleAxis() { 34 | override val value: String = "r" 35 | } 36 | 37 | private data class MultipleVisibleAxes(private val axes: Set) : VisibleAxis() { 38 | override val value: String = axes.joinToString(separator = ",") { it.value } 39 | 40 | override operator fun plus(axis: VisibleAxis): VisibleAxis { 41 | return MultipleVisibleAxes(axes + axis) 42 | } 43 | } 44 | 45 | open operator fun plus(axis: VisibleAxis): VisibleAxis { 46 | return MultipleVisibleAxes(setOf(this, axis)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/main/resources/libthermal_state.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slackhq/foundry/3eadab765ef7b74a7d2d28b4a95edbfa6f68a915/platforms/gradle/foundry-gradle-plugin/src/main/resources/libthermal_state.dylib -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/test/kotlin/foundry/gradle/fakes/NoOpLogger.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.fakes 17 | 18 | import org.gradle.api.logging.LogLevel 19 | import org.gradle.api.logging.Logger 20 | import org.slf4j.helpers.NOPLogger 21 | 22 | /** A [Logger] that doesn't log. */ 23 | open class NoOpLogger : Logger, org.slf4j.Logger by NOPLogger.NOP_LOGGER { 24 | override fun isQuietEnabled(): Boolean = false 25 | 26 | override fun log(level: LogLevel, message: String) = Unit 27 | 28 | override fun log(level: LogLevel, message: String, vararg objects: Any) = Unit 29 | 30 | override fun log(level: LogLevel, message: String, throwable: Throwable) = Unit 31 | 32 | override fun isEnabled(level: LogLevel): Boolean = true 33 | 34 | override fun lifecycle(message: String) = Unit 35 | 36 | override fun lifecycle(message: String, vararg objects: Any) = Unit 37 | 38 | override fun lifecycle(message: String, throwable: Throwable) = Unit 39 | 40 | override fun quiet(message: String) = Unit 41 | 42 | override fun quiet(message: String, vararg objects: Any) = Unit 43 | 44 | override fun quiet(message: String, throwable: Throwable) = Unit 45 | 46 | override fun isLifecycleEnabled(): Boolean = true 47 | } 48 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/test/kotlin/foundry/gradle/stats/ModuleStatsTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.stats 17 | 18 | import com.google.common.truth.Truth.assertThat 19 | import org.junit.Test 20 | 21 | class ModuleStatsTest { 22 | @Test 23 | fun parseProjectDeps() { 24 | // language=Kotlin 25 | val buildFileText = 26 | """ 27 | import slack.gradle.dependencies.SlackDependencies 28 | 29 | plugins { 30 | kotlin("jvm") 31 | `java-test-fixtures` 32 | id("net.ltgt.errorprone") 33 | } 34 | 35 | slack { 36 | features { 37 | moshi(codegen = false, adapters = true) 38 | } 39 | } 40 | 41 | dependencies { 42 | compileOnly(SlackDependencies.Androidx.annotation) 43 | compileOnly(projects.libraries.foundation.jsr305) 44 | implementation(SlackDependencies.Slack.eithernet) 45 | testFixturesApi(projects.libraries.foundation.guinness.testUtils) 46 | 47 | testImplementation(SlackDependencies.Testing.truth) 48 | testImplementation(projects.libraries.foundation.testCommons) 49 | } 50 | 51 | """ 52 | .trimIndent() 53 | 54 | val deps = StatsUtils.parseProjectDeps(buildFileText) 55 | assertThat(deps) 56 | .containsExactly("libraries.foundation.jsr305", "libraries.foundation.testCommons") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/src/test/kotlin/foundry/gradle/topography/ModuleFeatureTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.gradle.topography 17 | 18 | import com.google.common.truth.Truth.assertThat 19 | import org.junit.Test 20 | 21 | class ModuleFeatureTest { 22 | @Test 23 | fun overridesTest() { 24 | val customExplanation = "This is a custom explanation" 25 | val config = 26 | ModuleFeaturesConfig( 27 | _defaultFeatureOverrides = 28 | listOf(mapOf("name" to DefaultFeatures.Dagger.name, "explanation" to customExplanation)) 29 | ) 30 | 31 | val overriddenExplanation = 32 | config.loadFeatures().getValue(DefaultFeatures.Dagger.name).explanation 33 | assertThat(overriddenExplanation).isEqualTo(customExplanation) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/gradle/foundry-gradle-plugin/thermal_state.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Compile this into a dylib via 4 | // swiftc thermal_state.swift -emit-library 5 | @_cdecl("thermal_state") 6 | public func thermal_state() -> Int { 7 | return ProcessInfo().thermalState.rawValue 8 | } 9 | -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/README.md: -------------------------------------------------------------------------------- 1 | Artifactory Authenticator 2 | ========================= 3 | 4 | A simple IntelliJ plugin for authenticating plugin repositories that live on Artifactory and require authentication. We use this at Slack to authenticate our internal plugin repository and publish updates there. 5 | 6 | This uses the `PluginRepositoryAuthProvider` API. 7 | 8 | ## Usage 9 | 10 | Once installed, the artifactory repository can be configured in Settings > Artifactory Auth Settings. Fill in the information there and enable it. 11 | 12 | The check is a prefix check, so you should use a base url for your artifactory instance. 13 | 14 | ## Publishing 15 | 16 | To publish this plugin to a given artifactory repository, the following three Gradle properties must be set: 17 | 18 | ```properties 19 | FoundryIntellijArtifactoryBaseUrl=https://artifactory.example.com/artifactory 20 | FoundryIntellijArtifactoryUsername=jane.doe@example.com 21 | FoundryIntellijArtifactoryToken=1234567890abcdef1234567890abcdef12345678 22 | ``` 23 | 24 | Then run `./gradlew :platforms:intellij:artifactory-authenticator:uploadPluginToArtifactory` to publish the plugin to the configured repository. 25 | -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | java 18 | alias(libs.plugins.kotlin.jvm) 19 | alias(libs.plugins.intellij) 20 | alias(libs.plugins.pluginUploader) apply false 21 | } 22 | 23 | group = "com.slack.intellij" 24 | 25 | version = property("VERSION_NAME").toString() 26 | 27 | intellijPlatform { 28 | pluginConfiguration { 29 | name = "Artifactory Authenticator" 30 | id = "com.slack.intellij.artifactory" 31 | version = property("VERSION_NAME").toString() 32 | description = "A plugin for authenticating plugin repositories with Artifactory." 33 | vendor { 34 | name = "Slack" 35 | url = 36 | "https://github.com/slackhq/foundry/tree/main/platforms/intellij/artifactory-authenticator" 37 | email = "oss@slack-corp.com" 38 | } 39 | } 40 | } 41 | 42 | dependencies { 43 | testImplementation(libs.junit) 44 | testImplementation(libs.truth) 45 | } 46 | -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/gradle.properties: -------------------------------------------------------------------------------- 1 | INTELLIJ_PLUGIN=true 2 | PLUGIN_ID=com.slack.intellij.artifactory 3 | PLUGIN_NAME=Artifactory Authenticator 4 | PLUGIN_DESCRIPTION=A plugin for authenticating plugin repositories with Artifactory. 5 | VERSION_NAME=0.1.1 6 | PLUGIN_SINCE_BUILD=243 7 | ARTIFACTORY_URL_SUFFIX=artifactory-authenticator 8 | # Opt-out flag for bundling Kotlin standard library. 9 | # See https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#kotlin-standard-library 10 | kotlin.stdlib.default.dependency=false -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/src/main/kotlin/foundry/intellij/artifactory/AuthBundle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.artifactory 17 | 18 | import com.intellij.DynamicBundle 19 | import org.jetbrains.annotations.Nls 20 | import org.jetbrains.annotations.PropertyKey 21 | 22 | private const val BUNDLE_NAME = "messages.artifactoryAuthenticator" 23 | 24 | object AuthBundle : DynamicBundle(BUNDLE_NAME) { 25 | @Nls 26 | fun message(@PropertyKey(resourceBundle = BUNDLE_NAME) key: String, vararg params: Any): String = 27 | getMessage(key, *params) 28 | } 29 | -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/src/main/kotlin/foundry/intellij/artifactory/RepoAuthHotfix.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.artifactory 17 | 18 | import com.intellij.ide.AppLifecycleListener 19 | import com.intellij.ide.plugins.auth.PluginRepositoryAuthService 20 | import com.intellij.openapi.components.service 21 | import com.intellij.openapi.diagnostic.logger 22 | 23 | /** Workaround for https://youtrack.jetbrains.com/issue/IDEA-315487. */ 24 | class RepoAuthHotfix : AppLifecycleListener { 25 | private val logger = logger() 26 | 27 | override fun appFrameCreated(commandLineArgs: List) { 28 | logger.debug("Initializing ${PluginRepositoryAuthService::class.simpleName}") 29 | service() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.intellij.modules.platform 3 | 4 | 5 | 7 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | -------------------------------------------------------------------------------- /platforms/intellij/artifactory-authenticator/src/main/resources/messages/artifactoryAuthenticator.properties: -------------------------------------------------------------------------------- 1 | artifactoryAuth.configuration.title=Artifactory Auth Settings 2 | artifactoryAuth.configuration.url.title=Artifactory URL 3 | artifactoryAuth.configuration.username.title=Artifactory Username 4 | artifactoryAuth.configuration.token.title=Artifactory Token 5 | -------------------------------------------------------------------------------- /platforms/intellij/compose/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=skate-compose 2 | POM_NAME=Skate (Compose) 3 | POM_DESCRIPTION=Skate (Compose) 4 | INTELLIJ_PLUGIN=true 5 | # Set the default path for Roborazzi record images 6 | roborazzi.record.filePathStrategy=relativePathFromRoborazziContextOutputDirectory -------------------------------------------------------------------------------- /platforms/intellij/compose/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /platforms/intellij/compose/playground/src/jvmTest/kotlin/foundry/intellij/compose/playground/snapshots/images/foundry.intellij.compose.playground.MarkdownPlaygroundTest.snapshot.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:09c4018187ac6a76c2ecfb82608919d29a3c65e01f610bb6325afae0fc090d6e 3 | size 21744 4 | -------------------------------------------------------------------------------- /platforms/intellij/compose/playground/src/jvmTest/kotlin/foundry/intellij/compose/playground/snapshots/images/foundry.intellij.compose.playground.MarkdownPlaygroundTest.snapshot_2.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3db08ddfbafcd57ba5f4e85f554325a0b25834e03f3ffc78cc336b3c7292b602 3 | size 21248 4 | -------------------------------------------------------------------------------- /platforms/intellij/compose/playground/src/jvmTest/kotlin/foundry/intellij/compose/playground/snapshots/images/foundry.intellij.compose.playground.MarkdownPlaygroundTest.test.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a28db7245a0b40fd02b3c70d62345767f9472bfeb2a5ead8fb7d1a0f072c78ad 3 | size 22262 4 | -------------------------------------------------------------------------------- /platforms/intellij/compose/playground/src/jvmTest/kotlin/foundry/intellij/compose/playground/snapshots/images/foundry.intellij.compose.playground.MarkdownPlaygroundTest.test_2.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:985e8d862317262f57c36085e16a00360b63195d01c71949c7db72d15d4f4517 3 | size 21779 4 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/aibot/ChatColors.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.aibot 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | object ChatColors { 21 | val promptBackground = Color(0xFF45494A) 22 | 23 | val responseBackground = Color(0xFF2d2f30) 24 | 25 | val userTextColor = Color(0xFFEAEEF7) 26 | 27 | val responseTextColor = Color(0xFFE0EEF7) 28 | } 29 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/aibot/ChatPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.aibot 17 | 18 | import androidx.compose.runtime.Composable 19 | import androidx.compose.runtime.remember 20 | import androidx.compose.ui.awt.ComposePanel 21 | import com.slack.circuit.foundation.Circuit 22 | import com.slack.circuit.foundation.CircuitContent 23 | import foundry.intellij.compose.projectgen.FoundryDesktopTheme 24 | import java.awt.Dimension 25 | import javax.swing.JComponent 26 | 27 | object ChatPanel { 28 | fun createPanel(): JComponent { 29 | return ComposePanel().apply { 30 | preferredSize = Dimension(400, 600) 31 | setContent { FoundryDesktopTheme { ChatApp() } } 32 | } 33 | } 34 | 35 | @Composable 36 | private fun ChatApp() { 37 | val circuit = remember { 38 | Circuit.Builder() 39 | .addPresenter(ChatPresenter()) 40 | .addUi { state, modifier -> ChatWindowUi(state, modifier) } 41 | .build() 42 | } 43 | 44 | CircuitContent(ChatScreen, circuit = circuit) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/aibot/ChatScreen.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.aibot 17 | 18 | import com.slack.circuit.runtime.CircuitUiEvent 19 | import com.slack.circuit.runtime.CircuitUiState 20 | import com.slack.circuit.runtime.screen.Screen 21 | 22 | object ChatScreen : Screen { 23 | data class State( 24 | val messages: List, 25 | val isLoading: Boolean, 26 | val eventSink: (Event) -> Unit = {}, 27 | ) : CircuitUiState 28 | 29 | sealed class Event : CircuitUiEvent { 30 | data class SendMessage(val message: String) : Event() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/aibot/Message.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.aibot 17 | 18 | import androidx.compose.runtime.Immutable 19 | 20 | @Immutable data class Message(val text: String, val isMe: Boolean) 21 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/projectgen/FoundryDesktopTheme.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.projectgen 17 | 18 | import androidx.compose.runtime.Composable 19 | import org.jetbrains.jewel.bridge.theme.SwingBridgeTheme 20 | import org.jetbrains.jewel.foundation.ExperimentalJewelApi 21 | 22 | @OptIn(ExperimentalJewelApi::class) 23 | @Composable 24 | fun FoundryDesktopTheme(content: @Composable () -> Unit) { 25 | SwingBridgeTheme(content = content) 26 | } 27 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/projectgen/PrefixTransformation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.projectgen 17 | 18 | import androidx.compose.foundation.text.input.OutputTransformation 19 | import androidx.compose.foundation.text.input.TextFieldBuffer 20 | import androidx.compose.foundation.text.input.insert 21 | 22 | class PrefixTransformation(private val prefix: String) : OutputTransformation { 23 | override fun TextFieldBuffer.transformOutput() { 24 | insert(0, prefix) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/kotlin/foundry/intellij/compose/projectgen/ProjectGenScreen.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.compose.projectgen 17 | 18 | import androidx.compose.runtime.snapshots.SnapshotStateList 19 | import com.slack.circuit.runtime.CircuitUiEvent 20 | import com.slack.circuit.runtime.CircuitUiState 21 | import com.slack.circuit.runtime.screen.Screen 22 | 23 | internal object ProjectGenScreen : Screen { 24 | data class State( 25 | val uiElements: SnapshotStateList, 26 | // TODO make this a "next page" instead? 27 | val showDoneDialog: Boolean, 28 | val showErrorDialog: Boolean, 29 | val canGenerate: Boolean, 30 | val eventSink: (Event) -> Unit, 31 | ) : CircuitUiState 32 | 33 | sealed interface Event : CircuitUiEvent { 34 | object Generate : Event 35 | 36 | object Sync : Event 37 | 38 | object Quit : Event 39 | 40 | object Reset : Event 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /platforms/intellij/compose/src/jvmMain/resources/drawable/send.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /platforms/intellij/skate/README.md: -------------------------------------------------------------------------------- 1 | Skate Plugin 2 | ========================= 3 | 4 | An Intellij plugin that helps to improve local developer productivity by surfacing useful information in the IDE. 5 | 6 | We use this at Slack for several use cases: 7 | * Announce updates, latest changes and improvements through "What's New" panel 8 | * Annotate Feature Flag to help easily access its setup 9 | * Generate API model translators when migrating legacy API 10 | * Create initial new subproject setup from `File` dropdown 11 | 12 | ## Installation 13 | 14 | #### Artifactory 15 | 1. Install `artifactory-authenticator` plugin from disk and authenticate with Artifactory 16 | 2. Add custom plugin repository link from "Manage Plugin Repositories" 17 | 3. Search "Skate" in the plugins marketplace and install it 18 | 19 | #### Local installation 20 | 1. Build local version of the plugin with `./gradlew buildPlugin` 21 | 2. Open IDE settings, then "Install Plugin from Disk..." 22 | 23 | #### Local testing with `runLocalIde` 24 | 1. Add your local Android Studio path to your `~/.gradle/gradle.properties` file like this: `intellijPlatformTesting.idePath=/Users/username/Applications/Android Studio.app` 25 | 2. Run `./gradlew :platforms:intellij:skate:runLocalIde` from the CLI and it will open an Android Studio instance 26 | 27 | ## Implementation 28 | All registered plugin actions can be found in `skate.xml` config file 29 | 30 | ## Tracing 31 | We're sending analytics for almost all Skate features to track user usage. To set this up, 32 | 1. Register new feature event in `SkateTracingEvent` 33 | 2. Use `SkateSpanBuilder` to create the span for event you want to track 34 | 3. Make call to `SkateTraceReporter` to send up the traces 35 | 36 | ## Releasing 37 | 1. Update `change-notes.html` file under `skate/` and merge it to `main` 38 | 2. Run `publish-skate` Github Action. 39 | Behind the scene the action's running`./gradlew :platforms:intellij:skate:uploadPluginToArtifactory` 40 | -------------------------------------------------------------------------------- /platforms/intellij/skate/gradle.properties: -------------------------------------------------------------------------------- 1 | INTELLIJ_PLUGIN=true 2 | PLUGIN_ID=com.slack.intellij.skate 3 | PLUGIN_NAME=Skate 4 | PLUGIN_DESCRIPTION=A plugin for IntelliJ and Android Studio for faster Kotlin and Android development! 5 | VERSION_NAME=0.9.0 6 | PLUGIN_SINCE_BUILD=243 7 | ARTIFACTORY_URL_SUFFIX=skate 8 | # Opt-out flag for bundling Kotlin standard library. 9 | # See https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#kotlin-standard-library 10 | kotlin.stdlib.default.dependency=false -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/ChangelogJournal.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate 17 | 18 | import com.intellij.openapi.components.PersistentStateComponent 19 | import com.intellij.openapi.components.Service 20 | import com.intellij.openapi.components.State 21 | import com.intellij.openapi.components.Storage 22 | import com.intellij.util.xmlb.XmlSerializerUtil 23 | import com.intellij.util.xmlb.annotations.OptionTag 24 | import java.time.LocalDate 25 | 26 | @State(name = "ChangelogJournal", storages = [Storage("ChangelogJournal.xml")]) 27 | @Service(Service.Level.PROJECT) 28 | class ChangelogJournal : PersistentStateComponent { 29 | 30 | @OptionTag(converter = LocalDateConverter::class) var lastReadDate: LocalDate? = null 31 | 32 | companion object { 33 | fun getInstance(): ChangelogJournal { 34 | return ChangelogJournal() 35 | } 36 | } 37 | 38 | override fun getState(): ChangelogJournal { 39 | return this 40 | } 41 | 42 | override fun loadState(state: ChangelogJournal) { 43 | XmlSerializerUtil.copyBean(state, this) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/LocalDateConverter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate 17 | 18 | import com.intellij.util.xmlb.Converter 19 | import java.time.LocalDate 20 | import java.time.format.DateTimeFormatter 21 | import java.time.format.DateTimeParseException 22 | 23 | val MY_DATE_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") 24 | 25 | class LocalDateConverter : Converter() { 26 | override fun fromString(value: String): LocalDate? { 27 | val trimmedValue = value.trim('_') 28 | 29 | return try { 30 | LocalDate.parse(trimmedValue, MY_DATE_FORMATTER) 31 | } catch (e: DateTimeParseException) { 32 | println("Error parsing date string: $trimmedValue") 33 | println(e.message) 34 | System.err.println(e.stackTraceToString()) 35 | null 36 | } 37 | } 38 | 39 | override fun toString(value: LocalDate): String { 40 | return value.format(MY_DATE_FORMATTER) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/PostStartupActivityExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate 17 | 18 | import com.android.tools.idea.gradle.project.sync.GradleSyncState 19 | import com.intellij.openapi.components.service 20 | import com.intellij.openapi.project.Project 21 | import com.intellij.openapi.startup.ProjectActivity 22 | import foundry.intellij.skate.idemetrics.GradleSyncSubscriber 23 | 24 | internal class PostStartupActivityExtension : ProjectActivity { 25 | override suspend fun execute(project: Project) { 26 | GradleSyncState.subscribe(project, GradleSyncSubscriber()) 27 | val service = project.service() 28 | service.showWhatsNewPanel() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/SkateBundle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate 17 | 18 | import com.intellij.DynamicBundle 19 | import java.util.function.Supplier 20 | import org.jetbrains.annotations.Nls 21 | import org.jetbrains.annotations.PropertyKey 22 | 23 | private const val BUNDLE_NAME = "messages.skateBundle" 24 | 25 | object SkateBundle : DynamicBundle(BUNDLE_NAME) { 26 | @Nls 27 | fun message(@PropertyKey(resourceBundle = BUNDLE_NAME) key: String, vararg params: Any): String = 28 | getMessage(key, *params) 29 | 30 | @Nls 31 | fun lazy( 32 | @PropertyKey(resourceBundle = BUNDLE_NAME) key: String, 33 | vararg params: Any, 34 | ): Supplier = getLazyMessage(key, *params) 35 | } 36 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/SkateConfig.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate 17 | 18 | import com.intellij.openapi.components.service 19 | import com.intellij.openapi.options.BoundSearchableConfigurable 20 | import com.intellij.openapi.project.Project 21 | import com.intellij.openapi.ui.DialogPanel 22 | import foundry.intellij.skate.ui.SkateConfigUI 23 | 24 | class SkateConfig(private val project: Project) : 25 | BoundSearchableConfigurable( 26 | displayName = SkateBundle.message("skate.configuration.title"), 27 | helpTopic = SkateBundle.message("skate.configuration.title"), 28 | _id = "com.slack.skate.config", 29 | ) { 30 | private val settings = project.service() 31 | 32 | override fun createPanel(): DialogPanel { 33 | return SkateConfigUI(settings, project).createPanel() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/aibot/ChatBotToolWindow.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.aibot 17 | 18 | import com.intellij.openapi.project.Project 19 | import com.intellij.openapi.wm.ToolWindow 20 | import com.intellij.openapi.wm.ToolWindowFactory 21 | import com.intellij.ui.content.ContentFactory 22 | import foundry.intellij.compose.aibot.ChatPanel 23 | import javax.swing.JComponent 24 | 25 | class ChatBotToolWindow : ToolWindowFactory { 26 | override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { 27 | val contentFactory = ContentFactory.getInstance() 28 | val content = contentFactory.createContent(createComposePanel(), "", false) 29 | toolWindow.contentManager.addContent(content) 30 | } 31 | 32 | private fun createComposePanel(): JComponent { 33 | return ChatPanel.createPanel() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/codeowners/CodeOwnerInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.codeowners 17 | 18 | /** Represents a single code owner file line's info. */ 19 | data class CodeOwnerInfo( 20 | val team: String, 21 | val packagePattern: String, 22 | /** The line in the owners file this should focus to. Note: 0-based. */ 23 | val codeOwnerLineNumber: Int, 24 | ) 25 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/codeowners/model/CodeOwner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.codeowners.model 17 | 18 | import kotlinx.serialization.Serializable 19 | 20 | @Serializable 21 | data class CodeOwner( 22 | val name: String, 23 | val paths: List<@Serializable(with = PathObjectSerializer::class) Path>, 24 | ) 25 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/codeowners/model/CodeOwnersFile.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.codeowners.model 17 | 18 | import kotlinx.serialization.SerialName 19 | import kotlinx.serialization.Serializable 20 | 21 | @Serializable 22 | data class CodeOwnersFile( 23 | @SerialName("excluded_directories") val excludedDirectories: List, 24 | @SerialName("included_extensions") val includedDirectories: List, 25 | @SerialName("ownership") val ownership: List, 26 | ) 27 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/codeowners/model/Path.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.codeowners.model 17 | 18 | import kotlinx.serialization.Serializable 19 | 20 | @Serializable data class Path(val path: String, val notify: Boolean?) 21 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/featureflags/UastExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.featureflags 17 | 18 | import org.jetbrains.uast.UClass 19 | import org.jetbrains.uast.UFile 20 | 21 | fun UFile.allClassesAndInnerClasses(): Sequence { 22 | return classes.asSequence().flatMap(UClass::asSequenceWithInnerClasses) 23 | } 24 | 25 | fun UClass.asSequenceWithInnerClasses(): Sequence { 26 | return sequenceOf(this) 27 | .plus(innerClasses.asSequence().flatMap(UClass::asSequenceWithInnerClasses)) 28 | } 29 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/gradle/CopyGradleProjectPathProvider.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.gradle 17 | 18 | import com.intellij.ide.actions.DumbAwareCopyPathProvider 19 | import com.intellij.openapi.editor.Editor 20 | import com.intellij.openapi.project.Project 21 | import com.intellij.openapi.vcs.ProjectLevelVcsManager 22 | import com.intellij.openapi.vfs.VirtualFile 23 | 24 | /** 25 | * Action to copy the Gradle project path in the format ":path:to:project". If the selected file is 26 | * not a Gradle project directory, it will find the nearest parent Gradle project. 27 | */ 28 | class CopyGradleProjectPathProvider : DumbAwareCopyPathProvider() { 29 | 30 | override fun getPathToElement( 31 | project: Project, 32 | virtualFile: VirtualFile?, 33 | editor: Editor?, 34 | ): String? { 35 | if (virtualFile == null) return null 36 | 37 | val vcsRoot = ProjectLevelVcsManager.getInstance(project).getVcsRootObjectFor(virtualFile) 38 | if (vcsRoot == null) return null 39 | 40 | // Find the nearest Gradle project directory 41 | val gradleProjectDir = 42 | GradleProjectUtils.findNearestGradleProject(vcsRoot.path, virtualFile) ?: return null 43 | 44 | // Get the Gradle project path 45 | return GradleProjectUtils.getGradleProjectPath(project, gradleProjectDir) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/ideinstall/InstallationLocationStartupActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.ideinstall 17 | 18 | import com.intellij.openapi.components.service 19 | import com.intellij.openapi.project.Project 20 | import com.intellij.openapi.startup.ProjectActivity 21 | 22 | class InstallationLocationStartupActivity : ProjectActivity { 23 | override suspend fun execute(project: Project) { 24 | val service = project.service() 25 | service.checkInstallationLocation() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/modeltranslator/TranslatorAnnotator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.modeltranslator 17 | 18 | import com.intellij.lang.annotation.AnnotationHolder 19 | import com.intellij.lang.annotation.Annotator 20 | import com.intellij.lang.annotation.HighlightSeverity 21 | import com.intellij.psi.PsiElement 22 | import foundry.intellij.skate.SkateBundle 23 | import foundry.intellij.skate.modeltranslator.helper.TranslatorHelper 24 | 25 | class TranslatorAnnotator : Annotator { 26 | override fun annotate(element: PsiElement, holder: AnnotationHolder) { 27 | val bundle = TranslatorHelper.extractBundle(element) 28 | 29 | if (bundle != null) 30 | holder 31 | .newAnnotation( 32 | HighlightSeverity.WEAK_WARNING, 33 | SkateBundle.message("skate.modelTranslator.description"), 34 | ) 35 | .range(bundle.functionHeaderRange) 36 | .needsUpdateOnTyping(true) 37 | .withFix(GenerateTranslatorBodyAction(bundle)) 38 | .create() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/modeltranslator/model/TranslatorBundle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.modeltranslator.model 17 | 18 | import com.intellij.openapi.util.TextRange 19 | import org.jetbrains.kotlin.psi.KtImportDirective 20 | import org.jetbrains.kotlin.psi.KtNamedFunction 21 | 22 | /** 23 | * Contains the necessary information to annotate and generate a model translator. 24 | * 25 | * @property sourceModel The model to translate from. 26 | * @property destinationModel The model to translate to. 27 | * @property element The translator function. 28 | * @property importDirectives The list of imports in the translator file. 29 | * @property functionHeaderRange The text range from the begging of the translator function until 30 | * the end of the [destinationModel]. 31 | */ 32 | data class TranslatorBundle( 33 | val sourceModel: String, 34 | val destinationModel: String, 35 | val element: KtNamedFunction, 36 | val importDirectives: List, 37 | val functionHeaderRange: TextRange, 38 | ) 39 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/tracing/SkateSpanBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.tracing 17 | 18 | import foundry.tracing.KeyValue 19 | import foundry.tracing.model.TagBuilder 20 | import foundry.tracing.model.newTagBuilder 21 | import java.util.* 22 | 23 | class SkateSpanBuilder { 24 | private val keyValueList: TagBuilder = newTagBuilder() 25 | 26 | fun addTag(key: String, value: String) { 27 | keyValueList.apply { key.lowercase(Locale.US) tagTo value } 28 | } 29 | 30 | fun addTag(key: String, event: SkateTracingEvent) { 31 | keyValueList.apply { key.lowercase(Locale.US) tagTo event.name } 32 | } 33 | 34 | fun addTag(key: String, value: Long) { 35 | keyValueList.apply { key.lowercase(Locale.US) tagTo value } 36 | } 37 | 38 | fun addTag(key: String, value: Boolean) { 39 | keyValueList.apply { key.lowercase(Locale.US) tagTo value } 40 | } 41 | 42 | fun getKeyValueList(): List { 43 | return keyValueList.toList() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/tracing/SkateTracingEvent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.tracing 17 | 18 | sealed interface SkateTracingEvent { 19 | val name: String 20 | 21 | enum class ProjectGen : SkateTracingEvent { 22 | DIALOG_OPENED 23 | } 24 | 25 | enum class WhatsNew : SkateTracingEvent { 26 | PANEL_OPENED, 27 | PANEL_CLOSED, 28 | } 29 | 30 | enum class HoustonFeatureFlag : SkateTracingEvent { 31 | HOUSTON_FEATURE_FLAG_URL_CLICKED 32 | } 33 | 34 | enum class ModelTranslator : SkateTracingEvent { 35 | MODEL_TRANSLATOR_GENERATED 36 | } 37 | 38 | enum class Indexing : SkateTracingEvent { 39 | INDEXING_REASON, 40 | DUMB_MODE_WITHOUT_PAUSE_DURATION, 41 | PAUSED_DURATION, 42 | UPDATING_TIME, 43 | WAS_INTERRUPTED, 44 | SCANNING_TYPE, 45 | INDEXING_COMPLETED, 46 | DUMB_INDEXING_COMPLETED, 47 | } 48 | 49 | enum class GradleSync : SkateTracingEvent { 50 | GRADLE_SYNC_STARTED, 51 | GRADLE_SYNC_SUCCEDDED, 52 | GRADLE_SYNC_SKIPPED, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/ui/FileChoosing.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.ui 17 | 18 | import com.intellij.openapi.fileChooser.FileChooserDescriptor 19 | import com.intellij.openapi.vfs.VirtualFile 20 | 21 | /** 22 | * Provides utility function for creating file chooser descriptors to select specific types of 23 | * files, currently supports md files only. 24 | */ 25 | object FileChoosing { 26 | fun singleMdFileChooserDescriptor() = createSingleFileChooserDescriptor { 27 | it.extension.equals("md", ignoreCase = true) 28 | } 29 | 30 | private fun createSingleFileChooserDescriptor(fileFilter: (VirtualFile) -> Boolean) = 31 | object : FileChooserDescriptor(true, false, false, false, false, false) { 32 | override fun isFileSelectable(file: VirtualFile?) = file?.let { fileFilter(it) } ?: false 33 | 34 | override fun isFileVisible(file: VirtualFile?, showHiddenFiles: Boolean) = 35 | if (file == null || file.isDirectory) true else fileFilter(file) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/util/MemoizedSequence.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package foundry.intellij.skate.util 18 | 19 | // Adapted from 20 | // https://github.com/google/ksp/blob/main/common-util/src/main/kotlin/com/google/devtools/ksp/MemoizedSequence.kt 21 | // TODO: garbage collect underlying sequence after exhaust. 22 | class MemoizedSequence(sequence: Sequence) : Sequence { 23 | 24 | private val cache = arrayListOf() 25 | 26 | private val iter: Iterator by lazy { sequence.iterator() } 27 | 28 | private inner class CachedIterator() : Iterator { 29 | var idx = 0 30 | 31 | override fun hasNext(): Boolean { 32 | return idx < cache.size || iter.hasNext() 33 | } 34 | 35 | override fun next(): T { 36 | if (idx == cache.size) { 37 | cache.add(iter.next()) 38 | } 39 | val value = cache[idx] 40 | idx += 1 41 | return value 42 | } 43 | } 44 | 45 | override fun iterator(): Iterator { 46 | return CachedIterator() 47 | } 48 | } 49 | 50 | fun Sequence.memoized(): Sequence { 51 | return MemoizedSequence(this) 52 | } 53 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/util/ProjectUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.util 17 | 18 | import com.intellij.openapi.components.service 19 | import com.intellij.openapi.project.Project 20 | import foundry.intellij.skate.SkatePluginSettings 21 | import foundry.intellij.skate.SkateProjectService 22 | import foundry.intellij.skate.tracing.SkateTraceReporter 23 | 24 | fun Project.settings(): SkatePluginSettings = service() 25 | 26 | fun Project.isLinkifiedFeatureFlagsEnabled(): Boolean = settings().isLinkifiedFeatureFlagsEnabled 27 | 28 | fun Project.featureFlagFilePattern(): String? = settings().featureFlagFilePattern 29 | 30 | fun Project.isTracingEnabled(): Boolean = settings().isTracingEnabled 31 | 32 | fun Project.isProjectGenMenuActionEnabled(): Boolean = settings().isProjectGenMenuActionEnabled 33 | 34 | fun Project.tracingEndpoint(): String? = settings().tracingEndpoint 35 | 36 | fun Project.getTraceReporter(): SkateTraceReporter = service().traceReporter 37 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/main/kotlin/foundry/intellij/skate/util/StringExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.util 17 | 18 | import com.google.common.base.CaseFormat 19 | 20 | fun String.snakeToCamelCase(): String { 21 | return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, this) 22 | } 23 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/kotlin/foundry/intellij/skate/WhatsNewToolWindowListenerTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate 17 | 18 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 19 | import junit.framework.TestCase 20 | 21 | class WhatsNewToolWindowListenerTest : BasePlatformTestCase() { 22 | 23 | fun testVisibilityChangedFromInitialState() { 24 | val whatsNewToolWindowListener = WhatsNewToolWindowListener(project) 25 | val visibilityChanged = whatsNewToolWindowListener.visibilityChanged(true) 26 | TestCase.assertEquals(visibilityChanged, true) 27 | } 28 | 29 | fun testVisibilityChangedFalseWhenStateRemains() { 30 | val whatsNewToolWindowListener = WhatsNewToolWindowListener(project) 31 | val visibilityChanged = whatsNewToolWindowListener.visibilityChanged(false) 32 | TestCase.assertEquals(visibilityChanged, false) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/kotlin/foundry/intellij/skate/codeowners/CodeOwnerFileFetcherImplTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.codeowners 17 | 18 | import com.google.common.truth.Truth.assertThat 19 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 20 | import foundry.intellij.skate.util.settings 21 | 22 | private const val TEST_OWNERSHIP_YAML_FILE = "src/test/resources/test-code-ownership.yaml" 23 | 24 | class CodeOwnerFileFetcherImplTest : BasePlatformTestCase() { 25 | 26 | fun testGetCodeOwnershipFileSettingPresent() { 27 | val underTest = CodeOwnerFileFetcherImpl(project, this.basePath) 28 | project.settings().codeOwnerFilePath = TEST_OWNERSHIP_YAML_FILE 29 | project.settings().isCodeOwnerEnabled = true 30 | assertThat(underTest.getCodeOwnershipFile()).isNotNull() 31 | } 32 | 33 | fun testGetCodeOwnershipFileSettingNotPresent() { 34 | val underTest = CodeOwnerFileFetcherImpl(project, this.basePath) 35 | project.settings().codeOwnerFilePath = null 36 | project.settings().isCodeOwnerEnabled = true 37 | assertThat(underTest.getCodeOwnershipFile()).isNull() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/kotlin/foundry/intellij/skate/featureflags/BaseFeatureFlagTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.featureflags 17 | 18 | import com.intellij.psi.PsiFile 19 | import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixture4TestCase 20 | 21 | abstract class BaseFeatureFlagTest : LightPlatformCodeInsightFixture4TestCase() { 22 | // language=kotlin 23 | protected val fileContent = 24 | """ 25 | package slack.featureflag 26 | 27 | annotation class FeatureFlag(defaultValue: Boolean, val key: String = "", minimization: Minimization) 28 | 29 | enum class Minimization { AUTHENTICATED } 30 | 31 | enum class TestFeatures : 32 | FeatureFlagEnum { 33 | @Deprecated("test") 34 | @FeatureFlag(defaultValue = false, key ="test_flag_one", minimization = AUTHENTICATED) 35 | FLAG_ONE, 36 | @FeatureFlag(defaultValue = false, minimization = AUTHENTICATED) 37 | FLAG_TWO, 38 | @FeatureFlag(defaultValue = false, minimization = AUTHENTICATED) 39 | FLAG_THREE, 40 | } 41 | """ 42 | 43 | protected fun createKotlinFile(name: String, text: String): PsiFile { 44 | return myFixture.configureByText(name, text) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/kotlin/foundry/intellij/skate/featureflags/FeatureFlagExtractorTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.intellij.skate.featureflags 17 | 18 | import com.google.common.truth.Truth.assertThat 19 | import com.intellij.openapi.components.service 20 | import foundry.intellij.skate.SkatePluginSettings 21 | import org.junit.Test 22 | 23 | class FeatureFlagExtractorTest : BaseFeatureFlagTest() { 24 | 25 | @Test 26 | fun `test extraction of feature flags from provided content`() { 27 | project.service().featureFlagBaseUrl = "test.com?q=" 28 | project.service().featureFlagAnnotation = "slack.featureflag.FeatureFlag" 29 | val psiFile = createKotlinFile("TestFeature.kt", fileContent) 30 | val featureFlags = FeatureFlagExtractor.extractFeatureFlags(psiFile) 31 | val flagUrls = featureFlags.map { it.url } 32 | assertThat(flagUrls) 33 | .containsExactly("test.com?q=test_flag_one", "test.com?q=flag_two", "test.com?q=flag_three") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/resources/test-code-ownership.yaml: -------------------------------------------------------------------------------- 1 | excluded_directories: 2 | - .git 3 | 4 | included_extensions: 5 | - .kt 6 | - .kts 7 | - .java 8 | - .xml 9 | - .json 10 | 11 | ownership: 12 | - name: Team 1 13 | paths: 14 | - path: app/folder1/.* 15 | notify: false 16 | - app/folder2/.* 17 | - app/folder3/subfolder/.* 18 | bogusProp: Foo 19 | - name: Team 2 20 | paths: 21 | - app/folder3/.* 22 | bogusProp: Bar -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/ActionTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject 17 | import slack.model.Call 18 | 19 | fun CallObject.Action.toDomainModel(): Call.Action { 20 | TODO() 21 | } 22 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/CallExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject 17 | import slack.model.Call 18 | 19 | fun CallObject.toDomainModel(): Call { 20 | TODO() 21 | } 22 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/CallObjectTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject 17 | 18 | fun CallObject.toDomainModel() { 19 | TODO() 20 | } 21 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/CallObjectsTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.CallObject 17 | import slack.model.Call 18 | 19 | fun CallObject.toDomainModel(): Call { 20 | TODO() 21 | } 22 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/CallTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject 17 | import slack.model.Call 18 | 19 | fun CallObject.toDomainModel(): Call { 20 | TODO() 21 | } 22 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/FullyQualifiedActionTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example 17 | 18 | fun slack.api.schemas.CallObject.Action.toDomainModel(): slack.model.Call.Action { 19 | TODO() 20 | } 21 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/FullyQualifiedCallTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package example 17 | fun slack.api.schemas.CallObject.toDomainModel(): slack.model.Call { 18 | TODO() 19 | } 20 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/ImportAliasCallTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject as ApiCall 17 | import slack.model.Call as DomainCall 18 | 19 | fun ApiCall.toDomainModel(): DomainCall { 20 | TODO() 21 | } 22 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/NullableCallTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject 17 | import slack.model.Call 18 | 19 | fun CallObject.toDomainModel(): Call? { 20 | return null 21 | } 22 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/SingleLineCallTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.api.schemas.CallObject 17 | import slack.model.Call 18 | 19 | fun CallObject.toDomainModel(): Call = TODO() 20 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/StatusStringTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.model.Call 17 | 18 | fun String.toDomainModel(): Call.Transcription.Status { 19 | TODO() 20 | } 21 | -------------------------------------------------------------------------------- /platforms/intellij/skate/src/test/testData/TranscriptionStringTranslator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import slack.model.Call 17 | 18 | fun String.toDomainModel(): Call.Transcription { 19 | TODO() 20 | } 21 | -------------------------------------------------------------------------------- /regenerate_thermals_lib.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | cd platforms/gradle/foundry-gradle-plugin || exit 1 4 | swiftc thermal_state.swift -emit-library 5 | mv -f libthermal_state.dylib src/main/resources/libthermal_state.dylib 6 | cd .. -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | 5 | source tools/scripts/scriptUtil.sh 6 | 7 | NEW_VERSION=$1 8 | SNAPSHOT_VERSION=$(getProperty 'VERSION_NAME' gradle.properties) 9 | 10 | echo "Publishing $NEW_VERSION" 11 | 12 | # Prepare release 13 | sed -i '' "s/${SNAPSHOT_VERSION}/${NEW_VERSION}/g" gradle.properties 14 | git commit -am "Prepare for release $NEW_VERSION." 15 | git tag -a "$NEW_VERSION" -m "Version $NEW_VERSION" 16 | 17 | # Publish 18 | ./gradlew publish --no-configuration-cache -PSONATYPE_CONNECT_TIMEOUT_SECONDS=300 19 | 20 | # Prepare next snapshot 21 | echo "Restoring snapshot version $SNAPSHOT_VERSION" 22 | sed -i '' "s/${NEW_VERSION}/${SNAPSHOT_VERSION}/g" gradle.properties 23 | git commit -am "Prepare next development version." 24 | 25 | # Push it all up 26 | git push && git push --tags 27 | 28 | # Deploy docs 29 | ./deploy_website.sh -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:recommended" 4 | ], 5 | "branchPrefix": "test-renovate/", 6 | "gitAuthor": "OSS-Bot ", 7 | "repositories": [ 8 | "slackhq/foundry" 9 | ], 10 | "platformAutomerge": true, 11 | "packageRules": [ 12 | { 13 | "matchManagers": [ 14 | "pip_requirements" 15 | ], 16 | "groupName": "Docsite Dependencies", 17 | "automerge": true, 18 | "extends": [ 19 | "schedule:weekly" 20 | ], 21 | "additionalReviewers": [ 22 | "team:android-librarians" 23 | ] 24 | }, 25 | { 26 | "description": "Automerge non-major updates", 27 | "matchUpdateTypes": [ 28 | "minor", 29 | "patch" 30 | ], 31 | "automerge": true 32 | }, 33 | { 34 | "matchDepNames": [ 35 | "org.jetbrains.compose:compose-gradle-plugin", 36 | "org.jetbrains.compose" 37 | ], 38 | "versioning": "Compose semver", 39 | "description": "Allow versions like 1.7.1 and 1.7.0-rc1 but not wild compose versions like 1.7.1+build1910-release-1.7.1", 40 | "allowedVersions": "/^\\d+\\.\\d+\\.\\d+(-[a-zA-Z]+(\\.\\d+)?)?$/" 41 | }, 42 | { 43 | "matchDepNames": [ 44 | "com.google.guava:guava" 45 | ], 46 | "allowedVersions": "!/\\-android$/" 47 | }, 48 | { 49 | "matchDepNames": [ 50 | "org.jetbrains.intellij.platform", 51 | "org.jetbrains.intellij.platform.settings" 52 | ], 53 | "groupName": "IntelliJ Platform" 54 | }, 55 | { 56 | "matchDepNames": [ 57 | "renovatebot/github-action" 58 | ], 59 | "extends": [ 60 | "schedule:monthly" 61 | ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /spotless/spotless.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) $YEAR Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ -------------------------------------------------------------------------------- /tools/cli/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=cli 2 | POM_NAME=Foundry (CLI) 3 | POM_DESCRIPTION=Kotlin CLIs and CLI utilities, mostly intended for use with Clikt. 4 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/Toml.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli 17 | 18 | import java.io.File 19 | 20 | public object Toml { 21 | private val IGNORED_BLOCKS = 22 | sequenceOf("plugins", "libraries", "bundles").mapTo(LinkedHashSet()) { "[$it]" } 23 | 24 | /** 25 | * Parses the version declarations out of a given Gradle versions TOML file. This tries to be 26 | * efficient by only parsing the first part of the file and assumes that plugins are the next 27 | * block after the version declarations. 28 | */ 29 | public fun parseVersion(versionsToml: File): Map { 30 | return versionsToml.useLines(Charsets.UTF_8, ::parseVersion) 31 | } 32 | 33 | internal fun parseVersion(lines: Sequence): Map { 34 | return lines 35 | .filterNot { it.startsWith('#') || it.trim() == "[versions]" } 36 | .takeWhile { it.trim() !in IGNORED_BLOCKS } 37 | .filterNot { it.isBlank() } 38 | .associate { line -> 39 | val (k, v) = line.substringBefore("#").split("=").map { it.trim().removeSurrounding("\"") } 40 | k to v 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/buildkite/Keyable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.buildkite 17 | 18 | /** A buildkite element that can be identified with a [key]. */ 19 | public interface Keyable { 20 | public val key: String? 21 | } 22 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/playground.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | @file:JvmName("Playground") 17 | 18 | package foundry.cli 19 | 20 | public fun main() { 21 | // Use this function in testing CLIs locally without needing to worry 22 | // about modifying the original file with local testing arguments. 23 | // DO NOT CHECK IN CHANGES TO THIS FILE. REVIEWERS - DO NOT APPROVE 24 | // CHANGES TO THIS FILE 25 | } 26 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/shellsentry/ProcessingUtil.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.shellsentry 17 | 18 | import com.squareup.moshi.Moshi 19 | import com.squareup.moshi.addAdapter 20 | import foundry.cli.util.DurationJsonAdapter 21 | import foundry.cli.util.RegexJsonAdapter 22 | import foundry.cli.util.SingleItemListJsonAdapterFactory 23 | 24 | internal object ProcessingUtil { 25 | fun newMoshi(): Moshi { 26 | return Moshi.Builder() 27 | .add(SingleItemListJsonAdapterFactory()) 28 | .addAdapter(DurationJsonAdapter()) 29 | .add(RegexJsonAdapter.Factory()) 30 | .build() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/shellsentry/RetrySignal.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.shellsentry 17 | 18 | import com.squareup.moshi.JsonClass 19 | import dev.zacsweers.moshix.sealed.annotations.TypeLabel 20 | import kotlin.time.Duration 21 | 22 | @JsonClass(generateAdapter = true, generator = "sealed:type") 23 | public sealed interface RetrySignal { 24 | 25 | /** Unknown issue. */ 26 | @TypeLabel("unknown") public data object Unknown : RetrySignal 27 | 28 | /** Indicates an issue that is recognized but cannot be retried. */ 29 | @TypeLabel("ack") public data object Ack : RetrySignal 30 | 31 | /** Indicates this issue should be retried immediately. */ 32 | @TypeLabel("immediate") public data object RetryImmediately : RetrySignal 33 | 34 | /** Indicates this issue should be retried after a [delay]. */ 35 | @TypeLabel("delayed") 36 | @JsonClass(generateAdapter = true) 37 | public data class RetryDelayed( 38 | // Can't default to 1.minutes due to https://github.com/ZacSweers/MoshiX/issues/442 39 | val delay: Duration 40 | ) : RetrySignal 41 | } 42 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/shellsentry/ShellSentryConfig.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.shellsentry 17 | 18 | import com.squareup.moshi.Json 19 | import com.squareup.moshi.JsonClass 20 | import kotlin.reflect.full.declaredMemberProperties 21 | 22 | internal const val CURRENT_VERSION = 2 23 | 24 | /** Represents a configuration for [ShellSentryCli]. */ 25 | @JsonClass(generateAdapter = true) 26 | public data class ShellSentryConfig( 27 | val version: Int = CURRENT_VERSION, 28 | @Json(name = "gradle_enterprise_server") val gradleEnterpriseServer: String? = null, 29 | @Json(name = "known_issues") 30 | val knownIssues: List = 31 | KnownIssues::class.declaredMemberProperties.map { it.get(KnownIssues) as Issue }, 32 | /** 33 | * A minimum confidence level on a scale of [0-100] to accept. [AnalysisResult]s from 34 | * [ShellSentryExtension]s with lower confidence than this will be discarded. 35 | */ 36 | @Json(name = "min_confidence") val minConfidence: Int = 75, 37 | ) { 38 | init { 39 | check(version == CURRENT_VERSION) { 40 | "Incompatible config version. Found $version, expected $CURRENT_VERSION." 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/util/DurationJsonAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.util 17 | 18 | import com.squareup.moshi.JsonAdapter 19 | import com.squareup.moshi.JsonReader 20 | import com.squareup.moshi.JsonWriter 21 | import kotlin.time.Duration 22 | import kotlin.time.Duration.Companion.milliseconds 23 | 24 | /** A simple [Duration] adapter that converts a [Long] (in millis) to a [Duration]. */ 25 | internal class DurationJsonAdapter : JsonAdapter() { 26 | override fun fromJson(reader: JsonReader): Duration { 27 | return reader.nextLong().milliseconds 28 | } 29 | 30 | override fun toJson(writer: JsonWriter, value: Duration?) { 31 | writer.value(value?.inWholeMilliseconds) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tools/cli/src/main/kotlin/foundry/cli/util/RegexJsonAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.util 17 | 18 | import com.squareup.moshi.JsonAdapter 19 | import com.squareup.moshi.JsonReader 20 | import com.squareup.moshi.JsonWriter 21 | import com.squareup.moshi.Moshi 22 | import com.squareup.moshi.adapter 23 | import com.squareup.moshi.rawType 24 | import java.lang.reflect.Type 25 | 26 | /** A simple [Regex] adapter that converts Strings to a [Regex]. */ 27 | internal class RegexJsonAdapter(private val stringAdapter: JsonAdapter) : 28 | JsonAdapter() { 29 | override fun fromJson(reader: JsonReader) = stringAdapter.fromJson(reader)!!.toRegex() 30 | 31 | override fun toJson(writer: JsonWriter, value: Regex?) { 32 | error("RegexJsonAdapter is only used for deserialization") 33 | } 34 | 35 | internal class Factory : JsonAdapter.Factory { 36 | override fun create(type: Type, annotations: Set, moshi: Moshi): JsonAdapter<*>? { 37 | return when (type.rawType) { 38 | Regex::class.java -> { 39 | RegexJsonAdapter(moshi.adapter().nullSafe()).nullSafe() 40 | } 41 | else -> null 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tools/cli/src/test/kotlin/foundry/cli/TomlTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli 17 | 18 | import com.google.common.truth.Truth.assertThat 19 | import org.junit.Test 20 | 21 | class TomlTest { 22 | @Test 23 | fun simple() { 24 | // language=toml 25 | val toml = 26 | """ 27 | [versions] 28 | kotlin = "1.6.10" # Trailing comment is skipped 29 | # Skipped 30 | jvmTarget = "1.8" 31 | """ 32 | .trimIndent() 33 | val versions = Toml.parseVersion(toml.lineSequence()) 34 | assertThat(versions).containsExactly("kotlin", "1.6.10", "jvmTarget", "1.8") 35 | } 36 | 37 | @Test 38 | fun everythingAfterPluginsIsSkipped() { 39 | // language=toml 40 | val toml = 41 | """ 42 | [versions] 43 | kotlin = "1.6.10" 44 | jvmTarget = "1.8" 45 | 46 | [libraries] 47 | # Skipped 48 | jvmTarget = "17" 49 | """ 50 | .trimIndent() 51 | val versions = Toml.parseVersion(toml.lineSequence()) 52 | assertThat(versions).containsExactly("kotlin", "1.6.10", "jvmTarget", "1.8") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tools/cli/src/test/kotlin/foundry/cli/shellsentry/ShellSentryCliTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.shellsentry 17 | 18 | import com.github.ajalt.clikt.core.parse 19 | import com.google.common.truth.Truth.assertThat 20 | import org.junit.Rule 21 | import org.junit.Test 22 | import org.junit.rules.TemporaryFolder 23 | 24 | class ShellSentryCliTest { 25 | 26 | @JvmField @Rule val temporaryFolder = TemporaryFolder() 27 | 28 | @Test 29 | fun standardParsing() { 30 | val configFile = temporaryFolder.newFile("config.json") 31 | val args = "./gradlew build -Pvariant=debug" 32 | val parsed = 33 | ShellSentryCli().apply { 34 | parse( 35 | arrayOf( 36 | "--project-dir", 37 | temporaryFolder.root.absolutePath, 38 | "--bugsnag-key=1234", 39 | "--verbose", 40 | "--parse-only", 41 | "--config", 42 | configFile.absolutePath, 43 | "--", 44 | args, 45 | ) 46 | ) 47 | } 48 | assertThat(parsed.projectDir).isEqualTo(temporaryFolder.root.toPath()) 49 | assertThat(parsed.verbose).isTrue() 50 | assertThat(parsed.bugsnagKey).isEqualTo("1234") 51 | assertThat(parsed.configurationFile).isEqualTo(configFile.toPath()) 52 | assertThat(parsed.args).isEqualTo(listOf(args)) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tools/cli/src/test/kotlin/foundry/cli/util/RegexJsonAdapterFactoryTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.util 17 | 18 | import com.squareup.moshi.adapter 19 | import foundry.cli.shellsentry.ProcessingUtil 20 | import org.junit.Test 21 | 22 | class RegexJsonAdapterFactoryTest { 23 | @Test 24 | fun regexDeserialization() { 25 | val moshi = ProcessingUtil.newMoshi() 26 | val adapter = moshi.adapter() 27 | val regex = adapter.fromJson("""".*"""") 28 | assert(regex != null) 29 | assert(regex!!.pattern == ".*") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tools/cli/src/test/kotlin/foundry/cli/util/SingleItemListAdapterTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.cli.util 17 | 18 | import com.squareup.moshi.adapter 19 | import foundry.cli.shellsentry.ProcessingUtil 20 | import org.junit.Test 21 | 22 | class SingleItemListAdapterTest { 23 | @Test 24 | fun singleItem() { 25 | val moshi = ProcessingUtil.newMoshi() 26 | 27 | val list = moshi.adapter>().fromJson(""""foo"""")!! 28 | assert(list.size == 1) 29 | assert(list[0] == "foo") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tools/foundry-common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.mavenPublish) 19 | alias(libs.plugins.lint) 20 | } 21 | 22 | dependencies { 23 | api(platform(libs.coroutines.bom)) 24 | api(libs.moshi) 25 | api(libs.okio) 26 | 27 | implementation(libs.coroutines.core) 28 | implementation(libs.guava) 29 | 30 | testImplementation(libs.junit) 31 | testImplementation(libs.truth) 32 | } 33 | -------------------------------------------------------------------------------- /tools/foundry-common/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=foundry-common 2 | POM_NAME=Foundry (Common) 3 | POM_DESCRIPTION=Foundry (Common) 4 | -------------------------------------------------------------------------------- /tools/foundry-common/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 13 | 14 | 15 | 20 | 24 | 25 | 26 | 31 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tools/foundry-common/src/main/kotlin/foundry/common/Collections.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.common 17 | 18 | public fun Collection.mapToSet(transform: (T) -> R): Set { 19 | return mapTo(mutableSetOf(), transform) 20 | } 21 | 22 | public fun Collection.flatMapToSet(transform: (T) -> Iterable): Set { 23 | return flatMapTo(mutableSetOf(), transform) 24 | } 25 | 26 | public fun Collection.filterToSet(predicate: (T) -> Boolean): Set { 27 | return filterTo(mutableSetOf(), predicate) 28 | } 29 | 30 | /** 31 | * Flips a map. In the context of `ComputeAffectedProjectsTask`, we use this to flip a map of 32 | * projects to their dependencies to a map of projects to the projects that depend on them. We use 33 | * this to find all affected projects given a seed of changed projects. 34 | * 35 | * Example: 36 | * 37 | * ``` 38 | * Given a map 39 | * {a:[b, c], b:[d], c:[d], d:[]} 40 | * return 41 | * {b:[a], c:[a], d:[b, c]} 42 | * ``` 43 | */ 44 | public fun Map>.flip(): Map> { 45 | val flipped = mutableMapOf>() 46 | for ((project, dependenciesSet) in this) { 47 | for (dependency in dependenciesSet) { 48 | flipped.getOrPut(dependency, ::mutableSetOf).add(project) 49 | } 50 | } 51 | return flipped 52 | } 53 | -------------------------------------------------------------------------------- /tools/foundry-common/src/main/kotlin/foundry/common/FoundryKeys.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.common 17 | 18 | /** Key constants reused across multiple foundry projects. */ 19 | public object FoundryKeys { 20 | public const val DEFAULT_PACKAGE_PREFIX: String = "foundry.defaultPackagePrefix" 21 | } 22 | -------------------------------------------------------------------------------- /tools/foundry-common/src/main/kotlin/foundry/common/GradlePathUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.common 17 | 18 | import com.google.common.base.CaseFormat 19 | 20 | /** 21 | * Converts a kebab-case string (e.g., `some-module-name`) to lowerCamelCase (e.g., 22 | * `someModuleName`). 23 | * 24 | * Used to transform Gradle module names into Kotlin DSL-friendly accessors. 25 | */ 26 | private fun kebabCaseToCamelCase(s: String): String { 27 | return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, s) 28 | } 29 | 30 | /** 31 | * Returns a project accessor representation of the given [projectPath]. 32 | * 33 | * Example: `:libraries:foundation` -> `libraries.foundation`. 34 | */ 35 | public fun convertProjectPathToAccessor(projectPath: String): String { 36 | return projectPath.removePrefix(":").split(":").joinToString(separator = ".") { segment -> 37 | kebabCaseToCamelCase(segment) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/foundry-common/src/main/kotlin/foundry/common/Paths.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.common 17 | 18 | import okio.FileSystem 19 | import okio.Path 20 | 21 | public fun Path.prepareForGradleOutput(fs: FileSystem): Path = apply { 22 | if (fs.exists(this)) fs.delete(this) 23 | parent?.let(fs::createDirectories) 24 | } 25 | 26 | public fun Path.readLines(fs: FileSystem): List { 27 | return fs.read(this) { 28 | val lines = mutableListOf() 29 | while (!exhausted()) { 30 | readUtf8Line()?.let { lines += it } 31 | } 32 | lines 33 | } 34 | } 35 | 36 | public fun Path.writeLines(lines: Iterable, fs: FileSystem) { 37 | fs.write(this) { 38 | lines.forEach { line -> 39 | writeUtf8(line) 40 | writeUtf8("\n") 41 | } 42 | } 43 | } 44 | 45 | public fun Path.writeText(text: String, fs: FileSystem) { 46 | fs.write(this) { writeUtf8(text) } 47 | } 48 | -------------------------------------------------------------------------------- /tools/foundry-common/src/main/kotlin/foundry/common/RegexMap.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.common 17 | 18 | import java.util.TreeMap 19 | import org.intellij.lang.annotations.Language 20 | 21 | /** 22 | * A [Map] that can have [Regex] keys. This requires a custom impl because [Regex] is not 23 | * comparable, so we internally back these with a [TreeMap] rather than the conventional 24 | * [LinkedHashMap]. 25 | */ 26 | public class RegexMap internal constructor(delegate: Map) : 27 | Map by delegate { 28 | public constructor() : this(emptyMap()) 29 | } 30 | 31 | public fun buildRegexMap(body: RegexMapBuilder.() -> Unit): RegexMap = 32 | RegexMap(RegexMapBuilderImpl().apply(body).map) 33 | 34 | public interface RegexMapBuilder { 35 | public fun remove(@Language("RegExp") regex: String): Unit = replace(regex, "") 36 | 37 | public fun replace(@Language("RegExp") regex: String, replacement: String) 38 | } 39 | 40 | private class RegexMapBuilderImpl : RegexMapBuilder { 41 | val map = TreeMap(compareBy { it.pattern }) 42 | 43 | override fun replace(regex: String, replacement: String) { 44 | map.put(regex.toRegex(), replacement) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tools/robolectric-sdk-management/README.md: -------------------------------------------------------------------------------- 1 | robolectric-sdk-management 2 | ========================== 3 | 4 | Robolectric hosts instrumented Android API jars on maven central at specific coordinates that are often changed/tied to the robolectric version. To simplify management of robolectric, we hide their access behind a small SDK helper that can load them from Robolectric's JVM jar. We then use this in the Foundry gradle plugin to create resolvable configurations to load their coordinates via traditional maven resolution and store them in a "known" location. 5 | -------------------------------------------------------------------------------- /tools/robolectric-sdk-management/api/robolectric-sdk-management.api: -------------------------------------------------------------------------------- 1 | public final class foundry/tools/robolectric/sdk/management/RobolectricSdkAccess { 2 | public static final field INSTANCE Lfoundry/tools/robolectric/sdk/management/RobolectricSdkAccess; 3 | public final fun loadSdks (Ljava/util/Collection;)Ljava/util/List; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /tools/robolectric-sdk-management/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.dokka) 19 | alias(libs.plugins.detekt) 20 | alias(libs.plugins.lint) 21 | alias(libs.plugins.mavenPublish) 22 | } 23 | 24 | dependencies { implementation(libs.robolectric) } 25 | -------------------------------------------------------------------------------- /tools/robolectric-sdk-management/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=robolectric-sdk-management 2 | POM_NAME=Foundry (Robolectric SDK Management) 3 | POM_DESCRIPTION=Access APIs for managing Robolectric JARs for Android SDKs 4 | -------------------------------------------------------------------------------- /tools/scripts/scriptUtil.sh: -------------------------------------------------------------------------------- 1 | # Source this file to use its functions 2 | 3 | # Gets a property out of a .properties file 4 | # usage: getProperty $key $filename 5 | function getProperty() { 6 | grep "${1}" "$2" | cut -d'=' -f2 7 | } 8 | 9 | # Increments an input version string given a version type 10 | # usage: increment_version $current_version $version_type 11 | increment_version() { 12 | local current_version=$1 13 | local version_type=$2 14 | IFS='.' read -r major minor patch <<< "$current_version" 15 | case "$version_type" in 16 | major) ((major++)); minor=0; patch=0 ;; 17 | minor) ((minor++)); patch=0 ;; 18 | patch) ((patch++)) ;; 19 | esac 20 | echo "$major.$minor.$patch" 21 | } -------------------------------------------------------------------------------- /tools/skippy/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.moshix) 19 | alias(libs.plugins.mavenPublish) 20 | alias(libs.plugins.lint) 21 | } 22 | 23 | dependencies { 24 | api(platform(libs.coroutines.bom)) 25 | 26 | implementation(libs.clikt) 27 | implementation(libs.coroutines.core) 28 | implementation(libs.gradlePlugins.graphAssert) { because("To use in Gradle graphing APIs.") } 29 | implementation(libs.moshi) 30 | implementation(libs.okio) 31 | implementation(projects.tools.cli) 32 | implementation(projects.tools.foundryCommon) 33 | 34 | testImplementation(platform(libs.coroutines.bom)) 35 | testImplementation(libs.coroutines.test) 36 | testImplementation(libs.junit) 37 | testImplementation(libs.okio.fakefilesystem) 38 | testImplementation(libs.truth) 39 | } 40 | -------------------------------------------------------------------------------- /tools/skippy/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=skippy 2 | POM_NAME=Foundry (Skippy) 3 | POM_DESCRIPTION=Foundry (Skippy) 4 | -------------------------------------------------------------------------------- /tools/skippy/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tools/skippy/src/main/kotlin/foundry/skippy/AffectedProjectsDefaults.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.skippy 17 | 18 | import java.util.Collections.unmodifiableSet 19 | 20 | public object AffectedProjectsDefaults { 21 | public val DEFAULT_INCLUDE_PATTERNS: Set = 22 | unmodifiableSet( 23 | setOf( 24 | "**/*.kt", 25 | "*.gradle", 26 | "**/*.gradle", 27 | "*.gradle.kts", 28 | "**/*.gradle.kts", 29 | "**/*.java", 30 | "**/AndroidManifest.xml", 31 | "**/res/**", 32 | "**/src/*/resources/**", 33 | "gradle.properties", 34 | "**/gradle.properties", 35 | ) 36 | ) 37 | 38 | public val DEFAULT_NEVER_SKIP_PATTERNS: Set = 39 | unmodifiableSet( 40 | setOf( 41 | // root build.gradle.kts and settings.gradle.kts files 42 | "*.gradle.kts", 43 | "*.gradle", 44 | // root gradle.properties file 45 | "gradle.properties", 46 | // Version catalogs 47 | "**/*.versions.toml", 48 | // Gradle wrapper files 49 | "**/gradle/wrapper/**", 50 | "gradle/wrapper/**", 51 | "gradlew", 52 | "gradlew.bat", 53 | "**/gradlew", 54 | "**/gradlew.bat", 55 | // buildSrc 56 | "buildSrc/**", 57 | // CI 58 | ".github/workflows/**", 59 | ".github/actions/**", 60 | ) 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /tools/skippy/src/main/kotlin/foundry/skippy/AffectedProjectsResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.skippy 17 | 18 | import java.util.SortedSet 19 | 20 | public data class AffectedProjectsResult( 21 | val affectedProjects: SortedSet, 22 | val focusProjects: SortedSet, 23 | val affectedAndroidTestProjects: SortedSet, 24 | ) 25 | -------------------------------------------------------------------------------- /tools/skippy/src/main/kotlin/foundry/skippy/CliktFoundryLogger.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.skippy 17 | 18 | import com.github.ajalt.clikt.core.BaseCliktCommand 19 | import foundry.common.FoundryLogger 20 | 21 | internal fun FoundryLogger.Companion.clikt(command: BaseCliktCommand<*>): FoundryLogger = 22 | CliktFoundryLogger(command) 23 | 24 | private class CliktFoundryLogger(private val command: BaseCliktCommand<*>) : FoundryLogger { 25 | override fun debug(message: String) { 26 | command.echo(message) 27 | } 28 | 29 | override fun info(message: String) { 30 | command.echo(message) 31 | } 32 | 33 | override fun lifecycle(message: String) { 34 | command.echo(message) 35 | } 36 | 37 | override fun warn(message: String) { 38 | command.echo(message) 39 | } 40 | 41 | override fun warn(message: String, error: Throwable) { 42 | command.echo(message + "\n" + error.stackTraceToString()) 43 | } 44 | 45 | override fun error(message: String) { 46 | command.echo(message, err = true) 47 | } 48 | 49 | override fun error(message: String, error: Throwable) { 50 | command.echo(message + "\n" + error.stackTraceToString(), err = true) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tools/skippy/src/main/kotlin/foundry/skippy/DependencyMetadata.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.skippy 17 | 18 | public class DependencyMetadata( 19 | public val projectsToDependents: Map> = emptyMap(), 20 | public val projectsToDependencies: Map> = emptyMap(), 21 | ) 22 | -------------------------------------------------------------------------------- /tools/skippy/src/main/kotlin/foundry/skippy/DiagnosticWriter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.skippy 17 | 18 | public fun interface DiagnosticWriter { 19 | public fun write(name: String, content: () -> String) 20 | 21 | public object NoOp : DiagnosticWriter { 22 | override fun write(name: String, content: () -> String) {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tools/tracing/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.wire) 19 | alias(libs.plugins.mavenPublish) 20 | alias(libs.plugins.lint) 21 | } 22 | 23 | wire { 24 | kotlin {} 25 | sourcePath { 26 | srcDir(layout.projectDirectory.dir("src/main/proto")) 27 | include("trace.proto") 28 | } 29 | } 30 | 31 | dependencies { 32 | implementation(libs.coroutines.core) 33 | implementation(libs.okhttp) 34 | implementation(libs.okio) 35 | implementation(libs.retrofit) 36 | implementation(libs.retrofit.converters.wire) 37 | } 38 | -------------------------------------------------------------------------------- /tools/tracing/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=tracing 2 | POM_NAME=Foundry Tracing 3 | POM_DESCRIPTION=Foundry Tracing 4 | -------------------------------------------------------------------------------- /tools/tracing/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tools/tracing/src/main/kotlin/foundry/tracing/api/TracingService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.tracing.api 17 | 18 | import foundry.tracing.ListOfSpans 19 | import retrofit2.http.Body 20 | import retrofit2.http.POST 21 | import retrofit2.http.Url 22 | 23 | /** Represents a simple tracing API that accepts [ListOfSpans] proto bodies. */ 24 | internal interface TracingService { 25 | @POST suspend fun sendTrace(@Url url: String, @Body spans: ListOfSpans) 26 | } 27 | -------------------------------------------------------------------------------- /tools/tracing/src/main/kotlin/foundry/tracing/model/SpanIds.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.tracing.model 17 | 18 | import java.util.Locale 19 | import kotlin.random.Random 20 | import okio.ByteString 21 | import okio.ByteString.Companion.encodeUtf8 22 | 23 | /** Creates a new ID for a span or trace. */ 24 | public fun makeId(seed: Int? = null): ByteString = random16HexString(seed).encodeUtf8() 25 | 26 | private const val BYTES_FOR_16_HEX_DIGITS = 8 27 | 28 | /** Returns a [String] of 16 random hexadecimal digits. */ 29 | private fun random16HexString(seed: Int?): String { 30 | val bytes = ByteArray(BYTES_FOR_16_HEX_DIGITS) 31 | val random = seed?.let { Random(seed) } ?: Random.Default 32 | random.nextBytes(bytes) 33 | return bytes.joinToString("") { "%02x".format(Locale.US, it) } 34 | } 35 | -------------------------------------------------------------------------------- /tools/tracing/src/main/kotlin/foundry/tracing/model/Spans.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.tracing.model 17 | 18 | import foundry.tracing.Span 19 | import okio.ByteString 20 | 21 | /** Creates a span. If no trace ID is specified, a random one is generated. */ 22 | @Suppress("LongParameterList") 23 | public fun buildSpan( 24 | name: String, 25 | startTimestampMicros: Long, 26 | durationMicros: Long, 27 | traceId: ByteString = makeId(), 28 | parentId: ByteString = ByteString.EMPTY, 29 | addTags: TagBuilder.() -> Unit = {}, 30 | ): Span { 31 | return Span( 32 | id = makeId(), 33 | name = name, 34 | parent_id = parentId, 35 | trace_id = traceId, 36 | start_timestamp_micros = startTimestampMicros, 37 | duration_micros = durationMicros, 38 | tags = newTagBuilder().apply(addTags), 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /tools/tracing/src/main/kotlin/foundry/tracing/model/TagBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.tracing.model 17 | 18 | import foundry.tracing.KeyValue 19 | import foundry.tracing.ValueType 20 | import okio.ByteString 21 | 22 | public interface TagBuilder : MutableList { 23 | // Scoped functions for creating various types of KeyValues 24 | public infix fun String.tagTo(value: String): KeyValue = 25 | KeyValue(key = this, v_type = ValueType.STRING, v_str = value).also(::add) 26 | 27 | public infix fun String.tagTo(value: Boolean): KeyValue = 28 | KeyValue(key = this, v_type = ValueType.BOOL, v_bool = value).also(::add) 29 | 30 | public infix fun String.tagTo(value: Long): KeyValue = 31 | KeyValue(key = this, v_type = ValueType.INT64, v_int64 = value).also(::add) 32 | 33 | public infix fun String.tagTo(value: Double): KeyValue = 34 | KeyValue(key = this, v_type = ValueType.FLOAT64, v_float64 = value).also(::add) 35 | 36 | public infix fun String.tagTo(value: ByteString): KeyValue = 37 | KeyValue(key = this, v_type = ValueType.BINARY, v_binary = value).also(::add) 38 | } 39 | 40 | public fun newTagBuilder(): TagBuilder = 41 | object : TagBuilder, MutableList by mutableListOf() {} 42 | -------------------------------------------------------------------------------- /tools/tracing/src/main/kotlin/foundry/tracing/reporter/SimpleTraceReporter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.tracing.reporter 17 | 18 | import foundry.tracing.ListOfSpans 19 | import foundry.tracing.api.TracingService 20 | import okhttp3.OkHttpClient 21 | import retrofit2.Retrofit 22 | import retrofit2.converter.wire.WireConverterFactory 23 | import retrofit2.create 24 | 25 | /** Uploads traces to the given [endpoint]. */ 26 | public class SimpleTraceReporter( 27 | private val endpoint: String, 28 | private val client: Lazy, 29 | ) : TraceReporter { 30 | 31 | private val tracingService = 32 | Retrofit.Builder() 33 | .callFactory { client.value.newCall(it) } 34 | .addConverterFactory(WireConverterFactory.create()) 35 | .baseUrl("https://example.com") // Throwaway, URL is always passed directly in 36 | .validateEagerly(true) 37 | .build() 38 | .create() 39 | 40 | override suspend fun sendTrace(spans: ListOfSpans) { 41 | tracingService.sendTrace(endpoint, spans) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tools/tracing/src/main/kotlin/foundry/tracing/reporter/TraceReporter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package foundry.tracing.reporter 17 | 18 | import foundry.tracing.ListOfSpans 19 | 20 | /** Reports a build trace (modeled as list of spans, in protocol buffer format) to some location. */ 21 | public interface TraceReporter { 22 | public suspend fun sendTrace(spans: ListOfSpans) 23 | 24 | public object NoOpTraceReporter : TraceReporter { 25 | override suspend fun sendTrace(spans: ListOfSpans) { 26 | // Do nothing! 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools/version-number/api/version-number.api: -------------------------------------------------------------------------------- 1 | public final class foundry/common/versioning/VersionNumber : java/lang/Comparable { 2 | public static final field Companion Lfoundry/common/versioning/VersionNumber$Companion; 3 | public fun (IIIILjava/lang/String;)V 4 | public synthetic fun (IIIILjava/lang/String;Lfoundry/common/versioning/VersionNumber$AbstractScheme;Lkotlin/jvm/internal/DefaultConstructorMarker;)V 5 | public fun (IIILjava/lang/String;)V 6 | public fun compareTo (Lfoundry/common/versioning/VersionNumber;)I 7 | public synthetic fun compareTo (Ljava/lang/Object;)I 8 | public fun equals (Ljava/lang/Object;)Z 9 | public final fun getBaseVersion ()Lfoundry/common/versioning/VersionNumber; 10 | public final fun getMajor ()I 11 | public final fun getMicro ()I 12 | public final fun getMinor ()I 13 | public final fun getPatch ()I 14 | public final fun getQualifier ()Ljava/lang/String; 15 | public fun hashCode ()I 16 | public fun toString ()Ljava/lang/String; 17 | } 18 | 19 | public final class foundry/common/versioning/VersionNumber$Companion { 20 | public final fun getUNKNOWN ()Lfoundry/common/versioning/VersionNumber; 21 | public final fun parse (Ljava/lang/String;)Lfoundry/common/versioning/VersionNumber; 22 | public final fun scheme ()Lfoundry/common/versioning/VersionNumber$Scheme; 23 | public final fun version (I)Lfoundry/common/versioning/VersionNumber; 24 | public final fun version (II)Lfoundry/common/versioning/VersionNumber; 25 | public static synthetic fun version$default (Lfoundry/common/versioning/VersionNumber$Companion;IIILjava/lang/Object;)Lfoundry/common/versioning/VersionNumber; 26 | public final fun withPatchNumber ()Lfoundry/common/versioning/VersionNumber$Scheme; 27 | } 28 | 29 | public abstract interface class foundry/common/versioning/VersionNumber$Scheme { 30 | public abstract fun format (Lfoundry/common/versioning/VersionNumber;)Ljava/lang/String; 31 | public abstract fun parse (Ljava/lang/String;)Lfoundry/common/versioning/VersionNumber; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /tools/version-number/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Slack Technologies, LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | alias(libs.plugins.kotlin.jvm) 18 | alias(libs.plugins.mavenPublish) 19 | alias(libs.plugins.lint) 20 | } 21 | 22 | dependencies { 23 | testImplementation(libs.junit) 24 | testImplementation(libs.truth) 25 | } 26 | -------------------------------------------------------------------------------- /tools/version-number/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=version-number 2 | POM_NAME=VersionNumber 3 | POM_DESCRIPTION=VersionNumber 4 | --------------------------------------------------------------------------------