Skip to content

Commit

Permalink
feat(manager/mix): fix mix and git WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
1oglop1 committed Nov 24, 2024
1 parent cae7424 commit bd957d2
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 30 deletions.
51 changes: 50 additions & 1 deletion lib/modules/manager/mix/__fixtures__/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ defmodule MyProject.MixProject do
end

defp deps() do
[ #{:broadway_dashboard, "~> 0.2.2"},
[
#{:broadway_dashboard, "~> 0.2.2"},
#{:broadway_dashboard, "~> 0.2.2"},
# {:broadway_dashboard, "~> 0.2.2"},
# {:broadway_dashboard, "~> 0.2.2"},
Expand All @@ -32,6 +33,54 @@ defmodule MyProject.MixProject do
optional: true},
{:hammer_backend_redis, "~> 6.1"},
{:public, "== 1.6.14"},


# Basic Git URL
# Fetches the latest commit from the default branch
{:basic_dep, git: "https://github.com/user/repo.git"},

# Git URL with a specific branch
# Fetches the latest commit from the specified branch
{:branch_dep, git: "https://github.com/user/repo.git", branch: "main"},

# Git URL with a specific commit (ref)
# Fetches the exact commit specified
{:commit_dep, git: "https://github.com/user/repo.git", ref: "abc123"},

# Git URL with a specific commit and manager: :make
# Specifies that this dependency should be built using make instead of mix
{:make_dep, git: "https://github.com/user/repo.git", ref: "abc123", manager: :make},

# Git URL with a specific tag
# Fetches the exact commit pointed to by the tag
{:tag_dep, git: "https://github.com/user/repo.git", tag: "v1.0.0"},

# Git URL with a specific tag and compile path
# Specifies a subdirectory to compile the project from
# {:compile_dep, git: "https://github.com/user/repo.git", tag: "v1.0.0", compile: "src"},

# Git URL with a specific branch and app name
# Sets app to false, meaning this dependency won't be treated as an OTP application
# {:app_dep, git: "https://github.com/user/repo.git", branch: "dev", app: false},

# Git URL with a specific commit and override in umbrella
# Allows this dependency to override others in an umbrella project
# {:override_dep, git: "https://github.com/user/repo.git", ref: "abc123", override: true},

# Git URL with a specific tag and runtime: false
# Indicates this dependency is only needed at compile time, not at runtime
# {:compile_time_dep, git: "https://github.com/user/repo.git", tag: "v1.0.0", runtime: false},

# Git URL with a specific branch and only: :test
# Specifies this dependency is only needed in the test environment
# {:test_dep, git: "https://github.com/user/repo.git", branch: "test", only: :test},

# Git URL with a specific tag and optional: true
# Marks the dependency as optional, allowing the project to compile even if it's missing
# {:optional_dep, git: "https://github.com/user/repo.git", tag: "v1.0.0", optional: true},



]
end
end
5 changes: 5 additions & 0 deletions lib/modules/manager/mix/__fixtures__/mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@
"hammer_backend_redis": {:hex, :hammer_backend_redis, "6.1.5", "344dbbf6610d205760ec37e2848bff2aab5a2de182bb5cdaa72cc2fd19d74535", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "19c205c8de0e2e5817f2250100281c58e717cb11ff1bb410bf661ee78c24e79b"},
"public": {:hex, :public, "1.6.14", "344dbbf6610d205760ec37e2848bff2aab5a2de182bb5cdaa72cc2fd19d74535", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "19c205c8de0e2e5817f2250100281c58e717cb11ff1bb410bf661ee78c24e79b"},
"a_transient_dependency": {:hex, :a_transient_dependency, "1.6.14", "344dbbf6610d205760ec37e2848bff2aab5a2de182bb5cdaa72cc2fd19d74535", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "19c205c8de0e2e5817f2250100281c58e717cb11ff1bb410bf661ee78c24e79b"}
"basic_dep": {:git, "https://github.com/user/repo.git", "d2a084a3d2f2ab27b76192c71ccf0cfbd9276a5c", []},
"branch_dep": {:git, "https://github.com/user/repo.git", "3a9c2168ee9f35642aa378d3dc2a8b8e5265e6c2", [branch: "main"]},
"commit_dep": {:git, "https://github.com/user/repo.git", "abc1239d7a49d7b7aea5a31a70431f2db4e67ac0", [ref: "abc123"]},
"make_dep": {:git, "https://github.com/user/repo.git", "abc1239d7a49d7b7aea5a31a70431f2db4e67ac0", [ref: "abc123"]},
"tag_dep": {:git, "https://github.com/user/repo.git", "7e1ff6c2e62c7708db564f25b4b13944f6df8d4d", [tag: "v1.0.0"]},
}
79 changes: 73 additions & 6 deletions lib/modules/manager/mix/extract.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { Fixtures } from '../../../../test/fixtures';
import { GlobalConfig } from '../../../config/global';
import { extractPackageFile } from '.';
import { codeBlock } from 'common-tags';
import { fs } from '../../../../test/util';
import { valid } from 'semver';

jest.mock('../../../util/fs');

const mixExs = Fixtures.get("mix.exs")
const mixLock = Fixtures.get("mix.lock")

describe('modules/manager/mix/extract', () => {
beforeEach(() => {
GlobalConfig.set({ localDir: '' });
});
// beforeEach(() => {
// GlobalConfig.set({ localDir: '' });
// });

describe('extractPackageFile()', () => {
it('returns empty for invalid dependency file', async () => {
Expand All @@ -14,7 +22,7 @@ describe('modules/manager/mix/extract', () => {
});

it('extracts all dependencies when no lockfile', async () => {
const res = await extractPackageFile(Fixtures.get('mix.exs'), 'mix.exs');
const res = await extractPackageFile(mixExs, 'mix.exs');
expect(res?.deps).toEqual([
{
currentValue: '~> 0.8.1',
Expand Down Expand Up @@ -97,8 +105,8 @@ describe('modules/manager/mix/extract', () => {

it('extracts all dependencies and adds the locked version if lockfile present', async () => {
// allows fetching the sibling mix.lock file
GlobalConfig.set({ localDir: 'lib/modules/manager/mix/__fixtures__' });
const res = await extractPackageFile(Fixtures.get('mix.exs'), 'mix.exs');
fs.readLocalFile.mockResolvedValue(mixLock);
const res = await extractPackageFile(mixExs, 'mix.exs');
expect(res?.deps).toEqual([
{
currentValue: '~> 0.8.1',
Expand Down Expand Up @@ -190,5 +198,64 @@ describe('modules/manager/mix/extract', () => {
},
]);
});
it('skips git dependencies that are not semver for mix.exs',async()=>{

const lock = codeBlock`
%{
"basic_dep": {:git, "https://github.com/user/repo.git", "d2a084a3d2f2ab27b76192c71ccf0cfbd9276a5c", []},
"branch_dep": {:git, "https://github.com/user/repo.git", "3a9c2168ee9f35642aa378d3dc2a8b8e5265e6c2", [branch: "main"]},
"commit_dep": {:git, "https://github.com/user/repo.git", "abc1239d7a49d7b7aea5a31a70431f2db4e67ac0", [ref: "abc123"]},
"make_dep": {:git, "https://github.com/user/repo.git", "abc1239d7a49d7b7aea5a31a70431f2db4e67ac0", [ref: "abc123"]},
"non_semver_tag": {:git, "https://github.com/user/repo.git", "7e1ff6c2e62c7708db564f25b4b13944f6df8d4d", [tag: "non-semver-tag]},
}
`

fs.readLocalFile.mockResolvedValue(lock);
const content = codeBlock`
defp deps() do
[
{:basic_dep, git: "https://github.com/user/repo.git"},
{:branch_dep, git: "https://github.com/user/repo.git", branch: "main-not-semver"},
{:commit_dep, git: "https://github.com/user/repo.git", ref: "abc123notsemver"},
{:make_dep, git: "https://github.com/user/repo.git", ref: "abc123", manager: :make},
{:non_semver_tag, git: "https://github.com/user/repo.git", tag: "not-semver-tag"},
{:semver_tag, git: "https://github.com/user/repo.git", tag: "v0.1.0"},
]
end
`
const res = (await extractPackageFile(content, 'mix.exs'))!.deps
const skipFor = ['basic_dep','branch_dep','commit_dep','make_dep','non_semver_tag']
const skipped = res.filter(x=>x.skipReason)
expect(skipped).toHaveLength(5)
expect(res.every(x=>skipFor.includes(x.depName!)))
expect(skipped.every(x=>x.skipReason==='unsupported'))
expect(res).toHaveLength(6)
} );
it('skips git dependencies that are not semver for mix.lock',async()=>{
const content = codeBlock`
%{
"basic_dep": {:git, "https://github.com/user/repo.git", "d2a084a3d2f2ab27b76192c71ccf0cfbd9276a5c", []},
"branch_dep": {:git, "https://github.com/user/repo.git", "3a9c2168ee9f35642aa378d3dc2a8b8e5265e6c2", [branch: "main"]},
"commit_dep": {:git, "https://github.com/user/repo.git", "abc1239d7a49d7b7aea5a31a70431f2db4e67ac0", [ref: "abc123"]},
"make_dep": {:git, "https://github.com/user/repo.git", "abc1239d7a49d7b7aea5a31a70431f2db4e67ac0", [ref: "abc123"]},
"non_semver_tag": {:git, "https://github.com/user/repo.git", "7e1ff6c2e62c7708db564f25b4b13944f6df8d4d", [tag: "non-semver-tag]},
"semver_tag": {:git, "https://github.com/user/repo.git", "7e1ff6c2e62c7708db564f25b4b13944f6df8d4d", [tag: "v1.0.0"]},
}
`
const res = (await extractPackageFile(content, 'mix.lock'))!.deps
const skipFor = ['basic_dep','branch_dep','commit_dep','make_dep','non_semver_tag']
const skipped = res.filter(x=>x.skipReason)
expect(skipped).toHaveLength(5)
expect(res.every(x=>skipFor.includes(x.depName!)))
expect(skipped.every(x=>x.skipReason==='unsupported'))
expect(res).toHaveLength(6)
} );
it('things', async ()=>{
const x = !!valid("v1.2.3");
console.log(x)
return x
});
});

});
89 changes: 66 additions & 23 deletions lib/modules/manager/mix/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { newlineRegex, regEx } from '../../../util/regex';
import { GitTagsDatasource } from '../../datasource/git-tags';
import { GithubTagsDatasource } from '../../datasource/github-tags';
import { HexDatasource } from '../../datasource/hex';
import * as semver from '../../versioning/semver';
import type { PackageDependency, PackageFileContent } from '../types';
import {api as gitVersioning} from '../../versioning/git'

const depSectionRegExp = regEx(/defp\s+deps.*do/g);
const depMatchRegExp = regEx(
Expand All @@ -14,11 +16,11 @@ const gitRegexp = regEx(/git:\s*"(?<value>[^"]+)"/);
const githubRegexp = regEx(/github:\s*"(?<value>[^"]+)"/);
const refRegexp = regEx(/ref:\s*"(?<value>[^"]+)"/);
const branchOrTagRegexp = regEx(/(?:branch|tag):\s*"(?<value>[^"]+)"/);
const organizationRegexp = regEx(/organization:\s*"(?<value>[^"]+)"/);
const organizationRegexp = regEx(/organization:\s*"(?<value>[^"]+)"/); // HEX only
const commentMatchRegExp = regEx(/#.*$/);
const lockedVersionRegExp = regEx(
/^\s+"(?<app>\w+)".*?"(?<lockedVersion>\d+\.\d+\.\d+)"/,
);
/^\s+"(?<app>\w+)".*?"(?<lockedVersion>v?\d+\.\d+\.\d+)"/,
); // wrong regex for semver v#.#.#

export async function extractPackageFile(
content: string,
Expand Down Expand Up @@ -46,26 +48,21 @@ export async function extractPackageFile(
const organization = organizationRegexp.exec(opts)?.groups?.value;

let dep: PackageDependency;

if (git ?? github) {
dep = {
depName: app,
currentDigest: ref,
currentValue: branchOrTag,
datasource: git ? GitTagsDatasource.id : GithubTagsDatasource.id,
packageName: git ?? github,
};
} else {
dep = {
depName: app,
currentValue: requirement,
datasource: HexDatasource.id,
packageName: organization ? `${app}:${organization}` : app,
};
if (requirement?.startsWith('==')) {
dep.currentVersion = requirement.replace(regEx(/^==\s*/), '');
}
}
dep = handleGitDependecy({
branchOrTag,
git,
github,
ref,
}) ?? {
currentValue: requirement,
datasource: HexDatasource.id,
packageName: organization ? `${app}:${organization}` : app,
// this was the original
currentVersion: requirement?.startsWith('==')
? requirement.replace(regEx(/^==\s*/), '')
: undefined,
};
dep.depName = app;

deps.set(app, dep);
logger.trace({ dep }, `setting ${app}`);
Expand All @@ -85,6 +82,9 @@ export async function extractPackageFile(
if (groups?.app && groups?.lockedVersion) {
const dep = deps.get(groups.app);
if (!dep) {
logger.debug(
`${groups.app} exists in deps() but is missing in lockfile.`,
);
continue;
}
dep.lockedVersion = groups.lockedVersion;
Expand All @@ -101,3 +101,46 @@ export async function extractPackageFile(
lockFiles: lockFileContent ? [lockFileName] : undefined,
};
}

function handleGitDependecy(args: {
// app: string,
ref?: string;
branchOrTag?: string;
git?: string;
github?: string;
}): PackageDependency | undefined {
const { ref, branchOrTag, git, github } = args;

// not a git dep
if (!(git ?? github)) return undefined;

// const containsManager = app === 'make_dep' // TODO add supporting regex
// let skipReason: SkipReason = !(ref || branchOrTag) || containsManager ? undefined: "unsupported"
// one of branch, ref or tag
const isSemverVersion = semver.isVersion((ref ?? branchOrTag)!);

const dep: PackageDependency = {
// skipReason: "git-plugin",

currentValue: branchOrTag,
datasource: git ? GitTagsDatasource.id : GithubTagsDatasource.id,
packageName: git ?? github,
};

if (isSemverVersion && ref) { // ref is semver tag
dep.currentValue = ref;
dep.versioning = semver.id;
} else if (isSemverVersion) { // ref is semver branch
dep.currentValue = branchOrTag;
dep.versioning = semver.id;
} else if(gitVersioning.isVersion(ref)) { // ref is SHA
dep.currentDigest = ref
} else {
// dep.skipReason = 'unsupported';
dep.warnings = [{message:"hahsa",topic:"topic"}]
dep.currentValue = branchOrTag
dep.currentDigest = ref
}

return dep;
}

0 comments on commit bd957d2

Please sign in to comment.