Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[ContainerRegistry] Migrate samples to v2 workflow #14750

Merged
merged 6 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
18 changes: 13 additions & 5 deletions sdk/containerregistry/container-registry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
"audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit",
"build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1",
"build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1",
"build:samples": "dev-tool samples prep && cd dist-samples && tsc -p .",
"build:samples": "echo Obsolete.",
"build:test": "tsc -p . && rollup -c 2>&1",
"build": "tsc -p . && rollup -c 2>&1 && api-extractor run --local",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"clean": "rimraf dist dist-* test-dist temp types *.tgz *.log",
"docs": "typedoc --excludePrivate --excludeNotExported --excludeExternals --stripInternal --mode file --out ./dist/docs ./src",
"execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/dist-samples/typescript/src/",
"execute:samples": "dev-tool samples run samples-dev",
"extract-api": "tsc -p . && api-extractor run --local",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"generate:client": "autorest --typescript --v3 swagger",
"integration-test:browser": "echo skipped",
"integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 5000000 --full-trace \"dist-esm/test/{,!(browser)/**/}/*.spec.js\"",
Expand Down Expand Up @@ -125,6 +125,14 @@
"util": "^0.12.1"
},
"//sampleConfiguration": {
"skipFolder": true
"skipFolder": true,
"productName": "Azure Container Registry",
"productSlugs": [
"azure",
"azure-container-registry"
],
"requiredResources": {
"Azure Container Registry": "https://docs.microsoft.com/azure/container-registry/container-registry-get-started-portal"
}
}
}
3 changes: 2 additions & 1 deletion sdk/containerregistry/container-registry/sample.env
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Used in most samples. Retrieve these values from an instance in the Azure
# Portal.

# Retrieve this value from a Container Registry instance in the Azure Portal.
CONTAINER_REGISTRY_ENDPOINT: "<container registry REST API endpoint>",
REPOSITORY_NAME="Repository Name"
jeremymeng marked this conversation as resolved.
Show resolved Hide resolved

# Used to authenticate using Azure AD as a service principal for role-based
# authentication in the tokenAuth sample.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* @summary Demonstrates the use of a ContainerRegistryClient.
* @azsdk-weight 10
*/

import { ContainerRegistryClient } from "@azure/container-registry";
import { DefaultAzureCredential } from "@azure/identity";
import * as dotenv from "dotenv";
dotenv.config();

export async function main() {
// endpoint should be in the form of "https://myregistryname.azurecr.io"
// where "myregistryname" is the actual name of your registry
const endpoint = process.env.CONTAINER_REGISTRY_ENDPOINT || "<endpoint>";
const client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential());
await listRepositories(client);
await deleteRepository(client);
}

async function listRepositories(client: ContainerRegistryClient) {
console.log("Listing repositories");
const iterator = client.listRepositories();
for await (const repository of iterator) {
console.log(` repository: ${repository}`);
}

console.log(" by pages");
Copy link
Member

Choose a reason for hiding this comment

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

In .NET, iterating through the collection by pages -- rather than one element at a time and letting the client handle retrieving subsequent pages -- is a relatively advanced scenario and not something we distract customers with in our "getting started" documentation. I don't mind providing a sample for it, but I would make sure the sample indicated that this is relatively advanced, and not the "getting started" path.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's fair. I will extract it into a new method and add some comments

Copy link
Member

Choose a reason for hiding this comment

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

We do include paged iteration in some form or another in most package samples for packages that support it. For Form, we show how to do paged iteration of models. There, it is in a specific sample that we use to show methods of iterating over the models.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, in storage we also have separate samples iterators (because we have so many ways to use them). I will consider doing similar in next release.

Copy link
Member Author

Choose a reason for hiding this comment

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

Tracked in #14674

const pages = client.listRepositories().byPage({ maxPageSize: 2 });
let result = await pages.next();
while (!result.done) {
console.log(" -- page -- ");
for (const repository of result.value) {
console.log(` repository: ${repository}`);
}
result = await pages.next();
}
}

async function deleteRepository(client: ContainerRegistryClient) {
const response = await client.deleteRepository("hello-world");
console.log(
`Artifacts deleted: ${(response &&
response.deletedRegistryArtifactDigests &&
response.deletedRegistryArtifactDigests.length) ||
0}`
);
console.log(
`Tags deleted: ${(response &&
response.deletedRegistryArtifactDigests &&
response.deletedRegistryArtifactDigests.length) ||
0}`
);
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* @summary Demonstrates the use of a ContainerRepositoryClient.
* @azsdk-weight 5
*/

import { ContainerRepositoryClient, RegistryArtifactProperties } from "@azure/container-registry";
import { DefaultAzureCredential } from "@azure/identity";
import * as dotenv from "dotenv";
dotenv.config();

export async function main() {
// endpoint should be in the form of "https://myregistryname.azurecr.io"
// where "myregistryname" is the actual name of your registry
const endpoint = process.env.CONTAINER_REGISTRY_ENDPOINT || "<endpoint>";
const repository = process.env.REPOSITORY_NAME || "<repository name>";

const client = new ContainerRepositoryClient(endpoint, repository, new DefaultAzureCredential());
await getProperties(client);
await listTags(client);
const artifacts = await listArtifacts(client);
if (artifacts && artifacts.length) {
const digest = artifacts[0].digest;
if (digest) {
await getArtifactProperties(client, digest);

await deleteArtifact(client, digest);
}
}
}

async function listTags(client: ContainerRepositoryClient) {
console.log("Listing tags");
const iterator = client.listTags({ orderBy: "timeasc" });
for await (const tag of iterator) {
console.log(` tag: ${tag.name}`);
console.log(` digest: ${tag.digest}`);
console.log(` created on: ${tag.createdOn}`);
console.log(` last updated on: ${tag.lastUpdatedOn}`);
}

console.log(" by pages");
const pages = client.listTags().byPage({ maxPageSize: 2 });
Copy link
Member

Choose a reason for hiding this comment

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

See comment above re: byPage being advanced usage.

let result = await pages.next();
while (!result.done) {
console.log(" -- page -- ");
for (const tag of result.value) {
console.log(` tag: ${tag.name}`);
console.log(` digest: ${tag.digest}`);
console.log(` created on: ${tag.createdOn}`);
console.log(` last updated on: ${tag.lastUpdatedOn}`);
console.log("");
}
result = await pages.next();
}
}

async function listArtifacts(
client: ContainerRepositoryClient
): Promise<RegistryArtifactProperties[]> {
console.log("Listing artifacts");
const artifacts: RegistryArtifactProperties[] = [];
const iterator = client.listRegistryArtifacts();
for await (const artifact of iterator) {
artifacts.push(artifact);
console.log(` digest: ${artifact.digest}`);
console.log(` created on: ${artifact.createdOn}`);
console.log(` last updated on: ${artifact.lastUpdatedOn}`);
}

console.log(" by pages");
const pages = client.listRegistryArtifacts().byPage({ maxPageSize: 2 });
let result = await pages.next();
while (!result.done) {
console.log(" -- page -- ");
for (const artifact of result.value) {
console.log(` digest: ${artifact.digest}`);
console.log(` created on: ${artifact.createdOn}`);
console.log(` last updated on: ${artifact.lastUpdatedOn}`);
console.log("");
}
result = await pages.next();
}

return artifacts;
}

async function getProperties(client: ContainerRepositoryClient) {
console.log("Retrieving repository properties...");
const properties = await client.getProperties();
console.log(` name: ${properties.name}`);
console.log(` created on: ${properties.createdOn}`);
console.log(` last updated on: ${properties.lastUpdatedOn}`);
console.log(` artifact count: ${properties.registryArtifactCount}`);
console.log(` tag count: ${properties.tagCount}`);
const writableProps = properties.writeableProperties;
if (writableProps) {
console.log(" writable properties:");
console.log(
` { canDelete: ${writableProps.canDelete}, canList: ${writableProps.canList}, canRead: ${writableProps.canRead}, canWrite: ${writableProps.canWrite}}`
);
}
}

async function getArtifactProperties(client: ContainerRepositoryClient, digest: string) {
console.log(`Retrieving registry artifact properties for ${digest}`);
const properties = await client.getRegistryArtifactProperties(digest);
console.log(` created on: ${properties.createdOn}`);
console.log(` last updated on: ${properties.lastUpdatedOn}`);
console.log(` arch : ${properties.cpuArchitecture}`);
console.log(` os : ${properties.operatingSystem}`);
console.log(` size : ${properties.size} bytes`);
}

async function deleteArtifact(client: ContainerRepositoryClient, digest: string) {
console.log(`Deleting registry artifact for ${digest}`);
await client.deleteRegistryArtifact(digest);
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});

This file was deleted.

10 changes: 0 additions & 10 deletions sdk/containerregistry/container-registry/samples/tsconfig.json

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,45 +1,31 @@
<!-- The following YAML bit is needed by the docs system to publish the samples online. Uncomment/Update it when the samples can be published publically -->

## <!--

---
page_type: sample
languages:

- javascript
products:

# NOTE: You MUST use valid product slugs from the docs.microsoft.com taxonomy

# in this array. Please check to make sure that the items you enter into this

# list are valid! For example, "azure-template" is NOT a valid product slug

# and is provided here as an example only.

- azure
- azure-container-registry

# For urlFragment, use the base name of the package (not including the namespace)

# and append "-typescript" or "-javascript"

## urlFragment: container-registry-javascript

-->
- javascript
products:
- azure
- azure-container-registry
urlFragment: container-registry-javascript
---

# Azure Container Registry client library samples for JavaScript

These sample programs show how to use the JavaScript client libraries for Azure Container Registry in some common scenarios.

| **File Name** | **Description** |
| ----------------------------------------------------- | -------------------------------------------------- |
| [containerRegistryClient.js][containerregistryclient] | Demonstrates the use of a ContainerRegistryClient. |
| **File Name** | **Description** |
| --------------------------------------------------------- | ---------------------------------------------------- |
| [containerRegistryClient.js][containerregistryclient] | Demonstrates the use of a ContainerRegistryClient. |
| [containerRepositoryClient.js][containerrepositoryclient] | Demonstrates the use of a ContainerRepositoryClient. |

## Prerequisites

The samples are compatible with Node.js >= 8.0.0.
The sample programs are compatible with Node.js >=12.0.0.

You need [an Azure subscription][freesub] and the following Azure resources to run these sample programs:

- [Azure Container Registry][createinstance_azurecontainerregistry]

You need [an Azure subscription][freesub] to run these sample programs. Samples retrieve credentials to access the endpoint from environment variables. Alternatively, edit the source code to include the appropriate credentials. See each individual sample for details on which environment variables/credentials it requires to function.
Samples retrieve credentials to access the service endpoint from environment variables. Alternatively, edit the source code to include the appropriate credentials. See each individual sample for details on which environment variables/credentials it requires to function.

Adapting the samples to run in the browser may require some additional consideration. For details, please see the [package README][package].

Expand All @@ -61,17 +47,19 @@ npm install
node containerRegistryClient.js
```

Alternatively, run a single sample with the correct environment variables set (step 3 is not required if you do this), for example (cross-platform):
Alternatively, run a single sample with the correct environment variables set (setting up the `.env` file is not required if you do this), for example (cross-platform):

```bash
npx cross-env ENDPOINT="<endpoint>" API_KEY="<api key>" node containerRegistryClient.js
npx cross-env CONTAINER_REGISTRY_ENDPOINT="<container registry endpoint>" node containerRegistryClient.js
```

## Next Steps

Take a look at our [API Documentation][apiref] for more information about the APIs that are available in the clients.

[containerregistryclient]: https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/containerregistry/container-registry/samples/javascript/containerRegistryClient.js
[apiref]: https://docs.microsoft.com/javascript/api
[containerregistryclient]: https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/containerregistry/container-registry/samples/v1/javascript/containerRegistryClient.js
[containerrepositoryclient]: https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/containerregistry/container-registry/samples/v1/javascript/containerRepositoryClient.js
[apiref]: https://docs.microsoft.com/javascript/api/@azure/container-registry
[freesub]: https://azure.microsoft.com/free/
[createinstance_azurecontainerregistry]: https://docs.microsoft.com/azure/container-registry/container-registry-get-started-portal
[package]: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/containerregistry/container-registry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

const { ContainerRegistryClient } = require("@azure/container-registry");
const { DefaultAzureCredential } = require("@azure/identity");
require("dotenv").config();
const dotenv = require("dotenv");
dotenv.config();

async function main() {
const endpoint = process.env.ENDPOINT || "<endpoint>";

const endpoint = process.env.CONTAINER_REGISTRY_ENDPOINT || "<endpoint>";
const client = new ContainerRegistryClient(endpoint, new DefaultAzureCredential());
await listRepositories(client);
await deleteRepository(client);
Expand All @@ -38,14 +38,20 @@ async function listRepositories(client) {

async function deleteRepository(client) {
const response = await client.deleteRepository("hello-world");
console.log(`Artifacts deleted: ${response.deletedRegistryArtifactDigests.length || 0}`);
console.log(`Tags deleted: ${response.deletedRegistryArtifactDigests.length || 0}`);
console.log(
`Artifacts deleted: ${(response &&
response.deletedRegistryArtifactDigests &&
response.deletedRegistryArtifactDigests.length) ||
0}`
);
console.log(
`Tags deleted: ${(response &&
response.deletedRegistryArtifactDigests &&
response.deletedRegistryArtifactDigests.length) ||
0}`
);
}

main()
.then(() => {
console.log("Sample completes successfully.");
})
.catch((err) => {
console.error("The sample encountered an error:", err);
});
main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Loading