I am using TeamCity 9.0.2, and I would like to make a template implement another template, or make a build configuration implement more than one template.
Can this be achieved?
This was not available when you asked the question but since Team City 10 you can now use Kotlin to configure your builds and thus your templates.
From this you can make Templates implement other Templates.
I myself have made Templates inherit from other templates to cut down on reconfiguration time and to not have to repeat myself so many times.
open class TheBaseTemplate(uuidIn: String, extIdIn: String, nameIn: String, additionalSettings: Template.() -> Unit) : Template({
uuid = uuidIn
extId = extIdIn
name = nameIn
/* all the other settings that are the same for the derived templates*/
additionalSettings()
})
object DerivedTemplateA : TheBaseTemplate("myUuidA", "myExtIdA", "myNameA", {
params {
param("set this", "to this")
}
})
object DerivedTemplateB : TheBaseTemplate("myUuidB", "myExtIdB", "myNameB", {
params {
param("set this", "to that")
}
})
object Project : Project({
uuid = "project uuid"
extId = "project extid"
name = "project name"
buildType {
template(DerivedTemplateA)
/* the uuid, extId and name are set here */
}
buildType {
template(DerivedTemplateB)
/* the uuid, extId and name are set here */
}
template(DerivedTemplateA)
template(DerivedTemplateB)
})
The above code might be very hard to understand. It will take some time to familiarise yourself with Kotlin, what it does, and how it interfaces with TeamCity. I should point out that some imports are missing.
Additionally, take the example with a pinch of salt. It is a quick example to demonstrate one way of templates implementing other templates. Do not take this example as the definitive way to do things.
Unfortunately, this is currently not possible but already requested for a long time in TW-12153 (maybe you would like to vote for it).
To share several build steps among several build configurations or build configuration templates, I am using meta runners:
A Meta-Runner allows you to extract build steps, requirements and parameters from a build configuration and create a build runner out of them.
This build runner can then be used as any other build runner in a build step of any other build configuration or template.
Although using meta runners works as a workaround for us, editing meta runners is not as convenient as editing a build configuration template (as it usually requires editing the meta runner definition XML file by hand).
Update 2021
As #zosal points out in his answer TeamCity meanwhile provides another way of sharing common build configuration data or logic by means of the Kotlin DSL. The Kotlin DSL is a very powerful tool but may not always fit in your specific scenario. I would recommend to at least give it a try or watch one of the introductory tutorial videos.
Related
I'm working with a large, multi-module Android application, and I'm trying to define a Gradle task that collects the jars of all runtime dependencies. I'm trying something like this in app/build.gradle:
task collectDeps {
doLast {
configurations.releaseRuntimeClasspath.resolvedConfiguration.resolvedArtifacts.each {
// do stuff
}
}
}
I've used this snippet in the past on other Java projects, so I know that it conceptually works; this is just my first time trying it on a project with multiple build types and/or variants.
When run on the Android project, executing this task throws a variant resolution error:
Execution failed for task ':app:collectDeps'.
> Could not resolve all dependencies for configuration ':app:releaseRuntimeClasspath'.
> The consumer was configured to find a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.1.1', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm'. However we cannot choose between the following variants of project :myModule:
- Configuration ':myModule:releaseRuntimeElements' variant android-aar-metadata declares a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm':
- Unmatched attributes:
- Provides attribute 'artifactType' with value 'android-aar-metadata' but the consumer didn't ask for it
- Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it
- Provides a library but the consumer didn't ask for it
- Configuration ':myModule:releaseRuntimeElements' variant android-art-profile declares a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm':
- Unmatched attributes:
- Provides attribute 'artifactType' with value 'android-art-profile' but the consumer didn't ask for it
- Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it
- Provides a library but the consumer didn't ask for it
I've trimmed the error for brevity; there are ~20 variants in total. Note that myModule is a project dependency of the top-level app; if I remove that dependency, the error is the same but comes from a different module.
I should also note here that every other build target works fine; the application is quite mature, and the only change I've made is to add this new task to app/build.gradle. So I assume there's something about the way I'm resolving the dependencies that Gradle doesn't like, but I'm struggling to figure out what, or how to resolve it.
Googling this error is not very helpful; the Gradle documentation is quite vague about exactly how to resolve variants, and the solutions that are provided seem to focus on changing how dependencies are added to the project; but I don't necessarily want to do that, because the build works fine for every other use case.
Ideally, I'd like to be able to force a variant for the resolution specifically within my collectDeps task (in fact, ideally collectDeps would be defined in a plugin). Is this possible to do?
In case it matters, the build is using Gradle 7.2 and v7.1.1 of the Android Gradle Plugin
There may be a better way to handle this, but I ultimately managed to resolve my problem by taking inspiration from Sonatype's open source Nexus scanning plugin. The code looks like (this is in Kotlin, but can be modified to Groovy without much difficulty):
project.allprojects.forEach { project ->
val cfg = project.configurations.releaseRuntimeClasspath
try {
cfg.resolvedConfiguration.resolvedArtifacts.forEach {
// do stuff
}
} catch(e: Exception) {
when(e) {
is ResolveException, is AmbiguousVariantSelectionException -> {
val copyConfiguration = createCopyConfiguration(project)
cfg.allDependencies.forEach {
if(it is ProjectDependency) {
project.evaluationDependsOn(it.dependencyProject.path)
} else {
copyConfiguration.dependencies.add(it)
}
}
copyConfiguration.resolvedConfiguration.resolvedArtifacts.forEach {
// do stuff
}
}
else -> throw(e)
}
}
}
private fun createCopyConfiguration(project: Project): Configuration {
var configurationName = "myCopyConfiguration"
var i = 0
while(project.configurations.findByName(configurationName) != null) {
configurationName += i
i++
}
val copyConfiguration = project.configurations.create(configurationName)
copyConfiguration.attributes {
val factory = project.objects
this.attribute(Usage.USAGE_ATTRIBUTE, factory.named(Usage::class.java, Usage.JAVA_RUNTIME))
}
return copyConfiguration
}
The basic idea is that, if a configuration can't be resolved because of ambiguous variant selection, I create and inject a new parent configuration that specifies the attribute org.gradle.usage='java-runtime'; this is sufficient to disambiguate the variants.
Note that I didn't test this with any other attributes, so it's possible that it could work by setting, for example, the artifactType attribute instead; but my use case is more specifically related to the runtime classpath, so this worked for me
Just starting a new UI testing project, and wonder if there is any best practice to organize the Cypress end-to-end test structure? For example - 1) embedded inside the source (under integration/...) or 2) separate file folder for this project?
Looking for some general guidelines and best practice. Thanks.
It is up to you where you want to keep your test files there is no one single rule (Read this). In case you're writing the tests under integration folder, you don't have to do add any additional configurations as cypress by default searches for the test suite files from inside the integration folder. Also, in case if you decide to write your tests inside some other folder, you can add the required configurations in your cypress.json file and you are good to go.
This is how my folder structure inside integration folder looks like:
Locators contain all locators, so that they can be managed from a single place. Inside that I have a file called selectors.js
Module 1 and Module 2 contains the test suites asper the modules.
Example of the selectors.js file:
export default {
toDoBtn: 'button[type="submit"]',
input: 'form > input',
listItems: 'ul > li'
};
Example of the test suite:
import selectors from '../../integration/Locators/selectors.js';
describe('Add Items in todo list and Validate', () => {
before(function () {
cy.pageIsLoaded(selectors.toDoBtn) //This is a custom command
})
beforeEach(function () {
cy.fixture('testdata.json').then(function (testdata) {
this.testdata = testdata
})
})
it('Add Items', function () {
cy.addItems(selectors, this.testdata) //This is a custom command
})
it('Validate Added Items', function () {
cy.validateItems(selectors, this.testdata) //This is a custom command
})
})
It's obviously a matter of opinion, but here's what guides me
end-to-end tests are not as tightly coupled to source files as unit tests, so it makes sense to place them in a separate folder structure
you tend to work on a bunch of source files to build a feature, then write an e2e to test that feature, which points to a feature hierarchy
Cypress allows for non-standard test location, but be wary as third party plugins (which you may add late in the project) may not
Cypress commands are quite expressive, so it does not make sense to write custom commands for everything (simple is better than complex)
named selectors are expressive, but keep them local (inside the spec file) as they will differ subtly from one page to another. Better still, ditch selectors and use a search tool like cypress-get-it
We're currently using FHIR.net library(STU3). The FHIR Server from which we are receiving information has added a practitionerRole property to the Practitioner. Thus when Reading a Practitioner, we get the following Exception:
Encountered unknown member 'practitionerRole' while de-serializing (at path 'line 1, pos 2') in Hl7.Fhir.Rest.HttpToEntryExtensions.parseResource(String bodyText, String contentType, ParserSettings settings, Boolean throwOnFormatException)
The only solution I could think of is to add a practitionerRole property in the Model\Generated\Practitioner.cs class that would go like that:
[FhirElement("practitionerRole", InSummary = true, Order = 115)]
[Cardinality(Min = 0, Max = -1)]
[DataMember]
public List<Hl7.Fhir.Model.PractitionerRole> PractitionerRole
{
get { if (_PractitionerRole == null) _PractitionerRole = new List<Hl7.Fhir.Model.PractitionerRole>(); return _PractitionerRole; }
set { _PractitionerRole = value; OnPropertyChanged("PractitionerRole"); }
}
private List<Hl7.Fhir.Model.PractitionerRole> _PractitionerRole;
Is there any other solution than that? If so, which one?
Thank you in advance
It sounds like you're talking to a DSTU2 server. You'll need some sort of a conversion layer between your system and theirs.
As stated by FHIR employees in https://sea-region.github.com/standardhealth/shr_spec/issues/187 , DSTU2 and STU3 are two different versions of FHIR standard. If you check their last commits (https://www.nuget.org/packages?q=Fhir) as in August 2019, you will see they are maintaining both standards. That is probably due to the hospitals using STU3 version and do not want to adapt to the new version of FHIR, which is DSTU2.
The problem arises when you want to reach a class, let's say Patient, that coexists in two versions. Compiler can not decide which "Patient" class you refer to.
Normally, you could specialize using imports or predescription such as :
Hl7.Fhir.Model.Patient p = new Hl7.Fhir.Model.Patient();
BUT, Patient classes in both versions are described as Hl7.Fhir.Model.Patient. Their namespace is "Hl7.Fhir.Model" and their class name is "Patient".
Normally, you could workaround using keyword:
extern alias
BUT, since model classes in FHIR are read only, you can not use both versions in same project.
You need to uninstall unwanted FHIR version and install wanted version. To do these in Visual Studio,
go to Solution Manager> right click on "Manage Nuget Packages" > Search "Fhir" > uninstall unwanted FHIR version > install wanted version
You can also follow the unanswered question below:
C# T4 Template equivalent for "extern alias"
This is my repository in github: https://github.com/joedayz/lazybones-templates/
I used processTemplates according with the documentation
processTemplates 'build.gradle', props
processTemplates 'gradle.properties', props
processTemplates 'src/main/java/*.java', props
processTemplates 'settings.gradle', props
I request the user this information:
props.project_megaproceso = ask("Define value for 'megaproceso' [megaproceso]: ", "megaproceso", "megaproceso")
props.project_macroproceso = ask("Define value for 'macroproceso' [macroproceso]: ", "macroproceso", "macroproceso")
props.project_proceso = ask("Define value for 'proceso' [proceso]: ", "proceso", "proceso")
megaproceso2, macroproceso, proceso are directories or part of file names in my template.
How do I change the names of the unpacked directories and files? The code is in my github.
The post-install scripts for Lazybones currently have full access to both the standard JDK classes and the Apache Commons IO library, specifically to aid with file manipulation.
In this specific case, you can either use File.renameTo() or FileUtils.moveFile/Directory(). For example:
def prevPath = new File(projectDir, "megaproceso2-macroproceso-proceso.ear")
prevPath.renameTo(new File(
projectDir,
"${props.megaproceso}-${props.macroproceso}-${props.processo}.ear"))
The projectDir variable is one of several properties injected into the post-install script. You can find a list of them in the Template Developers Guide.
I think the main advantage of FileUtils.moveFile() is that it works even if you're moving files across devices, but that's not necessary here. Also note that you have to explicitly import the classes from Commons IO if you want to use them.
How to use Stanford parser from GATE embedded (using GATE through Java code). I currently use GATE_Developer_7.0 on my machine; i know that there is plugin for Stanford Parser in GATE but don't know how to use it using java code.
Thanks
The usual approach we always recommend for GATE Embedded is to build up your pipeline using GATE Developer, test it out and get it debugged by processing sample documents in the GUI. Once you're happy with the application, use "save application state" or "export for GATECloud.net" to produce a saved state that you can then load in your embedded code using the PersistenceManager. This will automatically ensure that all the necessary plugins are loaded and is generally much simpler and less error-prone than trying to build up your pipeline by hand in your code.
The BatchProcessApp example on the GATE website shows how you can load a saved application with the PersistenceManager, essentially it's
Gate.init(); // always the first thing you do
CorpusController controller = (CorpusController)PersistenceManager
.loadObjectFromFile(new File("/path/to/application.xgapp"));
Corpus corpus = Factory.newCorpus("myCorpus");
controller.setCorpus(corpus);
then for each document you want to process
Document doc = Factory.newDocument(....);
corpus.add(doc);
try {
controller.execute();
// code here to do stuff with the annotated document, e.g. extract
// annotations/features
} finally {
corpus.clear();
Factory.deleteResource(doc);
}