Is there a way in Jenkins to not only read but also write global parameters from a job?
To achieve reading I used this plugin: Global Variable String Parameter
However, I have found nothing yet to support write access to global parameters. I see that this could be seen critical as it can create race conditions.
What I actually want to do:
I have two Jenkins Jobs - each publishing my Android APK to the Google Play Store but into different release tracks (e.g. "release" and "beta").
I want the build number to be incremented automatically via gradle. But gradle needs to access the build number of the last build from anywhere outside of my VCS (to avoid requiring another commit). I want to guarantee that the build numbers are chronologically in order. Hence, keeping a separate build number for every Jenkins Job (e.g. in a "version.properties" file) is not a solution.
A plan B could be to switch to a date encoded build number. But I'm curious if there is a way for the incremental approach.
you can use "version.properties" file located in the jenkins workspace and not the job workspace.
1- inject environment variable from the file
2- build the apk
3- increment the version from the shell script
version=$(($version+1))
echo version=$version > ${JENKINS_HOME}/workspace/module.properties
Related
I have set build-related settings in $HOME/.gradle/gradle.properties
Although the build process is the same, it is a situation where I have to change the setting of $HOME/.gradle/gradle.properties for each runner of github actions because of other restrictions.
Therefore, I want to create $HOME/.gradle/gradle.properties for each runner. Can I change the path for each runner?
(It is a structure in which several runners are installed in one machine.)
I need to do a configuration, with android and iOS that when doing the deployment accepts the change, it is configured with firebase, which when I create a project and configure it, gives me a file google-services.json and in iOS a GoogleService-Info.plist, what I need is that for different environments, which are created in firebase, for example I would like to add the file google-service.json for the production environment, but if it is in staging, use the google settings- service-staging.json and so on.
So when you call the change in the project's build.gradle, pass it a global variable (I don't know if it can really be done)
def servicesJSON = file('google-services'+enviroment+'.json')
Something like this, so that depending on what comes to you, you know in what environment they are deploying...
For flavors (stage,prod) you should place separate json files in corresponding directories for android project.
e.g. https://android.jlelse.eu/how-to-use-different-google-services-json-file-with-multiple-product-flavors-android-7853d98dd6c0
Taking inspiration from The Twelve-Factor App: V. Build, release, run, I'm working on updating our CI/CD pipeline with these three distinct steps in mind for an app being built with react-native-web.
Specifically, I want to:
Build: generate an environment agnostic artifact of the code for each platform (web, android, ios)
Release: take an artifact and a config file (API URLs, API keys, debug settings, etc), and release to each platform
This is trivial for web, which is what The Twelve-Factor App had in mind. My question is how do I read a config file on mobile platforms and how can I incorporate this with react-native-web build artifacts? Does my artifact need to contain all of the source code and dependencies so I can pull in the config at release time and build then?
Ideally, each artifact would contain code compiled for each platform that somehow knows how to pull in a config file and do something with it. Next best would be to have the source code for each platform that I can compile with a config file at release time. Third best is have a way to give each distribution enough information at release time so it can request the config at runtime.
Full disclosure, I know nothing about building and deploying mobile apps so I apologize if there is an obvious solution for this!
It's similar for Android. Once the build binary is created it's immutable.
So unfortunately that negates option #1. We can't do anything else with the binary once we build it.
I think for react-native option two is the best approach.
Essentially you'll need to build the apps at release time once you have resolved what your configs need to be. That avoids any overhead of loading stuff at runtime in option #3 and still matches nicely to Twelve Factor. You'll still have a mobile binary that matches the same configuration as your release type.
For actually reading those values, you can just drop the config file into the project's root and we can help with the setup to pull them in.
I'll be glad to discuss those details if you'd like.
UPDATE:
Anything iOS does we can do (almost as well)
Current build tools compile all code into bytecode classes.dex and compress all resrouces into resrouces.arc but res/raw is left untouched.
This gives us a place to inject our files.
From there, the app will be able to read and parse at runtime.
For iOS, the build and (non-App Store) release process works like this at a high level:
Archive your project in Xcode, which results in an .xcarchive artifact.
Export your archive which signs and generates an .ipa file.
Either host this .ipa file yourself (with some additional metadata files) or upload it to a service like HockeyApp for distribution.
There are a few ways that you can manage config inside an Xcode project. One fairly common and straightforward way is to use the info.plist file to store custom keys and values. The app can then look up and use these values at runtime.
In the scenario you describe, it sounds like you want to be able to inject specific config values after step 2 but before step 3. Fortunately, the .ipa file generated during step 2 can be extracted, which will reveal a Payload folder containing an .app file. This file can be inspected, and inside you will see, amongst other things, the app's Info.plist. Modifying this file will allow for injection of whatever config values you want to set.
This will save needing to manage configs inside the Xcode project, and creating a separate archive for each configuration of the app. However what this doesn't solve is step 3. You are still going to need to distribute each configured .ipa file separately.
I am preparing a white label application (called product later in this post) and I want to set up a very good architecture. This will easily and quickly set up a new client by changing the design, activating features...
I have several servers (dev, pre-prod, prod) so the flavorDimensions server are present in the product and the flavorDimension client is on the client side.
I thought of this solution:
Set up one git per customer and one git for the product.
Clients will have access to the product code by git submodule. This allows me to separate the specific code from my client and the source code of the product.
Git -> Client 1
Submodule -> Product v1
Git -> Client 2
Submodule -> Product v1.2
...
Git -> Product v1.4
But I have a problem how to run it all correctly. The use of flavorDimensions client is hard because I need to make a copy-paste (with gradle) from my submodule to the app module before the build.
The generation of this structure breaks Gradle because its need to be synced every time. (Always Sync Now flag on Android Studio)
So I ask myself, is a good architecture or not ? What do you think ?
Or do you have other ideas and how to implement them?
Thanks for your support.
Hmm interesting take on it.
I have done similar things, but not quite like that. I use flavors for the deltas only. For example, themes, skins, app_icons, and Strings.xml. Maybe a few variations in layout or activities, but do my best to keep it generically served to minimize the maintenance of the code for various customer deployments as each additional flavor slows down the CI process significantly.
However, one key difference in what you are doing is you are not building a platform (aka everyone uses the same code GIT repo and API Server per se, you are building stand alone applications to supply full code and everything else to individual customers.
This sounds like it could be a maintenance nightmare, but if your situation requires that customer's get access to the code base for their product flavor, then I guess it makes sense. Not sure why they would get access to the code though as it is your product you are reskinning for customers right?
At any rate, you aren't asking for me to ask your reasoning haha, you are asking about architectural solutions. So here is my thoughts.
Make a task that copies the respective folders into a new module structure exactly like the modules you have now, but with changes to the package name so that they all slightly differ, then run your GIT push. You can run bash files from Gradle, so you can either write scripts and execute them from relative paths or you can write it directly in your Gradle file itself.
So I would update my Gradle to have separate dependency file like libs.gradle
->Put dependencies in that file like ext.libs {gson:"com.whatever:version"}
->apply from ../libs.gradle
->dependencies { libs.gson, etc..}
So i would assume your build task would do
->Create a new Module from All Source by copying files properly with new names if necessary to rename
->if using maven server, then deploy aar or jar for compiled new module
->Create a new dynamic Gradle file libs.gradle to replace current libs.gradle file that is updated source pointer to deployed artifacts
or created module
->run gradlesync, when complete run assembleRelease, then you can do your git push etc..
All of this can be synchronized and done from terminal and localized into commands. Flavors may not help a ton in this area as they are part of the build process so you kinda need pre build processes which you can create tasks to do pre-build, but the key is the packaging of dependencies and updating your libs.gradle file and making sure that you replace it per flavor. Or if you have fixed flavors you can just make a specific libs.gradle for each flavor and update it based on the compiled dependencies.
I don't know your overall picture, but it is all doable. Hope that helps. Goodluck.
I have the following problem wherein:
I have multiple product flavors In my Android project. {Say, Dev and Production}
I have a CI in place ,Jenkins to build my projects and make releases to different teams.
I have an asset file which is Flavor Specific, but is dependant upon the data that exists on a server. Example a json for a list of companies.
This list is different on Dev vs Production.
Since this is a huge json, we include it in our assets folder. Downloading this json at runtime will not allow the user to use the app quickly at least the first time.
Currently at compile time in Jenkins we wget/download this json and write them to our assets folder. To get the latest assets for that environment/product flavor at compile time.
This wget is written as a shell command in my Jenkins. After a successful wget we run the gradle assembleDev, repeat step 6 and then gradle assembleProduction
Now the problem lies with the fact that I am not comfortable having this wget in Jenkins for 2 reasons.
1) The Environment specific asset/json is not available on developer machines for their local testing, so they need to be aware all the time.
2) The code in Jenkins is obviously not present in my VCS/Git. Which I am not comfortable with.
What could be the possible solutions?
PS:- To put things in perspective, I have 22 Product Flavors and 8 such jsons.
In our production setup, we currently parse a Google Sheets document to find variables and write them into our strings.xml file.
So a some-what similar scenario.
We do this in our Gradle build script, that calls a Java class, that then executes the network logic, returns the downloaded data to Gradle, which writes it into the correct strings.xml file.
This means all of our code is present in our git repository and can be handled as such.
I find this to be quite elegant.
Note: We currently don't differentiate between product flavors, but that is easily done with a few extra lines in Gradle.