Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .config/cspell/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"msbuild",
"NOLOGO",
"packagejson",
"pcre",
"syncpack",
"unrs",
"muxer",
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/renovate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ permissions:
jobs:
renovate:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
feature: [dotnet, ripgrep]
steps:
- name: Checkout (GitHub)
uses: actions/checkout@v7
Expand All @@ -25,11 +29,11 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ github.token }}

- name: Refresh the dotnet config
- name: Refresh the ${{ matrix.feature }} config
uses: devcontainers/ci@v0.3
with:
cacheFrom: ghcr.io/${{ github.repository }}/devcontainer
push: never
runCmd: pnpm tsx scripts/tasks/features/dotnet/renovate.ts
runCmd: pnpm tsx scripts/tasks/features/${{ matrix.feature }}/renovate.ts
env: |
GH_TOKEN=${{ secrets.RENOVATE_TOKEN }}
134 changes: 134 additions & 0 deletions .github/workflows/ripgrep.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: "Ripgrep"

on:
pull_request:
paths:
- "features/ripgrep/config.json"
push:
branches:
- main
paths:
- "features/ripgrep/config.json"
workflow_dispatch:

permissions:
contents: read
packages: write

concurrency:
group: "ripgrep-${{ github.ref }}"
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
plan:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.plan.outputs.matrix }}
steps:
- name: Checkout (GitHub)
uses: actions/checkout@v7

- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}

- name: Plan the publishes
id: plan
uses: devcontainers/ci@v0.3
with:
cacheFrom: ghcr.io/${{ github.repository }}/devcontainer
push: never
runCmd: pnpm tsx scripts/tasks/features/ripgrep/planPublish.ts --channel "$CHANNEL"
env: |
CHANNEL=${{ github.head_ref || github.ref_name }}
GH_TOKEN=${{ github.token }}

image:
needs: plan
if: needs.plan.outputs.matrix != ''
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
steps:
- name: Checkout (GitHub)
uses: actions/checkout@v7

- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}

- name: Publish the image
uses: devcontainers/ci@v0.3
with:
cacheFrom: ghcr.io/${{ github.repository }}/devcontainer
push: never
runCmd: pnpm tsx scripts/tasks/features/ripgrep/publishImage.ts --version ${{ matrix.version }} --channel "$CHANNEL"
env: |
CHANNEL=${{ github.head_ref || github.ref_name }}
GH_TOKEN=${{ github.token }}

commit-tags:
needs:
- plan
- image
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.plan.result == 'success' && needs.image.result == 'success' && needs.plan.outputs.matrix != ''
permissions:
contents: write
packages: read
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
steps:
- name: Checkout (GitHub)
uses: actions/checkout@v7

- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}

- name: Tag the published version
uses: devcontainers/ci@v0.3
with:
cacheFrom: ghcr.io/${{ github.repository }}/devcontainer
push: never
runCmd: pnpm tsx scripts/tasks/features/ripgrep/tagPublished.ts --version ${{ matrix.version }}
env: |
GH_TOKEN=${{ github.token }}

verify:
needs:
- plan
- image
if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.image.result == 'success' || needs.image.result == 'skipped') }}
runs-on: ubuntu-latest
steps:
- name: Checkout (GitHub)
uses: actions/checkout@v7

- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}

- name: Verify the image
uses: devcontainers/ci@v0.3
with:
cacheFrom: ghcr.io/${{ github.repository }}/devcontainer
push: never
runCmd: pnpm verify ripgrep --images pull --channel "$CHANNEL"
env: |
CHANNEL=${{ github.head_ref || github.ref_name }}
GH_TOKEN=${{ github.token }}
9 changes: 9 additions & 0 deletions features/ripgrep/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM scratch AS linux-amd64-base
FROM scratch AS linux-arm64-base

ARG TARGETOS
ARG TARGETARCH
FROM ${TARGETOS}-${TARGETARCH}-base
ARG TARGETOS
ARG TARGETARCH
COPY ${TARGETOS}/${TARGETARCH}/features/ripgrep/ /features/ripgrep/
10 changes: 10 additions & 0 deletions features/ripgrep/NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Installed files

| Source | Destination | Mode |
| ------------------------------------- | ---------------------------------------------------- | ---- |
| `rg` | `/usr/local/bin/rg` | 0755 |
| `doc/rg.1` | `/usr/local/share/man/man1/rg.1` | 0644 |
| `complete/rg.bash` | `/usr/local/share/bash-completion/completions/rg` | 0644 |
| `complete/_rg` | `/usr/local/share/zsh/site-functions/_rg` | 0644 |
| `complete/rg.fish` | `/usr/local/share/fish/vendor_completions.d/rg.fish` | 0644 |
| `COPYING`, `LICENSE-MIT`, `UNLICENSE` | `/usr/local/share/doc/ripgrep/` | 0644 |
27 changes: 27 additions & 0 deletions features/ripgrep/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Ripgrep (ripgrep)

Installs the ripgrep line-oriented search tool.

## Example Usage

```dockerfile
FROM ghcr.io/devcontainer-config/features/ripgrep AS ripgrep

FROM base-image
COPY --from=ripgrep /features/ripgrep/ /opt/devcontainer-config/features/ripgrep/
```

## Installed files

| Source | Destination | Mode |
| ------------------------------------- | ---------------------------------------------------- | ---- |
| `rg` | `/usr/local/bin/rg` | 0755 |
| `doc/rg.1` | `/usr/local/share/man/man1/rg.1` | 0644 |
| `complete/rg.bash` | `/usr/local/share/bash-completion/completions/rg` | 0644 |
| `complete/_rg` | `/usr/local/share/zsh/site-functions/_rg` | 0644 |
| `complete/rg.fish` | `/usr/local/share/fish/vendor_completions.d/rg.fish` | 0644 |
| `COPYING`, `LICENSE-MIT`, `UNLICENSE` | `/usr/local/share/doc/ripgrep/` | 0644 |

---

_Note: This file was auto-generated from the [feature.json](https://github.com/devcontainer-config/features/blob/main/features/ripgrep/feature.json). Add additional notes to a `NOTES.md`._
16 changes: 16 additions & 0 deletions features/ripgrep/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"revision": 1,
"versions": {
"15.2.0": {
"aliases": ["15.2", "15", "latest"],
"x86_64-unknown-linux-musl": {
"url": "https://github.com/BurntSushi/ripgrep/releases/download/15.2.0/ripgrep-15.2.0-x86_64-unknown-linux-musl.tar.gz",
"sha256": "33e15bcf1624b25cdd2a55813a47a2f95dbe126268203e76aa6a585d1e7b149c"
},
"aarch64-unknown-linux-musl": {
"url": "https://github.com/BurntSushi/ripgrep/releases/download/15.2.0/ripgrep-15.2.0-aarch64-unknown-linux-musl.tar.gz",
"sha256": "800b1e7206afe799dfb5a6901f23147cfaabe0e52210538100f61e86e1740915"
}
}
}
}
6 changes: 6 additions & 0 deletions features/ripgrep/feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"id": "ripgrep",
"name": "Ripgrep",
"description": "Installs the ripgrep line-oriented search tool.",
"image": "ghcr.io/devcontainer-config/features/ripgrep"
}
20 changes: 20 additions & 0 deletions features/ripgrep/install
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh
set -e

mkdir -p /usr/local/bin
install -m 0755 rg /usr/local/bin/rg

mkdir -p /usr/local/share/man/man1
install -m 0644 doc/rg.1 /usr/local/share/man/man1/rg.1

mkdir -p /usr/local/share/bash-completion/completions
install -m 0644 complete/rg.bash /usr/local/share/bash-completion/completions/rg

mkdir -p /usr/local/share/zsh/site-functions
install -m 0644 complete/_rg /usr/local/share/zsh/site-functions/_rg

mkdir -p /usr/local/share/fish/vendor_completions.d
install -m 0644 complete/rg.fish /usr/local/share/fish/vendor_completions.d/rg.fish

mkdir -p /usr/local/share/doc/ripgrep
install -m 0644 COPYING LICENSE-MIT UNLICENSE /usr/local/share/doc/ripgrep/
3 changes: 2 additions & 1 deletion scripts/tasks/features/dotnet/buildImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import path from "node:path";
import { parseArgs } from "node:util";

import { $$ } from "@/scripts/shell.js";
import { defaultRefPrefix, mainChannel } from "@/scripts/tasks/features/tags.js";

import { assembleBuildContext } from "./buildContext.js";
import { readConfig } from "./generateConfig.js";
import { parseInvocation } from "./invocation.js";
import { ensurePackBinary } from "./packBinary.js";
import { paths } from "./paths.js";
import { defaultRefPrefix, imageRefs, mainChannel, tagNames } from "./tags.js";
import { imageRefs, tagNames } from "./tags.js";

const main = async (): Promise<void> => {
const { values } = parseArgs({
Expand Down
57 changes: 12 additions & 45 deletions scripts/tasks/features/dotnet/planPublish.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import { appendFile, mkdir, writeFile } from "node:fs/promises";
import path from "node:path";
import { parseArgs } from "node:util";

import { $ } from "execa";
import { planPublish } from "@/scripts/tasks/features/planPublish.js";
import { defaultRefPrefix, mainChannel } from "@/scripts/tasks/features/tags.js";

import type { Component } from "./generateConfig.js";
import { components, readConfig } from "./generateConfig.js";
import { login } from "./registry.js";
import { canonicalTag, defaultRefPrefix, imageRef, mainChannel, tagNames } from "./tags.js";

interface PlanEntry {
component: Component;
version: string;
}

const $$inspect = $({ reject: false, stdio: "ignore" });
import { canonicalTag, imageRef, tagNames } from "./tags.js";

const main = async (): Promise<void> => {
const { values } = parseArgs({
Expand All @@ -31,38 +21,15 @@ const main = async (): Promise<void> => {
const pairs = components.flatMap((component) =>
Object.keys(config.components[component].versions).map((version) => ({ component, version })),
);
const derived = pairs.map(({ component, version }) => ({
component,
version,
canonical: imageRef(prefix, component, canonicalTag(config, component, version, channel)),
tags: tagNames(config, component, version, channel),
}));

if (channel === mainChannel) {
await login(prefix);
}
const listed: PlanEntry[] = [];
for (const pair of derived) {
if (channel === mainChannel) {
const inspect = await $$inspect`docker buildx imagetools inspect ${pair.canonical}`;
if (inspect.exitCode === 0) {
console.log(`${pair.component} ${pair.version}: already published (${pair.canonical})`);
continue;
}
}
console.log(`${pair.component} ${pair.version}: to publish (${pair.tags.join(", ")})`);
listed.push({ component: pair.component, version: pair.version });
}

const plan = { include: listed };
const outPath = path.resolve(values.out);
await mkdir(path.dirname(outPath), { recursive: true });
await writeFile(outPath, `${JSON.stringify(plan, null, 2)}\n`);
const githubOutput = process.env.GITHUB_OUTPUT;
if (githubOutput !== undefined && githubOutput !== "") {
await appendFile(githubOutput, `matrix=${listed.length === 0 ? "" : JSON.stringify(plan)}\n`);
}
console.log(`${listed.length} of ${pairs.length} pairs to publish (${outPath})`);
await planPublish(
pairs.map(({ component, version }) => ({
label: `${component} ${version}`,
canonical: imageRef(prefix, component, canonicalTag(config, component, version, channel)),
tags: tagNames(config, component, version, channel),
entry: { component, version },
})),
{ channel, prefix, out: values.out },
);
};

if (import.meta.main) {
Expand Down
16 changes: 5 additions & 11 deletions scripts/tasks/features/dotnet/publishImage.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import path from "node:path";
import { parseArgs } from "node:util";

import { $$ } from "@/scripts/shell.js";
import { pushImage } from "@/scripts/tasks/features/image.js";
import { login } from "@/scripts/tasks/features/registry.js";
import { defaultRefPrefix, mainChannel } from "@/scripts/tasks/features/tags.js";

import { assembleBuildContext } from "./buildContext.js";
import { readConfig } from "./generateConfig.js";
import { resolveInstallBinaries } from "./installBinary.js";
import { parseComponent, parseVersion } from "./invocation.js";
import { paths } from "./paths.js";
import { ensurePayload } from "./payload.js";
import { login } from "./registry.js";
import { defaultRefPrefix, imageRefs, mainChannel, tagNames } from "./tags.js";
import { imageRefs, tagNames } from "./tags.js";

const main = async (): Promise<void> => {
const { values } = parseArgs({
Expand All @@ -36,13 +36,7 @@ const main = async (): Promise<void> => {
const context = await assembleBuildContext(component, version, installBinaries);
await login(prefix);
const refs = imageRefs(prefix, component, tags);
await $$`docker buildx build ${[
...["--platform", paths.dockerArchOptions.map((arch) => `linux/${arch}`).join(",")],
"--push",
...["--file", path.join(context, "docker", "Dockerfile")],
...refs.flatMap((ref) => ["--tag", ref]),
context,
]}`;
await pushImage(context, refs);
console.log(refs.join("\n"));
};

Expand Down
Loading
Loading