How to fetch Elixir dependencies per environment? - hex

There are multiple ways to install Elixir dependencies. I wonder what happens in the following cases:
1.
mix deps.get --only prod
What exactly dependencies are being fetched then?
2.
defp deps do
[
{:credo, "~> 0.8", only: ~w(dev)a, runtime: false},
]
end
How only option impact on a particular dependency?
3.
def project do
[
# ...
deps: deps(Mix.env()),
]
end
What is the difference if we specify dependencies like that?
I'm confused a little bit when to use what regarding defining dependencies.

When you write this :
mix deps.get --only prod
It will fetch all dependencies for the prod environment, namely the dependencies where there is no only option, and dependencies where the only option is specified and containing :prod (e.g {:some_dep, "~> 0.8", only: [:prod]})
When you write this :
defp deps do
[
{:some_dep, "~> 0.8"}
]
end
That tells mix to install some_dep in any environment it is run into.
When you write this :
defp deps do
[
{:another_dep, "~> 0.8", only: [:dev]}
]
end
It tells mix to install another_dep only when your environment is dev (MIX_ENV=dev).
If you are in any other environment (e.g. prod), mix deps.get will simply ignore another_dep and won't install it.
writing this :
def project do
[
# ...
deps: deps(Mix.env()),
]
end
will result in ** (CompileError) mix.exs:13: undefined function deps/1 because in your mix.exs, only deps/0 is defined. Now you might tell me why not implement deps(:dev), deps(:prod) and so on... Well, if you read what I explained before, you'll see that it is pointless, since the deps separation for each environment is already taken care of :)

I'm going to address these in reverse order.
using deps(Mix.env) would force you to specify each of your dependencies multiple times if they are used across multiple environments. Something along the lines of
def deps(:dev) do
[
{:ecto, "~> 2.1"}
{:credo, "~> 0.8", runtime: false}
]
end
def deps(:test) do
[
{:ecto, "~> 2.1"}
]
end
I will admit that I do not even know if this would work, but this is adding too much code for something that is already handled for you if you just specify the :only option.
Using :only allows you to specify which environments a dependency should be used in. In your example, {:credo, "~> 0.8", only: [:dev], runtime: false} you are telling mix that the credo package should only be used in the dev environment. If you do not include the :only option, the package will be used in all environments.
$ mix deps.get --only prod will only retrieve the packages relevant to the production environment. From the previous example, the credo package will not be retrieved because you told mix that credo should only be used in the dev environment.

Related

Building library with imports from another library using NX Monorepo

Here is the case. I am using Nrwl NX Monorepo. I have 2 libraries lib-a and lib-b both are publishable libraries created via NX. Now I create a MyClass.ts in lib-a. Naturally under paths in workspace/tsconfig.json paths NX creates an alias to this lib-a ("#workspace/lib-a": ["libs/lib-a/src/index.ts"]). So far so good.
Now we can use this class anywhere within the workspace/monorepo by importing it "import { MyClass } from '#workspace/lib-a';
Unfortunately we can not build lib-b which is importing MyClass. When we try to do it we get the bellow error. So question is how can we build lib-b ?
PS It seems strange that NX monorepo actually don't support such a common scenario linking 2 publishable libs.
"error TS6059: File "d:/workspace/libs/lib-a/src/index.ts" is not under 'rootDir' "d:\workspace\libs\lib-b\src" rootDir is expected to contain all source files"
Try adding
"paths": { "#workspace/*": ["dist/libs/*"] }
into your tsconfig.lib.json files. This should resolve the problem.
Try this solution. Not sure it's official, but in my case it's working well.
3 problems should be resolved:
TypeScript paths
Compiled JS paths
Working directory
First. TypeScript paths is resolved by adding "paths" into workspace/tsconfig.lib.json. NX does it automatically while lib gen. Look answer from Radovan Skendzic.
Second. Problem with compiled JS paths very good described here: Typescript paths not working in an Express project. So you need to install tsconfig-paths into your workspace:
yarn add -D tsconfig-paths
Third. Considering nx run [project]:[target] is working in workspace/ directory you should set CWD to libs/lib-b home directory - to find correct tsconfig.json
So, finally, you have the following executor (add this to your lib-b/project.json) that should work:
"targets": {
"start-dev": {
"executor": "#nrwl/workspace:run-commands",
"options": {
"commands": [
"nodemon -e ts,js --exec ts-node -r tsconfig-paths/register src/index.ts"
],
"cwd": "libs/lib-b"
}
},
...
}
Command to run:
nx run lib-b:start-dev
Don't override "baseUrl" and "paths" in any of child tsconfig!
Put all of your "paths" in tsconfig.base.ts!
Try adding lib-a as an implicit dependency of lib-b, add the line below into the libs/lib-b/project.json file and see what happens:
"implicitDependencies": ["lib-a"]
Running nx graph should show you a graph that should look something like this (do not consider the name of the libraries):
After that you should be able to build both libraries, I hope it works with you as well.

VSTS/Azure DevOps: Auto-Increment NuGet Package Version on Pack

Running the .NET Core Pack task, how do I get the outputted NuGet package version to auto-increment itself?
So, for example, if my current version is 1.0.0, then the next time I call the Pack task, I would like to see 1.0.1.
I'm using environment build variables with Build.BuildNumber and getting outputs at the moment of e.g. 20180913-.2.0, etc. I would like to establish to a more traditional versioning system.
From the docs, the variable Rev:.r is the daily build revision count. The accepted "solution" would lead to one day finishing having a version of 1.0.12, then the next day it will be 1.0.1.
If you want a simple incremental and unique semver, use 1.0.$(BuildID).
$(BuildID) is an internal immutable counter for your builds, and thus far cleaner than $(BuildNumber).
BuildID will always be incrementing - no reset.
Thus after a minor bump, you'd end up having say 1.2.123 becoming 1.3.124.
If you want to perform this task well, this can be done using npm version or similar, such as pubspec_version for Dart or Flutter builds.
- script: npm version $RELEASE_TYPE
where $RELEASE_TYPE is a variable you can set based on build (ie: CI, PR etc), having a value of major, minor, patch, prerelease etc.
- script: npm version $RELEASE_TYPE
condition: startsWith(variables['build.sourceBranch'], 'refs/head/release/')
env:
releaseType: minor
Update: Bump Repo Version and Use In Build (using npm)
To have the repo version update, I ended up including npm version as a DevDependency, with it's precommit hook to bump the project version on any commit.
This technique can be applied to other project types, placing them in a subfolder - although can lead to complications with server OS requirements.
To use this version in your build, add this bash script task, which gets and exports the version as a task variable:
v=`node -p "const p = require('./package.json'); p.version;"`
echo "##vso[task.setvariable variable=packageVersion]$v"
.Net Core Task only version
Unfortunately, no repo-bump.
Workaround 1:
jobs:
- job: versionJob #reads version number from the source file
steps:
- powershell: |
$fv = Get-Content versionFile
Write-Host ("##vso[task.setvariable variable=versionFromFile;isOutput=true]$fv")
displayName: 'version from file'
name: setVersionStep
- job: buildJob # consumes version number, calculates incremental number and set version using assemblyinfo.cs
dependsOn: versionJob
variables:
versionFromFile: $[ dependencies.versionJob.outputs['setVersionStep.versionFromFile'] ] # please note that spaces required between $[ and dependencies
buildIncrementalNumber: $[ counter(dependencies.versionJob.outputs['setVersionStep.versionFromFile'],1) ] #can't use $versionFromFile here
steps:
- powershell: |
Write-Host ($env:versionFromFile)
Write-Host ($env:versionFromFile + '.' + $env:buildIncrementalNumber)
displayName: 'version from file output'
Workaround 2:
This post describes a couple of others, using version-prefix and automatically applying the BuildNumber as a version-suffix.
I may have figured it out. For anyone tearing their hair out, try this:
Pack Task:
Automatic Package Versioning: Use an environment variable
Environment variable: Build.BuildNumber
Then, up in the top menu where you have Tasks, Variables, Triggers, Options, click Options and set:
Build number format: 1.0$(Rev:.r)
Save and queue. This will produce e.g. 1.0.1.
(Please Correct me if I am wrong, or if this does not work long-term.)
If you're just looking to bump the major, minor or revision version number, using counter operator in a variable is a simple and elegant approach. It will automatically add one to the current value.
Here's what I use:
variables:
major: '1'
minor: '0'
revision: $[counter(variables['minor'], 1)] #this will get reset when minor gets bumped. The number after Counter is the seed number (in my case, I started at 1).
app_version: '$(major).$(minor).$(revision)'
If you would like to see a real-world 4-job pipeline that uses this, I have one here https://github.com/LanceMcCarthy/DevReachCompanion/blob/master/azure-pipelines.yml
For me it's enough to set Build number format on Options tab to
$(date:yyyy).$(date:MMdd)$(rev:.r)
and add next build argument:
/p:Version=1.$(Build.BuildNumber) /p:AssemblyVersion=1.$(Build.BuildNumber)
In this case we manage major version manually, but minor version and build number will be set automatically. Easy to understand what version you have deployed.
I am using the ado pipeline and a yaml build. What I've done is utilized the pipeline variables, a counter function, and an inline powershell function to create the version number. It auto-increments and has made the entire build process nice.
Another SO Post about something similar

Hex tasks not found in list of mix tasks

I have a very simple project and I am trying to publish the first version to hex. However I cannot run the hex.publish task.
I get the error ** (Mix) The task "hex.publish" could not be found.
I am following these hex instructions.
My mix.exs file looks like the following.
defmodule Ace.Mixfile do
use Mix.Project
def project do
[app: :ace,
version: "0.2.0",
elixir: "~> 1.0",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
def application do
[
applications: [:logger],
mod: {Ace, []}
]
end
defp deps do
[]
end
end
You might not have hex installed. According to hex usage, please use
mix local.hex
in your terminal or CMD console.
Then mix hex.publish should work.

What does it mean: WARNING! Excluded dependencies (not part of the Hex package)?

When I try to publish a new version of my package on hex, it prints the following warning:
WARNING! Excluded dependencies (not part of the Hex package):
ex_doc
Full text of me running the command:
$ mix hex.publish
Publishing usefulness 0.0.5
Dependencies:
earmark >= 0.0.0
Files:
lib/usefulness.ex
lib/usefulness/stream.ex
lib/usefulness/string.ex
config/config.exs
test/test_helper.exs
test/usefulness_test.exs
mix.exs
README.md
LICENSE
App: usefulness
Name: usefulness
Description: Useful things
Version: 0.0.5
Build tools: mix
Licenses: Apache 2.0
Maintainers: afasdasd
Links:
Github: https://github.com/b-filip/usefulness
Elixir: ~> 1.2
WARNING! Excluded dependencies (not part of the Hex package):
ex_doc
Before publishing, please read Hex Code of Conduct: https://hex.pm/docs/codeofconduct
Proceed? [Yn]
I have no idea what this warning means
Here is what my project.deps in mix.exs consists of:
defp deps do
[
{:ex_doc, "~> 0.11", only: :dev},
{:earmark, ">= 0.0.0"}
]
end
It means you have a dependency in your project that will not be a dependency of your package that you publish to hex. This is normal, projects often have development dependencies for testing, static analysis, generating documentation etc.
Hex lists them so you can have a quick look and make sure you didn't leave out an actual dependency of your code, that would result in a broken package.
ExDoc should most likely not be a dependency of your package. You're good to go. Good work creating your hex package!

Making package a dependency of a new sbt task

When at the sbt CLI I can just type package and everything works fine - two jar files are produced. But I want to make package a dependency of a new task I am creating, so I want to make packaging happen as part of the build script. This is what I have:
lazy val deployTask = TaskKey[Unit]("deploy")
deployTask := { println("deploy happening now!") }
deployTask := {
(deployTask.in(file("."))).value
(Keys.`package` in Compile).value
}
My reading of the documentation tells me that Compile really means file("src/main/scala"), which is not what I want. It seems that I have to put in <Something>. What do I need to put in instead of <Something> to get package to mean what it means when I type it at the CLI?
At the CLI I should be able to:
clean
show deploy
, but unfortunately it does not do the packaging I expect.
These are the projects:
projects
[info] In file:/C:/dev/v2/atmosphere/
[info] atmosphereJS
[info] atmosphereJVM
[info] * root
So it makes sense that when I run package from the CLI the root project is used.
So another way of asking this question might be: "How do I make package work for root from the deploy task I am creating?"

Resources