I want to create pipeline for building Flutter(Android/iOS) application on Bitbucket easily. Unfortunately, I have not found any article or guide. Is it possible?
Web
image: cirrusci/flutter
pipelines:
branches:
dev:
- step:
name: Run unit tests
script:
- flutter test
- step:
name: Build web
script:
- flutter build web
- step:
name: Deploy to Firebase
deployment: production
script:
- pipe: atlassian/firebase-deploy:1.1.0
variables:
PROJECT_ID: $PROJECT_ID
KEY_FILE: $FIREBASE_KEY_FILE
DEBUG: 'true'
BUILD_DIR: $BUILD_DIR/web/
main:
- step:
name: Run unit tests
script:
- flutter pub get
- flutter test
Android
workflows:
internal-release:
name: Internal Release
environment:
vars:
databaseURL: https://my-app.firebaseio.com
apiKey: asdf
googleAppID: 1:123:android:456
AD_MOB_AD_ID: ca-app-pub-123/456
AD_MOB_APP_ID: ca-app-pub-123~456
FCI_KEYSTORE_PATH: $FCI_BUILD_DIR/android/app/key.jks
FCI_KEYSTORE: Encrypted(xxx)
FCI_KEYSTORE_PASSWORD: Encrypted(xxx==)
FCI_KEY_PASSWORD: Encrypted(xxx==)
FCI_KEY_ALIAS: Encrypted(xxx==)
GCLOUD_SERVICE_ACCOUNT_CREDENTIALS: Encrypted(xxx=)
flutter: stable
xcode: latest
cocoapods: default
triggering:
events:
- push
branch_patterns:
- pattern: '*'
include: true
source: true
cancel_previous_builds: true
when:
changeset:
includes:
- '.'
excludes:
- '**/*.yaml'
- '**/*.yml'
- '**/*.json'
- '**/*.md'
- '**/*.db'
scripts:
- |
# set up key.properties
echo $FCI_KEYSTORE | base64 --decode > $FCI_KEYSTORE_PATH
cat >> "$FCI_BUILD_DIR/android/key.properties" <<EOF
storePassword=$FCI_KEYSTORE_PASSWORD
keyPassword=$FCI_KEY_PASSWORD
keyAlias=$FCI_KEY_ALIAS
storeFile=$FCI_KEYSTORE_PATH
EOF
- |
# set up local properties
echo "flutter.sdk=$HOME/programs/flutter" > "$FCI_BUILD_DIR/android/local.properties"
- cd . && flutter packages pub get
# - cd . && flutter analyze
# - cd . && flutter test
- |
#!/usr/bin/env sh
if ! command -v yq &> /dev/null
then
HOMEBREW_NO_AUTO_UPDATE=1 brew install yq
exit
fi
- cd . && flutter build appbundle --release --build-name=$(yq e .version pubspec.yaml|awk -F+ '{print $1}') --build-number=$PROJECT_BUILD_NUMBER
- |
# generate signed universal apk with user specified keys
android-app-bundle build-universal-apk \
--bundle build/**/outputs/**/*.aab \
--ks $FCI_KEYSTORE_PATH \
--ks-pass $FCI_KEYSTORE_PASSWORD \
--ks-key-alias $FCI_KEY_ALIAS \
--key-pass $FCI_KEY_PASSWORD
artifacts:
- build/**/outputs/**/*.apk
- build/**/outputs/**/*.aab
- build/**/outputs/**/mapping.txt
- flutter_drive.log
publishing:
google_play:
credentials: Encrypted(xxx=)
track: internal
in_app_update_priority: 0
Related
I'm trying to setup test for my backend in Bitbucket Pipelines. But when I set jest.config with jest-mongodb the tests doesn't even start and exit with this error.
The tests are working perfectly fine on local.
Here's my pipeline configuration part that doesn't work:
image: node:18.12.0
definitions:
services:
mongo:
image: mongo
caches:
nodeall: ./node_modules
yarn: /usr/local/share/.cache/yarn
steps:
- step: &Quality-Check
name: Code Quality Checks ๐
script:
- echo Fixing code quality and format ๐
- yarn install
- yarn run lint:fix
- yarn format:fix
- step: &Testing
name: Testing ๐งช
caches:
- nodeall
script:
- yarn install
# - yarn run test
- echo Checking test coverage and generating report ๐
- yarn run test:coverage
artifacts:
- coverage/**
services:
- mongo
pipelines:
branches:
main:
- step:
name: Install dependencies
caches:
- nodeall
script:
- yarn install
- step: *Quality-Check
- step: *Testing
When i search for this error i'm headed to mongo-memory-server but i don't use this package in the code. And couldn't find anything.
I've tried changing anchors, calling mongo service earlier, changing mongo docker image but no success.
I'm expecting that the test and pipeline pass
EDIT
I tried 3 different Jest.configs and realise that the one that was on the project actually use memory-server.
Here are the 3 configs i tried
const { defaults: tsjPreset } = require('ts-jest/presets')
//Custom config with files
// module.exports = {
// preset: 'ts-jest',
// globalSetup: './mongo-memory-server/globalSetup.ts',
// globalTeardown: './mongo-memory-server/globalTeardown.ts',
// setupFilesAfterEnv: ['./mongo-memory-server/setupFile.ts'],
// }
//Config for mongo-memory-db
module.exports = {
preset: '#shelf/jest-mongodb',
transform: tsjPreset.transform,
}
// Basic config
// module.exports = {
// preset: 'ts-jest',
// testEnvironment: 'node',
// setupFiles: ['dotenv/config'],
// }
Rundeck job: When I create data in data workflow step as json list
{
"repo": ["repo1","repo2","repo3"],
"myrepo": "repo4"
}
how can I access the elements in the list from inline script in next step?
#stub.repo[1]#
doesn't work
#stub.myrepo#
works fine
Data Workflow step executed
Script:
echo "value: #stub.repo[1]]#"
echo "value2: #stub.myrepo#"
Result:
value:
value2: repo4
The easiest way to catch that array is to use the jq-JSON mapper log filter plugin in any step like the command step or script step (here are the releases, here is how to install the plugin, and here how Log filters works).
Using this plugin you can use the array positions directly, e.g: ${data.data.0}, ${data.data.1}, etc.
Job definition example with your JSON output for testing.
- defaultTab: summary
description: ''
executionEnabled: true
group: JSON
id: f0d2843f-8de3-4984-a9ae-2fd7ab3963ae
loglevel: INFO
name: test-json-array
nodeFilterEditable: false
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- plugins:
LogFilter:
- config:
filter: .[]
logData: 'true'
prefix: data
type: json-mapper
script: |-
cat <<-END
{
"repo": ["repo1","repo2","repo3"],
"myrepo": "repo4"
}
END
- exec: echo ${data.data.0}
keepgoing: false
strategy: node-first
uuid: f0d2843f-8de3-4984-a9ae-2fd7ab3963ae
Result.
More info about the plugin here.
I am following HashiCorp's learning guide on how to set up GitHub Actions and terraform. All is running great besides the step to update the PR with the Terraform Plan.
I am hitting the following error:
An error occurred trying to start process '/home/runner/runners/2.287.1/externals/node12/bin/node' with working directory '/home/runner/work/ccoe-aws-ou-scp-manage/ccoe-aws-ou-scp-manage'. Argument list too long
The code I am using is:
- uses: actions/github-script#0.9.0
if: github.event_name == 'pull_request'
env:
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `#### Terraform Format and Style ๐\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization โ๏ธ\`${{ steps.init.outcome }}\`
#### Terraform Plan ๐\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`${process.env.PLAN}\`\`\`
</details>
*Pusher: #${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
A clear COPY/Paste from the docs: https://learn.hashicorp.com/tutorials/terraform/github-actions
I have tried with
actions/github-script version 5 and 6 and still the same problem, But when I copy paste the plan all is great. If I do not use the output variable and use some place holder text for the body all is working great. I can see that the step.plan.outputs.stdout is Ok if I print only that.
I will be happy to share more details if needed.
I also encountered a similar issue.
I seem github-script can't give to argument for too long script.
reference:
https://github.com/robburger/terraform-pr-commenter/issues/6#issuecomment-826966670
https://github.community/t/maximum-length-for-the-comment-body-in-issues-and-pr/148867
my answer:
- name: truncate terraform plan result
run: |
plan=$(cat <<'EOF'
${{ format('{0}{1}', steps.plan.outputs.stdout, steps.plan.outputs.stderr) }}
EOF
)
echo "${plan}" | grep -v 'Refreshing state' >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: create comment from plan result
uses: actions/github-script#0.9.0
if: github.event_name == 'pull_request'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `#### Terraform Initialization โ๏ธ\`${{ steps.init.outcome }}\`
#### Terraform Plan ๐\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`\n
${ process.env.PLAN }
\`\`\`
</details>
*Pusher: #${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ inputs.TF_WORK_DIR }}\`, Workflow: \`${{ github.workflow }}\`*`;
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})```
Based on #Zambozo's hint in the comments, this worked for me great:
- name: Terraform Plan
id: plan
run: terraform plan -no-color -input=false
- name: generate random delimiter
run: echo "DELIMITER=$(uuidgen)" >> $GITHUB_ENV
- name: truncate terraform plan result
run: |
echo "PLAN<<${{ env.DELIMITER }}" >> $GITHUB_ENV
echo '[maybe truncated]' >> $GITHUB_ENV
tail --bytes=10000 <<'${{ env.DELIMITER }}' >> $GITHUB_ENV
${{ format('{0}{1}', steps.plan.outputs.stderr, steps.plan.outputs.stdout) }}
${{ env.DELIMITER }}
echo >> $GITHUB_ENV
echo "${{ env.DELIMITER }}" >> $GITHUB_ENV
- name: post plan as sticky comment
uses: marocchino/sticky-pull-request-comment#v2
with:
header: plan
message: |
#### Terraform Plan ๐\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
```
${{ env.PLAN }}
```
</details>
Notably GitHub does have an upper limit on comment size, so this only displays the last 10kB of the plan (showing the summary and warnings).
This also implements secure heredoc delimiting to avoid malicious output escaping.
Also note that the empty lines before and after the triplebacktics in the message are significant to avoid destroying the formatting.
I have a simple string test in my GCP CloudBuild step, but it never works. The step looks like this
steps:
- id: 'branch name'
name: 'alpine'
entrypoint: 'sh'
args:
- '-c'
- |
export ENV=$BRANCH_NAME
if [ $ENV = "master" ]; then
export ENV="test-dev"
fi
echo "***********************"
echo "$BRANCH_NAME"
echo "$ENV"
echo "***********************"
CloudBuild always reports this as sh: master: unknown operand. It's a literal, obviously.
I put the same code into a little sh script and it ran fine as long as I set a value for BRANCH_NAME. CloudBuild definitely supplies a value for BRANCH_NAME and it shows up in the echo "$BRANCH_NAME" while the echo "$ENV" is always empty.
Is there a way to make this string compare work?
When you use linux env var and not substitution variables (or predefined variables), you have to escape the $ with another one
steps:
- id: 'branch name'
name: 'alpine'
entrypoint: 'sh'
args:
- '-c'
- |
export ENV=$BRANCH_NAME
if [ $$ENV = "master" ]; then
export ENV="test-dev"
fi
echo "***********************"
echo "$BRANCH_NAME"
echo "$$ENV"
echo "***********************"
steps:
- task: Docker#2
displayName: Build and Push
inputs:
command: buildAndPush
containerRegistry: dockerRegistryServiceConnection1
repository: contosoRepository
tags: |
tag1
A convenience command called buildAndPush allows for build and push of images to container registry in a single command. See the above snippet
Question:
Do I need to log out from the container registry by adding following task?
- task: Docker#2
displayName: Logout of ACR
inputs:
command: logout
containerRegistry: dockerRegistryServiceConnection1
In my opinion this is not necessary to login or logout.
You may even find an example in documentation without login or logout:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build job
pool:
vmImage: $(vmImageName)
steps:
- task: Docker#2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
So you may wonder what actually login does. If you check a source code you will find that it actually set up DOCKER_CONFIG (The location of your client configuration files.)
export function run(connection: ContainerConnection): any {
var defer = Q.defer<any>();
connection.setDockerConfigEnvVariable();
defer.resolve(null);
return defer.promise;
}
and what logout does ;)
export function run(connection: ContainerConnection): any {
// logging out is being handled in connection.close() method, called after the command execution.
var defer = Q.defer<any>();
defer.resolve(null);
return <Q.Promise<any>>defer.promise;
}
So how does it work?
// Connect to any specified container registry
let connection = new ContainerConnection();
connection.open(null, registryAuthenticationToken, true, isLogout);
let dockerCommandMap = {
"buildandpush": "./dockerbuildandpush",
"build": "./dockerbuild",
"push": "./dockerpush",
"login": "./dockerlogin",
"logout": "./dockerlogout"
}
let telemetry = {
command: command,
jobId: tl.getVariable('SYSTEM_JOBID')
};
console.log("##vso[telemetry.publish area=%s;feature=%s]%s",
"TaskEndpointId",
"DockerV2",
JSON.stringify(telemetry));
/* tslint:disable:no-var-requires */
let commandImplementation = require("./dockercommand");
if (command in dockerCommandMap) {
commandImplementation = require(dockerCommandMap[command]);
}
let resultPaths = "";
commandImplementation.run(connection, (pathToResult) => {
resultPaths += pathToResult;
})
/* tslint:enable:no-var-requires */
.fin(function cleanup() {
if (command !== "login") {
connection.close(true, command);
}
})
Starting build command you will
connect to container registry
run command
close connection (if this is not a login command)
And this is what close connection does:
If registry info is present, remove auth for only that registry. (This can happen for any command - build, push, logout etc.)
Else, remove all auth data. (This would happen only in case of logout command. For other commands, logout is not called.)
Answering your question, you can live without login and logout command.