Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: s-weigand/setup-conda
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.2.0
Choose a base ref
...
head repository: s-weigand/setup-conda
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Nov 17, 2019

  1. Create CODE_OF_CONDUCT.md

    s-weigand authored Nov 17, 2019
    Copy the full SHA
    bb60f69 View commit details
  2. Update issue templates

    s-weigand authored Nov 17, 2019
    Copy the full SHA
    28901ae View commit details
  3. Copy the full SHA
    9d4498a View commit details
  4. initial testing state

    s-weigand committed Nov 17, 2019
    Copy the full SHA
    4fb6200 View commit details
  5. Copy the full SHA
    943dcb1 View commit details
  6. Copy the full SHA
    aa19ec5 View commit details
  7. Copy the full SHA
    0a47762 View commit details
  8. added conda init script

    s-weigand committed Nov 17, 2019
    Copy the full SHA
    247dcf9 View commit details
  9. Copy the full SHA
    27a57d0 View commit details
  10. Copy the full SHA
    f4805fa View commit details
  11. Copy the full SHA
    701133e View commit details
  12. Copy the full SHA
    5e1eb35 View commit details
  13. fixing bug on mac worker

    s-weigand committed Nov 17, 2019
    Copy the full SHA
    de78d86 View commit details
  14. Copy the full SHA
    5d83042 View commit details
  15. Copy the full SHA
    160fa0e View commit details
  16. testing python 3.8

    s-weigand committed Nov 17, 2019
    Copy the full SHA
    d3741a5 View commit details
  17. Copy the full SHA
    e32b01f View commit details
  18. Copy the full SHA
    4ddf735 View commit details
  19. changing back to python 3.6 as test case, and split integration tests

    into default and custom
    s-weigand committed Nov 17, 2019
    Copy the full SHA
    6d81c5b View commit details
  20. Copy the full SHA
    ef283ef View commit details
  21. Copy the full SHA
    2a7e5de View commit details
  22. Copy the full SHA
    9b92e25 View commit details

Commits on Nov 18, 2019

  1. v1.0.0

    s-weigand committed Nov 18, 2019
    Copy the full SHA
    0f0a395 View commit details
  2. Copy the full SHA
    fcea5d2 View commit details
  3. Copy the full SHA
    732e817 View commit details
  4. Copy the full SHA
    fdde464 View commit details
  5. Copy the full SHA
    4f5458a View commit details
  6. Copy the full SHA
    daf0377 View commit details
  7. Merge pull request #1 from s-weigand/test-index.js-up-to-date

    Test if dist/index.js up to date
    s-weigand authored Nov 18, 2019
    Copy the full SHA
    ca7421a View commit details

Commits on Nov 22, 2019

  1. Copy the full SHA
    36e784c View commit details
  2. Copy the full SHA
    bac0daf View commit details
  3. added python reset function to reset the default python

    if activate-conda is false
    s-weigand committed Nov 22, 2019
    Copy the full SHA
    78ab2b0 View commit details

Commits on Nov 24, 2019

  1. removed unneeded rebuild steps

    due to the dependency of integration tests on 'release-up-to-date'
    s-weigand committed Nov 24, 2019
    Copy the full SHA
    5194e69 View commit details

Commits on Nov 25, 2019

  1. removed unneeded import

    s-weigand committed Nov 25, 2019
    Copy the full SHA
    42bbd11 View commit details
  2. Copy the full SHA
    399bb21 View commit details
  3. updated docs

    s-weigand committed Nov 25, 2019
    Copy the full SHA
    ed93eab View commit details
  4. Copy the full SHA
    96b3d00 View commit details
  5. Merge pull request #2 from s-weigand/add-activate-flag

    Add activate-conda option
    s-weigand authored Nov 25, 2019
    Copy the full SHA
    62d72a2 View commit details
  6. Bump version: 1.0.0 → 1.0.1

    Allows users to choose if they want to have the miniconda python as their default python
    s-weigand committed Nov 25, 2019
    Copy the full SHA
    6e04e4b View commit details

Commits on Dec 18, 2019

  1. Merge tag 'v1.0.1'

    s-weigand committed Dec 18, 2019
    Copy the full SHA
    1e79d6b View commit details
  2. Copy the full SHA
    89ecf71 View commit details
  3. Merge pull request #4 from s-weigand/add-auto-major-release

    Added workflow to automatically publish major versions
    s-weigand authored Dec 18, 2019
    Copy the full SHA
    fd29ea5 View commit details

Commits on Jan 30, 2020

  1. fix small typo

    d-chambers authored Jan 30, 2020
    Copy the full SHA
    1b989eb View commit details
  2. Merge pull request #5 from d-chambers/patch-1

    fix small typo
    s-weigand authored Jan 30, 2020
    Copy the full SHA
    66ced16 View commit details

Commits on Mar 16, 2020

  1. Bump acorn from 5.7.3 to 5.7.4

    Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
    - [Release notes](https://github.com/acornjs/acorn/releases)
    - [Commits](acornjs/acorn@5.7.3...5.7.4)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Mar 16, 2020
    Copy the full SHA
    e36887f View commit details
  2. Merge pull request #8 from s-weigand/dependabot/npm_and_yarn/acorn-5.7.4

    Bump acorn from 5.7.3 to 5.7.4
    s-weigand authored Mar 16, 2020
    Copy the full SHA
    2ee360b View commit details

Commits on May 6, 2020

  1. made conda being updated from the default channel

    even if additional channels are given, to prevent errors on windows due to mismatching DLLs, see conda/conda#9003 (comment)
    s-weigand committed May 6, 2020
    Copy the full SHA
    e0c898b View commit details
  2. Merge pull request #9 from s-weigand/fix-conda-update-bug-on-win

    Fix conda update bug when additional channels are provided
    s-weigand authored May 6, 2020
    Copy the full SHA
    a49fa41 View commit details
  3. Copy the full SHA
    d84b67e View commit details

Commits on May 7, 2020

  1. Copy the full SHA
    2c006fd View commit details
131 changes: 131 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "s-weigand",
"name": "Sebastian Weigand",
"avatar_url": "https://avatars2.githubusercontent.com/u/9513634?v=4",
"profile": "https://github.com/s-weigand",
"contributions": [
"code",
"ideas",
"infra",
"maintenance",
"test",
"review"
]
},
{
"login": "bryant1410",
"name": "Santiago Castro",
"avatar_url": "https://avatars3.githubusercontent.com/u/3905501?v=4",
"profile": "https://santi.uy",
"contributions": [
"doc"
]
},
{
"login": "d-chambers",
"name": "Derrick",
"avatar_url": "https://avatars2.githubusercontent.com/u/11671536?v=4",
"profile": "https://github.com/d-chambers",
"contributions": [
"doc"
]
},
{
"login": "basic-ph",
"name": "Pietro Fumiani",
"avatar_url": "https://avatars2.githubusercontent.com/u/35763852?v=4",
"profile": "https://github.com/basic-ph",
"contributions": [
"bug"
]
},
{
"login": "dcdenu4",
"name": "Doug",
"avatar_url": "https://avatars3.githubusercontent.com/u/2659980?v=4",
"profile": "https://github.com/dcdenu4",
"contributions": [
"bug"
]
},
{
"login": "ocefpaf",
"name": "Filipe",
"avatar_url": "https://avatars.githubusercontent.com/u/950575?v=4",
"profile": "http://ocefpaf.github.io/python4oceanographers",
"contributions": [
"bug"
]
},
{
"login": "csadorf",
"name": "Carl Simon Adorf",
"avatar_url": "https://avatars.githubusercontent.com/u/1441208?v=4",
"profile": "https://carlsimonadorf.com",
"contributions": [
"bug"
]
},
{
"login": "wvxvw",
"name": "wvxvw",
"avatar_url": "https://avatars.githubusercontent.com/u/3147276?v=4",
"profile": "https://github.com/wvxvw",
"contributions": [
"bug"
]
},
{
"login": "violafanfani",
"name": "violafanfani",
"avatar_url": "https://avatars.githubusercontent.com/u/35488779?v=4",
"profile": "https://violafanfani.github.io/",
"contributions": [
"bug"
]
},
{
"login": "phdru",
"name": "Oleg Broytman",
"avatar_url": "https://avatars.githubusercontent.com/u/730158?v=4",
"profile": "http://phdru.name/",
"contributions": [
"bug",
"code"
]
},
{
"login": "pauleve",
"name": "Loïc Paulevé",
"avatar_url": "https://avatars.githubusercontent.com/u/228657?v=4",
"profile": "https://loicpauleve.name",
"contributions": [
"bug"
]
},
{
"login": "giumas",
"name": "giumas",
"avatar_url": "https://avatars.githubusercontent.com/u/2849257?v=4",
"profile": "http://www.hydroffice.org",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,
"projectName": "setup-conda",
"projectOwner": "s-weigand",
"repoType": "github",
"repoHost": "https://github.com",
"skipCi": true,
"commitType": "docs",
"commitConvention": "angular"
}
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

[*.py]
indent_size = 4
40 changes: 40 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**

- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]

**Smartphone (please complete the following information):**

- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: npm
directory: '/'
schedule:
interval: weekly
time: '04:00'
reviewers:
- s-weigand
# Maintain dependencies for GitHub Actions
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
time: '04:00'
reviewers:
- s-weigand
41 changes: 41 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: 'CodeQL'

on:
push:
branches: ['main']
pull_request:
branches: ['main']
schedule:
- cron: '37 21 * * 0'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [javascript]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-and-quality

- name: Autobuild
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: '/language:${{ matrix.language }}'
46 changes: 46 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Release
on:
release:
types: [published]

jobs:
release:
name: Release GitHub Actions
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Release GitHub Actions
uses: technote-space/release-github-actions@v8
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_EMAIL: s.weigand.pyh@gmail.com
BRANCH_NAME: release
OUTPUT_BUILD_INFO_FILENAME: build.json
TEST_TAG_PREFIX: test/
ORIGINAL_TAG_PREFIX: original/
CREATE_MINOR_VERSION_TAG: false
CLEAN_TARGETS: .[!.]*,__tests__,src,*.js,*.ts,*.json,*.lock,_config.yml,CODE_OF_CONDUCT.md,node_modules

test-integration:
runs-on: ${{ matrix.os }}
needs: release
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- name: Setup conda v1
uses: s-weigand/setup-conda@v1
- name: Check conda version
run: conda --version
- name: Check Python version
run: |
python --version
python -c "import sys;print(sys.executable);print(sys.version_info)"
- name: Check env
run: printenv
- name: Install and check pandoc version
run: |
conda install pandoc
pandoc -v
362 changes: 362 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,362 @@
name: 'Tests'

on:
push:
tags:
- v**
branches-ignore:
- 'dependabot/**'
pull_request:
workflow_dispatch:

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.8
- name: Create fake release file for actionlint
run: |
mkdir dist
touch dist/index.js
- name: Run pre-commit
uses: pre-commit/action@v3.0.1

jest-tests:
name: Unit test + Build
runs-on: ubuntu-latest
needs: pre-commit
steps:
- uses: actions/checkout@v4
- name: Install Dependencies
run: npm ci
- name: Test Build
run: npm run test_build
- name: Running jest tests
run: npm test
- name: Build dist
run: npm run package
- uses: actions/upload-artifact@v4
with:
name: dist-built
path: dist/index.js

test-integration-default:
name: Default settings
runs-on: ${{ matrix.os }}
needs: jest-tests
env:
CONDA_CHANNELS: 'defaults'
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Run setup-conda
uses: ./
- name: Install pandoc and graphviz
run: |
conda install pandoc graphviz
which pandoc
- name: Check env
run: printenv
- name: Run tests
run: |
python -m pip install -q pytest
python -m pytest -v integrationtests
- name: Run tests with bash on windows
if: matrix.os == 'windows-latest'
shell: bash
run: |
python -m pytest -v integrationtests
test-integration-test-env:
name: Env login shell
runs-on: ${{ matrix.os }}
needs: jest-tests
env:
CONDA_CHANNELS: 'defaults'
ENV_PYTHON: 3.8
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Run setup-conda
uses: ./
with:
activate-conda: false
- name: Create Test env
shell: bash -l {0}
run: |
conda create --name TEST python=3.8
source activate TEST
conda install pandoc graphviz
pip install -q pytest
which pip
which pandoc
printenv
- name: Check env
run: printenv
- name: Run tests
shell: bash -l {0}
run: |
source activate TEST
python -m pytest -v integrationtests
test-integration-test-env-no-login:
name: Env no login shell
runs-on: ${{ matrix.os }}
needs: jest-tests
env:
CONDA_CHANNELS: 'defaults'
ENV_PYTHON: 3.8
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Run setup-conda
uses: ./
with:
activate-conda: false
- name: Create Test env
shell: bash
run: |
conda create --name TEST python=3.8
source activate TEST
conda install pandoc graphviz
pip install -q pytest
which pip
which pandoc
printenv
- name: Check env
run: printenv
- name: Run tests
shell: bash
run: |
source activate TEST
python -m pytest -v integrationtests
test-integration-old:
name: Older Python (3.6)
runs-on: ${{ matrix.os }}
env:
ENV_PYTHON: '3.6'
CONDA_CHANNELS: 'defaults,anaconda,conda-forge'
needs: jest-tests
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Run setup-conda
uses: ./
with:
update-conda: true
python-version: 3.6
conda-channels: anaconda, conda-forge
- name: Install pandoc and graphviz
run: |
conda install pandoc graphviz
which pandoc
- name: Check env
run: printenv
- name: Run tests
run: |
python -m pip install -q pytest
python -m pytest -v integrationtests
test-integration-new:
name: Newer Python (3.11)
runs-on: ${{ matrix.os }}
env:
ENV_PYTHON: '3.11'
CONDA_CHANNELS: 'defaults,anaconda,conda-forge'
needs: jest-tests
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Run setup-conda
uses: ./
with:
update-conda: true
python-version: '3.11'
conda-channels: anaconda, conda-forge
- name: Install pandoc and graphviz
run: |
conda install pandoc graphviz
which pandoc
- name: Check env
run: printenv
- name: Run tests
run: |
python -m pip install -q pytest
python -m pytest -v integrationtests
test-no-activation:
name: System Python
runs-on: ${{ matrix.os }}
env:
NOT_ACTIVATED: true
CONDA_CHANNELS: 'defaults'
needs: jest-tests
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Run setup-conda
uses: ./
with:
activate-conda: false
- name: Install pandoc and graphviz
run: |
conda install pandoc graphviz
which pandoc
- name: Check env
run: printenv
- name: Run tests
run: |
python -m pip install -q pytest
python -m pytest -v integrationtests
test-no-activation-setup-python:
name: Setup Python
runs-on: ${{ matrix.os }}
env:
NOT_ACTIVATED: true
CONDA_CHANNELS: 'defaults'
needs: jest-tests
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
steps:
- uses: actions/checkout@v4
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Set up Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.8
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Run setup-conda
uses: ./
with:
activate-conda: false
- name: Install pandoc and graphviz
run: |
conda install pandoc graphviz
which pandoc
- name: Check env
run: printenv
- name: Run tests
run: |
python -m pip install -q pytest
python -m pytest -v integrationtests
test-pypy:
name: Test PyPy
runs-on: ${{ matrix.os }}
needs: jest-tests
env:
PYPY_TEST: true
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-12]
pypy-ver: ['pypy3.7']
include:
- os: ubuntu-latest
pypy-ver: 'pypy2.7'
steps:
- uses: actions/checkout@v4
- name: Download built dist
uses: actions/download-artifact@v4
with:
name: dist-built
path: dist
- name: Prepare tests
run: |
python --version
python integrationtests/prepare_tests.py
- name: Run setup-conda
uses: ./
with:
conda-channels: conda-forge
python-version: ${{ matrix.pypy-ver }}
- name: Run tests
run: |
pypy --version
- name: Check env
run: printenv
- name: Run tests
run: |
pypy -m ensurepip
pypy -m pip install --trusted-host pypi.python.org -q pytest
pypy -m pytest -v integrationtests/test_python_version.py
49 changes: 47 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
__tests__/runner/*

# comment out in distribution branches
node_modules/

# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
@@ -16,11 +26,12 @@ lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
@@ -33,12 +44,14 @@ bower_components
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

@@ -56,6 +69,38 @@ typings/

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# vscode config
.vscode

# ignore none relevat js files
lib
compare

# exclude dist folder
dist/

# test files
initial_settings.json
82 changes: 82 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
exclude: ^tests/data/(expected/.+|setup.py)$

repos:
###################
# FORMATTER #
###################
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-ast
- id: check-builtin-literals
- id: end-of-file-fixer
- id: trailing-whitespace
- id: debug-statements
- id: fix-encoding-pragma
args: [--remove]

- repo: https://github.com/MarcoGorelli/absolufy-imports
rev: v0.3.1
hooks:
- id: absolufy-imports

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8
hooks:
- id: prettier
additional_dependencies:
- 'prettier@3.3.3'
exclude_types:
- 'javascript'
- 'ts'
- 'tsx'
- 'json'
- 'css'
- 'scss'
exclude: "\\.jsonc|.all-contributorsrc"

- repo: https://github.com/PyCQA/docformatter
rev: 06907d0
hooks:
- id: docformatter
additional_dependencies: [tomli]
args: [--in-place, --config, ./pyproject.toml]

###################
# LINTER #
###################
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.7.0
hooks:
- id: ruff
name: 'ruff sort imports'
args:
- '--fix'
- '--select=I'
alias: isort
- id: ruff-format
# Commands above are both formatters an not linters
# See also: https://github.com/astral-sh/ruff/discussions/7310#discussioncomment-7102010
- id: ruff
name: 'ruff lint'

- repo: https://github.com/biomejs/pre-commit
rev: 'v0.5.0' # Use the sha / tag you want to point at
hooks:
- id: biome-check
additional_dependencies: ['@biomejs/biome@1.9.3']
- id: biome-format
additional_dependencies: ['@biomejs/biome@1.9.3']

- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
types: [file]
types_or: [python, markdown]

- repo: https://github.com/rhysd/actionlint
rev: 'v1.7.3'
hooks:
- id: actionlint
76 changes: 76 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socioeconomic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at s.weigand.phy@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
116 changes: 115 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,116 @@
# setup-conda
Github Action which installs conda

[![Tests](https://github.com/s-weigand/setup-conda/workflows/Tests/badge.svg)](https://github.com/s-weigand/setup-conda/actions)
[![All Contributors](https://img.shields.io/github/all-contributors/s-weigand/setup-conda)](#contributors-)

This action adds the [`conda`](https://conda.io/projects/conda/en/latest/user-guide/tasks/index.html)
command from the on the worker preinstalled miniconda version to the known shell commands.

> [!CAUTION]
> This action [is known to currently not work with macOS runner-images newer than `macOS-12` (i.e. `macOS-latest`)](https://github.com/s-weigand/setup-conda/issues/432).
## Inputs

| Name | Requirement | Default | Description |
| ---------------- | ----------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `activate-conda` | _optional_ | `true` | Whether to activate the conda base env. |
| `update-conda` | _optional_ | `false` | If conda should be updated before running other commands. |
| `python-version` | _optional_ | `'default'` | Python version which should be installed with conda. |
| `conda-channels` | _optional_ | `''` | Additional channels like 'conda-forge', as coma separated list, which can be used to install packages. The last channel in the list, will have the highest priority. |

# Usage

See [action.yml](action.yml)

## Basic:

The basic usage makes the conda python version the default python (`$ conda activate base`).

```yaml
steps:
- uses: actions/checkout@v3
- uses: s-weigand/setup-conda@v1
- run: conda --version
- run: which python
```
If you don't want to change the python version which is used
(e.g. you just need to install a none python package), you can use `activate-conda: false`.

```yaml
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.8
uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: s-weigand/setup-conda@v1
with:
activate-conda: false
- run: conda --version
- run: which python
```

## Matrix Testing:

```yaml
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
python-version: [3.6, 3.7, 3.8]
name: Python ${{ matrix.python-version }} example
steps:
- uses: actions/checkout@v3
- name: Setup conda
uses: s-weigand/setup-conda@v1
with:
update-conda: true
python-version: ${{ matrix.python-version }}
conda-channels: anaconda, conda-forge
- run: conda --version
- run: which python
```

# Similar projects

- [conda-incubator/setup-miniconda](https://github.com/conda-incubator/setup-miniconda)
- [mamba-org/setup-micromamba](https://github.com/mamba-org/setup-micromamba)
- [prefix-dev/setup-pixi](https://github.com/prefix-dev/setup-pixi)

# Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/s-weigand"><img src="https://avatars2.githubusercontent.com/u/9513634?v=4?s=100" width="100px;" alt="Sebastian Weigand"/><br /><sub><b>Sebastian Weigand</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/commits?author=s-weigand" title="Code">💻</a> <a href="#ideas-s-weigand" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-s-weigand" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-s-weigand" title="Maintenance">🚧</a> <a href="https://github.com/s-weigand/setup-conda/commits?author=s-weigand" title="Tests">⚠️</a> <a href="https://github.com/s-weigand/setup-conda/pulls?q=is%3Apr+reviewed-by%3As-weigand" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://santi.uy"><img src="https://avatars3.githubusercontent.com/u/3905501?v=4?s=100" width="100px;" alt="Santiago Castro"/><br /><sub><b>Santiago Castro</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/commits?author=bryant1410" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/d-chambers"><img src="https://avatars2.githubusercontent.com/u/11671536?v=4?s=100" width="100px;" alt="Derrick"/><br /><sub><b>Derrick</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/commits?author=d-chambers" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/basic-ph"><img src="https://avatars2.githubusercontent.com/u/35763852?v=4?s=100" width="100px;" alt="Pietro Fumiani"/><br /><sub><b>Pietro Fumiani</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Abasic-ph" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dcdenu4"><img src="https://avatars3.githubusercontent.com/u/2659980?v=4?s=100" width="100px;" alt="Doug"/><br /><sub><b>Doug</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Adcdenu4" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://ocefpaf.github.io/python4oceanographers"><img src="https://avatars.githubusercontent.com/u/950575?v=4?s=100" width="100px;" alt="Filipe"/><br /><sub><b>Filipe</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Aocefpaf" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://carlsimonadorf.com"><img src="https://avatars.githubusercontent.com/u/1441208?v=4?s=100" width="100px;" alt="Carl Simon Adorf"/><br /><sub><b>Carl Simon Adorf</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Acsadorf" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wvxvw"><img src="https://avatars.githubusercontent.com/u/3147276?v=4?s=100" width="100px;" alt="wvxvw"/><br /><sub><b>wvxvw</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Awvxvw" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://violafanfani.github.io/"><img src="https://avatars.githubusercontent.com/u/35488779?v=4?s=100" width="100px;" alt="violafanfani"/><br /><sub><b>violafanfani</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Aviolafanfani" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://phdru.name/"><img src="https://avatars.githubusercontent.com/u/730158?v=4?s=100" width="100px;" alt="Oleg Broytman"/><br /><sub><b>Oleg Broytman</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Aphdru" title="Bug reports">🐛</a> <a href="https://github.com/s-weigand/setup-conda/commits?author=phdru" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://loicpauleve.name"><img src="https://avatars.githubusercontent.com/u/228657?v=4?s=100" width="100px;" alt="Loïc Paulevé"/><br /><sub><b>Loïc Paulevé</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Apauleve" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.hydroffice.org"><img src="https://avatars.githubusercontent.com/u/2849257?v=4?s=100" width="100px;" alt="giumas"/><br /><sub><b>giumas</b></sub></a><br /><a href="https://github.com/s-weigand/setup-conda/issues?q=author%3Agiumas" title="Bug reports">🐛</a></td>
</tr>
</tbody>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
98 changes: 98 additions & 0 deletions __tests__/conda_actions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { readFileSync } from "node:fs";
import { EOL } from "node:os";
import { resolve } from "node:path";
import { addCondaToPath, parseActivationScriptOutput } from "../src/conda_actions";

describe("Parse env activation output", () => {
it("Parse linux activation", async () => {
const activationStr = readFileSync(
resolve(__dirname, "data/linux_conda_bash_activation.sh"),
).toString("utf8");
const { condaPaths, envVars } = await parseActivationScriptOutput(
activationStr,
"export ",
":",
);
expect(condaPaths.length).toBe(3);
expect(envVars.CONDA_PREFIX).toBe("/usr/share/miniconda/envs/__setup_conda");
expect(envVars).not.toHaveProperty("CONDA_SHLVL");
expect(envVars.CONDA_DEFAULT_ENV).toBe("__setup_conda");
expect(envVars.CONDA_PROMPT_MODIFIER).toBe("(__setup_conda) ");
expect(envVars.CONDA_EXE).toBe("/usr/share/miniconda/bin/conda");
expect(envVars._CE_M).toBe("");
expect(envVars._CE_CONDA).toBe("");
expect(envVars.CONDA_PYTHON_EXE).toBe("/usr/share/miniconda/bin/python");
});
it("Parse macOs activation", async () => {
const activationStr = readFileSync(
resolve(__dirname, "data/mac_conda_bash_activation.sh"),
).toString("utf8");
const { condaPaths, envVars } = await parseActivationScriptOutput(
activationStr,
"export ",
":",
);
expect(condaPaths.length).toBe(3);
expect(envVars.CONDA_PREFIX).toBe("/usr/local/miniconda/envs/__setup_conda");
expect(envVars).not.toHaveProperty("CONDA_SHLVL");
expect(envVars.CONDA_DEFAULT_ENV).toBe("__setup_conda");
expect(envVars.CONDA_PROMPT_MODIFIER).toBe("(__setup_conda) ");
expect(envVars.CONDA_EXE).toBe("/usr/local/miniconda/bin/conda");
expect(envVars._CE_M).toBe("");
expect(envVars._CE_CONDA).toBe("");
expect(envVars.CONDA_PYTHON_EXE).toBe("/usr/local/miniconda/bin/python");
});
it("Parse windows activation", async () => {
const activationStr = readFileSync(
resolve(__dirname, "data/windows_conda_powershell_activation.ps1"),
).toString("utf8");
const { condaPaths, envVars } = await parseActivationScriptOutput(activationStr, "$Env:", ";");
expect(condaPaths.length).toBe(9);
expect(envVars.CONDA_PREFIX).toBe("C:\\Miniconda\\envs\\__setup_conda");
expect(envVars).not.toHaveProperty("CONDA_SHLVL");
expect(envVars.CONDA_DEFAULT_ENV).toBe("__setup_conda");
expect(envVars.CONDA_PROMPT_MODIFIER).toBe("(__setup_conda) ");
expect(envVars.CONDA_EXE).toBe("C:\\Miniconda\\Scripts\\conda.exe");
expect(envVars._CE_M).toBe("");
expect(envVars._CE_CONDA).toBe("");
expect(envVars.CONDA_PYTHON_EXE).toBe("C:\\Miniconda\\python.exe");
});
});

const testConfig = {
activate_conda: false,
update_conda: false,
python_version: "",
conda_channels: [],
os: "linux",
};

describe("Throw error if CONDA env var isn't set", () => {
const OLD_ENV = process.env;

beforeEach(() => {
process.env = {};
});

afterAll(() => {
process.env = OLD_ENV;
});

it.each(["linux", "win32", "darwin"])("General error %p", async (os: string) => {
await expect(addCondaToPath({ ...testConfig, os })).rejects.toThrow(
"Could not determine conda base path, it seams conda is not installed.",
);
});

it("MacOs > 12 error", async () => {
process.env.ImageOS = "macos13";
await expect(addCondaToPath({ ...testConfig, os: "darwin" })).rejects.toThrow(
[
"Could not determine conda base path, it seams conda is not installed.",
'MacOS images newer than "macos-12" (i.e. "macOS-latest") are known to be ' +
"incompatible with this action due to a missing miniconda installation.",
"See: https://github.com/s-weigand/setup-conda/issues/432",
].join(EOL),
);
});
});
9 changes: 9 additions & 0 deletions __tests__/data/linux_conda_bash_activation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export PATH='/usr/share/miniconda/envs/__setup_conda/bin:/usr/share/miniconda/condabin:/usr/share/miniconda:/home/linuxbrew/.linuxbrew/bin'
export CONDA_PREFIX='/usr/share/miniconda/envs/__setup_conda'
export CONDA_SHLVL='1'
export CONDA_DEFAULT_ENV='__setup_conda'
export CONDA_PROMPT_MODIFIER='(__setup_conda) '
export CONDA_EXE='/usr/share/miniconda/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/usr/share/miniconda/bin/python'
9 changes: 9 additions & 0 deletions __tests__/data/mac_conda_bash_activation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export PATH='/usr/local/miniconda/envs/__setup_conda/bin:/usr/local/miniconda/condabin:/usr/local/miniconda:/usr/local/lib/ruby/gems/2.7.0/bin'
export CONDA_PREFIX='/usr/local/miniconda/envs/__setup_conda'
export CONDA_SHLVL='1'
export CONDA_DEFAULT_ENV='__setup_conda'
export CONDA_PROMPT_MODIFIER='(__setup_conda) '
export CONDA_EXE='/usr/local/miniconda/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/usr/local/miniconda/bin/python'
9 changes: 9 additions & 0 deletions __tests__/data/windows_conda_powershell_activation.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
$Env:PATH = "C:\Miniconda\envs\__setup_conda;C:\Miniconda\envs\__setup_conda\Library\mingw-w64\bin;C:\Miniconda\envs\__setup_conda\Library\usr\bin;C:\Miniconda\envs\__setup_conda\Library\bin;C:\Miniconda\envs\__setup_conda\Scripts;C:\Miniconda\envs\__setup_conda\bin;C:\Miniconda\condabin;C:\Miniconda\Scripts;C:\Miniconda;C:\Program Files\MongoDB\Server\5.0\bin"
$Env:CONDA_PREFIX = "C:\Miniconda\envs\__setup_conda"
$Env:CONDA_SHLVL = "1"
$Env:CONDA_DEFAULT_ENV = "__setup_conda"
$Env:CONDA_PROMPT_MODIFIER = "(__setup_conda) "
$Env:CONDA_EXE = "C:\Miniconda\Scripts\conda.exe"
$Env:_CE_M = ""
$Env:_CE_CONDA = ""
$Env:CONDA_PYTHON_EXE = "C:\Miniconda\python.exe"
37 changes: 37 additions & 0 deletions __tests__/load_config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { loadConfig } from "../src/load_config";

const testEnvVars = {
"INPUT_ACTIVATE-CONDA": "true",
"INPUT_UPDATE-CONDA": "true",
"INPUT_PYTHON-VERSION": "default",
"INPUT_CONDA-CHANNELS": " conda-forge, anaconda , bioconda",
};

describe("Reading of the config", () => {
beforeEach(() => {
for (const key in testEnvVars) {
process.env[key] = testEnvVars[key as keyof typeof testEnvVars];
}

process.stdout.write = jest.fn();
});

afterEach(() => {
for (const key in testEnvVars) Reflect.deleteProperty(testEnvVars, key);
});

it("test config values", () => {
const config = loadConfig();
expect(config.activate_conda).toEqual(true);
expect(config.update_conda).toEqual(true);
expect(config.python_version).toEqual("default");
expect(config.conda_channels).toEqual(["conda-forge", "anaconda", "bioconda"]);
expect(config.os).toEqual(process.platform);
});

it("no channels", () => {
process.env["INPUT_CONDA-CHANNELS"] = "";
const config = loadConfig();
expect(config.conda_channels).toEqual([]);
});
});
28 changes: 28 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: 'setup-conda'
description: 'Setup conda to use in later actions'
author: 'Sebastian Weigand'
inputs:
activate-conda:
description: "Whether to activate the conda base env (Default: 'true')"
required: false
default: 'true'
update-conda:
description: "If conda should be updated before running other commands (Default: 'false')"
required: false
default: 'false'
python-version:
description: "Python version which should be installed with conda (default: 'Default')"
required: false
default: 'default'
conda-channels:
description: "Additional channels like 'conda-forge' which can be used to install packages"
required: false
default: ''

runs:
using: 'node20'
main: 'dist/index.js'

branding:
icon: 'code'
color: 'yellow'
16 changes: 16 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.3/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"formatter": {
"indentStyle": "space", // default is `tab`
"lineWidth": 100 // default is `80`
}
}
Empty file added integrationtests/__init__.py
Empty file.
34 changes: 34 additions & 0 deletions integrationtests/prepare_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import json
import subprocess
import sys


def write_initial_settings():
"""Write initial settings to a file."""
initial_settings = {
"executable": sys.executable,
"version_info": str(sys.version_info),
}
with open("initial_settings.json", "w") as f:
json.dump(initial_settings, f)
print(json.dumps(initial_settings, indent=2))


def read_initial_settings():
"""Read initial settings to a file."""
with open("initial_settings.json") as f:
return json.load(f)


def run_cmd(cmd):
"""Run shell command in a python2/3 compatible way."""
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
)
process.wait()
stdout, stderr = process.communicate()
return process.returncode, stdout, stderr


if __name__ == "__main__":
write_initial_settings()
24 changes: 24 additions & 0 deletions integrationtests/test_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os

from integrationtests.prepare_tests import run_cmd


def test_conda_installed():
"""Conda is callable from the shell."""
returncode, stdout, stderr = run_cmd("conda --version")
assert returncode == 0
assert stdout.startswith(b"conda")
assert stderr == b""


def test_conda_channels():
"""Conda channels are added in order."""
returncode, stdout, stderr = run_cmd(" conda config --show channels")
expected = os.environ["CONDA_CHANNELS"].split(",")
channel_list = stdout.decode().partition(":")[2].split(" - ")
channel_list = [channel.strip() for channel in channel_list]
channel_list.remove("")

assert returncode == 0
assert channel_list == expected
assert stderr == b""
22 changes: 22 additions & 0 deletions integrationtests/test_installed_binaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import sys

from integrationtests.prepare_tests import run_cmd


def test_pandoc_installed():
"""Pandoc is callable from the shell."""
returncode, stdout, stderr = run_cmd("pandoc -v")
assert returncode == 0
assert stdout.startswith(b"pandoc")
assert stderr == b""


def test_garphviz_installed():
"""Graphviz is installed."""
if sys.platform == "win32":
returncode, stdout, stderr = run_cmd("dot.bat -V")
else:
returncode, stdout, stderr = run_cmd("dot -V")
assert returncode == 0
assert stdout == b""
assert stderr.startswith(b"dot - graphviz version")
34 changes: 34 additions & 0 deletions integrationtests/test_python_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import os
import sys

import pytest

from integrationtests.prepare_tests import read_initial_settings


@pytest.mark.skipif("NOT_ACTIVATED" not in os.environ, reason="Conda python is used")
def test_python_not_changed():
"""Same python as initially."""
initial_settings = read_initial_settings()
assert initial_settings["executable"] == sys.executable
assert initial_settings["version_info"] == str(sys.version_info)


@pytest.mark.skipif("NOT_ACTIVATED" in os.environ, reason="Conda python is not used")
def test_python_from_conda():
"""Same python if from conda."""
initial_settings = read_initial_settings()
assert initial_settings["executable"] != sys.executable
assert "miniconda" in sys.executable.lower()


@pytest.mark.skipif("ENV_PYTHON" not in os.environ, reason="Not a conda custom python")
def test_custom_python_from_conda():
"""Same python if from conda."""
assert sys.version.startswith(os.environ["ENV_PYTHON"])


@pytest.mark.skipif("PYPY_TEST" not in os.environ, reason="Not a pypy test")
def test_pypy_from_conda():
"""Installed python version is PyPy."""
assert sys.version.splitlines()[1].startswith("[PyPy")
9 changes: 9 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
clearMocks: true,
preset: "ts-jest",
moduleFileExtensions: ["js", "ts"],
testEnvironment: "node",
testMatch: ["**/*.test.ts"],
testRunner: "jest-circus/runner",
verbose: true,
};
3,997 changes: 3,997 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "setup-conda",
"version": "1.0.2",
"private": true,
"description": "Github Action to install conda",
"main": "dist/index.js",
"scripts": {
"test_build": "tsc",
"watch_test_build": "tsc -w",
"package": "ncc build src/main.ts -o dist",
"release-compare-file": "ncc build src/main.ts -o compare",
"format": "biome format --write --files-ignore-unknown=true --no-errors-on-unmatched",
"lint": "biome check --write --files-ignore-unknown=true --no-errors-on-unmatched",
"test": "jest",
"upgrade-deps": "ncu --upgrade"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s-weigand/setup-conda.git"
},
"keywords": ["actions", "node", "setup"],
"prettier": {
"semi": false,
"singleQuote": true,
"trailingComma": "all"
},
"author": "Sebastian Weigand",
"license": "Apache-2.0",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/exec": "^1.1.1",
"@actions/io": "^1.1.3",
"temp": "^0.9.4"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@types/jest": "^29.5.13",
"@types/node": "^22.7.7",
"@types/temp": "^0.9.4",
"@vercel/ncc": "^0.38.2",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"npm-check-updates": "^17.1.4",
"ts-jest": "^29.2.5",
"typescript": "^5.6.3"
}
}
295 changes: 295 additions & 0 deletions src/conda_actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
import { existsSync } from "node:fs";
import { EOL } from "node:os";
import { join, normalize } from "node:path";
import { addPath, endGroup, exportVariable, startGroup } from "@actions/core";
import { exec } from "@actions/exec";

import type { ConfigObject } from "./load_config";

/**
* Sets up conda to be later used.
*
* @param config Configuration of the action
*/
export const setup_conda = async (config: ConfigObject): Promise<void> => {
const initialPythonLocation = await get_python_location();
await addCondaToPath(config);
// await activate_conda(config)
await chown_conda_macOs(config);
await add_conda_channels(config);
await update_conda(config);
await install_python(config);
await activate_conda(config);
await reset_base_python(config, initialPythonLocation);
};

/**
* Only add path_to_add to the PATH variable if it exists
*
* @param path_to_add Path to add to the PATH variable
*/
const sane_add_path = (path_to_add: string): void => {
if (existsSync(path_to_add)) {
addPath(path_to_add);
}
};

/**
* Adds the bin dirs of default Python or Conda to Path
*
* @param python_dist_dir Root directory of a Python dist dir
* @param config Configuration of the action
*/
const add_bin_dir = (python_dist_dir: string, config: ConfigObject): void => {
if (config.os === "win32") {
sane_add_path(join(python_dist_dir, "mingw-w64", "Library", "bin"));
sane_add_path(join(python_dist_dir, "usr", "Library", "bin"));
sane_add_path(join(python_dist_dir, "Library", "bin"));
sane_add_path(join(python_dist_dir, "Scripts"));
} else {
sane_add_path(join(python_dist_dir, "bin"));
}
};

/**
* Add the conda main dir and the binary dir to the path variable.
*
* @param config Configuration of the action
*/
export const addCondaToPath = async (config: ConfigObject): Promise<void> => {
startGroup("Adding conda path to PATH");
console.log("The CONDA env var is:", process.env.CONDA);
const conda_base_path = process.env.CONDA;
let errorMessageAppendix: string[] = [];
if (conda_base_path === undefined) {
if (config.os === "darwin" && process.env.ImageOS !== undefined) {
const macImageVersion = Number(process.env.ImageOS.replace("macos", ""));
if (macImageVersion > 12) {
errorMessageAppendix = [
'MacOS images newer than "macos-12" (i.e. "macOS-latest") are known to be ' +
"incompatible with this action due to a missing miniconda installation.",
"See: https://github.com/s-weigand/setup-conda/issues/432",
];
}
}
throw new Error(
[
"Could not determine conda base path, it seams conda is not installed.",
...errorMessageAppendix,
].join(EOL),
);
}
sane_add_path(conda_base_path);
add_bin_dir(conda_base_path, config);
endGroup();
};

interface ParsedActivationScript {
condaPaths: string[];
envVars: { [name: string]: string };
}

/**
* Parse `conda shell.<shell_name> activate <env_name>`scripts outputs
*
* @param activationStr Output of the activation script
* @param envExport Prefix to which is used to export an env variable
* @param osPathSep Character to separate path in the PATH variable
* @returns condaPaths
*/
export const parseActivationScriptOutput = async (
activationStr: string,
envExport: string,
osPathSep: string,
): Promise<ParsedActivationScript> => {
let condaPaths: string[] = [];
const envVars: { [name: string]: string } = {};
const lines = activationStr.split(envExport);
for (const line of lines) {
if (line.startsWith("PATH")) {
const paths = line.replace(/PATH\s?=|'|"|\n|\s/g, "").split(osPathSep);
condaPaths = paths
.filter((path) => path.toLowerCase().indexOf("miniconda") !== -1)
.filter(
(orig, index, self) => index === self.findIndex((subSetItem) => subSetItem === orig),
);
} else {
// eslint-disable-next-line prefer-const
let [varName, varValue] = line.replace(/\s?=\s?/g, "=").split("=");

if (varValue !== undefined && varName !== "CONDA_SHLVL") {
varValue = varValue.replace(/('|")?\r?\n$/gm, "").replace(/^'|"/gm, "");
envVars[`${varName}`] = varValue;
}
}
}
return { condaPaths, envVars };
};

/**
* Activates the conda base env by changing the path and env variables.
*
* @param config Configuration of the action
*/
const activate_conda = async (config: ConfigObject): Promise<void> => {
const condaEnvName = config.python_version === "default" ? "base" : "__setup_conda";
startGroup(`Activating conda ${condaEnvName}`);
let parsedActivationScript: ParsedActivationScript;
let activationStr = "";

const options = { listeners: {} };
options.listeners = {
stdout: (data: Buffer) => {
activationStr = data.toString();
},
};
console.log("Conda activate script:");
if (config.os === "win32") {
await exec("conda", ["shell.powershell", "activate", condaEnvName], options);
parsedActivationScript = await parseActivationScriptOutput(activationStr, "$Env:", ";");
} else {
await exec("conda", ["shell.bash", "activate", condaEnvName], options);
parsedActivationScript = await parseActivationScriptOutput(activationStr, "export ", ":");
}
const condaPaths = parsedActivationScript.condaPaths.sort((a, _) => a.indexOf("envs"));
console.log("\n\nData used for activation:\n", {
condaPaths,
envVars: parsedActivationScript.envVars,
});
for (const condaPath of condaPaths) {
sane_add_path(condaPath);
}
for (const [varName, varValue] of Object.entries(parsedActivationScript.envVars)) {
exportVariable(varName, varValue);
}
endGroup();
};

const get_python_location = async (): Promise<string> => {
startGroup("Getting original pythonLocation");
let pythonLocation = "";

const options = { listeners: {} };
options.listeners = {
stdout: (data: Buffer) => {
pythonLocation = data.toString();
},
};
await exec("which", ["python"], options);
endGroup();
return pythonLocation;
};

/**
* Sets the python version back to the default version
*
* @param config Configuration of the action
*/
const reset_base_python = async (
config: ConfigObject,
initialPythonLocation: string,
): Promise<void> => {
if (config.activate_conda !== true) {
startGroup("Resetting Python:");
let pythonLocation = "";
if (process.env.pythonLocation) {
pythonLocation = process.env.pythonLocation;
} else {
pythonLocation = normalize(join(initialPythonLocation, ".."));

if (config.os === "win32") {
pythonLocation = pythonLocation.replace(/^\\c/, "C:");
}
}
console.log("Using python at: ", pythonLocation);
sane_add_path(pythonLocation);
add_bin_dir(pythonLocation, config);
}
endGroup();
};

/**
* Adds channels to the configuration of conda.
*
* @param config Configuration of the action
*/
const add_conda_channels = async (config: ConfigObject): Promise<void> => {
if (config.conda_channels.length !== 0) {
startGroup("Adding conda-channels:");
for (const channel of config.conda_channels) {
if (channel !== "") {
console.log("Adding: ", channel);
await exec("conda", ["config", "--add", "channels", channel]);
}
}
endGroup();
}
};

/**
* This is to prevent a bug not allowing to install
* conda packages on the maxOs runner,
* since the config and miniconda belong to a different user.
*
* @param config Configuration of the action
*/
const chown_conda_macOs = async (config: ConfigObject): Promise<void> => {
if (config.os === "darwin") {
console.log("Changing owner of conda folders");
const config_path = join(process.env.HOME as string, ".conda");
const user_name = process.env.USER;
await exec("sudo", ["chown", "-R", `${user_name}:staff`, config_path]);
await exec("sudo", ["chown", "-R", `${user_name}:staff`, process.env.CONDA as string]);
}
};

/**
* Updates conda itself.
*
* @param config Configuration of the action
*/
const update_conda = async (config: ConfigObject): Promise<void> => {
if (config.update_conda) {
startGroup("Updating conda:");
await exec("conda", ["update", "-y", "-n", "base", "-c", "defaults", "conda"]);
endGroup();
}
};

/**
* Create conda environment for Python or PyPy.
*
* @param requested_pyver Requested Python/PyPy version
*/
const create_conda_env = async (requested_pyver: string): Promise<void> => {
await exec("conda", ["create", "-y", "-n", "__setup_conda", requested_pyver]);
};

/**
* Installs the python version specified in inputs.
*
* @param config Configuration of the action
*/
const install_python = async (config: ConfigObject): Promise<void> => {
const { python_version } = config;
if (python_version !== "default") {
startGroup(`Installing conda python ${config.python_version}`);
if (python_version.match(/^\d+\.\d+(\.\d+)?$/) !== null) {
await create_conda_env(`python=${config.python_version}`);
} else if (python_version.match(/^pypy(([23]\.\d+)?(=(\d+)?(\.\d+)?(\.\d+)?)?)?$/) !== null) {
await create_conda_env(config.python_version);
} else {
throw new Error(
[
`The value of "python-version" you provided was ${python_version}, which is invalid.`,
'The value of "python-version" needs to be of form:',
/^\d+\.\d+(\.\d+)?$/,
"(for Python) or",
/^pypy(([23]\.\d+)?(=(\d+)?(\.\d+)?(\.\d+)?)?)?$/,
"(for PyPy and PyPy3)",
].join(EOL),
);
}
endGroup();
}
};
30 changes: 30 additions & 0 deletions src/load_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { getInput } from "@actions/core";

export interface ConfigObject {
activate_conda: boolean;
update_conda: boolean;
python_version: string;
conda_channels: string[];
os: string;
}

/**
* Read the values of the inputs and operating system.
*/
export const loadConfig = (): ConfigObject => {
const activate_conda = getInput("activate-conda") === "true";
const update_conda = getInput("update-conda") === "true";
const python_version = getInput("python-version");
const conda_channels = getInput("conda-channels")
.replace(/ /g, "")
.split(",")
.filter((channel) => channel !== "");
const os = process.platform;
return {
activate_conda,
update_conda,
python_version,
conda_channels,
os,
};
};
18 changes: 18 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { setFailed } from "@actions/core";
import { setup_conda } from "./conda_actions";
import { loadConfig } from "./load_config";

async function run(): Promise<void> {
try {
const config = loadConfig();
await setup_conda(config);
} catch (error) {
if (typeof error === "string") {
setFailed(error);
} else if (error instanceof Error) {
setFailed(error.message);
}
}
}

run();
63 changes: 63 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */

/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */

/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */

/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"exclude": ["node_modules", "**/*.test.ts"]
}