Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework Miniforge inputs #138

Merged
merged 5 commits into from
Dec 31, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/example-10.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ jobs:
id: setup-miniconda
with:
environment-file: etc/example-environment.yml
miniforge-variant: Miniforge3
miniforge-version: ${{ matrix.miniforge-version }}
- run: |
conda info
Expand Down Expand Up @@ -68,9 +67,11 @@ jobs:
- os: macos
environment-file: etc/example-empty-channels-environment.yml
miniforge-variant: Mambaforge-pypy3
miniforge-version: 4.9.2-4
- os: windows
environment-file: etc/example-explicit.Windows.conda.lock
condarc-file: etc/example-condarc.yml
miniforge-version: 4.9.2-4
miniforge-variant: Mambaforge
steps:
- uses: actions/checkout@v2
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,10 @@ jobs:
id: setup-miniconda
with:
environment-file: etc/example-environment.yml
miniforge-variant: Miniforge3
miniforge-version: ${{ matrix.miniforge-version }}
```

In addition to `Miniforge3` with `conda` and `CPython` for each
In addition to `Miniforge3`, with `conda` and `CPython`, for each
of its many supported platforms and architectures, additional variants including
`Mambaforge` (which comes pre-installed `mamba` in addition to `conda` on all platforms)
and `Miniforge-pypy3`/`Mamabaforge-pypy3` (which replace `CPython` with `pypy3`
Expand Down
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ inputs:
description:
"If provided, this variant of Miniforge will be downloaded and installed.
Currently-known values:
- Miniforge3
- Miniforge3 (default)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bollwyvl we should add the default here no?

    required: false
    default: "Miniforge3"	    

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll take a look...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6689c3c points out that we still have some incidental coupling between the various inputs... it still seems manageable, but i wish i could think of a way to simply express these constraints more declaratively... adding something like JSON schema could do, but more deps...

- Miniforge-pypy3
- Mambaforge
- Mambaforge-pypy3
Expand All @@ -31,7 +31,7 @@ inputs:
miniforge-version:
description:
"If provided, this version of the given Miniforge variant will be downloaded
and installed instead of the latest.
and installed.
Visit https://github.com/conda-forge/miniforge/releases/ for more information
on available versions"
required: false
Expand Down
8 changes: 3 additions & 5 deletions dist/delete/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1161,7 +1161,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PYTHON_SPEC = exports.WIN_PERMS_FOLDERS = exports.PROFILES = exports.ENV_VAR_CONDA_PKGS = exports.CONDA_CACHE_FOLDER = exports.CONDARC_PATH = exports.BOOTSTRAP_CONDARC = exports.FORCED_ERRORS = exports.IGNORED_WARNINGS = exports.MAMBA_SUBCOMMANDS = exports.KNOWN_EXTENSIONS = exports.BASE_ENV_NAMES = exports.MINIFORGE_URL_PREFIX = exports.MINIFORGE_RELEASE_JSON = exports.MINIFORGE_INDEX_URL = exports.OS_NAMES = exports.ARCHITECTURES = exports.MINICONDA_BASE_URL = exports.IS_UNIX = exports.IS_LINUX = exports.IS_MAC = exports.IS_WINDOWS = exports.MINICONDA_DIR_PATH = void 0;
exports.PYTHON_SPEC = exports.WIN_PERMS_FOLDERS = exports.PROFILES = exports.ENV_VAR_CONDA_PKGS = exports.CONDA_CACHE_FOLDER = exports.CONDARC_PATH = exports.BOOTSTRAP_CONDARC = exports.FORCED_ERRORS = exports.IGNORED_WARNINGS = exports.MAMBA_SUBCOMMANDS = exports.KNOWN_EXTENSIONS = exports.BASE_ENV_NAMES = exports.MINIFORGE_URL_PREFIX = exports.MINIFORGE_DEFAULT_VARIANT = exports.OS_NAMES = exports.ARCHITECTURES = exports.MINICONDA_BASE_URL = exports.IS_UNIX = exports.IS_LINUX = exports.IS_MAC = exports.IS_WINDOWS = exports.MINICONDA_DIR_PATH = void 0;
const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622));
//-----------------------------------------------------------------------
Expand All @@ -1184,10 +1184,8 @@ exports.OS_NAMES = {
darwin: "MacOSX",
linux: "Linux",
};
/** API endpoint for Miniforge releases */
exports.MINIFORGE_INDEX_URL = `https://api.github.com/repos/conda-forge/miniforge/releases?per_page=100`;
/** */
exports.MINIFORGE_RELEASE_JSON = "miniforge-releases.json";
/** A default Miniforge variant to use if only `miniforgeVersion` is given */
exports.MINIFORGE_DEFAULT_VARIANT = "Miniforge3";
/** Common download prefix */
exports.MINIFORGE_URL_PREFIX = "https://github.com/conda-forge/miniforge/releases/download";
/** Names for a conda `base` env */
Expand Down
78 changes: 16 additions & 62 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9358,7 +9358,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PYTHON_SPEC = exports.WIN_PERMS_FOLDERS = exports.PROFILES = exports.ENV_VAR_CONDA_PKGS = exports.CONDA_CACHE_FOLDER = exports.CONDARC_PATH = exports.BOOTSTRAP_CONDARC = exports.FORCED_ERRORS = exports.IGNORED_WARNINGS = exports.MAMBA_SUBCOMMANDS = exports.KNOWN_EXTENSIONS = exports.BASE_ENV_NAMES = exports.MINIFORGE_URL_PREFIX = exports.MINIFORGE_RELEASE_JSON = exports.MINIFORGE_INDEX_URL = exports.OS_NAMES = exports.ARCHITECTURES = exports.MINICONDA_BASE_URL = exports.IS_UNIX = exports.IS_LINUX = exports.IS_MAC = exports.IS_WINDOWS = exports.MINICONDA_DIR_PATH = void 0;
exports.PYTHON_SPEC = exports.WIN_PERMS_FOLDERS = exports.PROFILES = exports.ENV_VAR_CONDA_PKGS = exports.CONDA_CACHE_FOLDER = exports.CONDARC_PATH = exports.BOOTSTRAP_CONDARC = exports.FORCED_ERRORS = exports.IGNORED_WARNINGS = exports.MAMBA_SUBCOMMANDS = exports.KNOWN_EXTENSIONS = exports.BASE_ENV_NAMES = exports.MINIFORGE_URL_PREFIX = exports.MINIFORGE_DEFAULT_VARIANT = exports.OS_NAMES = exports.ARCHITECTURES = exports.MINICONDA_BASE_URL = exports.IS_UNIX = exports.IS_LINUX = exports.IS_MAC = exports.IS_WINDOWS = exports.MINICONDA_DIR_PATH = void 0;
const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622));
//-----------------------------------------------------------------------
Expand All @@ -9381,10 +9381,8 @@ exports.OS_NAMES = {
darwin: "MacOSX",
linux: "Linux",
};
/** API endpoint for Miniforge releases */
exports.MINIFORGE_INDEX_URL = `https://api.github.com/repos/conda-forge/miniforge/releases?per_page=100`;
/** */
exports.MINIFORGE_RELEASE_JSON = "miniforge-releases.json";
/** A default Miniforge variant to use if only `miniforgeVersion` is given */
exports.MINIFORGE_DEFAULT_VARIANT = "Miniforge3";
/** Common download prefix */
exports.MINIFORGE_URL_PREFIX = "https://github.com/conda-forge/miniforge/releases/download";
/** Names for a conda `base` env */
Expand Down Expand Up @@ -13578,10 +13576,14 @@ const RULES = [
`'python-version: ${i.pythonVersion}' requires 'activate-environment: true'`,
(i) => !!(i.minicondaVersion && i.miniforgeVariant) &&
`only one of 'miniconda-version: ${i.minicondaVersion}' or 'miniforge-variant: ${i.miniforgeVariant}' may be provided`,
(i) => !!(i.minicondaVersion && i.miniforgeVersion) &&
`only one of 'miniconda-version: ${i.minicondaVersion}' or 'miniforge-version: ${i.miniforgeVersion}' may be provided`,
(i) => !!(i.installerUrl && i.minicondaVersion) &&
`only one of 'installer-url: ${i.installerUrl}' or 'miniconda-version: ${i.minicondaVersion}' may be provided`,
(i) => !!(i.installerUrl && i.miniforgeVariant) &&
`only one of 'installer-url: ${i.installerUrl}' or 'miniforge-variant: ${i.miniforgeVariant}' may be provided`,
(i) => !!(i.installerUrl && i.miniforgeVersion) &&
`only one of 'installer-url: ${i.installerUrl}' or 'miniforge-version: ${i.miniforgeVersion}' may be provided`,
(i) => !!(i.installerUrl &&
!constants.KNOWN_EXTENSIONS.includes(urlExt(i.installerUrl))) &&
`'installer-url' extension '${urlExt(i.installerUrl)}' must be one of: ${constants.KNOWN_EXTENSIONS}`,
Expand Down Expand Up @@ -34161,75 +34163,29 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.miniforgeDownloader = exports.downloadMiniforge = void 0;
const fs = __importStar(__webpack_require__(747));
const core = __importStar(__webpack_require__(470));
const tc = __importStar(__webpack_require__(533));
const constants = __importStar(__webpack_require__(211));
const base = __importStar(__webpack_require__(122));
/**
* List available Miniforge versions
*
* @param arch
*/
function miniforgeVersions(variant, osName, arch) {
return __awaiter(this, void 0, void 0, function* () {
const assets = [];
let extension = constants.IS_UNIX ? "sh" : "exe";
const suffix = `${osName}-${arch}.${extension}`;
core.info(`Checking for cached Miniforge releases...`);
// Try to pull cached releases with an hour epoch: YYYY-MM-DDTHH
const cacheEpoch = new Date().toISOString().split(":")[0];
let downloadPath = tc.find(constants.MINIFORGE_RELEASE_JSON, cacheEpoch);
if (downloadPath !== "") {
core.info(`Found Miniforge releases in cache`);
}
else {
core.info(`Downloading Miniforge releases from ${constants.MINIFORGE_INDEX_URL}`);
downloadPath = yield tc.downloadTool(constants.MINIFORGE_INDEX_URL);
const cacheResult = yield tc.cacheFile(downloadPath, constants.MINIFORGE_RELEASE_JSON, constants.MINIFORGE_RELEASE_JSON, cacheEpoch);
core.info(`Cached Miniforge releases: ${cacheResult}!`);
}
const data = JSON.parse(fs.readFileSync(downloadPath, "utf8"));
for (const release of data) {
if (release.prerelease || release.draft) {
continue;
}
for (const asset of release.assets) {
if (asset.name.match(`${variant}-\\d`) && asset.name.endsWith(suffix)) {
assets.push(Object.assign(Object.assign({}, asset), { tag_name: release.tag_name }));
}
}
}
return assets;
});
}
/**
* Download specific Miniforge defined by variant, version and architecture
*/
function downloadMiniforge(inputs, options) {
return __awaiter(this, void 0, void 0, function* () {
let tool = inputs.miniforgeVariant.trim();
let version = inputs.miniforgeVersion.trim();
const version = inputs.miniforgeVersion.trim();
const arch = constants.ARCHITECTURES[inputs.architecture];
// Check valid arch
if (!arch) {
throw new Error(`Invalid 'architecture: ${inputs.architecture}'`);
}
let url;
let tool = inputs.miniforgeVariant.trim();
if (!tool.length) {
tool = constants.MINIFORGE_DEFAULT_VARIANT;
core.info(`Using default 'miniforge-variant: ${tool}'`);
}
const extension = constants.IS_UNIX ? "sh" : "exe";
const osName = constants.OS_NAMES[process.platform];
if (version) {
const fileName = [tool, version, osName, `${arch}.${extension}`].join("-");
url = [constants.MINIFORGE_URL_PREFIX, version, fileName].join("/");
}
else {
const assets = yield miniforgeVersions(inputs.miniforgeVariant, osName, arch);
if (!assets.length) {
throw new Error(`Couldn't fetch Miniforge versions and 'miniforge-version' not provided`);
}
version = assets[0].tag_name;
url = assets[0].browser_download_url;
}
const fileName = [tool, version, osName, `${arch}.${extension}`].join("-");
const url = [constants.MINIFORGE_URL_PREFIX, version, fileName].join("/");
core.info(`Will fetch ${tool} ${version} from ${url}`);
return yield base.ensureLocalInstaller({ url, tool, version, arch });
});
Expand All @@ -34244,9 +34200,7 @@ exports.downloadMiniforge = downloadMiniforge;
*/
exports.miniforgeDownloader = {
label: "download Minforge",
provides: (inputs, options) => __awaiter(void 0, void 0, void 0, function* () {
return inputs.miniforgeVariant !== "" && inputs.installerUrl === "";
}),
provides: (inputs, options) => __awaiter(void 0, void 0, void 0, function* () { return inputs.miniforgeVersion !== ""; }),
installerPath: (inputs, options) => __awaiter(void 0, void 0, void 0, function* () {
return {
localInstallerPath: yield downloadMiniforge(inputs, options),
Expand Down
7 changes: 2 additions & 5 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,8 @@ export const OS_NAMES: types.IOperatingSystems = {
linux: "Linux",
};

/** API endpoint for Miniforge releases */
export const MINIFORGE_INDEX_URL = `https://api.github.com/repos/conda-forge/miniforge/releases?per_page=100`;

/** */
export const MINIFORGE_RELEASE_JSON = "miniforge-releases.json";
/** A default Miniforge variant to use if only `miniforgeVersion` is given */
export const MINIFORGE_DEFAULT_VARIANT = "Miniforge3";

/** Common download prefix */
export const MINIFORGE_URL_PREFIX =
Expand Down
6 changes: 6 additions & 0 deletions src/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ const RULES: IRule[] = [
(i) =>
!!(i.minicondaVersion && i.miniforgeVariant) &&
`only one of 'miniconda-version: ${i.minicondaVersion}' or 'miniforge-variant: ${i.miniforgeVariant}' may be provided`,
(i) =>
!!(i.minicondaVersion && i.miniforgeVersion) &&
`only one of 'miniconda-version: ${i.minicondaVersion}' or 'miniforge-version: ${i.miniforgeVersion}' may be provided`,
(i) =>
!!(i.installerUrl && i.minicondaVersion) &&
`only one of 'installer-url: ${i.installerUrl}' or 'miniconda-version: ${i.minicondaVersion}' may be provided`,
(i) =>
!!(i.installerUrl && i.miniforgeVariant) &&
`only one of 'installer-url: ${i.installerUrl}' or 'miniforge-variant: ${i.miniforgeVariant}' may be provided`,
(i) =>
!!(i.installerUrl && i.miniforgeVersion) &&
`only one of 'installer-url: ${i.installerUrl}' or 'miniforge-version: ${i.miniforgeVersion}' may be provided`,
(i) =>
!!(
i.installerUrl &&
Expand Down
94 changes: 11 additions & 83 deletions src/installer/download-miniforge.ts
Original file line number Diff line number Diff line change
@@ -1,106 +1,36 @@
import * as fs from "fs";

import * as core from "@actions/core";
import * as tc from "@actions/tool-cache";

import * as types from "../types";
import * as constants from "../constants";

import * as base from "./base";

/**
* List available Miniforge versions
*
* @param arch
*/
async function miniforgeVersions(
variant: string,
osName: string,
arch: string
): Promise<types.IGithubAssetWithRelease[]> {
const assets: types.IGithubAssetWithRelease[] = [];
let extension: string = constants.IS_UNIX ? "sh" : "exe";
const suffix = `${osName}-${arch}.${extension}`;

core.info(`Checking for cached Miniforge releases...`);

// Try to pull cached releases with an hour epoch: YYYY-MM-DDTHH
const cacheEpoch = new Date().toISOString().split(":")[0];
let downloadPath = tc.find(constants.MINIFORGE_RELEASE_JSON, cacheEpoch);

if (downloadPath !== "") {
core.info(`Found Miniforge releases in cache`);
} else {
core.info(
`Downloading Miniforge releases from ${constants.MINIFORGE_INDEX_URL}`
);
downloadPath = await tc.downloadTool(constants.MINIFORGE_INDEX_URL);
const cacheResult = await tc.cacheFile(
downloadPath,
constants.MINIFORGE_RELEASE_JSON,
constants.MINIFORGE_RELEASE_JSON,
cacheEpoch
);
core.info(`Cached Miniforge releases: ${cacheResult}!`);
}

const data: types.IGithubRelease[] = JSON.parse(
fs.readFileSync(downloadPath, "utf8")
);

for (const release of data) {
if (release.prerelease || release.draft) {
continue;
}
for (const asset of release.assets) {
if (asset.name.match(`${variant}-\\d`) && asset.name.endsWith(suffix)) {
assets.push({ ...asset, tag_name: release.tag_name });
}
}
}

return assets;
}

/**
* Download specific Miniforge defined by variant, version and architecture
*/
export async function downloadMiniforge(
inputs: types.IActionInputs,
options: types.IDynamicOptions
): Promise<string> {
let tool = inputs.miniforgeVariant.trim();
let version = inputs.miniforgeVersion.trim();
const version = inputs.miniforgeVersion.trim();
const arch = constants.ARCHITECTURES[inputs.architecture];

// Check valid arch
if (!arch) {
throw new Error(`Invalid 'architecture: ${inputs.architecture}'`);
}

let url: string;

const extension: string = constants.IS_UNIX ? "sh" : "exe";
const osName: string = constants.OS_NAMES[process.platform];

if (version) {
const fileName = [tool, version, osName, `${arch}.${extension}`].join("-");
url = [constants.MINIFORGE_URL_PREFIX, version, fileName].join("/");
} else {
const assets = await miniforgeVersions(
inputs.miniforgeVariant,
osName,
arch
);
if (!assets.length) {
throw new Error(
`Couldn't fetch Miniforge versions and 'miniforge-version' not provided`
);
}
version = assets[0].tag_name;
url = assets[0].browser_download_url;
let tool = inputs.miniforgeVariant.trim();
if (!tool.length) {
tool = constants.MINIFORGE_DEFAULT_VARIANT;
core.info(`Using default 'miniforge-variant: ${tool}'`);
}

const extension = constants.IS_UNIX ? "sh" : "exe";
const osName = constants.OS_NAMES[process.platform];
const fileName = [tool, version, osName, `${arch}.${extension}`].join("-");
const url = [constants.MINIFORGE_URL_PREFIX, version, fileName].join("/");

core.info(`Will fetch ${tool} ${version} from ${url}`);

return await base.ensureLocalInstaller({ url, tool, version, arch });
Expand All @@ -115,9 +45,7 @@ export async function downloadMiniforge(
*/
export const miniforgeDownloader: types.IInstallerProvider = {
label: "download Minforge",
provides: async (inputs, options) => {
return inputs.miniforgeVariant !== "" && inputs.installerUrl === "";
},
provides: async (inputs, options) => inputs.miniforgeVersion !== "",
installerPath: async (inputs, options) => {
return {
localInstallerPath: await downloadMiniforge(inputs, options),
Expand Down