Image generation scipts
This commit is contained in:
Родитель
99d5e5105a
Коммит
b645c2fe85
|
@ -0,0 +1,68 @@
|
|||
name: Release Containers
|
||||
|
||||
on:
|
||||
#repository_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Get Tag Name
|
||||
id: get_tag_name
|
||||
uses: olegtarasov/get-tag@v1
|
||||
|
||||
- name: Container Registry Login
|
||||
id: docker_login
|
||||
uses: azure/docker-login@v1
|
||||
with:
|
||||
login-server: ${{ secrets.REGISTRY }}
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Checkout
|
||||
id: checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Push and Package
|
||||
id: push_and_package
|
||||
run: |
|
||||
# Push images and package
|
||||
yarn install
|
||||
build/vscdc pack --release ${{ steps.get_tag_name.outputs.tag }} \
|
||||
--github-repo ${{ github.repository }} \
|
||||
--registry ${{ secrets.REGISTRY }} \
|
||||
--registry-path ${{ secrets.REGISTRY_BASE_PATH }} \
|
||||
--stub-registry ${{ secrets.STUB_REGISTRY }} \
|
||||
--stub-registry-path ${{ secrets.STUB_REGISTRY_BASE_PATH }}
|
||||
|
||||
# Set an output with the resulting package name for upload
|
||||
PKG_PREFIX=$(node -p "require('./package.json').name")
|
||||
echo "::set-output name=package_name::$(ls $PKG_PREFIX-*.tgz)"
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1.0.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Upload NPM Package as Release Asset
|
||||
id: upload_release_asset
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./${{ steps.push_and_package.outputs.package_name }}
|
||||
asset_name: ${{ steps.push_and_package.outputs.package_name }}
|
||||
asset_content_type: application/gzip
|
|
@ -0,0 +1,69 @@
|
|||
name: CI & Push "dev"
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
push:
|
||||
branches: master
|
||||
paths:
|
||||
- 'containers/**'
|
||||
- 'script-library/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: "!contains(github.event.head_commit.message, 'Automated update') && !contains(github.event.head_commit.message, 'CI ignore')"
|
||||
|
||||
steps:
|
||||
|
||||
- name: Container Registry Login
|
||||
id: docker_login
|
||||
uses: azure/docker-login@v1
|
||||
with:
|
||||
login-server: ${{ secrets.REGISTRY }}
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Checkout
|
||||
id: checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Push "dev", Package, update CG manifest
|
||||
id: push_and_package
|
||||
run: |
|
||||
# Push dev images and package
|
||||
set -e
|
||||
|
||||
yarn install
|
||||
|
||||
GIT_BRANCH=$(echo "${{ github.ref }}" | grep -oP 'refs/(heads|tags)/\K(.+)')
|
||||
if [ "$GIT_BRANCH" == "" ]; then
|
||||
GIT_BRANCH=master
|
||||
fi
|
||||
build/vscdc pack --release $GIT_BRANCH \
|
||||
--github-repo ${{ github.repository }} \
|
||||
--registry ${{ secrets.REGISTRY }} \
|
||||
--registry-path ${{ secrets.REGISTRY_BASE_PATH }} \
|
||||
--stub-registry ${{ secrets.STUB_REGISTRY }} \
|
||||
--stub-registry-path ${{ secrets.STUB_REGISTRY_BASE_PATH }}
|
||||
|
||||
# Set an output with the resulting package name for upload
|
||||
PKG_PREFIX=$(node -p "require('./package.json').name")
|
||||
mv ./$PKG_PREFIX-*.tgz ./$PKG_PREFIX-${{ github.sha }}.tgz
|
||||
echo "::set-output name=package_name::$PKG_PREFIX-${{ github.sha }}.tgz"
|
||||
|
||||
# Update CG manifest
|
||||
build/vscdc cg --no-build --release $BRANCH --github-repo ${{ github.repository }} --registry ${{ secrets.REGISTRY }} --registry-path ${{ secrets.REGISTRY_BASE_PATH }}
|
||||
git config --global user.email "vscr-feedback@microsoft.com"
|
||||
git config --global user.name "CI"
|
||||
git add cgmanifest.json
|
||||
git commit -m 'Automated update' \
|
||||
&& git push "https://ci:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" "HEAD:${{ github.ref }}" \
|
||||
|| echo 'No updates to cgmanifest.json'
|
||||
|
||||
- name: Upload Package
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: ${{ steps.push_and_package.outputs.package_name }}
|
||||
path: ./${{ steps.push_and_package.outputs.package_name }}
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Run Push Script",
|
||||
"program": "${workspaceFolder}/build/vscdc",
|
||||
"args": [
|
||||
"push",
|
||||
"--release", "clantz/image-generation",
|
||||
"--github-repo", "microsoft/vscode-dev-containers",
|
||||
"--registry", "clantz.azurecr.io",
|
||||
"--registryPath", "vscode/devcontainers",
|
||||
"--stubRegistry", "clantz.azurecr.io",
|
||||
"--stubRegistryPath", "vscode/devcontainers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Run Pack Script",
|
||||
"program": "${workspaceFolder}/build/vscdc",
|
||||
"args": [
|
||||
"pack",
|
||||
"--no-clean",
|
||||
"--release", "clantz/image-generation",
|
||||
"--github-repo", "microsoft/vscode-dev-containers",
|
||||
"--registry", "clantz.azurecr.io",
|
||||
"--registryPath", "vscode/devcontainers",
|
||||
"--stubRegistry", "clantz.azurecr.io",
|
||||
"--stubRegistryPath", "vscode/devcontainers"
|
||||
]
|
||||
}, {
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Run CG Manifest Script",
|
||||
"program": "${workspaceFolder}/build/vscdc",
|
||||
"args": [
|
||||
"cg",
|
||||
"--no-build",
|
||||
"--release", "clantz/image-generation",
|
||||
"--github-repo", "microsoft/vscode-dev-containers",
|
||||
"--registry", "clantz.azurecr.io",
|
||||
"--registryPath", "vscode/devcontainers"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,3 +1,13 @@
|
|||
{
|
||||
"extensions.ignoreRecommendations": true
|
||||
"extensions.ignoreRecommendations": true,
|
||||
"cSpell.words": [
|
||||
"Distro",
|
||||
"Dockerfiles",
|
||||
"copyfiles",
|
||||
"devcontainer",
|
||||
"devcontainers",
|
||||
"dpkg",
|
||||
"npmignore",
|
||||
"redhat"
|
||||
]
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
trigger:
|
||||
branches:
|
||||
include: ['*']
|
||||
tags:
|
||||
include: ['*']
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "10.15.1"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.19.1"
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
yarn
|
||||
|
||||
NAME=$(node -p "require('./package.json').name")
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
|
||||
TMP_NAME="$NAME-$VERSION.tgz"
|
||||
|
||||
if [[ "$BUILD_SOURCEBRANCH" != refs/tags/* ]]; then
|
||||
VERSION="$VERSION-${BUILD_SOURCEVERSION:0:8}"
|
||||
fi
|
||||
|
||||
TGZ_NAME="$NAME-$VERSION.tgz"
|
||||
TGZ_PATH="$SYSTEM_ARTIFACTSDIRECTORY/$TGZ_NAME"
|
||||
|
||||
npm pack
|
||||
mv "$TMP_NAME" "$TGZ_PATH"
|
||||
|
||||
echo "##vso[task.setvariable variable=TgzName]$TGZ_NAME"
|
||||
echo "##vso[task.setvariable variable=TgzPath]$TGZ_PATH"
|
||||
displayName: Build
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Pipeline Artifact'
|
||||
inputs:
|
||||
artifactName: $(TgzName)
|
||||
targetPath: $(TgzPath)
|
||||
|
||||
- task: GitHubRelease@0
|
||||
displayName: 'Create GitHub Release'
|
||||
inputs:
|
||||
gitHubConnection: 'GitHub Connection'
|
||||
repositoryName: $(Build.Repository.Name)
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))
|
|
@ -0,0 +1,18 @@
|
|||
module.exports = {
|
||||
"env": {
|
||||
"commonjs": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"require-atomic-updates": 0
|
||||
}
|
||||
};
|
|
@ -0,0 +1,282 @@
|
|||
# Build and image generation for vscode-dev-containers
|
||||
|
||||
This folder contains scripts to build and push images into the Microsoft Container Registry (MCR) from this repository, generate or modify any associated content to use the built image, track dependencies, and create an npm package with the result that is shipped in the VS Code Remote - Containers extension.
|
||||
|
||||
## Build CLI
|
||||
|
||||
The Node.js based build CLI (`build/vsdc`) has commands to:
|
||||
|
||||
1. Build and push to a repository: `build/vsdc push`
|
||||
2. Build, push, and npm package assets that are modified as described above: `build/vsdc package`
|
||||
3. Generate cgmanifest.json: `build/vsdc cg`
|
||||
|
||||
Run with the `--help` option to see inputs.
|
||||
|
||||
## Setting up a container to be built
|
||||
|
||||
> **Note:** Only Microsoft VS Code team members can currently onboard an image to this process since it requires access the Microsoft Container Registry. However, if you have your own pre-built image or build process, you can simply reference it directly in you contributed container.
|
||||
|
||||
Image build/push to MCR is managed using config in `definition-build.json` files that are located in the container definition folder. The config lets you set dependencies between definitions and map actual image tags to multiple definitions. So, the steps to onboard an image are:
|
||||
|
||||
1. Create a `definition-build.json` file
|
||||
2. Update the `vscode` config files for MCR as appropriate (MS internal only).
|
||||
|
||||
Let's run through the `definition-build.json` file.
|
||||
|
||||
### The build property
|
||||
|
||||
The `build` property defines how the definition maps to image tags and what type of "stub" should be used. Consider the Debian 9 [definition-build.json](../containers/debian-9-git/definition-build.json) file.
|
||||
|
||||
```json
|
||||
"build": {
|
||||
"rootDistro": "debian",
|
||||
"latest": true,
|
||||
"tags": [
|
||||
"base:${VERSION}-debian-9",
|
||||
"base:${VERSION}-stretch"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The **`rootDistro`** property can be `debian`, `alpine`, or `redhat` currently. Ubuntu-based containers should use `debian`.
|
||||
|
||||
The **`latest`** and **`tags`** properties affect how tags are applied. For example, here is how several dev container folders map:
|
||||
|
||||
```text
|
||||
debian-9-git => mcr.microsoft.com/vscode/devcontainers/base:debian-9
|
||||
alpine-3.10-git => mcr.microsoft.com/vscode/devcontainers/base:alpine-3.10
|
||||
ubnutu-18.04-git => mcr.microsoft.com/vscode/devcontainers/base:ubuntu-18.04
|
||||
javascript-node-12 => mcr.microsoft.com/vscode/devcontainers/javascript-node:12
|
||||
typescript-node-10 => mcr.microsoft.com/vscode/devcontainers/typescript-node:12
|
||||
javascript-node-10 => mcr.microsoft.com/vscode/devcontainers/javascript-node:10
|
||||
typescript-node-10 => mcr.microsoft.com/vscode/devcontainers/typescript-node:10
|
||||
```
|
||||
|
||||
This results in just three "repositories" in the registry much like you would see for other images in Docker Hub.
|
||||
|
||||
- mcr.microsoft.com/vscode/devcontainers/base
|
||||
- mcr.microsoft.com/vscode/devcontainers/javascript-node
|
||||
- mcr.microsoft.com/vscode/devcontainers/typescript-node
|
||||
|
||||
The package version is then automatically added to these various tags in the `${VERSION}` location for an item in the `tags` property array as a part of the release. For example, release 0.40.0 would result in:
|
||||
|
||||
mcr.microsoft.com/vscode/devcontainers/base
|
||||
|
||||
- 0.40.0-debian-9
|
||||
- 0.40-debian-9
|
||||
- 0-debian-9
|
||||
- debian-9 <= Equivalent of latest for debian-9 specifically
|
||||
- 0.40.0-stretch
|
||||
- 0.40-stretch
|
||||
- 0-stretch
|
||||
- stretch <= Equivalent of latest for stretch specifically
|
||||
|
||||
In this case, Debian is also the one that is used for `latest` for the `base` repository, so that tag gets applied too. If you ran only the Alpine or Ubuntu versions, the latest tag would not update.
|
||||
|
||||
There's a special "dev" version that can be used to build master on CI - I ended up needing this to test and others would if they base an image off of one of the MCR images. e.g. `dev-debian-9`.
|
||||
|
||||
Finally, there is a **`parent`** property that can be used to specify if the container depends an image created as a part of another container build. For example, `typescript-node-10` uses the image from `javascript-node-10` and therefore includes the following:
|
||||
|
||||
```json
|
||||
"build" {
|
||||
"parent": "javascript-node-10"
|
||||
}
|
||||
```
|
||||
|
||||
### The dependencies property
|
||||
|
||||
The dependencies property is used for dependency and version tracking. Consider the Debian 9 [definition-build.json](../containers/debian-9-git/definition-build.json) file.
|
||||
|
||||
```json
|
||||
"dependencies": {
|
||||
"image": "debian:9",
|
||||
"imageLink": "https://hub.docker.com/_/debian",
|
||||
"debian": [
|
||||
"apt-utils",
|
||||
"..."
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The **`image`** property is the actual base Docker image either in Docker Hub or MCR. **`imageLink`** is then the link to a dscription of the image.
|
||||
|
||||
Following this is a list of libraries installed in the image by its Dockerfile. The following package types are currently supported:
|
||||
|
||||
- `debian` - Debian packages (apt-get)
|
||||
- `ubuntu` - Ubuntu packages (apt-get)
|
||||
- `alpine` - Alpine Linux packages (apk)
|
||||
- `npm` - npmjs.com packages installed using npm or yarn
|
||||
- `manual` - Useful for other types of registrations that do not have a specific type, like `git` in the example above.
|
||||
|
||||
For everything but `manual`, the image that is generated is started so the package versions can be queried automatically.
|
||||
|
||||
## Details
|
||||
|
||||
Currently the vscode-dev-containers repo contains pure Dockerfiles that need to be built when used. While this works well from the perspective of providing samples, some of the images install a significant number of runtimes or tools which can take a long time to build.
|
||||
|
||||
We can resolve this by pre-building some of these images, but in-so-doing we want to make sure we:
|
||||
|
||||
1. Ensure vscode-dev-containers continues to be a good source of samples
|
||||
2. Improve the performance using the most popular (or in some cases slowest to build) container images
|
||||
3. Make it easy for users to add additional software to the images
|
||||
4. Make it easy for contributors to build, customize, and contribute new definitions
|
||||
|
||||
We won't be able to build all images in the repository or publish them under a Microsoft registry, but we would want to allow contributors to build their own images for contributions if they wanted to do so by keeping the ability to use a stand alone Dockerfile, image reference, or docker-compose file like today.
|
||||
|
||||
## Image generation for vscode-dev-containers
|
||||
|
||||
In order to meet the above requirements, this first phase keeps the way the dev containers deployed as it is now - an npm package. Future phases could introduce a formal registry, but this is overkill current state.
|
||||
|
||||
### Versioning
|
||||
|
||||
At this phase, versioning of the image can be tied to the release of the npm package. For example, as of this writing, the current version is 0.35.0. All images that are generated would then inherit this version.
|
||||
|
||||
We would follow semver rules for bumping up the repository name - any fix that needs to be deployed immediately would be "fix" level semver bump. When released as latest, the image would be tagged as is done in other Docker images. Using the 0.35.0 example, new images would be tagged as:
|
||||
|
||||
- 0
|
||||
- 0.35
|
||||
- 0.35.0
|
||||
- latest
|
||||
|
||||
In the unlikely event a break fix needed to be deployed and not tagged latest, we would have a facility to tag as follows:
|
||||
|
||||
- 0.35
|
||||
- 0.35.0
|
||||
|
||||
This has a few advantages:
|
||||
|
||||
1. Tags are generated for each version of the repository that is cut. This allows us to refer directly to the exact version of the source code used to build the container image to avoid confusion. e.g. `https://github.com/microsoft/vscode-dev-containers/tree/v0.35.0/containers/javascript-node-8`
|
||||
2. Similarly, as containers are deprecated and removed from the repository, you can still refer back to the container source and README.
|
||||
3. Upstream changes that break existing images can be handled as needed.
|
||||
4. Developers can opt to use the image tag 0.35 to get the latest break fix version if desired or 0 to always get the latest non-breaking update.
|
||||
|
||||
This scheme will work in the near term where we do not have a large number of dev containers in the repository, but over time will not scale. However, to realistically support independent versioning, we'd need to build out a registry service - which may or may not be required. This will be evaluated at a later date.
|
||||
|
||||
### Deprecation of container definitions
|
||||
|
||||
The versioning scheme above allows us to version dev containers and reference them even when they are removed from `master`. To keep the number of containers in `master` reasonable, we would deprecate and remove containers under the following scenarios:
|
||||
|
||||
1. It refers to a runtime that is no longer supported - e.g. Node.js 8 is out of support as of the end of 2019, so we would deprecate `javascript-node-8`. Until that point, we would have containers for node 8, 10, and 12 (which just went LTS).
|
||||
2. The container is not used enough to maintain and has broken.
|
||||
3. The container refers to a product that has been deprecated.
|
||||
4. The container was contributed by a 3rd party, has issues, and the 3rd party is not responsive.
|
||||
|
||||
Since the images would continue to exist after this point and the source code is available under the version label, we can safely remove the containers from master without impacting customers.
|
||||
|
||||
### Release process and the contents of the npm package
|
||||
|
||||
When a release is cut, there are a few things that need to happen. One is obviously releasing the appropriate image. However, to continue to help customers understand how to customize their images, we would want to reference a user modifiable "stub" Dockerfile instead of an image directly. This also is important to help deal with shortcomings and workarounds that require something like specifying a build argument. For example:
|
||||
|
||||
```Dockerfile
|
||||
FROM mcr.microsoft.com/vscode/devcontainer/javascript-node:0.35-10
|
||||
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# [Optional] Update UID/GID if needed and install additional software
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
if [ "$USER_GID" != "1000" ]; then sudo groupmod 1000 --gid $USER_GID; fi \
|
||||
&& if [ "$USER_UID" != "1000" ]; then sudo usermod --uid $USER_UID 1000; fi; \
|
||||
fi \
|
||||
#
|
||||
# ***************************************************************
|
||||
# * Add steps for installing any other needed dependencies here *
|
||||
# ***************************************************************
|
||||
#
|
||||
# Clean up
|
||||
&& sudo apt-get autoremove -y \
|
||||
&& sudo apt-get clean -y \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
```
|
||||
|
||||
This retains its value as a sample but minimizes the number of actual build steps. This template would **evolve over time as new features are added**. For example, the above Dockerfile includes a way to make sure the user's GID/UID matches the local operating system - which is critical for Linux users. However, if we introduce a `user` concept in `devcontainer.json`, the template would no longer need to include this part of the file.
|
||||
|
||||
Referencing The MAJOR.MINOR version in this Dockerfile allows us to push fixes or upstream updates that do not materially change the definition.
|
||||
|
||||
### Repository contents
|
||||
|
||||
Consequently, this user stub Dockerfile needs to be versioned with the `devcontainer.json` file and can technically version independently of the actual main Dockerfile and image. Given this tie, it makes sense to keep this file with `devcontainer.json` in the repository. The repository therefore would could contain:
|
||||
|
||||
```text
|
||||
📁 .devcontainer
|
||||
📄 base.Dockerfile
|
||||
📄 devcontainer.json
|
||||
📄 Dockerfile
|
||||
📁 test-project
|
||||
📄 README.md
|
||||
```
|
||||
|
||||
Here, `devcontainer.json` points to `base.Dockerfile`, but this is the Dockerfile used to generate the actual image rather than the stub Dockerfile. The stub that references the image is in `base.Dockerfile`. To make things easy, we can also automatically generate this stub at release time if only a Dockerfile is present.
|
||||
|
||||
Testing, then, is as simple as it is now - open the folder in `vscode-dev-containers` in a container and edit / test as required. Anyone simply copying the folder contents then gets a fully working version of the container even if in-flight and there is no image for it yet.
|
||||
|
||||
In the vscode-dev-containers repo itself, the `FROM` statement in `Dockerfile` would always point to `latest` or `dev` since it what is in master may not have even been released yet. This would get dynamically updated as a part of the release process - which we will cover next.
|
||||
|
||||
```Dockerfile
|
||||
FROM mcr.microsoft.com/vs/devcontainer/javascript-node:dev-10
|
||||
```
|
||||
|
||||
#### Automated updates of other Dockerfiles
|
||||
|
||||
The process also automatically swaps out referenced MCR images for MAJOR.MINOR versions of built images in any Dockerfile that is added to the package. This allows us to push break fix and or security patches as break fix releases and people will get them. The build supports an option to not update `latest` and MAJOR versions, so we can also rev old MAJOR.MINOR versions if we have to, but normally we'd roll forward instead.
|
||||
|
||||
#### Common scripts
|
||||
|
||||
Another problem the build solves is mass updates - there's a set of things we want in every image and right now it requires ~54 changes to add things. With this new process, images use a tagged version of scripts in `script-library`. The build generates a SHA for script so they can be safely used in Dockerfiles that are not built into images while still allowing people to just grab `.devcontainer` from master and use it if they prefer.
|
||||
|
||||
#### Release process
|
||||
|
||||
When a release is cut, the contents of vscode-dev-containers repo would staged. The build process would then do the following for the appropriate dev containers:
|
||||
|
||||
1. Build an image using the `base.Dockerfile` and push it to a container registry with the appropriate version tags. If no `base.Dockerfile` is found, `Dockerfile` is renamed to `base.Dockerfile` and used instead.
|
||||
|
||||
2. After the image is built and pushed, `base.Dockerfile` is deleted from staging.
|
||||
|
||||
3. Next, `Dockerfile` is updated to point to the correct MAJOR.MINOR version. If no Dockerfile is found, a stub is used based on the root image (Alpine vs Debian).
|
||||
|
||||
```Dockerfile
|
||||
# For information on the contents of the image referenced below, see the Dockerfile at
|
||||
# https://github.com/microsoft/vscode-dev-containers/tree/v0.35.0/containers/javascript-node-10/.devcontainer/base.Dockerfile
|
||||
FROM mcr.microsoft.com/vs/devcontainer/javascript-node:0.35-10
|
||||
```
|
||||
|
||||
4. `devcontainer.json` is updated to point to `Dockerfile` instead of `base.Dockerfile` (if required) and add a comment to the source code README for this specific version.
|
||||
|
||||
```json
|
||||
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.35.0/containers/javascript-node-10
|
||||
{
|
||||
"name": "Node.js 10",
|
||||
"dockerFile": "user.Dockerfile",
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
These modified contents are then archived in an npm package exactly as they are today and shipped with the extension (and over time we could dynamically update this between extension releases).
|
||||
|
||||
```text
|
||||
📁 .devcontainer
|
||||
📄 devcontainer.json
|
||||
📄 Dockerfile
|
||||
```
|
|
@ -0,0 +1,35 @@
|
|||
#-------------------------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM REPLACE-ME
|
||||
|
||||
# The image referenced above includes a non-root user with sudo access. Add
|
||||
# the "remoteUser" property to devcontainer.json to use it. On Linux, the container
|
||||
# user's GID/UIDs will be updated to match your local UID/GID when using the image
|
||||
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
|
||||
# dockerComposeFile property or want the image itself to start with different ID
|
||||
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# [Optional] Update UID/GID if needed
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
apk add --no-cache shadow \
|
||||
&& USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd) \
|
||||
&& groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi
|
||||
|
||||
# ************************************************************************
|
||||
# * Uncomment this section to use RUN to install other dependencies. *
|
||||
# * Note that Alpine uses "apk" instead of "apt-get" like Debian/Ubuntu. *
|
||||
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
|
||||
# ************************************************************************
|
||||
# RUN apk update \
|
||||
# && apk add --no-cache <your-package-list-here>
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
|
@ -0,0 +1,42 @@
|
|||
#-------------------------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM REPLACE-ME
|
||||
|
||||
# The image referenced above includes a non-root user with sudo access. Add
|
||||
# the "remoteUser" property to devcontainer.json to use it. On Linux, the container
|
||||
# user's GID/UIDs will be updated to match your local UID/GID when using the image
|
||||
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
|
||||
# dockerComposeFile property or want the image itself to start with different ID
|
||||
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# [Optional] Update UID/GID if needed
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd) \
|
||||
&& groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi
|
||||
|
||||
# *************************************************************
|
||||
# * Uncomment this section to use RUN instructions to install *
|
||||
# * any needed dependencies after executing "apt-get update". *
|
||||
# * See https://docs.docker.com/engine/reference/builder/#run *
|
||||
# *************************************************************
|
||||
# ENV DEBIAN_FRONTEND=noninteractive
|
||||
# RUN apt-get update \
|
||||
# && apt-get -y install --no-reccomends <your-package-list-here> \
|
||||
# #
|
||||
# # Clean up
|
||||
# && apt-get autoremove -y \
|
||||
# && apt-get clean -y \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
# ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#-------------------------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM REPLACE-ME
|
||||
|
||||
# The image referenced above includes a non-root user with sudo access. Add
|
||||
# the "remoteUser" property to devcontainer.json to use it. On Linux, the container
|
||||
# user's GID/UIDs will be updated to match your local UID/GID when using the image
|
||||
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
|
||||
# dockerComposeFile property or want the image itself to start with different ID
|
||||
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# [Optional] Update UID/GID if needed
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd) \
|
||||
&& groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi
|
||||
|
||||
# ************************************************************************
|
||||
# * Uncomment this section to use RUN to install other dependencies. *
|
||||
# * Note that RedHat uses "yum" instead of "apt-get" like Debian/Ubuntu. *
|
||||
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
|
||||
# ************************************************************************
|
||||
# RUN yum -y install <your-package-list-here> \
|
||||
# #
|
||||
# # Clean up
|
||||
# && yum clean all
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"containerRegistry": "devcon.azurecr.io",
|
||||
"containerRegistryPath": "public/vscode/devcontainers",
|
||||
"stubRegistry": "mcr.microsoft.com",
|
||||
"stubRegistryPath": "vscode/devcontainers",
|
||||
|
||||
"filesToStage": [
|
||||
"+(containers|repository-containers)/**/!(test-project)/*",
|
||||
"LICENSE",
|
||||
"package.json",
|
||||
"yarn.lock",
|
||||
".npmignore"
|
||||
],
|
||||
|
||||
"githubRepoName": "microsoft/vscode-dev-containers",
|
||||
"containersPathInRepo": "containers",
|
||||
"scriptLibraryPathInRepo": "script-library",
|
||||
"definitionBuildConfigFile": "definition-build.json",
|
||||
|
||||
"devContainerJsonPreamble": "For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:",
|
||||
"dockerFilePreamble": "For information on the contents of the container image below, see following Dockerfile:"
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
const path = require('path');
|
||||
const push = require('./push').push;
|
||||
const asyncUtils = require('./utils/async');
|
||||
const configUtils = require('./utils/config');
|
||||
|
||||
// Example manifest: https://dev.azure.com/mseng/AzureDevOps/_git/Governance.Specs?path=%2Fcgmanifest.json&version=GBusers%2Fcajone%2Fcgmanifest.json
|
||||
// Docker images and native OS libraries need to be registered as "other" while others are scenario dependant
|
||||
|
||||
const dependencyLookupConfig = {
|
||||
debian: {
|
||||
// Command to get package versions: dpkg-query --show -f='${Package}\t${Version}\n' <package>
|
||||
// Output: <package> <version>
|
||||
// Command to get download URLs: apt-get update && apt-get install -y --reinstall --print-uris
|
||||
namePrefix: 'Debian Package:',
|
||||
listCommand: "dpkg-query --show -f='${Package}\t${Version}\n'",
|
||||
lineRegEx: /(.+)\t(.+)/,
|
||||
getUriCommand: 'apt-get update && apt-get install -y --reinstall --print-uris',
|
||||
uriMatchRegex: "'(.+)'\\s*${PACKAGE}_${VERSION}"
|
||||
},
|
||||
ubuntu: {
|
||||
// Command to get package versions: dpkg-query --show -f='${Package}\t${Version}\n' <package>
|
||||
// Output: <package> <version>
|
||||
// Command to get download URLs: apt-get update && apt-get install -y --reinstall --print-uris
|
||||
namePrefix: 'Ubuntu Package:',
|
||||
listCommand: "dpkg-query --show -f='${Package}\t${Version}\n'",
|
||||
lineRegEx: /(.+)\t(.+)/,
|
||||
getUriCommand: 'apt-get update && apt-get install -y --reinstall --print-uris',
|
||||
uriMatchRegex: "'(.+)'\\s*${PACKAGE}_${VERSION}"
|
||||
},
|
||||
alpine: {
|
||||
// Command to get package versions: apk info -e -v <package>
|
||||
// Output: <package-with-maybe-dashes>-<version-with-dashes>
|
||||
// Command to get download URLs: apk policy
|
||||
namePrefix: 'Alpine Package:',
|
||||
listCommand: "apk info -e -v",
|
||||
lineRegEx: /(.+)-([0-9].+)/,
|
||||
getUriCommand: 'apk update && apk policy',
|
||||
uriMatchRegex: '${PACKAGE} policy:\\n.*${VERSION}:\\n.*lib/apk/db/installed\\n\\s*(.+)\\n',
|
||||
uriSuffix: '/x86_64/${PACKAGE}-${VERSION}.apk'
|
||||
}
|
||||
}
|
||||
|
||||
async function generateComponentGovernanceManifest(repo, release, registry, registryPath, buildFirst) {
|
||||
// Load config files
|
||||
await configUtils.loadConfig();
|
||||
|
||||
if (buildFirst) {
|
||||
// Simulate the build and push process, but don't actually push
|
||||
console.log('(*) Simulating push process to trigger image builds...');
|
||||
await push(repo, release, false, registry, registryPath, registry, registryPath, true);
|
||||
} else {
|
||||
console.log('(*) Using existing local images...');
|
||||
}
|
||||
|
||||
const alreadyRegistered = {};
|
||||
const cgManifest = {
|
||||
"Registrations": [],
|
||||
"Version": 1
|
||||
}
|
||||
|
||||
console.log('(*) Generating manifest...');
|
||||
const definitionDependencies = configUtils.getAllDependencies();
|
||||
for (let definitionId in definitionDependencies) {
|
||||
const dependencies = definitionDependencies[definitionId];
|
||||
if (typeof dependencies === 'object') {
|
||||
|
||||
// Add Docker image registration
|
||||
const [image, imageVersion] = dependencies.image.split(':');
|
||||
if (typeof alreadyRegistered[dependencies.image] === 'undefined') {
|
||||
cgManifest.Registrations.push({
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": `Docker Image: ${image}`,
|
||||
"Version": imageVersion,
|
||||
"DownloadUrl": dependencies.imageLink
|
||||
}
|
||||
}
|
||||
});
|
||||
alreadyRegistered[dependencies.image] = [imageVersion];
|
||||
}
|
||||
|
||||
// Docker image to use to determine installed package versions
|
||||
const imageTag = configUtils.getTagsForVersion(definitionId, 'dev', registry, registryPath)[0]
|
||||
|
||||
// Run commands in the package to pull out needed versions
|
||||
cgManifest.Registrations = cgManifest.Registrations.concat(
|
||||
await generatePackageComponentList(dependencyLookupConfig.debian, dependencies.debian, imageTag, alreadyRegistered),
|
||||
await generatePackageComponentList(dependencyLookupConfig.ubuntu, dependencies.ubuntu, imageTag, alreadyRegistered),
|
||||
await generatePackageComponentList(dependencyLookupConfig.alpine, dependencies.alpine, imageTag, alreadyRegistered),
|
||||
await generateNpmComponentList(dependencies.npm, alreadyRegistered),
|
||||
filteredManualComponentRegistrations(dependencies.manual, alreadyRegistered));
|
||||
}
|
||||
}
|
||||
console.log('(*) Writing manifest...');
|
||||
await asyncUtils.writeFile(
|
||||
path.join(__dirname, '..', '..', 'cgmanifest.json'),
|
||||
JSON.stringify(cgManifest, undefined, 4))
|
||||
console.log('(*) Done!');
|
||||
}
|
||||
|
||||
async function generatePackageComponentList(config, packageList, imageTag, alreadyRegistered) {
|
||||
if(!packageList) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const componentList = [];
|
||||
console.log(`(*) Generating Linux package registrations for ${imageTag}...`);
|
||||
|
||||
// Generate and exec command to get installed package versions
|
||||
console.log('(*) Getting package versions...');
|
||||
const packageVersionListCommand = packageList.reduce((prev, current) => {
|
||||
return prev += ` ${current}`;
|
||||
}, config.listCommand);
|
||||
const packageVersionListOutput = await asyncUtils.spawn('docker',
|
||||
['run', '--rm', imageTag, packageVersionListCommand],
|
||||
{ shell: true, stdio: 'pipe' });
|
||||
|
||||
// Generate and exec command to extract download URIs
|
||||
console.log('(*) Getting package download URLs...');
|
||||
const packageUriCommand = packageList.reduce((prev, current) => {
|
||||
return prev += ` ${current}`;
|
||||
}, config.getUriCommand);
|
||||
const packageUriCommandOutput = await asyncUtils.spawn('docker',
|
||||
['run', '--rm', imageTag, `sh -c '${packageUriCommand}'`],
|
||||
{ shell: true, stdio: 'pipe' });
|
||||
|
||||
const packageVersionList = packageVersionListOutput.split('\n');
|
||||
packageVersionList.forEach((packageVersion) => {
|
||||
packageVersion = packageVersion.trim();
|
||||
if (packageVersion !== '') {
|
||||
const versionCaptureGroup = new RegExp(config.lineRegEx).exec(packageVersion);
|
||||
const package = versionCaptureGroup[1];
|
||||
const version = versionCaptureGroup[2];
|
||||
|
||||
const entry = createEntryForLinuxPackage(packageUriCommandOutput, config.namePrefix, package, version, alreadyRegistered, config.uriMatchRegex, config.uriSuffix)
|
||||
if (entry) {
|
||||
componentList.push(entry);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return componentList;
|
||||
}
|
||||
|
||||
function createEntryForLinuxPackage(packageUriCommandOutput, entryNamePrefix, package, version, alreadyRegistered, uriMatchRegex, uriSuffix)
|
||||
{
|
||||
const uniquePackageName = `${entryNamePrefix} ${package}`;
|
||||
if (typeof alreadyRegistered[uniquePackageName] === 'undefined'
|
||||
|| alreadyRegistered[uniquePackageName].indexOf(version) < 0) {
|
||||
|
||||
// Handle regex reserved charters in regex strings and that ":" is treaded as "1%3a" on Debian/Ubuntu
|
||||
const sanitizedPackage = package.replace(/\+/g, '\\+').replace(/\./g, '\\.');
|
||||
const sanitizedVersion = version.replace(/\+/g, '\\+').replace(/\./g, '\\.').replace(/:/g, '%3a');
|
||||
const uriCaptureGroup = new RegExp(
|
||||
uriMatchRegex.replace('${PACKAGE}', sanitizedPackage).replace('${VERSION}', sanitizedVersion), 'm')
|
||||
.exec(packageUriCommandOutput);
|
||||
|
||||
if (!uriCaptureGroup) {
|
||||
console.log(`(!) No URI found for ${package} ${version}`)
|
||||
}
|
||||
|
||||
const uriString = uriCaptureGroup ? uriCaptureGroup[1] : '';
|
||||
|
||||
alreadyRegistered[uniquePackageName] = alreadyRegistered[uniquePackageName] || [];
|
||||
alreadyRegistered[uniquePackageName].push(version);
|
||||
|
||||
return {
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": uniquePackageName,
|
||||
"Version": version,
|
||||
"DownloadUrl": `${uriString}${uriSuffix ?
|
||||
uriSuffix.replace('${PACKAGE}', package).replace('${VERSION}', version)
|
||||
: ''}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function filteredManualComponentRegistrations(manualRegistrations, alreadyRegistered) {
|
||||
if(!manualRegistrations) {
|
||||
return [];
|
||||
}
|
||||
const componentList = [];
|
||||
manualRegistrations.forEach((component) => {
|
||||
const key = JSON.stringify(component);
|
||||
if (typeof alreadyRegistered[key] === 'undefined') {
|
||||
componentList.push(component);
|
||||
alreadyRegistered[key] = [key];
|
||||
}
|
||||
});
|
||||
return componentList;
|
||||
}
|
||||
|
||||
async function generateNpmComponentList(packageList, alreadyRegistered) {
|
||||
if(!packageList) {
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log(`(*) Generating npm registrations...`);
|
||||
|
||||
const componentList = [];
|
||||
await asyncUtils.forEach(packageList, async (package) => {
|
||||
let version = '';
|
||||
if (package.indexOf('@') >= 0) {
|
||||
[package, version] = package.split('@');
|
||||
} else {
|
||||
const npmInfoRaw = await asyncUtils.spawn('npm', ['info', package, '--json'], { shell: true, stdio: 'pipe' });
|
||||
const npmInfo = JSON.parse(npmInfoRaw);
|
||||
version = npmInfo['dist-tags'].latest;
|
||||
}
|
||||
const uniquePackageName = `npm-${package}`;
|
||||
if (typeof alreadyRegistered[uniquePackageName] === 'undefined'
|
||||
|| alreadyRegistered[uniquePackageName].indexOf(version) < 0) {
|
||||
componentList.push({
|
||||
"Component": {
|
||||
"Type": "npm",
|
||||
"Npm": {
|
||||
"Name": package,
|
||||
"Version": version
|
||||
}
|
||||
}
|
||||
});
|
||||
alreadyRegistered[uniquePackageName] = alreadyRegistered[uniquePackageName] || [];
|
||||
alreadyRegistered[uniquePackageName].push(version);
|
||||
}
|
||||
});
|
||||
return componentList;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateComponentGovernanceManifest: generateComponentGovernanceManifest
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*--------------------------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
*-------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
const path = require('path');
|
||||
const push = require('./push').push;
|
||||
const prep = require('./prep');
|
||||
const asyncUtils = require('./utils/async');
|
||||
const configUtils = require('./utils/config');
|
||||
const packageJson = require('../../package.json');
|
||||
|
||||
async function package(repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, pushImages, cleanWhenDone, simulate) {
|
||||
stubRegistry = stubRegistry || registry;
|
||||
stubRegistryPath = stubRegistryPath || registryPath;
|
||||
|
||||
// Load config files
|
||||
await configUtils.loadConfig();
|
||||
|
||||
// Stage content
|
||||
const stagingFolder = await configUtils.getStagingFolder(release);
|
||||
const definitionStagingFolder = path.join(stagingFolder, 'containers');
|
||||
|
||||
if (pushImages) {
|
||||
// First, push images, update content
|
||||
await push(repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate);
|
||||
}
|
||||
|
||||
// Then package
|
||||
console.log(`\n(*) **** Package ${release} ****`);
|
||||
|
||||
console.log(`(*) Updating package.json with release version...`);
|
||||
const version = configUtils.getVersionFromRelease(release);
|
||||
const packageJsonVersion = version === 'dev' ? packageJson.version + '-dev' : version;
|
||||
const packageJsonPath = path.join(stagingFolder, 'package.json');
|
||||
const packageJsonRaw = await asyncUtils.readFile(packageJsonPath);
|
||||
const packageJsonModified = packageJsonRaw.replace(/"version".?:.?".+"/, `"version": "${packageJsonVersion}"`);
|
||||
await asyncUtils.writeFile(packageJsonPath, packageJsonModified);
|
||||
|
||||
// Update all definition config files for release (devcontainer.json, Dockerfile)
|
||||
const allDefinitions = await asyncUtils.readdir(definitionStagingFolder);
|
||||
await asyncUtils.forEach(allDefinitions, async (currentDefinitionId) => {
|
||||
await prep.updateConfigForRelease(
|
||||
path.join(definitionStagingFolder, currentDefinitionId),
|
||||
currentDefinitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath);
|
||||
});
|
||||
|
||||
console.log('(*) Packaging...');
|
||||
const opts = { stdio: 'inherit', cwd: stagingFolder, shell: true };
|
||||
await asyncUtils.spawn('yarn', ['install'], opts);
|
||||
await asyncUtils.spawn('npm', ['pack'], opts); // Need to use npm due to https://github.com/yarnpkg/yarn/issues/685
|
||||
|
||||
let outputPath = null;
|
||||
if (simulate) {
|
||||
console.log('(*) Simulating: Skipping package move.');
|
||||
} else {
|
||||
console.log('(*) Moving package...');
|
||||
outputPath = path.join(__dirname, '..', '..', `${packageJson.name}-${packageJsonVersion}.tgz`);
|
||||
await asyncUtils.rename(path.join(stagingFolder, `${packageJson.name}-${packageJsonVersion}.tgz`), outputPath);
|
||||
}
|
||||
|
||||
if (cleanWhenDone) {
|
||||
// And finally clean up
|
||||
console.log('(*) Cleaning up...');
|
||||
await asyncUtils.rimraf(stagingFolder);
|
||||
}
|
||||
|
||||
console.log('(*) Done!!');
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
package: package
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*--------------------------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
*-------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
const path = require('path');
|
||||
const asyncUtils = require('./utils/async');
|
||||
const configUtils = require('./utils/config');
|
||||
|
||||
const scriptSHA = {};
|
||||
|
||||
const assetsPath = path.join(__dirname, '..', 'assets');
|
||||
const stubPromises = {
|
||||
alpine: asyncUtils.readFile(path.join(assetsPath, 'alpine.Dockerfile')),
|
||||
debian: asyncUtils.readFile(path.join(assetsPath, 'debian.Dockerfile')),
|
||||
redhat: asyncUtils.readFile(path.join(assetsPath, 'redhat.Dockerfile'))
|
||||
}
|
||||
|
||||
const containersPathInRepo = configUtils.getConfig('containersPathInRepo');
|
||||
const scriptLibraryPathInRepo = configUtils.getConfig('scriptLibraryPathInRepo');
|
||||
|
||||
async function prepDockerFile(devContainerDockerfilePath, definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath, isForBuild) {
|
||||
// Use exact version of building, MAJOR.MINOR if not
|
||||
const version = isForBuild ? configUtils.getVersionFromRelease(release) : configUtils.majorMinorFromRelease(release);
|
||||
|
||||
// Read Dockerfile
|
||||
const devContainerDockerfileRaw = await asyncUtils.readFile(devContainerDockerfilePath);
|
||||
let devContainerDockerfileModified = devContainerDockerfileRaw;
|
||||
|
||||
// Replace script URL and generate SHA if applicable
|
||||
const scriptCaptureGroups = new RegExp(`COMMON_SCRIPT_SOURCE="(.+)/${scriptLibraryPathInRepo.replace('.', '\\.')}/(.+)"`).exec(devContainerDockerfileRaw);
|
||||
if (scriptCaptureGroups) {
|
||||
const scriptName = scriptCaptureGroups[2];
|
||||
const scriptSource = `https://raw.githubusercontent.com/${repo}/${release}/${scriptLibraryPathInRepo}/${scriptName}`;
|
||||
let sha = scriptSHA[scriptName];
|
||||
if (typeof sha === 'undefined') {
|
||||
const scriptRaw = await asyncUtils.getUrlAsString(scriptSource);
|
||||
sha = await asyncUtils.shaForString(scriptRaw);
|
||||
scriptSHA[scriptName] = sha;
|
||||
}
|
||||
devContainerDockerfileModified = devContainerDockerfileModified
|
||||
.replace(/COMMON_SCRIPT_SHA=".+"/, `COMMON_SCRIPT_SHA="${sha}"`)
|
||||
.replace(/COMMON_SCRIPT_SOURCE=".+"/, `COMMON_SCRIPT_SOURCE="${scriptSource}"`);
|
||||
}
|
||||
|
||||
if (isForBuild) {
|
||||
// If building, update FROM to target registry and version if definition has a parent
|
||||
const parentTag = configUtils.getParentTagForVersion(definitionId, version, registry, registryPath);
|
||||
if (parentTag) {
|
||||
devContainerDockerfileModified = devContainerDockerfileModified.replace(/FROM .+:.+/, `FROM ${parentTag}`)
|
||||
}
|
||||
} else {
|
||||
// Otherwise update any Dockerfiles that refer to an un-versioned tag of another dev container
|
||||
// to the MAJOR.MINOR version from this release.
|
||||
const expectedRegistry = configUtils.getConfig('stubRegistry', 'mcr.microsoft.com');
|
||||
const expectedRegistryPath = configUtils.getConfig('stubRegistryPath', 'vscode/devcontainers');
|
||||
const fromCaptureGroups = new RegExp(`FROM (${expectedRegistry}/${expectedRegistryPath}/.+:.+)`).exec(devContainerDockerfileRaw);
|
||||
if (fromCaptureGroups && fromCaptureGroups.length > 0) {
|
||||
const fromDefinitionTag = configUtils.getUpdatedTag(
|
||||
fromCaptureGroups[1],
|
||||
expectedRegistry,
|
||||
expectedRegistryPath,
|
||||
version,
|
||||
stubRegistry,
|
||||
stubRegistryPath);
|
||||
devContainerDockerfileModified = devContainerDockerfileModified
|
||||
.replace(fromCaptureGroups[0], `FROM ${fromDefinitionTag}`);
|
||||
}
|
||||
}
|
||||
|
||||
await asyncUtils.writeFile(devContainerDockerfilePath, devContainerDockerfileModified)
|
||||
}
|
||||
|
||||
function getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists) {
|
||||
return `# ${configUtils.getConfig('dockerFilePreamble')}\n` +
|
||||
`# https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}/.devcontainer/${baseDockerFileExists ? 'base.' : ''}Dockerfile\n` +
|
||||
`FROM ${imageTag}`;
|
||||
}
|
||||
|
||||
async function createStub(dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath) {
|
||||
const userDockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
|
||||
console.log('(*) Generating user Dockerfile...');
|
||||
const templateDockerfile = await configUtils.objectByDefinitionLinuxDistro(definitionId, stubPromises);
|
||||
const majorMinor = configUtils.majorMinorFromRelease(release);
|
||||
const imageTag = configUtils.getTagsForVersion(definitionId, majorMinor, stubRegistry, stubRegistryPath)[0];
|
||||
const userDockerFile = templateDockerfile.replace(
|
||||
'FROM REPLACE-ME', getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists));
|
||||
await asyncUtils.writeFile(userDockerFilePath, userDockerFile);
|
||||
}
|
||||
|
||||
async function updateStub(dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, registry, registryPath) {
|
||||
console.log('(*) Updating user Dockerfile...');
|
||||
const userDockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
|
||||
const userDockerFile = await asyncUtils.readFile(userDockerFilePath);
|
||||
|
||||
const majorMinor = configUtils.majorMinorFromRelease(release);
|
||||
const imageTag = configUtils.getTagsForVersion(definitionId, majorMinor, registry, registryPath)[0];
|
||||
const userDockerFileModified = userDockerFile.replace(/FROM .+:.+/,
|
||||
getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists));
|
||||
await asyncUtils.writeFile(userDockerFilePath, userDockerFileModified);
|
||||
}
|
||||
|
||||
async function updateConfigForRelease(definitionPath, definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath) {
|
||||
// Look for context in devcontainer.json and use it to build the Dockerfile
|
||||
console.log(`(*) Making version specific updates to ${definitionId}...`);
|
||||
const dotDevContainerPath = path.join(definitionPath, '.devcontainer');
|
||||
const devContainerJsonPath = path.join(dotDevContainerPath, 'devcontainer.json');
|
||||
const devContainerJsonRaw = await asyncUtils.readFile(devContainerJsonPath);
|
||||
const devContainerJsonModified =
|
||||
`// ${configUtils.getConfig('devContainerJsonPreamble')}\n// https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}\n` +
|
||||
devContainerJsonRaw;
|
||||
await asyncUtils.writeFile(devContainerJsonPath, devContainerJsonModified);
|
||||
|
||||
// Replace version specific content in Dockerfile
|
||||
const dockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
|
||||
if (await asyncUtils.exists(dockerFilePath)) {
|
||||
await prepDockerFile(dockerFilePath, definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath, false);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createStub: createStub,
|
||||
updateStub: updateStub,
|
||||
updateConfigForRelease: updateConfigForRelease,
|
||||
prepDockerFile: prepDockerFile
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*--------------------------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
*-------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
const path = require('path');
|
||||
const jsonc = require('jsonc').jsonc;
|
||||
const asyncUtils = require('./utils/async');
|
||||
const configUtils = require('./utils/config');
|
||||
const prep = require('./prep');
|
||||
|
||||
async function push(repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate, definitionId) {
|
||||
stubRegistry = stubRegistry || registry;
|
||||
stubRegistryPath = stubRegistryPath || registryPath;
|
||||
|
||||
// Load config files
|
||||
await configUtils.loadConfig();
|
||||
|
||||
// Stage content
|
||||
const stagingFolder = await configUtils.getStagingFolder(release);
|
||||
const definitionStagingFolder = path.join(stagingFolder, 'containers');
|
||||
|
||||
// Build and push subset of images
|
||||
const definitionsToPush = definitionId ? [definitionId] : configUtils.getSortedDefinitionBuildList();
|
||||
await asyncUtils.forEach(definitionsToPush, async (currentDefinitionId) => {
|
||||
console.log(`**** Pushing ${currentDefinitionId} ${release} ****`);
|
||||
await pushImage(
|
||||
path.join(definitionStagingFolder, currentDefinitionId),
|
||||
currentDefinitionId, repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate);
|
||||
});
|
||||
|
||||
return stagingFolder;
|
||||
}
|
||||
|
||||
async function pushImage(definitionPath, definitionId, repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate) {
|
||||
const dotDevContainerPath = path.join(definitionPath, '.devcontainer');
|
||||
// Use base.Dockerfile for image build if found, otherwise use Dockerfile
|
||||
const baseDockerFileExists = await asyncUtils.exists(path.join(dotDevContainerPath, 'base.Dockerfile'));
|
||||
const dockerFilePath = path.join(dotDevContainerPath, `${baseDockerFileExists ? 'base.' : ''}Dockerfile`);
|
||||
|
||||
// Make sure there's a Dockerfile present
|
||||
if (!await asyncUtils.exists(dockerFilePath)) {
|
||||
throw `Invalid path ${dockerFilePath}`;
|
||||
}
|
||||
|
||||
// Determine tags to use
|
||||
const versionTags = configUtils.getTagList(definitionId, release, updateLatest, registry, registryPath)
|
||||
console.log(`(*) Tags:${versionTags.reduce((prev, current) => prev += `\n ${current}`, '')}`);
|
||||
|
||||
// Look for context in devcontainer.json and use it to build the Dockerfile
|
||||
console.log('(*) Reading devcontainer.json...');
|
||||
const devContainerJsonPath = path.join(dotDevContainerPath, 'devcontainer.json');
|
||||
const devContainerJsonRaw = await asyncUtils.readFile(devContainerJsonPath);
|
||||
const devContainerJson = jsonc.parse(devContainerJsonRaw);
|
||||
|
||||
// Update common setup script download URL, SHA
|
||||
console.log(`(*) Prep Dockerfile for ${definitionId}...`);
|
||||
await prep.prepDockerFile(dockerFilePath,
|
||||
definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath, true);
|
||||
|
||||
// Build image
|
||||
console.log(`(*) Building image...`);
|
||||
const workingDir = path.resolve(dotDevContainerPath, devContainerJson.context || '.')
|
||||
const buildParams = versionTags.reduce((prev, current) => prev.concat(['-t', current]), []);
|
||||
const spawnOpts = { stdio: 'inherit', cwd: workingDir, shell: true };
|
||||
await asyncUtils.spawn('docker', ['build', workingDir, '-f', dockerFilePath].concat(buildParams), spawnOpts);
|
||||
|
||||
// Push
|
||||
if (simulate) {
|
||||
console.log(`(*) Simulating: Skipping push to registry.`);
|
||||
} else {
|
||||
console.log(`(*) Pushing ${definitionId}...`);
|
||||
await asyncUtils.forEach(versionTags, async (versionTag) => {
|
||||
await asyncUtils.spawn('docker', ['push', versionTag], spawnOpts);
|
||||
});
|
||||
}
|
||||
|
||||
// If base.Dockerfile found, update stub/devcontainer.json, otherwise create
|
||||
if (baseDockerFileExists) {
|
||||
await prep.updateStub(
|
||||
dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath);
|
||||
console.log('(*) Updating devcontainer.json...');
|
||||
await asyncUtils.writeFile(devContainerJsonPath, devContainerJsonRaw.replace('"base.Dockerfile"', '"Dockerfile"'));
|
||||
console.log('(*) Removing base.Dockerfile...');
|
||||
await asyncUtils.rimraf(dockerFilePath);
|
||||
} else {
|
||||
await prep.createStub(
|
||||
dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath);
|
||||
}
|
||||
|
||||
console.log('(*) Done!\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
push: push
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*--------------------------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
*-------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const crypto = require('crypto');
|
||||
const rimrafCb = require('rimraf');
|
||||
const mkdirpCb = require('mkdirp');
|
||||
const copyFilesCb = require('copyfiles');
|
||||
const spawnCb = require('child_process').spawn;
|
||||
|
||||
module.exports = {
|
||||
|
||||
// async forEach
|
||||
forEach: async (array, cb) => {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
await cb(array[i], i, array);
|
||||
}
|
||||
},
|
||||
|
||||
// async spawn
|
||||
spawn: async (command, args, opts) => {
|
||||
console.log(`(*) Spawn: ${command}${args.reduce((prev, current) => `${prev} ${current}`, '')}`);
|
||||
|
||||
opts = opts || { stdio: 'inherit', shell: true };
|
||||
return new Promise((resolve, reject) => {
|
||||
let result = '';
|
||||
let errorOutput = '';
|
||||
const proc = spawnCb(command, args, opts);
|
||||
proc.on('close', (code, signal) => {
|
||||
if (code !== 0) {
|
||||
console.log(result);
|
||||
console.error(errorOutput);
|
||||
reject(`Non-zero exit code: ${code} ${signal || ''}`);
|
||||
return;
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
if (proc.stdout) {
|
||||
proc.stdout.on('data', (chunk) => result += chunk.toString());
|
||||
}
|
||||
if (proc.stderr) {
|
||||
proc.stderr.on('data', (chunk) => result += chunk.toString());
|
||||
}
|
||||
proc.on('error', reject);
|
||||
});
|
||||
},
|
||||
|
||||
// async rename
|
||||
rename: async (from, to) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.rename(from, to, (err) => err ? reject(err) : resolve());
|
||||
});
|
||||
},
|
||||
|
||||
// async readFile
|
||||
readFile: async (filePath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(filePath, 'utf8', (err, data) => err ? reject(err) : resolve(data.toString()));
|
||||
});
|
||||
},
|
||||
|
||||
// async writeFile
|
||||
writeFile: async function (filePath, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(filePath, data, 'utf8', (err) => err ? reject(err) : resolve(filePath));
|
||||
});
|
||||
},
|
||||
|
||||
// async mkdirp
|
||||
mkdirp: async (pathToMake) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
mkdirpCb(pathToMake, (err, made) => err ? reject(err) : resolve(made));
|
||||
});
|
||||
},
|
||||
|
||||
// async rimraf
|
||||
rimraf: async (pathToRemove, opts) => {
|
||||
opts = opts || {};
|
||||
return new Promise((resolve, reject) => {
|
||||
rimrafCb(pathToRemove, opts, (err) => err ? reject(err) : resolve(pathToRemove));
|
||||
});
|
||||
},
|
||||
|
||||
// async copyfiles
|
||||
copyFiles: async (source, blobs, target) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
process.chdir(source);
|
||||
copyFilesCb(
|
||||
blobs.concat(target),
|
||||
{ all: true },
|
||||
(err) => err ? reject(err) : resolve(target));
|
||||
});
|
||||
},
|
||||
|
||||
// async readdir
|
||||
readdir: async (dirPath, opts) => {
|
||||
opts = opts || {};
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readdir(dirPath, opts, (err, files) => err ? reject(err) : resolve(files));
|
||||
});
|
||||
},
|
||||
|
||||
// async exists
|
||||
exists: async (filePath) => {
|
||||
return fs.existsSync(filePath);
|
||||
},
|
||||
|
||||
// async gen SHA 256 hash for file
|
||||
shaForFile: async (filePath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fd = fs.createReadStream(filePath);
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.setEncoding('hex');
|
||||
fd.on('end', function () {
|
||||
hash.end();
|
||||
resolve(hash.read());
|
||||
});
|
||||
fd.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
fd.pipe(hash);
|
||||
})
|
||||
},
|
||||
|
||||
// async gen SHA 256 hash for string
|
||||
shaForString: async (content) => {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(content);
|
||||
return hash.digest('hex');
|
||||
},
|
||||
|
||||
// async HTTPS get
|
||||
getUrlAsString: async (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let content = '';
|
||||
const req = https.get(url, function (res) {
|
||||
res.on('data', function (chunk) {
|
||||
content += chunk.toString();
|
||||
});
|
||||
});
|
||||
req.on("error", reject);
|
||||
req.on('close', () => resolve(content));
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,251 @@
|
|||
/*--------------------------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
*-------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const asyncUtils = require('./async');
|
||||
const jsonc = require('jsonc').jsonc;
|
||||
const config = require('../../config.json');
|
||||
|
||||
config.definitionDependencies = config.definitionDependencies || {};
|
||||
config.definitionBuildSettings = config.definitionBuildSettings || {};
|
||||
|
||||
const stagingFolders = {};
|
||||
const definitionTagLookup = {};
|
||||
|
||||
// Must be called first
|
||||
async function loadConfig(repoPath) {
|
||||
repoPath = repoPath || path.join(__dirname, '..', '..', '..');
|
||||
|
||||
const containersPath = path.join(repoPath, getConfig('containersPathInRepo', 'containers'));
|
||||
const definitions = await asyncUtils.readdir(containersPath, { withFileTypes: true });
|
||||
await asyncUtils.forEach(definitions, async (definitionFolder) => {
|
||||
if (!definitionFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
const definitionId = definitionFolder.name;
|
||||
const possibleDefinitionBuildJson = path.join(containersPath, definitionId, getConfig('definitionBuildConfigFile', 'definition-build.json'));
|
||||
if (await asyncUtils.exists(possibleDefinitionBuildJson)) {
|
||||
const buildJson = await jsonc.read(possibleDefinitionBuildJson);
|
||||
if (buildJson.build) {
|
||||
config.definitionBuildSettings[definitionId] = buildJson.build;
|
||||
}
|
||||
if (buildJson.dependencies) {
|
||||
config.definitionDependencies[definitionId] = buildJson.dependencies;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Populate tag lookup
|
||||
for (let definitionId in config.definitionBuildSettings) {
|
||||
if (config.definitionBuildSettings[definitionId].tags) {
|
||||
const blankTagList = getTagsForVersion(definitionId, '', 'ANY', 'ANY');
|
||||
blankTagList.forEach((blankTag) => {
|
||||
definitionTagLookup[blankTag] = definitionId;
|
||||
});
|
||||
const devTagList = getTagsForVersion(definitionId, 'dev', 'ANY', 'ANY');
|
||||
devTagList.forEach((devTag) => {
|
||||
definitionTagLookup[devTag] = definitionId;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a value from the config file or a similarly named env var
|
||||
function getConfig(property, defaultVal) {
|
||||
defaultVal = defaultVal || null;
|
||||
// Generate env var name from property - camelCase to CAMEL_CASE
|
||||
const envVar = property.split('').reduce((prev, next) => {
|
||||
if (next >= 'A' && next <= 'Z') {
|
||||
return prev + '_' + next;
|
||||
} else {
|
||||
return prev + next.toLocaleUpperCase();
|
||||
}
|
||||
}, '');
|
||||
|
||||
return process.env[envVar] || config[property] || defaultVal;
|
||||
}
|
||||
|
||||
|
||||
// Convert a release string (v1.0.0) or branch (master) into a version
|
||||
function getVersionFromRelease(release) {
|
||||
// Already is a version
|
||||
if (!isNaN(parseInt(release.charAt(0)))) {
|
||||
return release;
|
||||
}
|
||||
|
||||
// Is a release string
|
||||
if (release.charAt(0) === 'v' && !isNaN(parseInt(release.charAt(1)))) {
|
||||
return release.substr(1);
|
||||
}
|
||||
|
||||
// Is a branch
|
||||
return 'dev';
|
||||
}
|
||||
|
||||
// Look up distro and fallback to debian if not specified
|
||||
function getLinuxDistroForDefinition(definitionId) {
|
||||
return config.definitionBuildSettings[definitionId].rootDistro || 'debian';
|
||||
}
|
||||
|
||||
// Generate 'latest' flavor of a given definition's tag
|
||||
function getLatestTag(definitionId, registry, registryPath) {
|
||||
if (typeof config.definitionBuildSettings[definitionId] === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
return config.definitionBuildSettings[definitionId].tags.reduce((list, tag) => {
|
||||
list.push(`${registry}/${registryPath}/${tag.replace(/:.+/, ':latest')}`);
|
||||
return list;
|
||||
}, []);
|
||||
|
||||
}
|
||||
|
||||
// Create all the needed variants of the specified version identifier for a given definition
|
||||
function getTagsForVersion(definitionId, version, registry, registryPath) {
|
||||
if (typeof config.definitionBuildSettings[definitionId] === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
return config.definitionBuildSettings[definitionId].tags.reduce((list, tag) => {
|
||||
// One of the tags that needs to be supported is one where there is no version, but there
|
||||
// are other attributes. For example, python:3 in addition to python:0.35.0-3. So, a version
|
||||
// of '' is allowed. However, there are also instances that are just the version, so in
|
||||
// these cases latest would be used instead. However, latest is passed in separately.
|
||||
const baseTag = tag.replace('${VERSION}', version).replace(':-', ':');
|
||||
if (baseTag.charAt(baseTag.length - 1) !== ':') {
|
||||
list.push(`${registry}/${registryPath}/${baseTag}`);
|
||||
}
|
||||
return list;
|
||||
}, []);
|
||||
}
|
||||
|
||||
// Generate complete list of tags for a given definition
|
||||
function getTagList(definitionId, release, updateLatest, registry, registryPath) {
|
||||
const version = getVersionFromRelease(release);
|
||||
if (version === 'dev') {
|
||||
return getTagsForVersion(definitionId, 'dev', registry, registryPath);
|
||||
}
|
||||
|
||||
const versionParts = version.split('.');
|
||||
if (versionParts.length !== 3) {
|
||||
throw (`Invalid version format in ${version}.`);
|
||||
}
|
||||
|
||||
const versionList = updateLatest ? [
|
||||
version,
|
||||
`${versionParts[0]}.${versionParts[1]}`,
|
||||
`${versionParts[0]}`,
|
||||
'' // This is the equivalent of latest for qualified tags- e.g. python:3 instead of python:0.35.0-3
|
||||
] : [
|
||||
version,
|
||||
`${versionParts[0]}.${versionParts[1]}`
|
||||
];
|
||||
|
||||
// If this variant should actually be the latest tag, use it
|
||||
let tagList = (updateLatest && config.definitionBuildSettings[definitionId].latest) ? getLatestTag(definitionId, registry, registryPath) : [];
|
||||
versionList.forEach((tagVersion) => {
|
||||
tagList = tagList.concat(getTagsForVersion(definitionId, tagVersion, registry, registryPath));
|
||||
});
|
||||
|
||||
return tagList;
|
||||
}
|
||||
|
||||
// Walk the image build config and sort list so parents build before children
|
||||
function getSortedDefinitionBuildList() {
|
||||
const sortedList = [];
|
||||
const settingsCopy = JSON.parse(JSON.stringify(config.definitionBuildSettings));
|
||||
|
||||
for (let definitionId in config.definitionBuildSettings) {
|
||||
const add = (defId) => {
|
||||
if (typeof settingsCopy[defId] === 'object') {
|
||||
add(settingsCopy[defId].parent);
|
||||
sortedList.push(defId);
|
||||
settingsCopy[defId] = undefined;
|
||||
}
|
||||
}
|
||||
add(definitionId);
|
||||
}
|
||||
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
// Get parent tag for a given child definition
|
||||
function getParentTagForVersion(definitionId, version, registry, registryPath) {
|
||||
const parentId = config.definitionBuildSettings[definitionId].parent;
|
||||
return parentId ? getTagsForVersion(parentId, version, registry, registryPath)[0] : null;
|
||||
}
|
||||
|
||||
function getUpdatedTag(currentTag, currentRegistry, currentRegistryPath, updatedVersion, updatedRegistry, updatedRegistryPath) {
|
||||
updatedRegistry = updatedRegistry || currentRegistry;
|
||||
updatedRegistryPath = updatedRegistryPath || currentRegistryPath;
|
||||
const captureGroups = new RegExp(`${currentRegistry}/${currentRegistryPath}/(.+:.+)`).exec(currentTag);
|
||||
const updatedTags = getTagsForVersion(definitionTagLookup[`ANY/ANY/${captureGroups[1]}`], updatedVersion, updatedRegistry, updatedRegistryPath);
|
||||
if (updatedTags && updatedTags.length > 0) {
|
||||
console.log(` Updating ${currentTag}\n to ${updatedTags[0]}`);
|
||||
return updatedTags[0];
|
||||
}
|
||||
// In the case where this is already a tag with a version number in it,
|
||||
// we won't get an updated tag returned, so we'll just reuse the current tag.
|
||||
return currentTag;
|
||||
}
|
||||
|
||||
// Return just the manor and minor version of a release number
|
||||
function majorMinorFromRelease(release) {
|
||||
const version = getVersionFromRelease(release);
|
||||
|
||||
if (version === 'dev') {
|
||||
return 'dev';
|
||||
}
|
||||
|
||||
const versionParts = version.split('.');
|
||||
return `${versionParts[0]}.${versionParts[1]}`;
|
||||
}
|
||||
|
||||
// Return an object from a map based on the linux distro for the definition
|
||||
function objectByDefinitionLinuxDistro(definitionId, objectsByDistro) {
|
||||
const distro = getLinuxDistroForDefinition(definitionId);
|
||||
const obj = objectsByDistro[distro];
|
||||
return obj;
|
||||
}
|
||||
|
||||
function getDefinitionDependencies(definitionId) {
|
||||
return config.definitionDependencies[definitionId];
|
||||
}
|
||||
|
||||
function getAllDependencies() {
|
||||
return config.definitionDependencies;
|
||||
}
|
||||
|
||||
async function getStagingFolder(release) {
|
||||
if (!stagingFolders[release]) {
|
||||
const stagingFolder = path.join(os.tmpdir(), 'vscode-dev-containers', release);
|
||||
console.log(`(*) Copying files to ${stagingFolder}\n`);
|
||||
await asyncUtils.rimraf(stagingFolder); // Clean out folder if it exists
|
||||
await asyncUtils.mkdirp(stagingFolder); // Create the folder
|
||||
await asyncUtils.copyFiles(
|
||||
path.resolve(__dirname, '..', '..', '..'),
|
||||
getConfig('filesToStage'),
|
||||
stagingFolder);
|
||||
|
||||
stagingFolders[release] = stagingFolder;
|
||||
}
|
||||
return stagingFolders[release];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
loadConfig: loadConfig,
|
||||
getTagList: getTagList,
|
||||
getSortedDefinitionBuildList: getSortedDefinitionBuildList,
|
||||
getParentTagForVersion: getParentTagForVersion,
|
||||
getUpdatedTag: getUpdatedTag,
|
||||
majorMinorFromRelease: majorMinorFromRelease,
|
||||
objectByDefinitionLinuxDistro: objectByDefinitionLinuxDistro,
|
||||
getDefinitionDependencies: getDefinitionDependencies,
|
||||
getAllDependencies: getAllDependencies,
|
||||
getStagingFolder: getStagingFolder,
|
||||
getLinuxDistroForDefinition: getLinuxDistroForDefinition,
|
||||
getVersionFromRelease: getVersionFromRelease,
|
||||
getTagsForVersion: getTagsForVersion,
|
||||
getConfig: getConfig
|
||||
};
|
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env node
|
||||
/*--------------------------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
*-------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
const push = require('./src/push').push;
|
||||
const package = require('./src/package').package;
|
||||
const createStub = require('./src/prep').createStub;
|
||||
const generateComponentGovernanceManifest = require('./src/cgmanifest').generateComponentGovernanceManifest;
|
||||
const configUtils = require('./src/utils/config');
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
console.log('vscode-dev-containers CLI\nCopyright (c) Microsoft Corporation. All rights reserved.\n')
|
||||
|
||||
require('yargs')
|
||||
.command('pack', 'package dev container definitions', (yargs) => {
|
||||
yargs
|
||||
.options({
|
||||
'release': {
|
||||
describe: 'vscode-dev-containers release tag or a branch',
|
||||
default: `v${packageJson.version}`
|
||||
},
|
||||
'registry': {
|
||||
describe: 'container registry to push images to',
|
||||
default: configUtils.getConfig('containerRegistry', 'docker.io')
|
||||
},
|
||||
'registry-path': {
|
||||
describe: 'container registry path',
|
||||
default: configUtils.getConfig('containerRegistryPath', 'vscode/devcontainers')
|
||||
},
|
||||
'stub-registry': {
|
||||
describe: 'registry to add to stub',
|
||||
default: configUtils.getConfig('stubRegistry', configUtils.getConfig('containerRegistry', 'docker.io'))
|
||||
},
|
||||
'stub-registry-path': {
|
||||
describe: 'stub registry path',
|
||||
default: configUtils.getConfig('stubRegistryPath', configUtils.getConfig('containerRegistryPath', ''))
|
||||
},
|
||||
'github-repo': {
|
||||
describe: 'vscode-dev-containers repo name',
|
||||
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
|
||||
},
|
||||
'push-images': {
|
||||
describe: 'whether to push before packaging',
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
'update-latest': {
|
||||
describe: 'whether to tag latest and {MAJOR}',
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
'clean': {
|
||||
describe: 'whether to clean up staging folder when done',
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
'simulate': {
|
||||
describe: 'whether to simulate a push instead of doing it',
|
||||
type: 'boolean',
|
||||
default: false
|
||||
}
|
||||
})
|
||||
}, packCommand)
|
||||
.command('push [devcontainer]', 'push dev container images to a repository', (yargs) => {
|
||||
yargs
|
||||
.positional('devcontainer', {
|
||||
describe: 'ID of dev container to push',
|
||||
default: null
|
||||
})
|
||||
.options({
|
||||
'release': {
|
||||
describe: 'vscode-dev-containers release tag or branch',
|
||||
default: `v${packageJson.version}`
|
||||
},
|
||||
'registry': {
|
||||
describe: 'container registry to push images to',
|
||||
default: configUtils.getConfig('containerRegistry', 'docker.io')
|
||||
},
|
||||
'registry-path': {
|
||||
describe: 'container registry path',
|
||||
default: configUtils.getConfig('containerRegistryPath', '')
|
||||
},
|
||||
'stub-registry': {
|
||||
describe: 'registry to add to stub',
|
||||
default: configUtils.getConfig('stubRegistry', configUtils.getConfig('containerRegistry', 'docker.io'))
|
||||
},
|
||||
'stub-registry-path': {
|
||||
describe: 'stub registry path',
|
||||
default: configUtils.getConfig('stubRegistryPath', configUtils.getConfig('containerRegistryPath', ''))
|
||||
},
|
||||
'github-repo': {
|
||||
describe: 'vscode-dev-containers repo name',
|
||||
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
|
||||
},
|
||||
'update-latest': {
|
||||
describe: 'whether to tag latest and {MAJOR} if pushing',
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
'simulate': {
|
||||
describe: 'whether to simulate a push instead of doing it',
|
||||
type: 'boolean',
|
||||
default: false
|
||||
}
|
||||
})
|
||||
}, pushCommand)
|
||||
.command('stub <devcontainer> [path]', 'generates a stub user.Dockerfile', (yargs) => {
|
||||
yargs
|
||||
.positional('devcontainer', {
|
||||
describe: 'ID of dev container to stub',
|
||||
})
|
||||
.positional('path', {
|
||||
describe: 'path to .devcontainer folder',
|
||||
default: '.'
|
||||
})
|
||||
.options({
|
||||
'release': {
|
||||
describe: 'vscode-dev-containers release tag or branch',
|
||||
default: 'dev'
|
||||
},
|
||||
'stub-registry': {
|
||||
describe: 'registry to add to stub',
|
||||
default: configUtils.getConfig('stubRegistry', configUtils.getConfig('containerRegistry', 'docker.io'))
|
||||
},
|
||||
'stub-registry-path': {
|
||||
describe: 'stub registry path',
|
||||
default: configUtils.getConfig('stubRegistryPath', configUtils.getConfig('containerRegistryPath', ''))
|
||||
},
|
||||
'github-repo': {
|
||||
describe: 'vscode-dev-containers repo name',
|
||||
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
|
||||
},
|
||||
'has-base-dockerfile': {
|
||||
describe: 'whether base.Dockerfile exists',
|
||||
type: 'boolean',
|
||||
default: true
|
||||
}
|
||||
})
|
||||
}, stubCommand)
|
||||
.command('cg', 'generate cgmanifest.json', (yargs) => {
|
||||
yargs
|
||||
.options({
|
||||
'release': {
|
||||
describe: 'vscode-dev-containers release tag or branch',
|
||||
default: 'master'
|
||||
},
|
||||
'registry': {
|
||||
describe: 'container registry to push images to',
|
||||
default: configUtils.getConfig('containerRegistry', 'docker.io')
|
||||
},
|
||||
'registry-path': {
|
||||
describe: 'container registry path',
|
||||
default: configUtils.getConfig('containerRegistryPath', '')
|
||||
},
|
||||
'github-repo': {
|
||||
describe: 'vscode-dev-containers repo name',
|
||||
default: configUtils.getConfig('vscodeDevContainersRepo', 'https://github.com/microsoft/vscode-dev-containers')
|
||||
},
|
||||
'build': {
|
||||
describe: 'whether to skip the image build step',
|
||||
default: true
|
||||
}
|
||||
})
|
||||
}, cgCommand)
|
||||
.demandCommand()
|
||||
.help()
|
||||
.argv;
|
||||
|
||||
function pushCommand(argv) {
|
||||
push(argv.githubRepo, argv.release, argv.updateLatest, argv.registry, argv.registryPath, argv.stubRegistry, argv.stubRegistryPath, argv.simulate, argv.devcontainer)
|
||||
.catch((reason) => {
|
||||
console.error(`(!) Push failed - ${reason}`);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function packCommand(argv) {
|
||||
package(argv.githubRepo, argv.release, argv.updateLatest, argv.registry, argv.registryPath, argv.stubRegistry, argv.stubRegistryPath, argv.pushImages, argv.clean, argv.simulate)
|
||||
.catch((reason) => {
|
||||
console.error(`(!) Packaging failed - ${reason}`);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function stubCommand(argv) {
|
||||
createStub(argv.devcontainer, argv.path, argv.githubRepo, argv.release, argv.hasBaseDockerfile, argv.stubRegistry, argv.stubRegistryPath)
|
||||
.catch((reason) => {
|
||||
console.error(`(!) Stub generation failed - ${reason}`);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function cgCommand(argv) {
|
||||
generateComponentGovernanceManifest(argv.githubRepo, argv.release, argv.registry, argv.registryPath, argv.build)
|
||||
.catch((reason) => {
|
||||
console.error(`(!) Component governance manifest generation failed - ${reason}`);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@node vscdc %@
|
514
cgmanifest.json
514
cgmanifest.json
|
@ -1,255 +1,5 @@
|
|||
{
|
||||
"Registrations": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Docker Image: debian",
|
||||
"Version": "9",
|
||||
"DownloadUrl": "https://hub.docker.com/_/debian"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: apt-transport-https",
|
||||
"Version": "1.4.9",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-transport-https_1.4.9_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: apt-utils",
|
||||
"Version": "1.4.9",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-utils_1.4.9_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: ca-certificates",
|
||||
"Version": "20161130+nmu1+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/ca-certificates/ca-certificates_20161130+nmu1+deb9u1_all.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: curl",
|
||||
"Version": "7.52.1-5+deb9u9",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/curl/curl_7.52.1-5+deb9u9_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: dialog",
|
||||
"Version": "1.3-20160828-2",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/d/dialog/dialog_1.3-20160828-2_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: git",
|
||||
"Version": "1:2.11.0-3+deb9u4",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/git/git_2.11.0-3+deb9u4_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: iproute2",
|
||||
"Version": "4.9.0-1+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/iproute2/iproute2_4.9.0-1+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libc6",
|
||||
"Version": "2.24-11+deb9u4",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libgcc1",
|
||||
"Version": "1:6.3.0-18+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libgcc1_6.3.0-18+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libgssapi-krb5-2",
|
||||
"Version": "1.15-1+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/k/krb5/libgssapi-krb5-2_1.15-1+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libicu57",
|
||||
"Version": "57.1-6+deb9u3",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/icu/libicu57_57.1-6+deb9u3_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: liblttng-ust0",
|
||||
"Version": "2.9.0-2+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/ust/liblttng-ust0_2.9.0-2+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libssl1.0.2",
|
||||
"Version": "1.0.2t-1~deb9u1",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl1.0/libssl1.0.2_1.0.2t-1~deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libssl1.1",
|
||||
"Version": "1.1.0l-1~deb9u1",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.0l-1~deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libstdc++6",
|
||||
"Version": "6.3.0-18+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libstdc++6_6.3.0-18+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: lsb-release",
|
||||
"Version": "9.20161125",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/l/lsb/lsb-release_9.20161125_all.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: procps",
|
||||
"Version": "2:3.3.12-3+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/p/procps/procps_3.3.12-3+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: sudo",
|
||||
"Version": "1.8.19p1-2.1+deb9u1",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/s/sudo/sudo_1.8.19p1-2.1+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: unzip",
|
||||
"Version": "6.0-21+deb9u2",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/unzip/unzip_6.0-21+deb9u2_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: wget",
|
||||
"Version": "1.18-5+deb9u3",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/w/wget/wget_1.18-5+deb9u3_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: zlib1g",
|
||||
"Version": "1:1.2.8.dfsg-5",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zlib/zlib1g_1.2.8.dfsg-5_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: zsh",
|
||||
"Version": "5.3.1-4+b3",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zsh/zsh_5.3.1-4+b3_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Docker Image: ubuntu",
|
||||
"Version": "18.04",
|
||||
"DownloadUrl": "https://hub.docker.com/_/ubuntu"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
|
@ -265,8 +15,8 @@
|
|||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Alpine Package: git",
|
||||
"Version": "2.22.0-r0",
|
||||
"DownloadUrl": "http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/git-2.22.0-r0.apk"
|
||||
"Version": "2.22.2-r0",
|
||||
"DownloadUrl": "http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/git-2.22.2-r0.apk"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -386,7 +136,7 @@
|
|||
"Other": {
|
||||
"Name": "Alpine Package: libssl1.1",
|
||||
"Version": "1.1.1d-r0",
|
||||
"DownloadUrl": "http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/libssl1.1-1.1.1d-r0.apk"
|
||||
"DownloadUrl": "1.1.1d-r2:/x86_64/libssl1.1-1.1.1d-r0.apk"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -460,6 +210,246 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Docker Image: debian",
|
||||
"Version": "9",
|
||||
"DownloadUrl": "https://hub.docker.com/_/debian"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: apt-transport-https",
|
||||
"Version": "1.4.9",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-transport-https_1.4.9_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: apt-utils",
|
||||
"Version": "1.4.9",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-utils_1.4.9_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: ca-certificates",
|
||||
"Version": "20161130+nmu1+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/ca-certificates/ca-certificates_20161130+nmu1+deb9u1_all.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: curl",
|
||||
"Version": "7.52.1-5+deb9u9",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/curl/curl_7.52.1-5+deb9u9_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: dialog",
|
||||
"Version": "1.3-20160828-2",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/d/dialog/dialog_1.3-20160828-2_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: git",
|
||||
"Version": "1:2.11.0-3+deb9u5",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/g/git/git_2.11.0-3+deb9u5_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: iproute2",
|
||||
"Version": "4.9.0-1+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/iproute2/iproute2_4.9.0-1+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libc6",
|
||||
"Version": "2.24-11+deb9u4",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libgcc1",
|
||||
"Version": "1:6.3.0-18+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libgcc1_6.3.0-18+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libgssapi-krb5-2",
|
||||
"Version": "1.15-1+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/k/krb5/libgssapi-krb5-2_1.15-1+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libicu57",
|
||||
"Version": "57.1-6+deb9u3",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/icu/libicu57_57.1-6+deb9u3_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: liblttng-ust0",
|
||||
"Version": "2.9.0-2+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/ust/liblttng-ust0_2.9.0-2+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libssl1.0.2",
|
||||
"Version": "1.0.2u-1~deb9u1",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl1.0/libssl1.0.2_1.0.2u-1~deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libssl1.1",
|
||||
"Version": "1.1.0l-1~deb9u1",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.0l-1~deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: libstdc++6",
|
||||
"Version": "6.3.0-18+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libstdc++6_6.3.0-18+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: lsb-release",
|
||||
"Version": "9.20161125",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/l/lsb/lsb-release_9.20161125_all.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: procps",
|
||||
"Version": "2:3.3.12-3+deb9u1",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/p/procps/procps_3.3.12-3+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: sudo",
|
||||
"Version": "1.8.19p1-2.1+deb9u1",
|
||||
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/s/sudo/sudo_1.8.19p1-2.1+deb9u1_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: unzip",
|
||||
"Version": "6.0-21+deb9u2",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/unzip/unzip_6.0-21+deb9u2_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: wget",
|
||||
"Version": "1.18-5+deb9u3",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/w/wget/wget_1.18-5+deb9u3_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: zlib1g",
|
||||
"Version": "1:1.2.8.dfsg-5",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zlib/zlib1g_1.2.8.dfsg-5_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: zsh",
|
||||
"Version": "5.3.1-4+b3",
|
||||
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zsh/zsh_5.3.1-4+b3_amd64.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
|
@ -475,8 +465,8 @@
|
|||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Debian Package: yarn",
|
||||
"Version": "1.19.1-1",
|
||||
"DownloadUrl": "https://dl.yarnpkg.com/debian/pool/main/y/yarn/yarn_1.19.1_all.deb"
|
||||
"Version": "1.21.1-1",
|
||||
"DownloadUrl": "https://dl.yarnpkg.com/debian/pool/main/y/yarn/yarn_1.21.1_all.deb"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -485,7 +475,7 @@
|
|||
"Type": "npm",
|
||||
"Npm": {
|
||||
"Name": "eslint",
|
||||
"Version": "6.6.0"
|
||||
"Version": "6.8.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -513,7 +503,17 @@
|
|||
"Type": "npm",
|
||||
"Npm": {
|
||||
"Name": "typescript",
|
||||
"Version": "3.7.2"
|
||||
"Version": "3.7.4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "other",
|
||||
"Other": {
|
||||
"Name": "Docker Image: ubuntu",
|
||||
"Version": "18.04",
|
||||
"DownloadUrl": "https://hub.docker.com/_/ubuntu"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# Development Container Contribution Templates
|
||||
|
||||
This folder contains a set of templates that you can use to contribute a new development container to this repository. See [CONTRIBUTING.md](../CONTRIBUTING.md) for details on contributing a container.
|
||||
|
||||
If you are looking for a list of dev container definitions that are included in the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension, see the [containers](../containers) folder instead.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the MIT License. See [LICENSE](https://github.com/Microsoft/vscode-dev-containers/blob/master/LICENSE)
|
|
@ -13,32 +13,39 @@ FROM debian:9
|
|||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# The node image includes a non-root user with sudo access. Use the
|
||||
# "remoteUser" property in devcontainer.json to use it. On Linux, update
|
||||
# these values to ensure the container user's UID/GID matches your local values.
|
||||
# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
|
||||
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
|
||||
# will be updated to match your local UID/GID (when using the dockerFile property).
|
||||
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
ARG USERNAME=vscode
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
|
||||
#
|
||||
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
|
||||
&& apt-get -y install git iproute2 procps lsb-release \
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/ash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh \
|
||||
#
|
||||
# *****************************************************
|
||||
# * Add steps for installing needed dependencies here *
|
||||
# *****************************************************
|
||||
#
|
||||
# Create a non-root user
|
||||
&& groupadd --gid $USER_GID $USERNAME \
|
||||
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
|
||||
# [Optional] Add sudo support for the non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
# *********************************************************************
|
||||
# * Uncomment this section to use RUN to install other dependencies. *
|
||||
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
|
||||
# *********************************************************************
|
||||
# && apt-get -y install --no-reccomends <your-package-name-here>
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
|
@ -46,5 +53,5 @@ RUN apt-get update \
|
|||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM debian:9
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
|
@ -16,24 +15,31 @@ ARG USERNAME=vscode
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
|
||||
#
|
||||
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
|
||||
&& apt-get -y install git iproute2 procps lsb-release \
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/ash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh \
|
||||
#
|
||||
# *****************************************************
|
||||
# * Add steps for installing needed dependencies here *
|
||||
# *****************************************************
|
||||
#
|
||||
# Create a non-root user
|
||||
&& groupadd --gid $USER_GID $USERNAME \
|
||||
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
|
||||
# [Optional] Add sudo support for the non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
# *********************************************************************
|
||||
# * Uncomment this section to use RUN to install other dependencies. *
|
||||
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
|
||||
# *********************************************************************
|
||||
# && apt-get -y install --no-reccomends <your-package-list-here>
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
|
@ -41,4 +47,5 @@ RUN apt-get update \
|
|||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
definition-build.json
|
||||
.npmignore
|
||||
README.md
|
|
@ -0,0 +1,13 @@
|
|||
# Development Container Definitions
|
||||
|
||||
This folder contains a set of development container configuration files or "definitions" that are included with the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension. This list is presented when you open a folder in a container that does not already have a `.devcontainer.json` or `.devcontainer/devcontainer.json` file in it.
|
||||
|
||||
Each folder contains a README with more details on the contents of the definition and how to use it.
|
||||
|
||||
See [CONTRIBUTING.md](../CONTRIBUTING.md) for details on contributing to this repository.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the MIT License. See [LICENSE](https://github.com/Microsoft/vscode-dev-containers/blob/master/LICENSE)
|
|
@ -12,13 +12,19 @@ ARG USERNAME=vscode
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-alpine.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Install git, bash, dependencies, and add a non-root user
|
||||
RUN apk add --no-cache git bash libgcc libstdc++ \
|
||||
RUN apk update \
|
||||
&& apk add --no-cache wget coreutils ca-certificates \
|
||||
#
|
||||
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
|
||||
&& addgroup -g $USER_GID $USERNAME \
|
||||
&& adduser -S -s /bin/bash -u $USER_UID -G $USERNAME $USERNAME \
|
||||
# [Optional] Add sudo support for the non-root user
|
||||
&& apk add --no-cache sudo \
|
||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/ash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"build": {
|
||||
"rootDistro": "alpine",
|
||||
"tags": [
|
||||
"base:${VERSION}-alpine-3.10"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"image": "alpine:3.10",
|
||||
"imageLink": "https://hub.docker.com/_/alpine",
|
||||
"alpine": [
|
||||
"git",
|
||||
"bash",
|
||||
"libgcc",
|
||||
"libstdc++",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"procps",
|
||||
"coreutils",
|
||||
"ca-certificates",
|
||||
"krb5-libs",
|
||||
"libintl",
|
||||
"libssl1.1",
|
||||
"lttng-ust",
|
||||
"tzdata",
|
||||
"userspace-rcu",
|
||||
"zlib",
|
||||
"shadow",
|
||||
"sudo",
|
||||
"zsh"
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
WORKSPACE
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
||||
|
|
|
@ -15,20 +15,25 @@ ARG USERNAME=vscode
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
|
||||
#
|
||||
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
|
||||
&& apt-get -y install git iproute2 procps lsb-release \
|
||||
#
|
||||
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
|
||||
&& groupadd --gid $USER_GID $USERNAME \
|
||||
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
|
||||
# [Optional] Add sudo support for the non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"build": {
|
||||
"latest": true,
|
||||
"rootDistro": "debian",
|
||||
"tags": [
|
||||
"base:${VERSION}-debian-9",
|
||||
"base:${VERSION}-stretch"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"image": "debian:9",
|
||||
"imageLink": "https://hub.docker.com/_/debian",
|
||||
"debian": [
|
||||
"apt-utils",
|
||||
"dialog",
|
||||
"ca-certificates",
|
||||
"git",
|
||||
"iproute2",
|
||||
"procps",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"lsb-release",
|
||||
"apt-transport-https",
|
||||
"libc6",
|
||||
"libgcc1",
|
||||
"libgssapi-krb5-2",
|
||||
"libicu57",
|
||||
"liblttng-ust0",
|
||||
"libssl1.1",
|
||||
"libstdc++6",
|
||||
"zlib1g",
|
||||
"libssl1.0.2",
|
||||
"sudo",
|
||||
"zsh"
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
.ionide
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -16,7 +16,7 @@ ARG USER_GID=$USER_UID
|
|||
RUN groupadd --gid $USER_GID $USERNAME \
|
||||
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
|
||||
# [Optional] Add sudo support for the non-root user
|
||||
&& yum install -y sudo \
|
||||
&& yum install -y sudo \
|
||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -16,12 +16,25 @@ ARG USERNAME=node
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
|
||||
#
|
||||
# Verify git and needed tools are installed
|
||||
&& apt-get -y install git iproute2 procps \
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh \
|
||||
#
|
||||
# Remove outdated yarn from /opt and install via package
|
||||
# so it can be easily updated via apt-get upgrade yarn
|
||||
|
@ -37,17 +50,6 @@ RUN apt-get update \
|
|||
# Install eslint globally
|
||||
&& npm install -g eslint \
|
||||
#
|
||||
# [Optional] Update a non-root user to UID/GID if needed.
|
||||
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi \
|
||||
# [Optional] Add add sudo support for non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"build": {
|
||||
"rootDistro": "debian",
|
||||
"tags": [
|
||||
"javascript-node:${VERSION}-10"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"image": "node:10",
|
||||
"imageLink": "https://hub.docker.com/_/node",
|
||||
"debian": [
|
||||
"apt-utils",
|
||||
"dialog",
|
||||
"ca-certificates",
|
||||
"git",
|
||||
"iproute2",
|
||||
"procps",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"lsb-release",
|
||||
"apt-transport-https",
|
||||
"libc6",
|
||||
"libgcc1",
|
||||
"libgssapi-krb5-2",
|
||||
"libicu57",
|
||||
"libssl1.1",
|
||||
"libstdc++6",
|
||||
"zlib1g",
|
||||
"libssl1.0.2",
|
||||
"sudo",
|
||||
"yarn",
|
||||
"zsh"
|
||||
],
|
||||
"npm": [
|
||||
"eslint"
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -3,10 +3,7 @@
|
|||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM node:12
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12
|
||||
|
||||
# The node image includes a non-root user with sudo access. Use the
|
||||
# "remoteUser" property in devcontainer.json to use it. On Linux, update
|
||||
|
@ -16,42 +13,27 @@ ARG USERNAME=node
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
#
|
||||
# Verify git and needed tools are installed
|
||||
&& apt-get -y install git iproute2 procps \
|
||||
#
|
||||
# Remove outdated yarn from /opt and install via package
|
||||
# so it can be easily updated via apt-get upgrade yarn
|
||||
&& rm -rf /opt/yarn-* \
|
||||
&& rm -f /usr/local/bin/yarn \
|
||||
&& rm -f /usr/local/bin/yarnpkg \
|
||||
&& apt-get install -y curl apt-transport-https lsb-release \
|
||||
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
|
||||
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
|
||||
&& apt-get update \
|
||||
&& apt-get -y install --no-install-recommends yarn \
|
||||
#
|
||||
# Install eslint globally
|
||||
&& npm install -g eslint \
|
||||
#
|
||||
# [Optional] Update a non-root user to UID/GID if needed.
|
||||
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
# [Optional] Update UID/GID if needed
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi \
|
||||
# [Optional] Add add sudo support for non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& chmod -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
# *************************************************************
|
||||
# * Uncomment this section to use RUN instructions to install *
|
||||
# * any needed dependencies after executing "apt-get update". *
|
||||
# * See https://docs.docker.com/engine/reference/builder/#run *
|
||||
# *************************************************************
|
||||
# ENV DEBIAN_FRONTEND=noninteractive
|
||||
# RUN apt-get update \
|
||||
# && apt-get -y install --no-reccomends <your-package-list-here> \
|
||||
# #
|
||||
# # Clean up
|
||||
# && apt-get autoremove -y \
|
||||
# && apt-get clean -y \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
# ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM node:12
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12
|
||||
|
||||
# The node image includes a non-root user with sudo access. Use the
|
||||
# "remoteUser" property in devcontainer.json to use it. On Linux, update
|
||||
|
@ -16,42 +13,27 @@ ARG USERNAME=node
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
#
|
||||
# Verify git and needed tools are installed
|
||||
&& apt-get -y install git iproute2 procps \
|
||||
#
|
||||
# Remove outdated yarn from /opt and install via package
|
||||
# so it can be easily updated via apt-get upgrade yarn
|
||||
&& rm -rf /opt/yarn-* \
|
||||
&& rm -f /usr/local/bin/yarn \
|
||||
&& rm -f /usr/local/bin/yarnpkg \
|
||||
&& apt-get install -y curl apt-transport-https lsb-release \
|
||||
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
|
||||
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
|
||||
&& apt-get update \
|
||||
&& apt-get -y install --no-install-recommends yarn \
|
||||
#
|
||||
# Install eslint globally
|
||||
&& npm install -g eslint \
|
||||
#
|
||||
# [Optional] Update a non-root user to UID/GID if needed.
|
||||
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
# [Optional] Update UID/GID if needed
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi \
|
||||
# [Optional] Add add sudo support for non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& chmod -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
# *************************************************************
|
||||
# * Uncomment this section to use RUN instructions to install *
|
||||
# * any needed dependencies after executing "apt-get update". *
|
||||
# * See https://docs.docker.com/engine/reference/builder/#run *
|
||||
# *************************************************************
|
||||
# ENV DEBIAN_FRONTEND=noninteractive
|
||||
# RUN apt-get update \
|
||||
# && apt-get -y install --no-reccomends <your-package-list-here> \
|
||||
# #
|
||||
# # Clean up
|
||||
# && apt-get autoremove -y \
|
||||
# && apt-get clean -y \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
# ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -16,12 +16,25 @@ ARG USERNAME=node
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
|
||||
#
|
||||
# Verify git and needed tools are installed
|
||||
&& apt-get -y install git iproute2 procps \
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh \
|
||||
#
|
||||
# Remove outdated yarn from /opt and install via package
|
||||
# so it can be easily updated via apt-get upgrade yarn
|
||||
|
@ -37,17 +50,6 @@ RUN apt-get update \
|
|||
# Install eslint globally
|
||||
&& npm install -g eslint \
|
||||
#
|
||||
# [Optional] Update a non-root user to UID/GID if needed.
|
||||
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi \
|
||||
# [Optional] Add add sudo support for non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"build": {
|
||||
"latest": true,
|
||||
"rootDistro": "debian",
|
||||
"tags": [
|
||||
"javascript-node:${VERSION}-12"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"image": "node:12",
|
||||
"imageLink": "https://hub.docker.com/_/node",
|
||||
"debian": [
|
||||
"apt-utils",
|
||||
"dialog",
|
||||
"ca-certificates",
|
||||
"git",
|
||||
"iproute2",
|
||||
"procps",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"lsb-release",
|
||||
"apt-transport-https",
|
||||
"libc6",
|
||||
"libgcc1",
|
||||
"libgssapi-krb5-2",
|
||||
"libicu57",
|
||||
"libssl1.1",
|
||||
"libstdc++6",
|
||||
"zlib1g",
|
||||
"libssl1.0.2",
|
||||
"sudo",
|
||||
"yarn",
|
||||
"zsh"
|
||||
],
|
||||
"npm": [
|
||||
"eslint"
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
environment.yml
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
requirements.txt
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
Двоичные данные
containers/ruby-2-rails-5/.npmignore
Двоичные данные
containers/ruby-2-rails-5/.npmignore
Двоичный файл не отображается.
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
README.md
|
||||
.vscode
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
Cargo.lock
|
||||
Cargo.toml
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -3,55 +3,43 @@
|
|||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM node:10
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:10
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# The node image includes a non-root user with sudo access. Use the "remoteUser"
|
||||
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
|
||||
# will be updated to match your local UID/GID (when using the dockerFile property).
|
||||
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
# The javascript-node image includes a non-root node user with sudo access. Use
|
||||
# the "remoteUser" property in devcontainer.json to use it. On Linux, the container
|
||||
# user's GID/UIDs will be updated to match your local UID/GID when using the image
|
||||
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
|
||||
# dockerComposeFile property or want the image itself to start with different ID
|
||||
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
ARG USERNAME=node
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
#
|
||||
# Verify git and needed tools are installed
|
||||
&& apt-get -y install git iproute2 procps \
|
||||
#
|
||||
# Remove outdated yarn from /opt and install via package
|
||||
# so it can be easily updated via apt-get upgrade yarn
|
||||
&& rm -rf /opt/yarn-* \
|
||||
&& rm -f /usr/local/bin/yarn \
|
||||
&& rm -f /usr/local/bin/yarnpkg \
|
||||
&& apt-get install -y curl apt-transport-https lsb-release \
|
||||
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
|
||||
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
|
||||
&& apt-get update \
|
||||
&& apt-get -y install --no-install-recommends yarn \
|
||||
#
|
||||
# Install tslint and typescript globally
|
||||
&& npm install -g tslint eslint typescript \
|
||||
#
|
||||
# [Optional] Update a non-root user to UID/GID if needed.
|
||||
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
# Alter node user as needed, install tslint, typescript. eslint is installed by javascript image
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi \
|
||||
# [Optional] Add add sudo support for non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# Install tslint, typescript. eslint is installed by javascript image
|
||||
&& npm install -g tslint typescript
|
||||
|
||||
# *********************************************************************
|
||||
# * Uncomment this section to use RUN to install other dependencies. *
|
||||
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
|
||||
# *********************************************************************
|
||||
# ENV DEBIAN_FRONTEND=noninteractive
|
||||
# RUN apt-get update \
|
||||
# && apt-get -y install --no-reccomends <your-package-list-here> \
|
||||
# #
|
||||
# # Clean up
|
||||
# && apt-get autoremove -y \
|
||||
# && apt-get clean -y \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
# ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
||||
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"build": {
|
||||
"latest": true,
|
||||
"rootDistro": "debian",
|
||||
"parent": "javascript-node-10",
|
||||
"tags": [
|
||||
"typescript-node:${VERSION}-10"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"image": "node:10",
|
||||
"imageLink": "https://hub.docker.com/_/node",
|
||||
"debian": [
|
||||
"apt-utils",
|
||||
"dialog",
|
||||
"ca-certificates",
|
||||
"git",
|
||||
"iproute2",
|
||||
"procps",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"lsb-release",
|
||||
"apt-transport-https",
|
||||
"libc6",
|
||||
"libgcc1",
|
||||
"libgssapi-krb5-2",
|
||||
"libicu57",
|
||||
"libssl1.1",
|
||||
"libstdc++6",
|
||||
"zlib1g",
|
||||
"libssl1.0.2",
|
||||
"sudo",
|
||||
"yarn",
|
||||
"zsh"
|
||||
],
|
||||
"npm": [
|
||||
"eslint",
|
||||
"tslint",
|
||||
"typescript"
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
|
@ -3,55 +3,42 @@
|
|||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
FROM node:12
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# The node image includes a non-root user with sudo access. Use the "remoteUser"
|
||||
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
|
||||
# will be updated to match your local UID/GID (when using the dockerFile property).
|
||||
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
# The javascript-node image includes a non-root node user with sudo access. Use
|
||||
# the "remoteUser" property in devcontainer.json to use it. On Linux, the container
|
||||
# user's GID/UIDs will be updated to match your local UID/GID when using the image
|
||||
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
|
||||
# dockerComposeFile property or want the image itself to start with different ID
|
||||
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||
ARG USERNAME=node
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
#
|
||||
# Verify git and needed tools are installed
|
||||
&& apt-get -y install git iproute2 procps \
|
||||
#
|
||||
# Remove outdated yarn from /opt and install via package
|
||||
# so it can be easily updated via apt-get upgrade yarn
|
||||
&& rm -rf /opt/yarn-* \
|
||||
&& rm -f /usr/local/bin/yarn \
|
||||
&& rm -f /usr/local/bin/yarnpkg \
|
||||
&& apt-get install -y curl apt-transport-https lsb-release \
|
||||
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
|
||||
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
|
||||
&& apt-get update \
|
||||
&& apt-get -y install --no-install-recommends yarn \
|
||||
#
|
||||
# Install tslint and typescript globally
|
||||
&& npm install -g tslint eslint typescript \
|
||||
#
|
||||
# [Optional] Update a non-root user to UID/GID if needed.
|
||||
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
# Alter node user as needed, install tslint, typescript. eslint is installed by javascript image
|
||||
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
|
||||
groupmod --gid $USER_GID $USERNAME \
|
||||
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
|
||||
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
|
||||
fi \
|
||||
# [Optional] Add add sudo support for non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# Install tslint, typescript. eslint is installed by javascript image
|
||||
&& npm install -g tslint typescript
|
||||
|
||||
# *********************************************************************
|
||||
# * Uncomment this section to use RUN to install other dependencies. *
|
||||
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
|
||||
# *********************************************************************
|
||||
# ENV DEBIAN_FRONTEND=noninteractive
|
||||
# RUN apt-get update \
|
||||
# && apt-get -y install --no-reccomends <your-package-list-here> \
|
||||
# #
|
||||
# # Clean up
|
||||
# && apt-get autoremove -y \
|
||||
# && apt-get clean -y \
|
||||
# && rm -rf /var/lib/apt/lists/*
|
||||
# ENV DEBIAN_FRONTEND=dialog
|
||||
|
||||
# Uncomment to default to non-root user
|
||||
# USER $USER_UID
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"build": {
|
||||
"rootDistro": "debian",
|
||||
"parent": "javascript-node-12",
|
||||
"tags": [
|
||||
"typescript-node:${VERSION}-12"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"image": "node:12",
|
||||
"imageLink": "https://hub.docker.com/_/node",
|
||||
"debian": [
|
||||
"apt-utils",
|
||||
"dialog",
|
||||
"ca-certificates",
|
||||
"git",
|
||||
"iproute2",
|
||||
"procps",
|
||||
"curl",
|
||||
"wget",
|
||||
"unzip",
|
||||
"lsb-release",
|
||||
"apt-transport-https",
|
||||
"libc6",
|
||||
"libgcc1",
|
||||
"libgssapi-krb5-2",
|
||||
"libicu57",
|
||||
"libssl1.1",
|
||||
"libstdc++6",
|
||||
"zlib1g",
|
||||
"libssl1.0.2",
|
||||
"sudo",
|
||||
"yarn",
|
||||
"zsh"
|
||||
],
|
||||
"npm": [
|
||||
"eslint",
|
||||
"tslint",
|
||||
"typescript"
|
||||
],
|
||||
"manual": [
|
||||
{
|
||||
"Component": {
|
||||
"Type": "git",
|
||||
"git": {
|
||||
"Name": "Oh My Zsh!",
|
||||
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
|
||||
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
README.md
|
||||
test-project
|
||||
definition-build.json
|
||||
.vscode
|
||||
.npmignore
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||
#-------------------------------------------------------------------------------------------------------------
|
||||
FROM ubuntu:bionic
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
FROM ubuntu:18.04
|
||||
|
||||
# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
|
||||
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
|
||||
|
@ -15,20 +12,25 @@ ARG USERNAME=vscode
|
|||
ARG USER_UID=1000
|
||||
ARG USER_GID=$USER_UID
|
||||
|
||||
# Set to false to skip installing zsh and Oh My ZSH!
|
||||
ARG INSTALL_ZSH="true"
|
||||
|
||||
# Location and expected SHA for common setup script - SHA generated on release
|
||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
|
||||
# Avoid warnings by switching to noninteractive
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Configure apt and install packages
|
||||
RUN apt-get update \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
|
||||
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
|
||||
#
|
||||
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
|
||||
&& apt-get -y install git iproute2 procps lsb-release \
|
||||
#
|
||||
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
|
||||
&& groupadd --gid $USER_GID $USERNAME \
|
||||
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
|
||||
# [Optional] Add sudo support for the non-root user
|
||||
&& apt-get install -y sudo \
|
||||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
|
||||
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
|
||||
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
|
||||
&& /bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
|
||||
&& rm /tmp/common-setup.sh \
|
||||
#
|
||||
# Clean up
|
||||
&& apt-get autoremove -y \
|
||||
|
@ -36,4 +38,4 @@ RUN apt-get update \
|
|||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Switch back to dialog for any ad-hoc use of apt-get
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
ENV DEBIAN_FRONTEND=dialog
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче